From 9846a5c6e73b3a146084894a11550dbbf184a22a Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Wed, 15 Aug 2012 22:36:33 +0300 Subject: [PATCH] Restructure ProgramData to support sharing between Programs This removes a major annoyance when dealing with ObjectInstances and shaders. It also paves way for Effects being able to provide uniforms, and support for GL_ARB_uniform_buffer_object. --- demos/cubemap.cpp | 2 +- demos/shaders.cpp | 10 +- source/ambientocclusion.cpp | 2 - source/animatedobject.cpp | 8 +- source/bloom.cpp | 11 +-- source/bloom.h | 3 +- source/programdata.cpp | 179 ++++++++++++++++-------------------- source/programdata.h | 37 ++++---- source/renderpass.cpp | 2 +- source/uniformblock.cpp | 113 +++++++++++++++++++++++ source/uniformblock.h | 50 ++++++++++ 11 files changed, 274 insertions(+), 143 deletions(-) create mode 100644 source/uniformblock.cpp create mode 100644 source/uniformblock.h diff --git a/demos/cubemap.cpp b/demos/cubemap.cpp index 4f663055..1778fb7f 100644 --- a/demos/cubemap.cpp +++ b/demos/cubemap.cpp @@ -90,7 +90,7 @@ int main() features.material = true; features.reflection = true; GL::Program shprog(features); - GL::ProgramData shdata(shprog); + GL::ProgramData shdata; shdata.uniform("environment", 0); shdata.uniform("reflectivity", 0.5f); diff --git a/demos/shaders.cpp b/demos/shaders.cpp index b7f2a196..ae5c98fb 100644 --- a/demos/shaders.cpp +++ b/demos/shaders.cpp @@ -65,7 +65,6 @@ int main() mat.set_specular(GL::Color(0.45, 0.5, 0.4)); mat.set_shininess(50); vector programs; - vector progdata; for(unsigned i=0; i<12; ++i) { GL::Program::StandardFeatures feat; @@ -80,13 +79,12 @@ int main() programs.back()->bind_attribute(4, "tangent"); programs.back()->bind_attribute(5, "binormal"); programs.back()->link(); - progdata.push_back(new GL::ProgramData(*programs.back())); - progdata.back()->uniform("normalmap", 1); } - else - progdata.push_back(0); } + GL::ProgramData progdata; + progdata.uniform("normalmap", 1); + GL::Lighting lighting; GL::Light light; light.set_position(GL::Vector4(0, 2, 3, 0)); @@ -117,7 +115,7 @@ int main() for(unsigned i=0; i<12; ++i) { GL::MatrixStack::Push push(renderer.matrix_stack()); - renderer.set_shader(programs[i], progdata[i]); + renderer.set_shader(programs[i], &progdata); renderer.matrix_stack() *= GL::Matrix::translation(-3.3+(i%4)*2.2, 0, -3.5+(i/4)*3.0); renderer.matrix_stack() *= GL::Matrix::rotation(angle, 0, 0, 1); mesh.draw(renderer); diff --git a/source/ambientocclusion.cpp b/source/ambientocclusion.cpp index 0cd3693b..a14d3508 100644 --- a/source/ambientocclusion.cpp +++ b/source/ambientocclusion.cpp @@ -75,9 +75,7 @@ namespace GL { AmbientOcclusion::AmbientOcclusion(unsigned w, unsigned h, float depth_ratio): occlude_shader(vertex_shader, occlude_fs), - occlude_shdata(occlude_shader), combine_shader(vertex_shader, combine_fs), - combine_shdata(combine_shader), quad(VERTEX2) { occlusion.storage(GL::RGB, w, h); diff --git a/source/animatedobject.cpp b/source/animatedobject.cpp index 0cc36786..08666633 100644 --- a/source/animatedobject.cpp +++ b/source/animatedobject.cpp @@ -13,12 +13,8 @@ AnimatedObject::AnimatedObject(const Object &o): shdata(0) { if(const Technique *tech = object.get_technique()) - { - // XXX Should create separate ProgramData for each pass - const RenderPass &pass = tech->get_pass(Tag()); - if(const Program *shprog = pass.get_shader_program()) - shdata = new ProgramData(*shprog); - } + if(tech->has_shaders()) + shdata = new ProgramData; } void AnimatedObject::set_matrix(const Matrix &m) diff --git a/source/bloom.cpp b/source/bloom.cpp index 76460b99..36cdb8dd 100644 --- a/source/bloom.cpp +++ b/source/bloom.cpp @@ -57,16 +57,11 @@ namespace GL { Bloom::Bloom(unsigned w, unsigned h): blur_shader(blur_vs, blur_fs), - blur_shdata_common(blur_shader), - blur_shdata_x(blur_shader), - blur_shdata_y(blur_shader), combine_shader(combine_vs, combine_fs), - combine_shdata(combine_shader), quad(VERTEX2) { - int loc = blur_shader.get_uniform_location("delta"); - blur_shdata_x.uniform(loc, 1.0f/w, 0.0f); - blur_shdata_y.uniform(loc, 0.0f, 1.0f/h); + blur_shdata[0].uniform("delta", 1.0f/w, 0.0f); + blur_shdata[1].uniform("delta", 0.0f, 1.0f/h); blur_shdata_common.uniform("source", 0); for(unsigned i=0; i<2; ++i) @@ -130,7 +125,7 @@ void Bloom::render(const Texture2D &src, const Texture2D &) { Bind bind_tex(i ? tex[0] : src); fbo.attach(COLOR_ATTACHMENT0, tex[i], 0); - (i ? blur_shdata_y : blur_shdata_x).apply(); + blur_shdata[i].apply(); quad.draw(); } } diff --git a/source/bloom.h b/source/bloom.h index 00130fa1..e6738b2f 100644 --- a/source/bloom.h +++ b/source/bloom.h @@ -27,8 +27,7 @@ private: Texture2D tex[2]; Program blur_shader; ProgramData blur_shdata_common; - ProgramData blur_shdata_x; - ProgramData blur_shdata_y; + ProgramData blur_shdata[2]; Program combine_shader; ProgramData combine_shdata; Texturing combine_texturing; diff --git a/source/programdata.cpp b/source/programdata.cpp index 50cefd4f..535e9e79 100644 --- a/source/programdata.cpp +++ b/source/programdata.cpp @@ -1,9 +1,11 @@ #include "color.h" +#include "error.h" #include "extension.h" #include "matrix.h" #include "program.h" #include "programdata.h" #include "uniform.h" +#include "uniformblock.h" #include "vector.h" using namespace std; @@ -11,181 +13,160 @@ using namespace std; namespace Msp { namespace GL { -ProgramData::ProgramData(const Program &p): - program(p) +ProgramData::ProgramData(): + modified(false) { static RequireExtension _ext("GL_ARB_shader_objects"); } +// Blocks are intentionally left uncopied ProgramData::ProgramData(const ProgramData &other): - program(other.program), - data(other.data) + uniforms(other.uniforms), + modified(false) { - for(map::iterator i=data.begin(); i!=data.end(); ++i) + for(UniformMap::iterator i=uniforms.begin(); i!=uniforms.end(); ++i) i->second = i->second->clone(); } ProgramData::~ProgramData() { - for(map::iterator i=data.begin(); i!=data.end(); ++i) + for(UniformMap::iterator i=uniforms.begin(); i!=uniforms.end(); ++i) delete i->second; + for(BlockMap::iterator i=blocks.begin(); i!=blocks.end(); ++i) + delete i->second.block; } -void ProgramData::uniform(int index, Uniform *uni) +void ProgramData::uniform(const string &name, Uniform *uni) { - map::iterator i = data.find(index); - if(i!=data.end()) + UniformMap::iterator i = uniforms.find(name); + if(i!=uniforms.end()) { delete i->second; i->second = uni; } else - data[index] = uni; -} - -void ProgramData::uniform(int index, int v) -{ - if(index>=0) - uniform(index, new Uniform1i(v)); -} - -void ProgramData::uniform(int index, float v) -{ - if(index>=0) - uniform(index, new Uniform1f(v)); -} - -void ProgramData::uniform(int index, float v0, float v1) -{ - if(index>=0) - uniform(index, new Uniform2f(v0, v1)); -} - -void ProgramData::uniform2(int index, const float *v) -{ - uniform(index, v[0], v[1]); -} - -void ProgramData::uniform(int index, float v0, float v1, float v2) -{ - if(index>=0) - uniform(index, new Uniform3f(v0, v1, v2)); -} - -void ProgramData::uniform(int index, const Vector3 &v) -{ - uniform(index, v.x, v.y, v.z); -} - -void ProgramData::uniform3(int index, const float *v) -{ - uniform(index, v[0], v[1], v[2]); -} - -void ProgramData::uniform(int index, float v0, float v1, float v2, float v3) -{ - if(index>=0) - uniform(index, new Uniform4f(v0, v1, v2, v3)); -} - -void ProgramData::uniform(int index, const Vector4 &v) -{ - uniform(index, v.x, v.y, v.z, v.w); -} - -void ProgramData::uniform(int index, const Color &c) -{ - uniform(index, c.r, c.g, c.b, c.a); -} - -void ProgramData::uniform4(int index, const float *v) -{ - uniform(index, v[0], v[1], v[2], v[3]); -} + uniforms[name] = uni; -void ProgramData::uniform_matrix4(int index, const float *v) -{ - if(index>=0) - uniform(index, new UniformMatrix4x4f(v)); -} - -void ProgramData::uniform_matrix4(int index, const Matrix &m) -{ - if(index>=0) - { - float v[16]; - copy(m.data(), m.data()+16, v); - uniform_matrix4(index, v); - } + modified = true; } void ProgramData::uniform(const string &name, int v) { - uniform(program.get_uniform_location(name), v); + uniform(name, new Uniform1i(v)); } void ProgramData::uniform(const string &name, float v) { - uniform(program.get_uniform_location(name), v); + uniform(name, new Uniform1f(v)); } void ProgramData::uniform(const string &name, float v0, float v1) { - uniform(program.get_uniform_location(name), v0, v1); + uniform(name, new Uniform2f(v0, v1)); } void ProgramData::uniform2(const string &name, const float *v) { - uniform2(program.get_uniform_location(name), v); + uniform(name, v[0], v[1]); } void ProgramData::uniform(const string &name, float v0, float v1, float v2) { - uniform(program.get_uniform_location(name), v0, v1, v2); + uniform(name, new Uniform3f(v0, v1, v2)); } void ProgramData::uniform(const string &name, const Vector3 &v) { - uniform(program.get_uniform_location(name), v); + uniform(name, v.x, v.y, v.z); } void ProgramData::uniform3(const string &name, const float *v) { - uniform3(program.get_uniform_location(name), v); + uniform(name, v[0], v[1], v[2]); } void ProgramData::uniform(const string &name, float v0, float v1, float v2, float v3) { - uniform(program.get_uniform_location(name), v0, v1, v2, v3); + uniform(name, new Uniform4f(v0, v1, v2, v3)); } void ProgramData::uniform(const string &name, const Vector4 &v) { - uniform(program.get_uniform_location(name), v); + uniform(name, v.x, v.y, v.z, v.w); +} + +void ProgramData::uniform(const string &name, const Color &c) +{ + uniform(name, c.r, c.g, c.b, c.a); } void ProgramData::uniform4(const string &name, const float *v) { - uniform4(program.get_uniform_location(name), v); + uniform(name, v[0], v[1], v[2], v[3]); } void ProgramData::uniform_matrix4(const string &name, const float *v) { - uniform_matrix4(program.get_uniform_location(name), v); + uniform(name, new UniformMatrix4x4f(v)); } void ProgramData::uniform_matrix4(const string &name, const Matrix &m) { - uniform_matrix4(program.get_uniform_location(name), m); + float v[16]; + copy(m.data(), m.data()+16, v); + uniform_matrix4(name, v); +} + +const UniformBlock &ProgramData::get_block(const Program &prog) const +{ + if(modified) + { + for(BlockMap::iterator i=blocks.begin(); i!=blocks.end(); ++i) + i->second.dirty = true; + modified = false; + } + + unsigned 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; + } + + UniformBlock &block = *i->second.block; + if(i->second.dirty) + { + for(UniformMap::const_iterator j=uniforms.begin(); j!=uniforms.end(); ++j) + { + int loc = prog.get_uniform_location(j->first); + if(loc>=0) + block.uniform(loc, *j->second); + } + i->second.dirty = false; + } + + return block; } void ProgramData::apply() const { - for(map::const_iterator i=data.begin(); i!=data.end(); ++i) - i->second->apply(i->first); + const Program *prog = Program::current(); + if(!prog) + throw invalid_operation("ProgramData::apply"); + + const UniformBlock &block = get_block(*prog); + block.apply(-1); } +ProgramData::Block::Block(): + dirty(false), + block(0) +{ } + + ProgramData::Loader::Loader(ProgramData &pd): DataFile::ObjectLoader(pd) { diff --git a/source/programdata.h b/source/programdata.h index 7d106305..6d0ebf8a 100644 --- a/source/programdata.h +++ b/source/programdata.h @@ -11,6 +11,7 @@ class Color; class Matrix; class Program; class Uniform; +class UniformBlock; class Vector3; class Vector4; @@ -33,32 +34,30 @@ public: }; private: - const Program &program; - std::map data; + struct Block + { + bool dirty; + UniformBlock *block; + + Block(); + }; + + typedef std::map UniformMap; + typedef std::map BlockMap; + + UniformMap uniforms; + mutable BlockMap blocks; + mutable bool modified; ProgramData &operator=(const ProgramData &); public: - explicit ProgramData(const Program &); + ProgramData(); ProgramData(const ProgramData &); ~ProgramData(); private: - void uniform(int, Uniform *); + void uniform(const std::string &, Uniform *); public: - void uniform(int, int); - void uniform(int, float); - void uniform(int, float, float); - void uniform2(int, const float *); - void uniform(int, float, float, float); - void uniform(int, const Vector3 &); - void uniform3(int, const float *); - void uniform(int, float, float, float, float); - void uniform(int, const Vector4 &); - void uniform(int, const Color &); - void uniform4(int, const float *); - void uniform_matrix4(int, const float *); - void uniform_matrix4(int, const Matrix &); - void uniform(const std::string &, int); void uniform(const std::string &, float); void uniform(const std::string &, float, float); @@ -73,6 +72,8 @@ public: void uniform_matrix4(const std::string &, const float *); void uniform_matrix4(const std::string &, const Matrix &); + const UniformBlock &get_block(const Program &) const; + void apply() const; }; diff --git a/source/renderpass.cpp b/source/renderpass.cpp index fc2d37ed..b0289284 100644 --- a/source/renderpass.cpp +++ b/source/renderpass.cpp @@ -113,7 +113,7 @@ void RenderPass::Loader::uniforms() if(!obj.shprog) throw invalid_operation("RenderPass::Loader::uniforms"); if(!obj.shdata) - obj.shdata = new ProgramData(*obj.shprog); + obj.shdata = new ProgramData; load_sub(*obj.shdata); } diff --git a/source/uniformblock.cpp b/source/uniformblock.cpp new file mode 100644 index 00000000..95e1c2b3 --- /dev/null +++ b/source/uniformblock.cpp @@ -0,0 +1,113 @@ +#include +#include "color.h" +#include "matrix.h" +#include "uniform.h" +#include "uniformblock.h" +#include "vector.h" + +using namespace std; + +namespace Msp { +namespace GL { + +UniformBlock::~UniformBlock() +{ + for(map::iterator i=uniforms.begin(); i!=uniforms.end(); ++i) + delete i->second; +} + +void UniformBlock::uniform(int index, Uniform *uni) +{ + map::iterator i = uniforms.find(index); + if(i!=uniforms.end()) + { + delete i->second; + i->second = uni; + } + else + uniforms[index] = uni; +} + +void UniformBlock::uniform(int index, const Uniform &uni) +{ + uniform(index, uni.clone()); +} + +void UniformBlock::uniform(int index, int v) +{ + uniform(index, new Uniform1i(v)); +} + +void UniformBlock::uniform(int index, float v) +{ + uniform(index, new Uniform1f(v)); +} + +void UniformBlock::uniform(int index, float v0, float v1) +{ + uniform(index, new Uniform2f(v0, v1)); +} + +void UniformBlock::uniform2(int index, const float *v) +{ + uniform(index, v[0], v[1]); +} + +void UniformBlock::uniform(int index, float v0, float v1, float v2) +{ + uniform(index, new Uniform3f(v0, v1, v2)); +} + +void UniformBlock::uniform(int index, const Vector3 &v) +{ + uniform(index, v.x, v.y, v.z); +} + +void UniformBlock::uniform3(int index, const float *v) +{ + uniform(index, v[0], v[1], v[2]); +} + +void UniformBlock::uniform(int index, float v0, float v1, float v2, float v3) +{ + uniform(index, new Uniform4f(v0, v1, v2, v3)); +} + +void UniformBlock::uniform(int index, const Vector4 &v) +{ + uniform(index, v.x, v.y, v.z, v.w); +} + +void UniformBlock::uniform(int index, const Color &c) +{ + uniform(index, c.r, c.g, c.b, c.a); +} + +void UniformBlock::uniform4(int index, const float *v) +{ + uniform(index, v[0], v[1], v[2], v[3]); +} + +void UniformBlock::uniform_matrix4(int index, const float *v) +{ + uniform(index, new UniformMatrix4x4f(v)); +} + +void UniformBlock::uniform_matrix4(int index, const Matrix &m) +{ + float v[16]; + copy(m.data(), m.data()+16, v); + uniform_matrix4(index, v); +} + +void UniformBlock::apply(int index) const +{ + if(index>=0) + throw logic_error("GL_ARB_uniform_buffer_object support not implemented yet"); + + for(map::const_iterator i=uniforms.begin(); i!=uniforms.end(); ++i) + i->second->apply(i->first); +} + +} // namespace GL +} // namespace Msp diff --git a/source/uniformblock.h b/source/uniformblock.h new file mode 100644 index 00000000..815f49b1 --- /dev/null +++ b/source/uniformblock.h @@ -0,0 +1,50 @@ +#ifndef MSP_GL_UNIFORMBLOCK_H_ +#define MSP_GL_UNIFORMBLOCK_H_ + +#include + +namespace Msp { +namespace GL { + +class Color; +class Matrix; +class Uniform; +class Vector3; +class Vector4; + +class UniformBlock +{ +private: + std::map uniforms; + + UniformBlock(const UniformBlock &); + UniformBlock &operator=(const UniformBlock &); +public: + UniformBlock() { } + ~UniformBlock(); + +private: + void uniform(int, Uniform *); +public: + void uniform(int, const Uniform &); + void uniform(int, int); + void uniform(int, float); + void uniform(int, float, float); + void uniform2(int, const float *); + void uniform(int, float, float, float); + void uniform(int, const Vector3 &); + void uniform3(int, const float *); + void uniform(int, float, float, float, float); + void uniform(int, const Vector4 &); + void uniform(int, const Color &); + void uniform4(int, const float *); + void uniform_matrix4(int, const float *); + void uniform_matrix4(int, const Matrix &); + + void apply(int) const; +}; + +} // namespace GL +} // namespace Msp + +#endif -- 2.43.0