From 66181b3f47322ffc9b8aebf04a8c222abe1a75a2 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Mon, 25 Jan 2021 02:56:06 +0200 Subject: [PATCH] Make buffer storage immutable and use ARB_buffer_storage --- extensions/arb_buffer_storage.glext | 1 + source/buffer.cpp | 45 ++++++++++++++++++++++++++--- source/buffer.h | 15 +++++++--- source/bufferable.cpp | 4 ++- source/bufferable.h | 5 ++-- source/instancearray.cpp | 11 +++++-- source/mesh.cpp | 25 ++++++---------- source/programdata.cpp | 11 ++++++- 8 files changed, 85 insertions(+), 32 deletions(-) create mode 100644 extensions/arb_buffer_storage.glext diff --git a/extensions/arb_buffer_storage.glext b/extensions/arb_buffer_storage.glext new file mode 100644 index 00000000..aa03b2ad --- /dev/null +++ b/extensions/arb_buffer_storage.glext @@ -0,0 +1 @@ +extension ARB_buffer_storage diff --git a/source/buffer.cpp b/source/buffer.cpp index 35975f17..46afb273 100644 --- a/source/buffer.cpp +++ b/source/buffer.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -45,22 +46,58 @@ void Buffer::require_buffer_type(BufferType type) static Require _req_ubo(ARB_uniform_buffer_object); } +void Buffer::storage(unsigned sz) +{ + if(size>0) + throw invalid_operation("Buffer::storage"); + if(sz==0) + throw invalid_argument("Buffer::storage"); + + size = sz; + if(ARB_buffer_storage) + { + static const int flags = GL_MAP_READ_BIT|GL_MAP_WRITE_BIT|GL_DYNAMIC_STORAGE_BIT; + if(ARB_direct_state_access) + glNamedBufferStorage(id, size, 0, flags); + else + { + BindRestore _bind(this, type); + glBufferStorage(type, size, 0, flags); + } + } +} + void Buffer::set_usage(BufferUsage u) { // TODO OpenGL ES 2.0 doesn't support read or copy usages usage = u; } -void Buffer::data(unsigned sz, const void *d) +void Buffer::data(const void *d) { + if(size==0) + throw invalid_operation("Buffer::data"); + + if(ARB_buffer_storage) + return sub_data(0, size, d); + if(ARB_direct_state_access) - glNamedBufferData(id, sz, d, usage); + glNamedBufferData(id, size, d, usage); else { BindRestore _bind(this, type); - glBufferData(type, sz, d, usage); + glBufferData(type, size, d, usage); } - size = sz; +} + +void Buffer::data(unsigned sz, const void *d) +{ + if(size==0) + storage(sz); + else if(sz!=size) + throw incompatible_data("Buffer::data"); + + data(d); } void Buffer::sub_data(unsigned off, unsigned sz, const void *d) diff --git a/source/buffer.h b/source/buffer.h index 2961cdb3..b0f23ef2 100644 --- a/source/buffer.h +++ b/source/buffer.h @@ -83,16 +83,23 @@ public: /** Returns the default binding type for the buffer. */ BufferType get_type() const { return type; } + /** Defines the storage size of the buffer. Must be called before data can + be uploaded. Storage cannot be changed once set. */ + void storage(unsigned); + /** Sets the usage hint of the buffer. It will take effect the next time the buffer's contents are defined. */ DEPRECATED void set_usage(BufferUsage); /** Uploads data into the buffer, completely replacing any previous - contents. */ - void data(unsigned, const void *); + contents. Storage must be defined beforehand. The data must have size + matching the defined storage. */ + void data(const void *); + + DEPRECATED void data(unsigned, const void *); - /** Overwrites part of the buffer data with new data. The buffer size can - not be changed with this call. */ + /** Overwrites part of the buffer data with new data. Storage must be + defined beforehand. */ void sub_data(unsigned, unsigned, const void *); unsigned get_size() const { return size; } diff --git a/source/bufferable.cpp b/source/bufferable.cpp index fc0e3d21..4544c508 100644 --- a/source/bufferable.cpp +++ b/source/bufferable.cpp @@ -48,15 +48,17 @@ void Bufferable::use_buffer(Buffer *buf, Bufferable *prev) update_offset(); } -void Bufferable::buffer_resized() +void Bufferable::change_buffer(Buffer *buf) { for(Bufferable *b=this; b; b=b->next_in_buffer) { + b->buffer = buf; b->location_dirty = true; b->dirty = true; } for(Bufferable *b=prev_in_buffer; b; b=b->prev_in_buffer) { + b->buffer = buf; b->location_dirty = true; b->dirty = true; } diff --git a/source/bufferable.h b/source/bufferable.h index 86c5c77f..8e656246 100644 --- a/source/bufferable.h +++ b/source/bufferable.h @@ -45,9 +45,8 @@ public: buffer, and this object is inserted after it. */ void use_buffer(Buffer *buf, Bufferable *prev = 0); - /** Informs the objects in this chain that the buffer has been resized and - data should be reuploaded. */ - void buffer_resized(); + /** Sets the buffer for the entire chain of objects. */ + void change_buffer(Buffer *); /** Returns the total amount of storage required by this object and others in the same chain, including any alignment between objects. */ diff --git a/source/instancearray.cpp b/source/instancearray.cpp index 8fead4e9..abd9fcd0 100644 --- a/source/instancearray.cpp +++ b/source/instancearray.cpp @@ -78,9 +78,12 @@ void InstanceArray::append(ObjectInstance *inst) { instance_data->append(); unsigned req_size = instance_data->get_required_buffer_size(); - // XXX Inefficient, but will be rewritten imminently - if(instance_buffer->get_size()data(req_size, 0); + if(instance_buffer->get_size()>0 && instance_buffer->get_size()use_buffer(instance_buffer); + } } update_instance_matrix(instances.size()-1); } @@ -125,6 +128,8 @@ void InstanceArray::render(Renderer &renderer, const Tag &tag) const const Mesh *mesh = object.get_mesh(); mesh->get_vertices().refresh(); + if(instance_buffer->get_size()==0) + instance_buffer->storage(instance_data->get_required_buffer_size()); instance_data->refresh(); Renderer::Push push(renderer); diff --git a/source/mesh.cpp b/source/mesh.cpp index 3569e1c3..72936e66 100644 --- a/source/mesh.cpp +++ b/source/mesh.cpp @@ -54,35 +54,28 @@ void Mesh::check_buffers(unsigned mask) { if(mask&VERTEX_BUFFER) { - if(!vbuf) + unsigned req_size = vertices.get_required_buffer_size(); + if(!vbuf || (vbuf->get_size()>0 && vbuf->get_size()get_size()get_size()>0 && ibuf->get_size()get_size()data(vertices.get_required_buffer_size(), 0); + vbuf->storage(vertices.get_required_buffer_size()); if(dirty&INDEX_BUFFER) - ibuf->data(batches.front().get_required_buffer_size(), 0); + ibuf->storage(batches.front().get_required_buffer_size()); dirty = 0; } diff --git a/source/programdata.cpp b/source/programdata.cpp index 1589d9b0..4a6c262a 100644 --- a/source/programdata.cpp +++ b/source/programdata.cpp @@ -603,7 +603,16 @@ void ProgramData::apply() const { unsigned required_size = last_block->get_required_buffer_size(); if(last_block->get_required_buffer_size()>buffer->get_size()) - buffer->data(required_size, 0); + { + if(buffer->get_size()>0) + { + delete buffer; + buffer = new Buffer(UNIFORM_BUFFER); + last_block->change_buffer(buffer); + } + + buffer->storage(required_size); + } } } -- 2.45.2