mirror of
https://github.com/enduro2d/enduro2d.git
synced 2025-12-15 00:11:55 +07:00
Merge pull request #63 from enduro2d/feature/render_optimization
Feature/render optimization
This commit is contained in:
@@ -266,7 +266,7 @@ namespace e2d
|
||||
explicit index_buffer(internal_state_uptr);
|
||||
~index_buffer() noexcept;
|
||||
public:
|
||||
void update(const buffer& indices, std::size_t offset) noexcept;
|
||||
void update(buffer_view indices, std::size_t offset) noexcept;
|
||||
std::size_t buffer_size() const noexcept;
|
||||
std::size_t index_count() const noexcept;
|
||||
const index_declaration& decl() const noexcept;
|
||||
@@ -293,7 +293,7 @@ namespace e2d
|
||||
explicit vertex_buffer(internal_state_uptr);
|
||||
~vertex_buffer() noexcept;
|
||||
public:
|
||||
void update(const buffer& vertices, std::size_t offset) noexcept;
|
||||
void update(buffer_view vertices, std::size_t offset) noexcept;
|
||||
std::size_t buffer_size() const noexcept;
|
||||
std::size_t vertex_count() const noexcept;
|
||||
const vertex_declaration& decl() const noexcept;
|
||||
@@ -615,13 +615,49 @@ namespace e2d
|
||||
v2f, v3f, v4f,
|
||||
m2f, m3f, m4f>;
|
||||
|
||||
template < typename T >
|
||||
class property_map final {
|
||||
public:
|
||||
property_map() = default;
|
||||
|
||||
property_map(property_map&& other) = default;
|
||||
property_map& operator=(property_map&& other) = default;
|
||||
|
||||
property_map(const property_map& other) = default;
|
||||
property_map& operator=(const property_map& other) = default;
|
||||
|
||||
T* find(str_hash key) noexcept;
|
||||
const T* find(str_hash key) const noexcept;
|
||||
|
||||
void assign(str_hash key, T&& value);
|
||||
void assign(str_hash key, const T& value);
|
||||
|
||||
void clear() noexcept;
|
||||
std::size_t size() const noexcept;
|
||||
|
||||
template < typename F >
|
||||
void foreach(F&& f) const;
|
||||
void merge(const property_map& other);
|
||||
bool equals(const property_map& other) const noexcept;
|
||||
private:
|
||||
struct entry {
|
||||
str_hash key;
|
||||
T value;
|
||||
public:
|
||||
entry(str_hash k, T&& v);
|
||||
entry(str_hash k, const T& v);
|
||||
bool operator==(const entry& other) const;
|
||||
};
|
||||
vector<entry> entries_;
|
||||
};
|
||||
|
||||
class property_block final {
|
||||
public:
|
||||
property_block() = default;
|
||||
~property_block() noexcept = default;
|
||||
|
||||
property_block(property_block&&) noexcept = default;
|
||||
property_block& operator=(property_block&&) noexcept = default;
|
||||
property_block(property_block&&) = default;
|
||||
property_block& operator=(property_block&&) = default;
|
||||
|
||||
property_block(const property_block&) = default;
|
||||
property_block& operator=(const property_block&) = default;
|
||||
@@ -652,8 +688,8 @@ namespace e2d
|
||||
std::size_t sampler_count() const noexcept;
|
||||
std::size_t property_count() const noexcept;
|
||||
private:
|
||||
hash_map<str_hash, sampler_state> samplers_;
|
||||
hash_map<str_hash, property_value> properties_;
|
||||
property_map<sampler_state> samplers_;
|
||||
property_map<property_value> properties_;
|
||||
};
|
||||
|
||||
class pass_state final {
|
||||
@@ -890,12 +926,12 @@ namespace e2d
|
||||
const pixel_declaration& decl);
|
||||
|
||||
index_buffer_ptr create_index_buffer(
|
||||
const buffer& indices,
|
||||
buffer_view indices,
|
||||
const index_declaration& decl,
|
||||
index_buffer::usage usage);
|
||||
|
||||
vertex_buffer_ptr create_vertex_buffer(
|
||||
const buffer& vertices,
|
||||
buffer_view vertices,
|
||||
const vertex_declaration& decl,
|
||||
vertex_buffer::usage usage);
|
||||
|
||||
|
||||
@@ -75,36 +75,138 @@ namespace e2d
|
||||
|
||||
#undef DEFINE_ADD_ATTRIBUTE_SPECIALIZATION
|
||||
|
||||
//
|
||||
// render::property_map::entry
|
||||
//
|
||||
|
||||
template < typename T >
|
||||
render::property_map<T>::entry::entry(str_hash k, T&& v)
|
||||
: key(k), value(std::move(v)) {}
|
||||
|
||||
template < typename T >
|
||||
render::property_map<T>::entry::entry(str_hash k, const T& v)
|
||||
: key(k), value(v) {}
|
||||
|
||||
template < typename T >
|
||||
bool render::property_map<T>::entry::operator==(const entry& other) const {
|
||||
return key == other.key
|
||||
&& value == other.value;
|
||||
}
|
||||
|
||||
//
|
||||
// render::property_map
|
||||
//
|
||||
|
||||
template < typename T >
|
||||
T* render::property_map<T>::find(str_hash key) noexcept {
|
||||
const auto iter = std::lower_bound(
|
||||
entries_.begin(), entries_.end(), key,
|
||||
[](const entry& e, str_hash key){
|
||||
return e.key < key;
|
||||
});
|
||||
if ( iter != entries_.end() && iter->key == key ) {
|
||||
return &iter->value;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
const T* render::property_map<T>::find(str_hash key) const noexcept {
|
||||
const auto iter = std::lower_bound(
|
||||
entries_.begin(), entries_.end(), key,
|
||||
[](const entry& e, str_hash key){
|
||||
return e.key < key;
|
||||
});
|
||||
if ( iter != entries_.end() && iter->key == key ) {
|
||||
return &iter->value;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
void render::property_map<T>::assign(str_hash key, T&& value) {
|
||||
const auto iter = std::lower_bound(
|
||||
entries_.begin(), entries_.end(), key,
|
||||
[](const entry& e, str_hash key){
|
||||
return e.key < key;
|
||||
});
|
||||
if ( iter != entries_.end() && iter->key == key ) {
|
||||
iter->value = std::move(value);
|
||||
} else {
|
||||
entries_.emplace(iter, key, std::move(value));
|
||||
}
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
void render::property_map<T>::assign(str_hash key, const T& value) {
|
||||
const auto iter = std::lower_bound(
|
||||
entries_.begin(), entries_.end(), key,
|
||||
[](const entry& e, str_hash key){
|
||||
return e.key < key;
|
||||
});
|
||||
if ( iter != entries_.end() && iter->key == key ) {
|
||||
iter->value = value;
|
||||
} else {
|
||||
entries_.emplace(iter, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
void render::property_map<T>::clear() noexcept {
|
||||
entries_.clear();
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
std::size_t render::property_map<T>::size() const noexcept {
|
||||
return entries_.size();
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
template < typename F >
|
||||
void render::property_map<T>::foreach(F&& f) const {
|
||||
for ( std::size_t i = 0, e = entries_.size(); i < e; ++i ) {
|
||||
f(entries_[i].key, entries_[i].value);
|
||||
}
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
void render::property_map<T>::merge(const property_map& other) {
|
||||
other.foreach([this](str_hash name, const T& value){
|
||||
assign(name, value);
|
||||
});
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
bool render::property_map<T>::equals(const property_map& other) const noexcept {
|
||||
return entries_ == other.entries_;
|
||||
}
|
||||
|
||||
//
|
||||
// render::property_block
|
||||
//
|
||||
|
||||
template < typename T >
|
||||
render::property_block& render::property_block::property(str_hash name, T&& v) {
|
||||
properties_[name] = std::forward<T>(v);
|
||||
properties_.assign(name, std::forward<T>(v));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
const T* render::property_block::property(str_hash name) const noexcept {
|
||||
const auto iter = properties_.find(name);
|
||||
return iter != properties_.end()
|
||||
? stdex::get_if<T>(&iter->second)
|
||||
const property_value* prop = properties_.find(name);
|
||||
return prop
|
||||
? stdex::get_if<T>(prop)
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
template < typename F >
|
||||
void render::property_block::foreach_by_samplers(F&& f) const {
|
||||
for ( const auto& p : samplers_ ) {
|
||||
stdex::invoke(f, p.first, p.second);
|
||||
}
|
||||
samplers_.foreach(std::forward<F>(f));
|
||||
}
|
||||
|
||||
template < typename F >
|
||||
void render::property_block::foreach_by_properties(F&& f) const {
|
||||
for ( const auto& p : properties_ ) {
|
||||
stdex::invoke(f, p.first, p.second);
|
||||
}
|
||||
properties_.foreach(std::forward<F>(f));
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -17,8 +17,8 @@ namespace e2d
|
||||
sprite_renderer() = default;
|
||||
sprite_renderer(const sprite_asset::ptr& sprite);
|
||||
|
||||
sprite_renderer& tint(const color& value) noexcept;
|
||||
const color& tint() const noexcept;
|
||||
sprite_renderer& tint(const color32& value) noexcept;
|
||||
const color32& tint() const noexcept;
|
||||
|
||||
sprite_renderer& filtering(bool value) noexcept;
|
||||
bool filtering() const noexcept;
|
||||
@@ -26,7 +26,7 @@ namespace e2d
|
||||
sprite_renderer& sprite(const sprite_asset::ptr& value) noexcept;
|
||||
const sprite_asset::ptr& sprite() const noexcept;
|
||||
private:
|
||||
color tint_ = color::white();
|
||||
color32 tint_ = color32::white();
|
||||
bool filtering_ = true;
|
||||
sprite_asset::ptr sprite_;
|
||||
};
|
||||
@@ -37,12 +37,12 @@ namespace e2d
|
||||
inline sprite_renderer::sprite_renderer(const sprite_asset::ptr& sprite)
|
||||
: sprite_(sprite) {}
|
||||
|
||||
inline sprite_renderer& sprite_renderer::tint(const color& value) noexcept {
|
||||
inline sprite_renderer& sprite_renderer::tint(const color32& value) noexcept {
|
||||
tint_ = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline const color& sprite_renderer::tint() const noexcept {
|
||||
inline const color32& sprite_renderer::tint() const noexcept {
|
||||
return tint_;
|
||||
}
|
||||
|
||||
|
||||
@@ -517,7 +517,14 @@ namespace e2d { namespace math
|
||||
//
|
||||
|
||||
template < typename T >
|
||||
std::enable_if_t<std::is_arithmetic<T>::value, T>
|
||||
std::enable_if_t<std::is_integral<T>::value, T>
|
||||
mod(T x, T y) noexcept {
|
||||
E2D_ASSERT(y != T(0));
|
||||
return x % y;
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
std::enable_if_t<std::is_floating_point<T>::value, T>
|
||||
mod(T x, T y) noexcept {
|
||||
E2D_ASSERT(y != T(0));
|
||||
return std::fmod(x, y);
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
namespace e2d
|
||||
{
|
||||
class buffer;
|
||||
class buffer_view;
|
||||
class color;
|
||||
class color32;
|
||||
class image;
|
||||
|
||||
@@ -43,8 +43,63 @@ namespace e2d
|
||||
std::size_t size_ = 0;
|
||||
};
|
||||
|
||||
class buffer_view {
|
||||
public:
|
||||
buffer_view() noexcept = default;
|
||||
buffer_view(const buffer_view&) noexcept = default;
|
||||
buffer_view& operator=(const buffer_view&) noexcept = default;
|
||||
|
||||
buffer_view(std::nullptr_t) noexcept = delete;
|
||||
buffer_view(std::nullptr_t, std::size_t) noexcept = delete;
|
||||
|
||||
buffer_view(const void* data, std::size_t size) noexcept
|
||||
: data_(data)
|
||||
, size_(size){
|
||||
E2D_ASSERT(!size || data);
|
||||
}
|
||||
|
||||
buffer_view(const buffer& buffer) noexcept
|
||||
: data_(buffer.data())
|
||||
, size_(buffer.size()) {}
|
||||
|
||||
template < typename T >
|
||||
buffer_view(const vector<T>& buffer) noexcept
|
||||
: data_(buffer.data())
|
||||
, size_(buffer.size() * sizeof(T)) {}
|
||||
|
||||
template < typename T, std::size_t N >
|
||||
buffer_view(const array<T,N>& buffer) noexcept
|
||||
: data_(buffer.data())
|
||||
, size_(buffer.size() * sizeof(T)) {}
|
||||
|
||||
const void* data() const noexcept {
|
||||
return data_;
|
||||
}
|
||||
|
||||
std::size_t size() const noexcept {
|
||||
return size_;
|
||||
}
|
||||
|
||||
bool empty() const noexcept {
|
||||
return size_ == 0;
|
||||
}
|
||||
|
||||
void swap(buffer_view& other) noexcept {
|
||||
std::swap(data_, other.data_);
|
||||
std::swap(size_, other.size_);
|
||||
}
|
||||
private:
|
||||
const void* data_ = nullptr;
|
||||
std::size_t size_ = 0;
|
||||
};
|
||||
|
||||
void swap(buffer& l, buffer& r) noexcept;
|
||||
bool operator<(const buffer& l, const buffer& r) noexcept;
|
||||
bool operator==(const buffer& l, const buffer& r) noexcept;
|
||||
bool operator!=(const buffer& l, const buffer& r) noexcept;
|
||||
|
||||
void swap(buffer_view& l, buffer_view& r) noexcept;
|
||||
bool operator<(const buffer_view& l, const buffer_view& r) noexcept;
|
||||
bool operator==(const buffer_view& l, const buffer_view& r) noexcept;
|
||||
bool operator!=(const buffer_view& l, const buffer_view& r) noexcept;
|
||||
}
|
||||
|
||||
@@ -114,19 +114,19 @@ namespace
|
||||
|
||||
const auto indices = generate_quad_indices();
|
||||
index_buffer_ = the<render>().create_index_buffer(
|
||||
buffer(indices.data(), indices.size() * sizeof(indices[0])),
|
||||
indices,
|
||||
index_declaration::index_type::unsigned_byte,
|
||||
index_buffer::usage::static_draw);
|
||||
|
||||
const auto vertices1 = generate_quad_vertices(texture1_->size());
|
||||
vertex_buffer1_ = the<render>().create_vertex_buffer(
|
||||
buffer(vertices1.data(), vertices1.size() * sizeof(vertices1[0])),
|
||||
vertices1,
|
||||
vertex1::decl(),
|
||||
vertex_buffer::usage::static_draw);
|
||||
|
||||
const auto vertices2 = generate_quad_colors();
|
||||
vertex_buffer2_ = the<render>().create_vertex_buffer(
|
||||
buffer(vertices2.data(), vertices2.size() * sizeof(vertices2[0])),
|
||||
vertices2,
|
||||
vertex2::decl(),
|
||||
vertex_buffer::usage::static_draw);
|
||||
|
||||
|
||||
@@ -173,19 +173,19 @@ namespace
|
||||
|
||||
const auto indices = generate_cube_indices();
|
||||
index_buffer_ = the<render>().create_index_buffer(
|
||||
buffer(indices.data(), indices.size() * sizeof(indices[0])),
|
||||
indices,
|
||||
index_declaration::index_type::unsigned_byte,
|
||||
index_buffer::usage::static_draw);
|
||||
|
||||
const auto vertices1 = generate_cube_vertices(make_vec3(1.f));
|
||||
vertex_buffer1_ = the<render>().create_vertex_buffer(
|
||||
buffer(vertices1.data(), vertices1.size() * sizeof(vertices1[0])),
|
||||
vertices1,
|
||||
vertex1::decl(),
|
||||
vertex_buffer::usage::static_draw);
|
||||
|
||||
const auto vertices2 = generate_cube_colors();
|
||||
vertex_buffer2_ = the<render>().create_vertex_buffer(
|
||||
buffer(vertices2.data(), vertices2.size() * sizeof(vertices2[0])),
|
||||
vertices2,
|
||||
vertex2::decl(),
|
||||
vertex_buffer::usage::static_draw);
|
||||
|
||||
|
||||
@@ -128,13 +128,13 @@ namespace
|
||||
|
||||
const auto indices = generate_cube_indices();
|
||||
index_buffer_ = the<render>().create_index_buffer(
|
||||
buffer(indices.data(), indices.size() * sizeof(indices[0])),
|
||||
indices,
|
||||
index_declaration::index_type::unsigned_byte,
|
||||
index_buffer::usage::static_draw);
|
||||
|
||||
const auto vertices = generate_cube_vertices(make_vec3(1.f));
|
||||
vertex_buffer_ = the<render>().create_vertex_buffer(
|
||||
buffer(vertices.data(), vertices.size() * sizeof(vertices[0])),
|
||||
vertices,
|
||||
vertex::decl(),
|
||||
vertex_buffer::usage::static_draw);
|
||||
|
||||
|
||||
@@ -158,13 +158,13 @@ namespace e2d
|
||||
for ( int i = 0; i < draw_data->CmdListsCount; ++i ) {
|
||||
const ImDrawList* cmd_list = draw_data->CmdLists[i];
|
||||
|
||||
update_index_buffer(
|
||||
update_index_buffer({
|
||||
cmd_list->IdxBuffer.Data,
|
||||
math::numeric_cast<std::size_t>(cmd_list->IdxBuffer.Size) * sizeof(ImDrawIdx));
|
||||
math::numeric_cast<std::size_t>(cmd_list->IdxBuffer.Size) * sizeof(ImDrawIdx)});
|
||||
|
||||
update_vertex_buffer(
|
||||
update_vertex_buffer({
|
||||
cmd_list->VtxBuffer.Data,
|
||||
math::numeric_cast<std::size_t>(cmd_list->VtxBuffer.Size) * sizeof(ImDrawVert));
|
||||
math::numeric_cast<std::size_t>(cmd_list->VtxBuffer.Size) * sizeof(ImDrawVert)});
|
||||
|
||||
const auto geometry = render::geometry()
|
||||
.indices(index_buffer_)
|
||||
@@ -301,19 +301,19 @@ namespace e2d
|
||||
return math::max(osize * 2u, nsize);
|
||||
}
|
||||
|
||||
void update_index_buffer(const void* indices, std::size_t size) {
|
||||
if ( index_buffer_ && index_buffer_->buffer_size() >= size ) {
|
||||
index_buffer_->update(buffer(indices, size), 0);
|
||||
void update_index_buffer(buffer_view indices) {
|
||||
if ( index_buffer_ && index_buffer_->buffer_size() >= indices.size() ) {
|
||||
index_buffer_->update(indices, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
const std::size_t new_buffer_size = calculate_new_buffer_size(
|
||||
sizeof(ImDrawIdx),
|
||||
index_buffer_ ? index_buffer_->buffer_size() : 0u,
|
||||
size);
|
||||
indices.size());
|
||||
|
||||
buffer new_buffer_data(new_buffer_size);
|
||||
std::memcpy(new_buffer_data.data(), indices, size);
|
||||
std::memcpy(new_buffer_data.data(), indices.data(), indices.size());
|
||||
|
||||
index_buffer_ = render_.create_index_buffer(
|
||||
new_buffer_data,
|
||||
@@ -327,19 +327,19 @@ namespace e2d
|
||||
}
|
||||
}
|
||||
|
||||
void update_vertex_buffer(const void* vertices, std::size_t size) {
|
||||
if ( vertex_buffer_ && vertex_buffer_->buffer_size() >= size ) {
|
||||
vertex_buffer_->update(buffer(vertices, size), 0);
|
||||
void update_vertex_buffer(buffer_view vertices) {
|
||||
if ( vertex_buffer_ && vertex_buffer_->buffer_size() >= vertices.size() ) {
|
||||
vertex_buffer_->update(vertices, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
const std::size_t new_buffer_size = calculate_new_buffer_size(
|
||||
sizeof(ImDrawVert),
|
||||
vertex_buffer_ ? vertex_buffer_->buffer_size() : 0u,
|
||||
size);
|
||||
vertices.size());
|
||||
|
||||
buffer new_buffer_data(new_buffer_size);
|
||||
std::memcpy(new_buffer_data.data(), vertices, size);
|
||||
std::memcpy(new_buffer_data.data(), vertices.data(), vertices.size());
|
||||
|
||||
vertex_buffer_ = render_.create_vertex_buffer(
|
||||
new_buffer_data,
|
||||
|
||||
@@ -717,56 +717,46 @@ namespace e2d
|
||||
}
|
||||
|
||||
render::property_block& render::property_block::merge(const property_block& pb) {
|
||||
pb.foreach_by_properties([this](str_hash name, const property_value& v){
|
||||
property(name, v);
|
||||
});
|
||||
pb.foreach_by_samplers([this](str_hash name, const sampler_state& s){
|
||||
sampler(name, s);
|
||||
});
|
||||
properties_.merge(pb.properties_);
|
||||
samplers_.merge(pb.samplers_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool render::property_block::equals(const property_block& other) const noexcept {
|
||||
return properties_ == other.properties_
|
||||
&& samplers_ == other.samplers_;
|
||||
if ( properties_.size() != other.properties_.size() ) {
|
||||
return false;
|
||||
}
|
||||
if ( samplers_.size() != other.samplers_.size() ) {
|
||||
return false;
|
||||
}
|
||||
return properties_.equals(other.properties_)
|
||||
&& samplers_.equals(other.samplers_);
|
||||
}
|
||||
|
||||
render::property_block& render::property_block::sampler(str_hash name, const sampler_state& s) {
|
||||
samplers_[name] = s;
|
||||
samplers_.assign(name, s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
render::sampler_state* render::property_block::sampler(str_hash name) noexcept {
|
||||
const auto iter = samplers_.find(name);
|
||||
return iter != samplers_.end()
|
||||
? &iter->second
|
||||
: nullptr;
|
||||
return samplers_.find(name);
|
||||
}
|
||||
|
||||
const render::sampler_state* render::property_block::sampler(str_hash name) const noexcept {
|
||||
const auto iter = samplers_.find(name);
|
||||
return iter != samplers_.end()
|
||||
? &iter->second
|
||||
: nullptr;
|
||||
return samplers_.find(name);
|
||||
}
|
||||
|
||||
render::property_block& render::property_block::property(str_hash name, const property_value& v) {
|
||||
properties_[name] = v;
|
||||
properties_.assign(name, v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
render::property_value* render::property_block::property(str_hash name) noexcept {
|
||||
const auto iter = properties_.find(name);
|
||||
return iter != properties_.end()
|
||||
? &iter->second
|
||||
: nullptr;
|
||||
return properties_.find(name);
|
||||
}
|
||||
|
||||
const render::property_value* render::property_block::property(str_hash name) const noexcept {
|
||||
const auto iter = properties_.find(name);
|
||||
return iter != properties_.end()
|
||||
? &iter->second
|
||||
: nullptr;
|
||||
return properties_.find(name);
|
||||
}
|
||||
|
||||
std::size_t render::property_block::sampler_count() const noexcept {
|
||||
|
||||
@@ -121,7 +121,7 @@ namespace e2d
|
||||
: state_(std::move(state)) {}
|
||||
index_buffer::~index_buffer() noexcept = default;
|
||||
|
||||
void index_buffer::update(const buffer& indices, std::size_t offset) noexcept {
|
||||
void index_buffer::update(buffer_view indices, std::size_t offset) noexcept {
|
||||
E2D_UNUSED(indices, offset);
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ namespace e2d
|
||||
: state_(std::move(state)) {}
|
||||
vertex_buffer::~vertex_buffer() noexcept = default;
|
||||
|
||||
void vertex_buffer::update(const buffer& vertices, std::size_t offset) noexcept {
|
||||
void vertex_buffer::update(buffer_view vertices, std::size_t offset) noexcept {
|
||||
E2D_UNUSED(vertices, offset);
|
||||
}
|
||||
|
||||
@@ -212,7 +212,7 @@ namespace e2d
|
||||
}
|
||||
|
||||
index_buffer_ptr render::create_index_buffer(
|
||||
const buffer& indices,
|
||||
buffer_view indices,
|
||||
const index_declaration& decl,
|
||||
index_buffer::usage usage)
|
||||
{
|
||||
@@ -221,7 +221,7 @@ namespace e2d
|
||||
}
|
||||
|
||||
vertex_buffer_ptr render::create_vertex_buffer(
|
||||
const buffer& vertices,
|
||||
buffer_view vertices,
|
||||
const vertex_declaration& decl,
|
||||
vertex_buffer::usage usage)
|
||||
{
|
||||
|
||||
@@ -355,7 +355,7 @@ namespace e2d
|
||||
}
|
||||
index_buffer::~index_buffer() noexcept = default;
|
||||
|
||||
void index_buffer::update(const buffer& indices, std::size_t offset) noexcept {
|
||||
void index_buffer::update(buffer_view indices, std::size_t offset) noexcept {
|
||||
const std::size_t buffer_offset = offset * state_->decl().bytes_per_index();
|
||||
E2D_ASSERT(indices.size() + buffer_offset <= state_->size());
|
||||
E2D_ASSERT(indices.size() % state_->decl().bytes_per_index() == 0);
|
||||
@@ -396,7 +396,7 @@ namespace e2d
|
||||
}
|
||||
vertex_buffer::~vertex_buffer() noexcept = default;
|
||||
|
||||
void vertex_buffer::update(const buffer& vertices, std::size_t offset) noexcept {
|
||||
void vertex_buffer::update(buffer_view vertices, std::size_t offset) noexcept {
|
||||
const std::size_t buffer_offset = offset * state_->decl().bytes_per_vertex();
|
||||
E2D_ASSERT(vertices.size() + buffer_offset <= state_->size());
|
||||
E2D_ASSERT(vertices.size() % state_->decl().bytes_per_vertex() == 0);
|
||||
@@ -689,7 +689,7 @@ namespace e2d
|
||||
}
|
||||
|
||||
index_buffer_ptr render::create_index_buffer(
|
||||
const buffer& indices,
|
||||
buffer_view indices,
|
||||
const index_declaration& decl,
|
||||
index_buffer::usage usage)
|
||||
{
|
||||
@@ -725,7 +725,7 @@ namespace e2d
|
||||
}
|
||||
|
||||
vertex_buffer_ptr render::create_vertex_buffer(
|
||||
const buffer& vertices,
|
||||
buffer_view vertices,
|
||||
const vertex_declaration& decl,
|
||||
vertex_buffer::usage usage)
|
||||
{
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace
|
||||
}
|
||||
|
||||
const index_buffer_ptr index_buffer = render.create_index_buffer(
|
||||
buffer(indices.data(), indices.size() * sizeof(indices[0])),
|
||||
indices,
|
||||
index_declaration::index_type::unsigned_int,
|
||||
index_buffer::usage::static_draw);
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace
|
||||
{
|
||||
const vector<v3f>& vertices = mesh.vertices();
|
||||
const vertex_buffer_ptr vertex_buffer = render.create_vertex_buffer(
|
||||
buffer(vertices.data(), vertices.size() * sizeof(vertices[0])),
|
||||
vertices,
|
||||
vertex_buffer_decl,
|
||||
vertex_buffer::usage::static_draw);
|
||||
if ( vertex_buffer ) {
|
||||
@@ -80,7 +80,7 @@ namespace
|
||||
for ( std::size_t i = 0; i < uv_count; ++i ) {
|
||||
const vector<v2f>& uvs = mesh.uvs(i);
|
||||
const vertex_buffer_ptr uv_buffer = render.create_vertex_buffer(
|
||||
buffer(uvs.data(), uvs.size() * sizeof(uvs[0])),
|
||||
uvs,
|
||||
uv_buffer_decls[i],
|
||||
vertex_buffer::usage::static_draw);
|
||||
if ( uv_buffer ) {
|
||||
@@ -96,7 +96,7 @@ namespace
|
||||
for ( std::size_t i = 0; i < color_count; ++i ) {
|
||||
const vector<color32>& colors = mesh.colors(i);
|
||||
const vertex_buffer_ptr color_buffer = render.create_vertex_buffer(
|
||||
buffer(colors.data(), colors.size() * sizeof(colors[0])),
|
||||
colors,
|
||||
color_buffer_decls[i],
|
||||
vertex_buffer::usage::static_draw);
|
||||
if ( color_buffer ) {
|
||||
@@ -108,7 +108,7 @@ namespace
|
||||
{
|
||||
const vector<v3f>& normals = mesh.normals();
|
||||
const vertex_buffer_ptr normal_buffer = render.create_vertex_buffer(
|
||||
buffer(normals.data(), normals.size() * sizeof(normals[0])),
|
||||
normals,
|
||||
normal_buffer_decl,
|
||||
vertex_buffer::usage::static_draw);
|
||||
if ( normal_buffer ) {
|
||||
@@ -119,7 +119,7 @@ namespace
|
||||
{
|
||||
const vector<v3f>& tangents = mesh.tangents();
|
||||
const vertex_buffer_ptr tangent_buffer = render.create_vertex_buffer(
|
||||
buffer(tangents.data(), tangents.size() * sizeof(tangents[0])),
|
||||
tangents,
|
||||
tangent_buffer_decl,
|
||||
vertex_buffer::usage::static_draw);
|
||||
if ( tangent_buffer ) {
|
||||
@@ -130,7 +130,7 @@ namespace
|
||||
{
|
||||
const vector<v3f>& bitangents = mesh.bitangents();
|
||||
const vertex_buffer_ptr bitangent_buffer = render.create_vertex_buffer(
|
||||
buffer(bitangents.data(), bitangents.size() * sizeof(bitangents[0])),
|
||||
bitangents,
|
||||
bitangent_buffer_decl,
|
||||
vertex_buffer::usage::static_draw);
|
||||
if ( bitangent_buffer ) {
|
||||
|
||||
@@ -33,8 +33,8 @@ namespace e2d { namespace render_system_impl
|
||||
const index_type* indices, std::size_t index_count,
|
||||
const vertex_type* vertices, std::size_t vertex_count);
|
||||
|
||||
void flush();
|
||||
void clear() noexcept;
|
||||
render::property_block& flush();
|
||||
void clear(bool clear_internal_props) noexcept;
|
||||
private:
|
||||
void update_buffers_();
|
||||
void render_buffers_();
|
||||
@@ -65,6 +65,8 @@ namespace e2d { namespace render_system_impl
|
||||
vertex_declaration vertex_decl_;
|
||||
index_buffer_ptr index_buffer_;
|
||||
vertex_buffer_ptr vertex_buffer_;
|
||||
render::property_block property_cache_;
|
||||
render::property_block internal_properties_;
|
||||
private:
|
||||
static std::size_t calculate_new_buffer_size(
|
||||
std::size_t esize, std::size_t osize, std::size_t nsize);
|
||||
@@ -134,29 +136,33 @@ namespace e2d { namespace render_system_impl
|
||||
vertices_.end(),
|
||||
vertices, vertices + vertex_count);
|
||||
}
|
||||
} catch (...) {
|
||||
clear();
|
||||
} catch ( ... ) {
|
||||
clear(false);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template < typename Index, typename Vertex >
|
||||
void batcher<Index, Vertex>::flush() {
|
||||
render::property_block& batcher<Index, Vertex>::flush() {
|
||||
try {
|
||||
update_buffers_();
|
||||
render_buffers_();
|
||||
} catch (...) {
|
||||
clear();
|
||||
clear(false);
|
||||
throw;
|
||||
}
|
||||
clear();
|
||||
clear(false);
|
||||
return internal_properties_;
|
||||
}
|
||||
|
||||
template < typename Index, typename Vertex >
|
||||
void batcher<Index, Vertex>::clear() noexcept {
|
||||
void batcher<Index, Vertex>::clear(bool clear_internal_props) noexcept {
|
||||
batches_.clear();
|
||||
indices_.clear();
|
||||
vertices_.clear();
|
||||
if ( clear_internal_props ) {
|
||||
internal_properties_.clear();
|
||||
}
|
||||
}
|
||||
|
||||
template < typename Index, typename Vertex >
|
||||
@@ -175,18 +181,29 @@ namespace e2d { namespace render_system_impl
|
||||
.indices(index_buffer_)
|
||||
.add_vertices(vertex_buffer_);
|
||||
|
||||
for ( const batch_type& batch : batches_ ) {
|
||||
const render::material& mat = batch.material->content();
|
||||
render_.execute(render::draw_command(mat, geo, batch.properties)
|
||||
.index_range(batch.start, batch.count));
|
||||
try {
|
||||
for ( const batch_type& batch : batches_ ) {
|
||||
const render::material& mat = batch.material->content();
|
||||
render_.execute(render::draw_command(
|
||||
mat,
|
||||
geo,
|
||||
property_cache_
|
||||
.merge(internal_properties_)
|
||||
.merge(batch.properties)
|
||||
).index_range(batch.start, batch.count));
|
||||
}
|
||||
} catch ( ... ) {
|
||||
property_cache_.clear();
|
||||
throw;
|
||||
}
|
||||
property_cache_.clear();
|
||||
}
|
||||
|
||||
template < typename Index, typename Vertex >
|
||||
void batcher<Index, Vertex>::update_index_buffer_() {
|
||||
const std::size_t min_ib_size = indices_.size() * sizeof(indices_[0]);
|
||||
if ( index_buffer_ && index_buffer_->buffer_size() >= min_ib_size ) {
|
||||
index_buffer_->update(buffer(indices_.data(), min_ib_size), 0u);
|
||||
index_buffer_->update(indices_, 0u);
|
||||
} else {
|
||||
const std::size_t new_ib_size = calculate_new_buffer_size(
|
||||
sizeof(Index),
|
||||
@@ -213,7 +230,7 @@ namespace e2d { namespace render_system_impl
|
||||
void batcher<Index, Vertex>::update_vertex_buffer_() {
|
||||
const std::size_t min_vb_size = vertices_.size() * sizeof(vertices_[0]);
|
||||
if ( vertex_buffer_ && vertex_buffer_->buffer_size() >= min_vb_size ) {
|
||||
vertex_buffer_->update(buffer(vertices_.data(), min_vb_size), 0u);
|
||||
vertex_buffer_->update(vertices_, 0u);
|
||||
} else {
|
||||
const std::size_t new_vb_size = calculate_new_buffer_size(
|
||||
sizeof(Vertex),
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace e2d { namespace render_system_impl
|
||||
const m4f& m_v = cam_n ? cam_n->world_matrix() : m4f::identity();
|
||||
const m4f& m_p = cam.projection();
|
||||
|
||||
internal_properties_
|
||||
batcher_.flush()
|
||||
.property(matrix_v_property_hash, m_v)
|
||||
.property(matrix_p_property_hash, m_p)
|
||||
.property(matrix_vp_property_hash, m_v * m_p)
|
||||
@@ -52,6 +52,10 @@ namespace e2d { namespace render_system_impl
|
||||
.color_value(cam.background())));
|
||||
}
|
||||
|
||||
drawer::context::~context() noexcept {
|
||||
batcher_.clear(true);
|
||||
}
|
||||
|
||||
void drawer::context::draw(
|
||||
const const_node_iptr& node)
|
||||
{
|
||||
@@ -87,15 +91,14 @@ namespace e2d { namespace render_system_impl
|
||||
return;
|
||||
}
|
||||
|
||||
batcher_.flush();
|
||||
|
||||
const model& mdl = mdl_r.model()->content();
|
||||
const mesh& msh = mdl.mesh()->content();
|
||||
|
||||
try {
|
||||
property_cache_
|
||||
.merge(batcher_.flush())
|
||||
.property("u_matrix_m", node->world_matrix())
|
||||
.merge(internal_properties_);
|
||||
.merge(node_r.properties());
|
||||
|
||||
const std::size_t submesh_count = math::min(
|
||||
msh.indices_submesh_count(),
|
||||
@@ -161,7 +164,7 @@ namespace e2d { namespace render_system_impl
|
||||
const f32 th = tex_r.size.y / tex_s.y;
|
||||
|
||||
const m4f& sm = node->world_matrix();
|
||||
const color32 tc = color32(spr_r.tint());
|
||||
const color32& tc = spr_r.tint();
|
||||
|
||||
const batcher_type::index_type indices[] = {
|
||||
0u, 1u, 2u, 2u, 3u, 0u};
|
||||
@@ -181,15 +184,16 @@ namespace e2d { namespace render_system_impl
|
||||
: render::sampler_mag_filter::nearest;
|
||||
|
||||
try {
|
||||
property_cache_
|
||||
.sampler(sprite_texture_sampler_hash, render::sampler_state()
|
||||
.texture(tex_a->content())
|
||||
.min_filter(min_filter)
|
||||
.mag_filter(mag_filter))
|
||||
.merge(node_r.properties());
|
||||
|
||||
batcher_.batch(
|
||||
mat_a,
|
||||
property_cache_
|
||||
.sampler(sprite_texture_sampler_hash, render::sampler_state()
|
||||
.texture(tex_a->content())
|
||||
.min_filter(min_filter)
|
||||
.mag_filter(mag_filter))
|
||||
.merge(node_r.properties())
|
||||
.merge(internal_properties_),
|
||||
property_cache_,
|
||||
indices, E2D_COUNTOF(indices),
|
||||
vertices, E2D_COUNTOF(vertices));
|
||||
} catch (...) {
|
||||
|
||||
@@ -37,6 +37,7 @@ namespace e2d { namespace render_system_impl
|
||||
engine& engine,
|
||||
render& render,
|
||||
batcher_type& batcher);
|
||||
~context() noexcept;
|
||||
|
||||
void draw(
|
||||
const const_node_iptr& node);
|
||||
@@ -56,7 +57,6 @@ namespace e2d { namespace render_system_impl
|
||||
render& render_;
|
||||
batcher_type& batcher_;
|
||||
render::property_block property_cache_;
|
||||
render::property_block internal_properties_;
|
||||
};
|
||||
public:
|
||||
drawer(engine& e, debug& d, render& r);
|
||||
|
||||
@@ -138,4 +138,32 @@ namespace e2d
|
||||
bool operator!=(const buffer& l, const buffer& r) noexcept {
|
||||
return !(l == r);
|
||||
}
|
||||
|
||||
void swap(buffer_view& l, buffer_view& r) noexcept {
|
||||
l.swap(r);
|
||||
}
|
||||
|
||||
bool operator<(const buffer_view& l, const buffer_view& r) noexcept {
|
||||
const void* ld = l.data();
|
||||
const void* rd = r.data();
|
||||
const std::size_t ls = l.size();
|
||||
const std::size_t rs = r.size();
|
||||
return
|
||||
(ls < rs) ||
|
||||
(ls == rs && ls > 0 && std::memcmp(ld, rd, ls) < 0);
|
||||
}
|
||||
|
||||
bool operator==(const buffer_view& l, const buffer_view& r) noexcept {
|
||||
const void* ld = l.data();
|
||||
const void* rd = r.data();
|
||||
const std::size_t ls = l.size();
|
||||
const std::size_t rs = r.size();
|
||||
return
|
||||
(ls == rs) &&
|
||||
(ls == 0 || std::memcmp(ld, rd, ls) == 0);
|
||||
}
|
||||
|
||||
bool operator!=(const buffer_view& l, const buffer_view& r) noexcept {
|
||||
return !(l == r);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,3 +171,90 @@ TEST_CASE("buffer") {
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("buffer_view") {
|
||||
{
|
||||
buffer_view v0;
|
||||
REQUIRE(v0.data() == nullptr);
|
||||
REQUIRE(v0.size() == 0);
|
||||
REQUIRE(v0.empty());
|
||||
|
||||
const char* s = "hello";
|
||||
|
||||
buffer_view v1{s, 5};
|
||||
REQUIRE(v1.data() == s);
|
||||
REQUIRE(v1.size() == 5);
|
||||
REQUIRE_FALSE(v1.empty());
|
||||
|
||||
buffer_view v2{s, 3};
|
||||
REQUIRE(v2.data() == s);
|
||||
REQUIRE(v2.size() == 3);
|
||||
|
||||
buffer b0("hello", 5);
|
||||
buffer_view v3(b0);
|
||||
REQUIRE(v3.data() == b0.data());
|
||||
REQUIRE(v3.size() == 5);
|
||||
|
||||
vector<u16> b1{'h', 'e', 'l', 'l', 'o'};
|
||||
buffer_view v4(b1);
|
||||
REQUIRE(v4.data() == b1.data());
|
||||
REQUIRE(v4.size() == 10);
|
||||
|
||||
array<u32,5> b2{'h', 'e', 'l', 'l', 'o'};
|
||||
buffer_view v5(b2);
|
||||
REQUIRE(v5.data() == b2.data());
|
||||
REQUIRE(v5.size() == 20);
|
||||
}
|
||||
{
|
||||
const char* s0 = "hell";
|
||||
const char* s1 = "world";
|
||||
|
||||
buffer_view v0{s0, 4};
|
||||
buffer_view v1{s1, 5};
|
||||
v0.swap(v1);
|
||||
REQUIRE(v0.data() == s1);
|
||||
REQUIRE(v0.size() == 5);
|
||||
REQUIRE(v1.data() == s0);
|
||||
REQUIRE(v1.size() == 4);
|
||||
}
|
||||
{
|
||||
buffer_view v0{"hello", 5};
|
||||
buffer_view v1(v0);
|
||||
REQUIRE(v1.data() == v0.data());
|
||||
REQUIRE(v1.size() == 5);
|
||||
buffer_view v2;
|
||||
v2 = v1;
|
||||
REQUIRE(v2.data() == v0.data());
|
||||
REQUIRE(v2.size() == 5);
|
||||
}
|
||||
{
|
||||
REQUIRE_FALSE(buffer_view() < buffer_view());
|
||||
REQUIRE_FALSE(buffer_view("aa",2) < buffer_view("aa",2));
|
||||
|
||||
REQUIRE(buffer_view() < buffer_view("a",1));
|
||||
REQUIRE_FALSE(buffer_view("a",1) < buffer_view());
|
||||
|
||||
REQUIRE(buffer_view("aa",2) < buffer_view("ab",2));
|
||||
REQUIRE_FALSE(buffer_view("ab",2) < buffer_view("aa",2));
|
||||
|
||||
REQUIRE(buffer_view("aa",2) < buffer_view("aaa",3));
|
||||
REQUIRE(buffer_view("aa",2) < buffer_view("abb",3));
|
||||
REQUIRE_FALSE(buffer_view("aaa",3) < buffer_view("aa",2));
|
||||
REQUIRE_FALSE(buffer_view("abb",3) < buffer_view("aa",2));
|
||||
}
|
||||
{
|
||||
REQUIRE(buffer_view() == buffer_view());
|
||||
REQUIRE_FALSE(buffer_view() != buffer_view());
|
||||
|
||||
REQUIRE_FALSE(buffer_view() == buffer_view("hello",5));
|
||||
REQUIRE_FALSE(buffer_view("hello",5) == buffer_view());
|
||||
REQUIRE(buffer_view("hello",5) == buffer_view("hello",5));
|
||||
REQUIRE_FALSE(buffer_view("hello",5) != buffer_view("hello",5));
|
||||
|
||||
REQUIRE(buffer_view("hello",5) != buffer_view("world",5));
|
||||
REQUIRE_FALSE(buffer_view("hello",5) == buffer_view("world",5));
|
||||
|
||||
REQUIRE(buffer_view("hello",5) != buffer_view("hello, world",12));
|
||||
REQUIRE_FALSE(buffer_view("hello",5) == buffer_view("hello, world",12));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user