From 8eb9a8d90e5597154dab666481037b306b7bbca2 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sat, 25 Aug 2012 00:55:06 +0300 Subject: [PATCH] Construct uniform buffers for named uniform blocks --- source/buffer.h | 4 +-- source/programdata.cpp | 59 +++++++++++++++++++++++++++++++++++------ source/programdata.h | 6 ++++- source/uniform.h | 31 +++++++++++++++++++++- source/uniformblock.cpp | 41 +++++++++++++++++++++++++--- source/uniformblock.h | 18 +++++++++++-- 6 files changed, 141 insertions(+), 18 deletions(-) diff --git a/source/buffer.h b/source/buffer.h index bd3a999e..6f0a9708 100644 --- a/source/buffer.h +++ b/source/buffer.h @@ -33,8 +33,8 @@ class BufferRange; /** A buffer for storing data in GL memory. Putting vertex and index data in -buffers can improve rendering performance. The VertexArray and Mesh classes -contain built-in support for buffers. +buffers can improve rendering performance. The VertexArray, Mesh and +UniformBlock classes contain built-in support for buffers. */ class Buffer { diff --git a/source/programdata.cpp b/source/programdata.cpp index 5bfbd68f..04fdd6b8 100644 --- a/source/programdata.cpp +++ b/source/programdata.cpp @@ -1,3 +1,4 @@ +#include "buffer.h" #include "color.h" #include "error.h" #include "extension.h" @@ -14,6 +15,8 @@ namespace Msp { namespace GL { ProgramData::ProgramData(): + last_block(0), + buffer(0), modified(false) { static RequireExtension _ext("GL_ARB_shader_objects"); @@ -22,6 +25,8 @@ ProgramData::ProgramData(): // Blocks are intentionally left uncopied ProgramData::ProgramData(const ProgramData &other): uniforms(other.uniforms), + last_block(0), + buffer(0), modified(false) { for(UniformMap::iterator i=uniforms.begin(); i!=uniforms.end(); ++i) @@ -145,7 +150,7 @@ void ProgramData::uniform_matrix4_array(const string &name, unsigned n, const fl uniform(name, new UniformArray(n, v)); } -const UniformBlock &ProgramData::get_block(const Program &prog) const +const UniformBlock &ProgramData::get_block(const Program &prog, const string &name) const { if(modified) { @@ -154,23 +159,54 @@ const UniformBlock &ProgramData::get_block(const Program &prog) const modified = false; } - unsigned layout_hash = prog.get_uniform_layout_hash(); + const Program::UniformBlockInfo *info = 0; + unsigned layout_hash; + if(!name.empty()) + { + info = &prog.get_uniform_block_info(name); + layout_hash = info->layout_hash; + } + else + layout_hash = prog.get_uniform_layout_hash(); + map::iterator i = blocks.find(layout_hash); if(i==blocks.end()) { i = blocks.insert(BlockMap::value_type(layout_hash, Block())).first; i->second.dirty = true; - i->second.block = new UniformBlock; + if(info) + { + i->second.block = new UniformBlock(info->data_size); + if(!buffer) + buffer = new Buffer(UNIFORM_BUFFER); + i->second.block->use_buffer(buffer, last_block); + last_block = i->second.block; + } + else + i->second.block = new UniformBlock; } UniformBlock &block = *i->second.block; if(i->second.dirty) { - for(UniformMap::const_iterator j=uniforms.begin(); j!=uniforms.end(); ++j) + if(info) { - int loc = prog.get_uniform_location(j->first); - if(loc>=0) - block.attach(loc, *j->second); + for(vector::const_iterator j=info->uniforms.begin(); j!=info->uniforms.end(); ++j) + { + // XXX individual array elements + UniformMap::const_iterator k = uniforms.find((*j)->name); + if(k!=uniforms.end()) + block.attach(**j, *k->second); + } + } + else + { + for(UniformMap::const_iterator j=uniforms.begin(); j!=uniforms.end(); ++j) + { + int loc = prog.get_uniform_location(j->first); + if(loc>=0) + block.attach(loc, *j->second); + } } i->second.dirty = false; } @@ -184,7 +220,14 @@ void ProgramData::apply() const if(!prog) throw invalid_operation("ProgramData::apply"); - const UniformBlock &block = get_block(*prog); + const Program::UniformBlockMap &prog_blocks = prog->get_uniform_blocks(); + for(Program::UniformBlockMap::const_iterator i=prog_blocks.begin(); i!=prog_blocks.end(); ++i) + { + const UniformBlock &block = get_block(*prog, i->second.name); + block.apply(i->second.bind_point); + } + + const UniformBlock &block = get_block(*prog, string()); block.apply(-1); } diff --git a/source/programdata.h b/source/programdata.h index d74017b5..885804f0 100644 --- a/source/programdata.h +++ b/source/programdata.h @@ -7,6 +7,7 @@ namespace Msp { namespace GL { +class Buffer; class Color; class Matrix; class Program; @@ -45,8 +46,11 @@ private: typedef std::map UniformMap; typedef std::map BlockMap; + // XXX All these mutables are a bit silly, but I'm out of better ideas UniformMap uniforms; mutable BlockMap blocks; + mutable UniformBlock *last_block; + mutable Buffer *buffer; mutable bool modified; ProgramData &operator=(const ProgramData &); @@ -77,7 +81,7 @@ public: void uniform4_array(const std::string &, unsigned, const float *); void uniform_matrix4_array(const std::string &, unsigned, const float *); - const UniformBlock &get_block(const Program &) const; + const UniformBlock &get_block(const Program &, const std::string &) const; void apply() const; }; diff --git a/source/uniform.h b/source/uniform.h index 216d3be6..f8a59f2a 100644 --- a/source/uniform.h +++ b/source/uniform.h @@ -2,6 +2,7 @@ #define MSP_GL_UNIFORM_H_ #include +#include "program.h" namespace Msp { namespace GL { @@ -17,6 +18,7 @@ public: virtual ~Uniform() { } virtual void apply(int) const = 0; + virtual void store(const Program::UniformInfo &, void *) const = 0; virtual Uniform *clone() const = 0; }; @@ -39,6 +41,12 @@ public: static void apply(int, unsigned, const T *); + virtual void store(const Program::UniformInfo &info, void *buffer) const + { store(info, buffer, &value); } + + static void store(const Program::UniformInfo &, void *buffer, const T *value) + { *reinterpret_cast(buffer) = *value; } + virtual UniformScalar *clone() const { return new UniformScalar(value); } }; @@ -66,6 +74,12 @@ public: static void apply(int index, unsigned size, const T *value); + virtual void store(const Program::UniformInfo &info, void *buffer) const + { store(info, buffer, value); } + + static void store(const Program::UniformInfo &, void *buffer, const T *value) + { std::copy(value, value+vecsize, reinterpret_cast(buffer)); } + virtual UniformVector *clone() const { return new UniformVector(value); } }; @@ -94,6 +108,15 @@ public: static void apply(int index, unsigned size, const T *value); + virtual void store(const Program::UniformInfo &info, void *buffer) const + { store(info, buffer, value); } + + static void store(const Program::UniformInfo &info, void *buffer, const T *value) + { + for(unsigned i=0; i::store(info, reinterpret_cast(buffer)+i*info.matrix_stride, value+i*rows); + } + virtual UniformMatrix *clone() const { return new UniformMatrix(value); } }; @@ -106,6 +129,7 @@ class UniformArray: public Uniform { private: typedef typename T::BaseType BaseType; + enum { elemsize = sizeof(typename T::Type)/sizeof(typename T::BaseType) }; BaseType *values; unsigned size; @@ -114,7 +138,6 @@ public: UniformArray(unsigned n, const BaseType *vp): size(n) { - unsigned elemsize = sizeof(typename T::Type)/sizeof(typename T::BaseType); values = new BaseType[elemsize*size]; std::copy(vp, vp+elemsize*size, values); } @@ -122,6 +145,12 @@ public: virtual void apply(int index) const { T::apply(index, size, values); } + virtual void store(const Program::UniformInfo &info, void *buffer) const + { + for(unsigned i=0; i(buffer)+i*info.array_stride, values+i*elemsize); + } + virtual UniformArray *clone() const { return new UniformArray(size, values); } }; diff --git a/source/uniformblock.cpp b/source/uniformblock.cpp index 2ff00fa2..2b9a135c 100644 --- a/source/uniformblock.cpp +++ b/source/uniformblock.cpp @@ -1,5 +1,7 @@ #include +#include "buffer.h" #include "color.h" +#include "error.h" #include "matrix.h" #include "uniform.h" #include "uniformblock.h" @@ -10,18 +12,49 @@ using namespace std; namespace Msp { namespace GL { +UniformBlock::UniformBlock() +{ } + +UniformBlock::UniformBlock(unsigned s): + size(s), + data(size) +{ } + void UniformBlock::attach(int index, const Uniform &uni) { uniforms[index] = &uni; } +void UniformBlock::attach(const Program::UniformInfo &info, const Uniform &uni) +{ + uniforms[info.location] = &uni; + if(buffer) + { + uni.store(info, &data[info.location]); + dirty = true; + } +} + void UniformBlock::apply(int index) const { - if(index>=0) - throw logic_error("GL_ARB_uniform_buffer_object support not implemented yet"); + if((index>=0) != (buffer!=0)) + throw invalid_operation("UniformBlock::apply"); - for(map::const_iterator i=uniforms.begin(); i!=uniforms.end(); ++i) - i->second->apply(i->first); + if(buffer) + { + if(dirty) + { + update_buffer_data(); + if(!buf_range) + buf_range = new BufferRange(*buffer, buffer_offset, size); + } + buf_range->bind_to(UNIFORM_BUFFER, index); + } + else + { + for(map::const_iterator i=uniforms.begin(); i!=uniforms.end(); ++i) + i->second->apply(i->first); + } } } // namespace GL diff --git a/source/uniformblock.h b/source/uniformblock.h index 3a1cdb95..fbc9c704 100644 --- a/source/uniformblock.h +++ b/source/uniformblock.h @@ -2,27 +2,41 @@ #define MSP_GL_UNIFORMBLOCK_H_ #include +#include +#include "bufferable.h" +#include "program.h" namespace Msp { namespace GL { +class BufferRange; class Color; class Matrix; class Uniform; class Vector3; class Vector4; -class UniformBlock +class UniformBlock: public Bufferable { private: std::map uniforms; + unsigned size; + std::vector data; + mutable BufferRange *buf_range; UniformBlock(const UniformBlock &); UniformBlock &operator=(const UniformBlock &); public: - UniformBlock() { } + UniformBlock(); + UniformBlock(unsigned); +private: + virtual const void *get_data() const { return &data[0]; } + virtual unsigned get_data_size() const { return size; } + +public: void attach(int, const Uniform &); + void attach(const Program::UniformInfo &, const Uniform &); void apply(int) const; }; -- 2.45.2