Merge pull request #63 from enduro2d/feature/render_optimization

Feature/render optimization
This commit is contained in:
BlackMat MATov
2019-04-07 15:33:09 +07:00
committed by GitHub
19 changed files with 441 additions and 114 deletions

View File

@@ -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);

View File

@@ -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));
}
//

View File

@@ -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_;
}

View File

@@ -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);

View File

@@ -12,6 +12,7 @@
namespace e2d
{
class buffer;
class buffer_view;
class color;
class color32;
class image;

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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,

View File

@@ -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 {

View File

@@ -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)
{

View File

@@ -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)
{

View File

@@ -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 ) {

View File

@@ -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),

View File

@@ -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 (...) {

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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));
}
}