]> git.tdb.fi Git - libs/gl.git/commitdiff
Make buffer storage immutable and use ARB_buffer_storage
authorMikko Rasa <tdb@tdb.fi>
Mon, 25 Jan 2021 00:56:06 +0000 (02:56 +0200)
committerMikko Rasa <tdb@tdb.fi>
Mon, 25 Jan 2021 00:56:06 +0000 (02:56 +0200)
extensions/arb_buffer_storage.glext [new file with mode: 0644]
source/buffer.cpp
source/buffer.h
source/bufferable.cpp
source/bufferable.h
source/instancearray.cpp
source/mesh.cpp
source/programdata.cpp

diff --git a/extensions/arb_buffer_storage.glext b/extensions/arb_buffer_storage.glext
new file mode 100644 (file)
index 0000000..aa03b2a
--- /dev/null
@@ -0,0 +1 @@
+extension ARB_buffer_storage
index 35975f1712ed2973c10a926d55812a9efb1c2f3c..46afb273deacde9611ce29801de2684809f1927f 100644 (file)
@@ -1,4 +1,5 @@
 #include <stdexcept>
+#include <msp/gl/extensions/arb_buffer_storage.h>
 #include <msp/gl/extensions/arb_direct_state_access.h>
 #include <msp/gl/extensions/arb_map_buffer_range.h>
 #include <msp/strings/format.h>
@@ -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)
index 2961cdb315ae70802847e8b5e414e325f512aa4f..b0f23ef26cbbce70bc3a880fdfb85488e9995f7b 100644 (file)
@@ -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; }
index fc0e3d21a203972b29e65165a5d09dd33241ba09..4544c508cb072c4e47e02c357aab452d41e2a754 100644 (file)
@@ -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;
        }
index 86c5c77fc4d39226295c3e442903eb476e85de1b..8e656246f32dab7bebc307fac698e8c66fa57f88 100644 (file)
@@ -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. */
index 8fead4e907fb1e7dff900306ae8dca5367a1f280..abd9fcd0bd870d14def0192392490b09c702fa2d 100644 (file)
@@ -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()<req_size)
-                               instance_buffer->data(req_size, 0);
+                       if(instance_buffer->get_size()>0 && instance_buffer->get_size()<req_size)
+                       {
+                               delete instance_buffer;
+                               instance_buffer = new Buffer(ARRAY_BUFFER);
+                               instance_data->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);
index 3569e1c38badaac3a1f705769bfd4e6e625ff3e0..72936e66fb535a2e0020a896040221df2c60b777 100644 (file)
@@ -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()<req_size))
                {
+                       delete vbuf;
                        vbuf = new Buffer(ARRAY_BUFFER);
                        vertices.use_buffer(vbuf);
                        vtx_setup.set_vertex_array(vertices);
-               }
-               unsigned req_size = vertices.get_required_buffer_size();
-               if(vbuf->get_size()<req_size)
-               {
                        dirty |= VERTEX_BUFFER;
-                       vertices.buffer_resized();
                }
        }
 
        if(mask&INDEX_BUFFER)
        {
-               if(!ibuf)
+               unsigned req_size = (batches.empty() ? 0 : batches.front().get_required_buffer_size());
+               if(!ibuf || (ibuf->get_size()>0 && ibuf->get_size()<req_size))
                {
+                       delete ibuf;
                        ibuf = new Buffer(ELEMENT_ARRAY_BUFFER);
                        if(!batches.empty())
-                               batches.front().use_buffer(ibuf);
+                               batches.front().change_buffer(ibuf);
                        vtx_setup.set_index_buffer(*ibuf);
-               }
-               unsigned req_size = (batches.empty() ? 0 : batches.front().get_required_buffer_size());
-               if(ibuf->get_size()<req_size)
-               {
                        dirty |= INDEX_BUFFER;
-                       if(!batches.empty())
-                               batches.front().buffer_resized();
                }
        }
 }
@@ -182,9 +175,9 @@ void Mesh::draw(Renderer &renderer, const VertexSetup *vs, unsigned count) const
 void Mesh::resize_buffers() const
 {
        if(dirty&VERTEX_BUFFER)
-               vbuf->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;
 }
 
index 1589d9b0d44e00258d2457fc1f8acb0def28b23e..4a6c262a37a646bfd128f3cda4143ae5007e2a70 100644 (file)
@@ -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);
+                       }
                }
        }