]> git.tdb.fi Git - libs/gl.git/commitdiff
Support using storage blocks for rendering
authorMikko Rasa <tdb@tdb.fi>
Tue, 18 Jul 2023 08:28:40 +0000 (11:28 +0300)
committerMikko Rasa <tdb@tdb.fi>
Tue, 18 Jul 2023 08:31:37 +0000 (11:31 +0300)
20 files changed:
extensions/arb_program_interface_query.glext [new file with mode: 0644]
extensions/arb_shader_storage_buffer_object.glext [new file with mode: 0644]
source/backends/opengl/device_backend.cpp
source/backends/opengl/device_backend.h
source/backends/opengl/pipelinestate_backend.cpp
source/backends/opengl/program_backend.cpp
source/backends/opengl/program_backend.h
source/backends/vulkan/buffer_backend.cpp
source/backends/vulkan/pipelinestate_backend.cpp
source/backends/vulkan/program_backend.cpp
source/core/device.h
source/core/module.h
source/core/pipelinestate.cpp
source/core/pipelinestate.h
source/core/program.cpp
source/core/reflectdata.cpp
source/core/reflectdata.h
source/materials/programdata.cpp
source/render/renderer.cpp
source/render/renderer.h

diff --git a/extensions/arb_program_interface_query.glext b/extensions/arb_program_interface_query.glext
new file mode 100644 (file)
index 0000000..6939527
--- /dev/null
@@ -0,0 +1 @@
+extension ARB_program_interface_query
diff --git a/extensions/arb_shader_storage_buffer_object.glext b/extensions/arb_shader_storage_buffer_object.glext
new file mode 100644 (file)
index 0000000..87a0725
--- /dev/null
@@ -0,0 +1 @@
+extension ARB_shader_storage_buffer_object
index 0fcbe07212ccb93783af6e473a7177783d9b98b2..c13a7f0435babb82c6b715729c8c4f73587f467b 100644 (file)
@@ -4,6 +4,7 @@
 #include <msp/gl/extensions/arb_gpu_shader5.h>
 #include <msp/gl/extensions/arb_separate_shader_objects.h>
 #include <msp/gl/extensions/arb_shader_image_load_store.h>
+#include <msp/gl/extensions/arb_shader_storage_buffer_object.h>
 #include <msp/gl/extensions/arb_uniform_buffer_object.h>
 #include <msp/gl/extensions/arb_vertex_shader.h>
 #include <msp/gl/extensions/ext_framebuffer_multisample.h>
@@ -65,6 +66,8 @@ void OpenGLDevice::fill_info()
        }
        if(ARB_shader_image_load_store)
                glGetIntegerv(GL_MAX_IMAGE_UNITS, reinterpret_cast<int *>(&lim.max_storage_texture_bindings));
+       if(ARB_shader_storage_buffer_object)
+               glGetIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, reinterpret_cast<int *>(&lim.max_storage_buffer_bindings));
        if(EXT_framebuffer_object)
                glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, reinterpret_cast<int *>(&lim.max_color_attachments));
        if(EXT_framebuffer_multisample)
@@ -86,6 +89,7 @@ void OpenGLDevice::fill_info()
        feat.arb_gpu_shader5 = ARB_gpu_shader5;
        feat.arb_separate_shader_objects = ARB_separate_shader_objects;
        feat.arb_uniform_buffer_object = ARB_uniform_buffer_object;
+       feat.arb_shader_storage_buffer_object = ARB_shader_storage_buffer_object;
        feat.ext_gpu_shader4 = EXT_gpu_shader4;
        feat.ext_texture_array = EXT_texture_array;
        feat.uniform_binding_range = lim.max_uniform_bindings;
@@ -95,6 +99,7 @@ void OpenGLDevice::fill_info()
        state.bound_tex_targets.resize(lim.max_texture_bindings);
        state.bound_storage_textures.resize(lim.max_storage_texture_bindings);
        state.bound_uniform_blocks.resize(lim.max_uniform_bindings);
+       state.bound_storage_buffers.resize(lim.max_storage_buffer_bindings);
 }
 
 } // namespace GL
index cb945b726460e489086fc81b80ca4a41f31262f5..ea526e1a01bf9b571d7108d9873555b2bb18af92 100644 (file)
@@ -19,6 +19,7 @@ struct OpenGLDeviceState
        std::vector<int> bound_tex_targets;
        std::vector<char> bound_storage_textures;
        std::vector<char> bound_uniform_blocks;
+       std::vector<char> bound_storage_buffers;
        unsigned restart_index = 0;
        unsigned n_clip_distances = 0;
        const OpenGLBuffer *scratch_buffer = 0;
index da5f495712408926bde3f9445349b383009c819c..7c41bd364a17c9d672c4f244c1e5461e862eac0b 100644 (file)
@@ -2,6 +2,7 @@
 #include <msp/gl/extensions/arb_sampler_objects.h>
 #include <msp/gl/extensions/arb_shader_image_load_store.h>
 #include <msp/gl/extensions/arb_shader_objects.h>
+#include <msp/gl/extensions/arb_shader_storage_buffer_object.h>
 #include <msp/gl/extensions/arb_uniform_buffer_object.h>
 #include <msp/gl/extensions/arb_vertex_array_object.h>
 #include <msp/gl/extensions/arb_tessellation_shader.h>
@@ -130,6 +131,12 @@ void OpenGLPipelineState::apply() const
                                                        call.func(call.location, call.size, data+call.location*16);
                                        }
                                }
+                               else if(r.type==PipelineState::STORAGE_BLOCK)
+                               {
+                                       static Require _req(ARB_shader_storage_buffer_object);
+                                       glBindBufferBase(GL_SHADER_STORAGE_BUFFER, r.binding, r.buffer->id);
+                                       dev_state.bound_storage_buffers[r.binding] = 1;
+                               }
                                else if(r.type==PipelineState::SAMPLED_TEXTURE)
                                {
                                        if(ARB_direct_state_access)
@@ -301,6 +308,13 @@ void OpenGLPipelineState::clear()
                                dev_state.bound_uniform_blocks[i] = 0;
                        }
 
+               for(unsigned i=0; i<dev_state.bound_storage_buffers.size(); ++i)
+                       if(dev_state.bound_storage_buffers[i])
+                       {
+                               glBindBufferBase(GL_SHADER_STORAGE_BUFFER, i, 0);
+                               dev_state.bound_storage_buffers[i] = 0;
+                       }
+
                glDisable(GL_DEPTH_TEST);
                glDepthMask(true);
                glDisable(GL_STENCIL_TEST);
index 52d48c22699fd382ec90a5b649d7c6e3adf5fbbf..35e2230b3eeacf57b1a49c7ac5d9359fa3184540 100644 (file)
@@ -5,8 +5,10 @@
 #include <msp/gl/extensions/arb_fragment_shader.h>
 #include <msp/gl/extensions/arb_gl_spirv.h>
 #include <msp/gl/extensions/arb_geometry_shader4.h>
+#include <msp/gl/extensions/arb_program_interface_query.h>
 #include <msp/gl/extensions/arb_separate_shader_objects.h>
 #include <msp/gl/extensions/arb_shader_objects.h>
+#include <msp/gl/extensions/arb_shader_storage_buffer_object.h>
 #include <msp/gl/extensions/arb_uniform_buffer_object.h>
 #include <msp/gl/extensions/arb_tessellation_shader.h>
 #include <msp/gl/extensions/arb_vertex_shader.h>
@@ -160,6 +162,8 @@ void OpenGLProgram::add_glsl_stages(const GlslModule &mod, const map<string, int
        link(mod);
        query_uniforms();
        query_attributes();
+       if(ARB_shader_storage_buffer_object && ARB_program_interface_query)
+               query_storage_blocks();
        if(is_compute())
        {
                int wg_size[3];
@@ -170,12 +174,20 @@ void OpenGLProgram::add_glsl_stages(const GlslModule &mod, const map<string, int
        const map<string, unsigned> &block_bindings = compiler.get_uniform_block_bindings();
        if(!block_bindings.empty())
        {
+               int first_storage = -1;
                for(unsigned i=0; i<rd.blocks.size(); ++i)
                {
                        auto j = block_bindings.find(rd.blocks[i].name);
                        if(j!=block_bindings.end())
                        {
-                               glUniformBlockBinding(id, i, j->second);
+                               if(rd.blocks[i].is_storage())
+                               {
+                                       if(first_storage<0)
+                                               first_storage = i;
+                                       glShaderStorageBlockBinding(id, i-first_storage, j->second);
+                               }
+                               else
+                                       glUniformBlockBinding(id, i, j->second);
                                rd.blocks[i].bind_point = j->second;
                        }
                }
@@ -472,6 +484,30 @@ void OpenGLProgram::query_attributes()
        sort_member(rd.attributes, &ReflectData::AttributeInfo::name);
 }
 
+void OpenGLProgram::query_storage_blocks()
+{
+       ReflectData &rd = static_cast<Program *>(this)->reflect_data;
+
+       unsigned count = 0;
+       glGetProgramInterfaceiv(id, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, reinterpret_cast<int *>(&count));
+       rd.blocks.reserve(rd.blocks.size()+count);
+       for(unsigned i=0; i<count; ++i)
+       {
+               rd.blocks.emplace_back();
+               ReflectData::BlockInfo &info = rd.blocks.back();
+
+               char name[128];
+               int len;
+               glGetProgramResourceName(id, GL_SHADER_STORAGE_BLOCK, i, sizeof(name), &len, name);
+               info.tag = info.name.assign(name, len);
+
+               GLenum prop = GL_BUFFER_BINDING;
+               int value;
+               glGetProgramResourceiv(id, GL_SHADER_STORAGE_BLOCK, i, 1, &prop, 1, 0, &value);
+               info.bind_point = value;
+       }
+}
+
 void OpenGLProgram::finalize_uniforms()
 {
        ReflectData &rd = static_cast<Program *>(this)->reflect_data;
index 9f77afdfba06c066a24a32ae14bf935b1a46d481..3a4c3b439ed2f0f93654d823d6ae68a64e5706e8 100644 (file)
@@ -58,6 +58,7 @@ protected:
        void query_uniforms();
        void query_uniform_blocks(const std::vector<ReflectData::UniformInfo *> &);
        void query_attributes();
+       void query_storage_blocks();
        void finalize_uniforms();
 
        bool is_compute() const { return stage_ids[COMPUTE]; }
index bde76beaf8119b5985203b593117b0b799a2311b..e83ccdac1a54a863a618df20f6ad538490f936cf 100644 (file)
@@ -39,7 +39,7 @@ void VulkanBuffer::allocate()
        buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
        buffer_info.size = self.get_total_size();
        buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT|VK_BUFFER_USAGE_TRANSFER_DST_BIT|VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT|
-               VK_BUFFER_USAGE_INDEX_BUFFER_BIT|VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
+               VK_BUFFER_USAGE_STORAGE_BUFFER_BIT|VK_BUFFER_USAGE_INDEX_BUFFER_BIT|VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
        buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
 
        vk.CreateBuffer(buffer_info, handle);
index 1cd7d2d34eb14061ef879bce76a2ff5427df0991..dd3b8347ff15a5eaa9a5897ac0e58a10f088cb7e 100644 (file)
@@ -66,7 +66,7 @@ void VulkanPipelineState::update() const
                for(const PipelineState::BoundResource &r: self.resources)
                        if(r.changed || changed_sets==~0U)
                        {
-                               if(r.type==PipelineState::UNIFORM_BLOCK)
+                               if(r.type==PipelineState::UNIFORM_BLOCK || r.type==PipelineState::STORAGE_BLOCK)
                                        r.used = self.shprog->uses_block_binding(r.binding);
                                else if(r.type==PipelineState::SAMPLED_TEXTURE || r.type==PipelineState::STORAGE_TEXTURE)
                                {
@@ -336,6 +336,8 @@ uint64_t VulkanPipelineState::compute_descriptor_set_hash(unsigned index) const
                        result = hash_update<64>(result, reinterpret_cast<uintptr_t>(i->block));
                        result = hash_update<64>(result, reinterpret_cast<uintptr_t>(i->buffer->handle));
                }
+               else if(i->type==PipelineState::STORAGE_BLOCK)
+                       result = hash_update<64>(result, reinterpret_cast<uintptr_t>(i->buffer->handle));
                else if(i->type==PipelineState::SAMPLED_TEXTURE)
                {
                        result = hash_update<64>(result, reinterpret_cast<uintptr_t>(i->texture->handle));
@@ -359,7 +361,7 @@ bool VulkanPipelineState::is_descriptor_set_dynamic(unsigned index) const
 
        auto i = lower_bound_member(self.resources, static_cast<int>(index)<<20, &PipelineState::BoundResource::binding);
        for(; (i!=self.resources.end() && static_cast<unsigned>(i->binding)>>20==index); ++i)
-               if(i->used && i->type==PipelineState::UNIFORM_BLOCK && i->buffer->get_usage()==STREAMING)
+               if(i->used && (i->type==PipelineState::UNIFORM_BLOCK || i->type==PipelineState::STORAGE_BLOCK) && i->buffer->get_usage()==STREAMING)
                        return true;
 
        return false;
@@ -381,7 +383,7 @@ unsigned VulkanPipelineState::fill_descriptor_writes(unsigned index, unsigned fr
        for(auto i=begin; (i!=self.resources.end() && static_cast<unsigned>(i->binding)>>20==index); ++i)
                if(i->used)
                {
-                       if(i->type==PipelineState::UNIFORM_BLOCK)
+                       if(i->type==PipelineState::UNIFORM_BLOCK || i->type==PipelineState::STORAGE_BLOCK)
                                ++n_buffers;
                        else if(i->type==PipelineState::SAMPLED_TEXTURE || i->type==PipelineState::STORAGE_TEXTURE)
                                ++n_images;
@@ -402,18 +404,29 @@ unsigned VulkanPipelineState::fill_descriptor_writes(unsigned index, unsigned fr
                if(!i->used)
                        continue;
 
-               if(i->type==PipelineState::UNIFORM_BLOCK)
+               if(i->type==PipelineState::UNIFORM_BLOCK || i->type==PipelineState::STORAGE_BLOCK)
                {
                        buffer_ptr->buffer = handle_cast<::VkBuffer>(i->buffer->handle);
-                       buffer_ptr->offset = i->block->get_offset();
+                       if(i->block)
+                       {
+                               buffer_ptr->offset = i->block->get_offset();
+                               buffer_ptr->range = i->block->get_data_size();
+                       }
+                       else
+                       {
+                               buffer_ptr->offset = 0;
+                               buffer_ptr->range = i->buffer->get_size();
+                       }
                        if(i->buffer->get_usage()==STREAMING)
                                buffer_ptr->offset += frame*i->buffer->get_size();
-                       buffer_ptr->range = i->block->get_data_size();
 
                        write_ptr->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
                        write_ptr->dstBinding = i->binding&0xFFFFF;
                        write_ptr->descriptorCount = 1;
-                       write_ptr->descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+                       if(i->type==PipelineState::UNIFORM_BLOCK)
+                               write_ptr->descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+                       else if(i->type==PipelineState::STORAGE_BLOCK)
+                               write_ptr->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
                        write_ptr->pBufferInfo = buffer_ptr;
 
                        ++buffer_ptr;
index 8c2a5c3345f5090a8331bc08003c0f57ca48798e..73df3396b134d239428767ddd39dd7a795a90f65 100644 (file)
@@ -126,7 +126,10 @@ void VulkanProgram::finalize_uniforms()
                                bindings.emplace_back();
                                VkDescriptorSetLayoutBinding &binding = bindings.back();
                                binding.binding = b.bind_point&0xFFFFF;
-                               binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+                               if(b.is_storage())
+                                       binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+                               else
+                                       binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
                                binding.descriptorCount = 1;
                                binding.stageFlags = stage_flags;
                                binding.pImmutableSamplers = 0;
index b010baaaac93dcf4ff36384e1fbcf3fe702dfd2a..518a0d157a8fe9199c4ea4a5e413dee4fc3f0e86 100644 (file)
@@ -18,6 +18,7 @@ struct DeviceLimits
        unsigned max_vertex_attributes = 16;
        unsigned max_texture_bindings = 16;
        unsigned max_storage_texture_bindings = 8;
+       unsigned max_storage_buffer_bindings = 8;
        unsigned max_color_attachments = 8;
        unsigned max_samples = 4;
        unsigned max_uniform_bindings = 24;
index 3c11f9d4200bf5665780b01668ccccf1be26cc09..09d940761da8634dfd43b036451dd7842a1a5af4 100644 (file)
@@ -115,7 +115,8 @@ public:
                INPUT = 1,
                UNIFORM = 2,
                OUTPUT = 3,
-               PUSH_CONSTANT = 9
+               PUSH_CONSTANT = 9,
+               STORAGE_BUFFER = 12
        };
 
        enum BuiltinSemantic
index dd5b51a3d9e161218c0c96e1fba099a189fe3445..e971e36922ce9abf1fa5e0c5a277c43eace34734 100644 (file)
@@ -84,6 +84,11 @@ void PipelineState::set_uniform_block(int binding, const UniformBlock *block)
        }
 }
 
+void PipelineState::set_storage_block(unsigned binding, const Buffer *buffer)
+{
+       set_buffer_resource(binding, 0, buffer);
+}
+
 void PipelineState::set_texture(unsigned binding, const Texture *tex, const Sampler *samp)
 {
        set_texture(binding, tex, -1, samp);
@@ -104,6 +109,24 @@ void PipelineState::set_storage_texture(unsigned binding, const Texture *tex)
        set_texture_resource(binding, tex, 0, 0);
 }
 
+void PipelineState::set_buffer_resource(unsigned binding, const UniformBlock *block, const Buffer *buffer)
+{
+       auto i = lower_bound_member(resources, static_cast<int>(binding), &BoundResource::binding);
+       if(i==resources.end() || i->binding!=static_cast<int>(binding))
+               i = resources.insert(i, BoundResource(binding));
+
+       ResourceType type = (buffer ? block ? UNIFORM_BLOCK : STORAGE_BLOCK : NO_RESOURCE);
+       if(i->type!=type || block!=i->block || buffer!=i->buffer)
+       {
+               i->type = type;
+               i->block = block;
+               i->buffer = buffer;
+               i->changed = true;
+               i->used = buffer;
+               changes |= RESOURCES;
+       }
+}
+
 void PipelineState::set_texture_resource(unsigned binding, const Texture *tex, int level, const Sampler *samp)
 {
        auto i = lower_bound_member(resources, static_cast<int>(binding), &BoundResource::binding);
@@ -173,7 +196,7 @@ void PipelineState::check_bound_resources() const
                {
                        auto i = lower_bound_member(resources, b.bind_point, &PipelineState::BoundResource::binding);
                        if(i==resources.end() || i->binding!=b.bind_point)
-                               IO::print(IO::cerr, "Warning: No resource present for uniform block binding %d:%d (%s)\n", b.bind_point>>20, b.bind_point&0xFFFFF, b.name);
+                               IO::print(IO::cerr, "Warning: No resource present for block binding %d:%d (%s)\n", b.bind_point>>20, b.bind_point&0xFFFFF, b.name);
                }
 
        for(const ReflectData::UniformInfo &u: shprog->get_uniforms())
index a7c1c82f7376dde175a9e463b45d0cb7501d104a..4adc29d1238e3f7cb62d9365ca88ecc5d4aa27d7 100644 (file)
@@ -36,6 +36,7 @@ private:
        {
                NO_RESOURCE,
                UNIFORM_BLOCK,
+               STORAGE_BLOCK,
                SAMPLED_TEXTURE,
                STORAGE_TEXTURE
        };
@@ -103,10 +104,12 @@ public:
        void set_scissor(const Rect &);
        void set_shader_program(const Program *);
        void set_uniform_block(int, const UniformBlock *);
+       void set_storage_block(unsigned, const Buffer *);
        void set_texture(unsigned, const Texture *, const Sampler *);
        void set_texture(unsigned, const Texture *, int, const Sampler *);
        void set_storage_texture(unsigned, const Texture *);
 private:
+       void set_buffer_resource(unsigned, const UniformBlock *, const Buffer *);
        void set_texture_resource(unsigned, const Texture *, int, const Sampler *);
 public:
        void set_vertex_setup(const VertexSetup *);
index 54b58220e0946cd32d6a8e778f436497f2a77f8a..bbc420f8233861f7053e2f5619ec7ee5cc16122e 100644 (file)
@@ -80,12 +80,13 @@ void Program::collect_uniforms(const SpirVModule &mod)
 
        for(const SpirVModule::Variable &v: mod.get_variables())
        {
-               if((v.storage==SpirVModule::UNIFORM || v.storage==SpirVModule::PUSH_CONSTANT) && v.struct_type)
+               if((v.storage==SpirVModule::UNIFORM || v.storage==SpirVModule::PUSH_CONSTANT || v.storage==SpirVModule::STORAGE_BUFFER) && v.struct_type)
                {
                        reflect_data.blocks.emplace_back();
                        ReflectData::BlockInfo &info = reflect_data.blocks.back();
                        info.tag = info.name = v.struct_type->name;
-                       info.data_size = v.struct_type->size;
+                       if(v.storage!=SpirVModule::STORAGE_BUFFER)
+                               info.data_size = v.struct_type->size;
                        if(v.storage==SpirVModule::PUSH_CONSTANT)
                        {
                                info.bind_point = ReflectData::PUSH_CONSTANT;
@@ -100,11 +101,14 @@ void Program::collect_uniforms(const SpirVModule &mod)
                                reflect_data.n_descriptor_sets = max(reflect_data.n_descriptor_sets, v.descriptor_set+1);
                        }
 
-                       string prefix;
-                       if(!v.name.empty())
-                               prefix = v.struct_type->name+".";
                        block_uniform_names.emplace_back();
-                       collect_block_uniforms(*v.struct_type, prefix, 0, block_uniform_names.back());
+                       if(!info.is_storage())
+                       {
+                               string prefix;
+                               if(!v.name.empty())
+                                       prefix = v.struct_type->name+".";
+                               collect_block_uniforms(*v.struct_type, prefix, 0, block_uniform_names.back());
+                       }
                }
                else if(v.storage==SpirVModule::UNIFORM_CONSTANT && (v.location>=0 || v.binding>=0))
                {
index db583bf7c15fd4abac63b13784435f90733e56e4..be4f940027410ad2ea8ec004538948bdd589b597 100644 (file)
@@ -12,10 +12,11 @@ void ReflectData::update_layout_hash()
 {
        layout_hash = hash<32>(blocks.size());
        for(const BlockInfo &b: blocks)
-       {
-               layout_hash = hash_update<32>(layout_hash, b.bind_point);
-               layout_hash = hash_update<32>(layout_hash, b.layout_hash);
-       }
+               if(!b.is_storage())
+               {
+                       layout_hash = hash_update<32>(layout_hash, b.bind_point);
+                       layout_hash = hash_update<32>(layout_hash, b.layout_hash);
+               }
 }
 
 void ReflectData::update_used_bindings()
index 83b01671efc81965659ce4abb3a0defaee94cda4..5b913c4028b86eeda95fe9a381a0e50d6f511b34 100644 (file)
@@ -55,6 +55,7 @@ struct ReflectData
 
                void sort_uniforms();
                void update_layout_hash();
+               bool is_storage() const { return bind_point>=0 && !data_size; }
        };
 
        struct AttributeInfo
index 7a72e1c6480e74e64d0c085c35265eb33ed3478a..f0214666cbc3a0ff285e5f53952c23e2656adbc9 100644 (file)
@@ -470,8 +470,11 @@ vector<ProgramData::ProgramBlock>::iterator ProgramData::get_program(const Progr
                return i;
 
        const vector<ReflectData::BlockInfo> &block_infos = prog.get_blocks();
+       unsigned count = 0;
+       for(const ReflectData::BlockInfo &b: block_infos)
+               count += !b.is_storage();
        unsigned index = i-programs.begin();
-       programs.insert(i, 1+block_infos.size(), ProgramBlock(prog_hash));
+       programs.insert(i, 1+count, ProgramBlock(prog_hash));
 
        /* Block indices may change if new shared blocks need to be inserted.  Store
        the hashes so they can be matched up later. */
@@ -483,6 +486,9 @@ vector<ProgramData::ProgramBlock>::iterator ProgramData::get_program(const Progr
        unsigned j = index+1;
        for(const ReflectData::BlockInfo &b: block_infos)
        {
+               if(b.is_storage())
+                       continue;
+
                block_hashes[j] = b.layout_hash;
                programs[j].bind_point = b.bind_point;
                ++j;
@@ -631,6 +637,9 @@ vector<ProgramData::ProgramBlock>::const_iterator ProgramData::prepare_program(c
                        auto j = prog_begin+1;
                        for(const ReflectData::BlockInfo &b: block_infos)
                        {
+                               if(b.is_storage())
+                                       continue;
+
                                SharedBlock &shared = blocks[j->block_index];
                                if(shared.dirty==ALL_ONES)
                                        update_block_uniform_indices(shared, b);
@@ -645,6 +654,9 @@ vector<ProgramData::ProgramBlock>::const_iterator ProgramData::prepare_program(c
                auto j = prog_begin+1;
                for(const ReflectData::BlockInfo &b: block_infos)
                {
+                       if(b.is_storage())
+                               continue;
+
                        SharedBlock &shared = blocks[j->block_index];
                        if(shared.dirty)
                        {
index 34d18d0916ade96a62082fb991ad75f705d69d69..299cdb17d829fdc205172ab5a3ebb06dcc8de2a8 100644 (file)
@@ -160,6 +160,12 @@ void Renderer::add_shader_data(const ProgramData &d)
        changed |= SHADER_DATA;
 }
 
+void Renderer::set_storage_buffer(Tag tag, const Buffer *buf)
+{
+       State &state = get_state();
+       set_resource(buffer_stack, state.buffer_count, tag, buf);
+}
+
 void Renderer::set_texture(Tag tag, const Texture *tex, const Sampler *samp)
 {
        set_texture(tag, tex, -1, samp);
@@ -442,6 +448,15 @@ void Renderer::apply_state()
                        }
                }
 
+       for(const BoundResource<const Buffer *> &b: buffer_stack)
+               if(b.resource && b.replaced<0)
+               {
+                       if(b.binding<0 || shprog_changed)
+                               b.binding = state.shprog->get_block_binding(b.tag);
+                       if(b.binding>=0)
+                               ps.set_storage_block(b.binding, b.resource);
+               }
+
        static const DepthTest default_depth_test;
        ps.set_depth_test(state.depth_test ? *state.depth_test : default_depth_test);
        static const StencilTest default_stencil_test;
index 2d60a0c205cc6888f849535cbede1c5da6efcff6..e670cafa880dc18e67796cc04ccc28eb5637f996 100644 (file)
@@ -103,6 +103,7 @@ private:
                unsigned texture_count = 0;
                const Program *shprog = 0;
                unsigned shdata_count = 0;
+               unsigned buffer_count = 0;
                const VertexSetup *vertex_setup = 0;
                FaceWinding front_face = NON_MANIFOLD;
                CullMode face_cull = NO_CULL;
@@ -126,6 +127,7 @@ private:
        State *current_state = 0;
        ProgramData standard_shdata;
        std::vector<BoundProgramData> shdata_stack;
+       std::vector<BoundResource<const Buffer *>> buffer_stack;
        std::vector<BoundResource<SampledTexture>> texture_stack;
        const Texture &placeholder_texture;
        const Sampler &default_sampler;
@@ -195,6 +197,8 @@ public:
        last will be used. */
        void add_shader_data(const ProgramData &data);
 
+       void set_storage_buffer(Tag, const Buffer *);
+
        void set_texture(Tag, const Texture *, const Sampler * = 0);
        void set_texture(Tag, const Texture *, int, const Sampler * = 0);
        void set_storage_texture(Tag, const Texture *);