]> git.tdb.fi Git - libs/gl.git/commitdiff
Rewrite state management
authorMikko Rasa <tdb@tdb.fi>
Mon, 16 Aug 2021 16:11:25 +0000 (19:11 +0300)
committerMikko Rasa <tdb@tdb.fi>
Mon, 16 Aug 2021 16:11:35 +0000 (19:11 +0300)
Global bindings have been removed from the central classes (and will be
removed from others soon) since those would translate poorly to Vulkan.
Instead a new PipelineState class is used to tie all of the state
together and apply it at once.

35 files changed:
source/core/batch.cpp
source/core/buffer.cpp
source/core/buffer.h
source/core/bufferable.h
source/core/clipping.h
source/core/pipelinestate.cpp [new file with mode: 0644]
source/core/pipelinestate.h [new file with mode: 0644]
source/core/program.cpp
source/core/program.h
source/core/sampler.cpp
source/core/sampler.h
source/core/texture.cpp
source/core/texture.h
source/core/texture1d.cpp
source/core/texture1d.h
source/core/texture2d.cpp
source/core/texture2d.h
source/core/texture3d.cpp
source/core/texture3d.h
source/core/texturecube.cpp
source/core/texturecube.h
source/core/texunit.cpp [deleted file]
source/core/texunit.h [deleted file]
source/core/uniformblock.cpp
source/core/uniformblock.h
source/core/vertexsetup.cpp
source/core/vertexsetup.h
source/core/windingtest.h
source/effects/bloom.cpp
source/effects/environmentmap.cpp
source/render/programdata.cpp
source/render/programdata.h
source/render/renderer.cpp
source/render/renderer.h
source/render/view.cpp

index 68e232ba29de5447fd9050d27894000f2765e86f..2bc44c9ddfe285c1dac5afa2fb2cd28ef63fba16 100644 (file)
@@ -188,9 +188,7 @@ unsigned Batch::get_index(unsigned i) const
 
 void Batch::draw() const
 {
-       BindRestore _bind_ibuf(get_buffer(), ELEMENT_ARRAY_BUFFER);
        const void *data_ptr = setup_draw();
-
        glDrawElements(prim_type, size(), gl_index_type, data_ptr);
 }
 
@@ -198,9 +196,7 @@ void Batch::draw_instanced(unsigned count) const
 {
        static Require req(ARB_draw_instanced);
 
-       BindRestore _bind_ibuf(get_buffer(), ELEMENT_ARRAY_BUFFER);
        const void *data_ptr = setup_draw();
-
        glDrawElementsInstanced(prim_type, size(), gl_index_type, data_ptr, count);
 }
 
index 4750846ab1dceb291a600043977f1c06f868f403..ecf7b49a15e35d29493c83f1a6ea2f8013065483 100644 (file)
@@ -15,9 +15,6 @@ using namespace std;
 namespace Msp {
 namespace GL {
 
-const Buffer *Buffer::bound[5] = { 0, 0, 0, 0, 0 };
-BufferType buffer_types[] = { ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER, PIXEL_PACK_BUFFER, PIXEL_UNPACK_BUFFER, UNIFORM_BUFFER };
-
 Buffer::Buffer():
        size(0),
        allocated(false)
@@ -32,21 +29,9 @@ Buffer::Buffer():
 
 Buffer::~Buffer()
 {
-       for(unsigned i=0; i<5; ++i)
-               if(bound[i]==this)
-                       unbind_from(buffer_types[i]);
        glDeleteBuffers(1, &id);
 }
 
-void Buffer::require_buffer_type(BufferType type)
-{
-       static Require _req_vbo(ARB_vertex_buffer_object);
-       if(type==PIXEL_PACK_BUFFER || type==PIXEL_UNPACK_BUFFER)
-               static Require _req_pbo(ARB_pixel_buffer_object);
-       else if(type==UNIFORM_BUFFER)
-               static Require _req_ubo(ARB_uniform_buffer_object);
-}
-
 void Buffer::storage(unsigned sz)
 {
        if(size>0)
@@ -75,8 +60,9 @@ void Buffer::allocate()
                        glNamedBufferStorage(id, size, 0, flags);
                else
                {
-                       BindRestore _bind(this, ARRAY_BUFFER);
-                       glBufferStorage(ARRAY_BUFFER, size, 0, flags);
+                       glBindBuffer(GL_ARRAY_BUFFER, id);
+                       glBufferStorage(GL_ARRAY_BUFFER, size, 0, flags);
+                       glBindBuffer(GL_ARRAY_BUFFER, 0);
                }
 
                allocated = true;
@@ -101,8 +87,9 @@ void Buffer::data(const void *d)
                glNamedBufferData(id, size, d, STATIC_DRAW);
        else
        {
-               BindRestore _bind(this, ARRAY_BUFFER);
-               glBufferData(ARRAY_BUFFER, size, d, STATIC_DRAW);
+               glBindBuffer(GL_ARRAY_BUFFER, id);
+               glBufferData(GL_ARRAY_BUFFER, size, d, STATIC_DRAW);
+               glBindBuffer(GL_ARRAY_BUFFER, 0);
        }
 
        allocated = true;
@@ -129,8 +116,9 @@ void Buffer::sub_data(unsigned off, unsigned sz, const void *d)
                glNamedBufferSubData(id, off, sz, d);
        else
        {
-               BindRestore _bind(this, ARRAY_BUFFER);
-               glBufferSubData(ARRAY_BUFFER, off, sz, d);
+               glBindBuffer(GL_ARRAY_BUFFER, id);
+               glBufferSubData(GL_ARRAY_BUFFER, off, sz, d);
+               glBindBuffer(GL_ARRAY_BUFFER, 0);
        }
 }
 
@@ -140,11 +128,6 @@ void Buffer::require_size(unsigned req_sz) const
                throw buffer_too_small(format("buffer has %d bytes; %d required", size, req_sz));
 }
 
-BufferRange *Buffer::create_range(unsigned s, unsigned o)
-{
-       return new BufferRange(*this, s, o);
-}
-
 void *Buffer::map()
 {
        static Require _req(ARB_map_buffer_range);
@@ -154,8 +137,10 @@ void *Buffer::map()
                return glMapNamedBufferRange(id, 0, size, GL_MAP_READ_BIT|GL_MAP_WRITE_BIT);
        else
        {
-               BindRestore _bind(this, ARRAY_BUFFER);
-               return glMapBufferRange(ARRAY_BUFFER, 0, size, GL_MAP_READ_BIT|GL_MAP_WRITE_BIT);
+               glBindBuffer(GL_ARRAY_BUFFER, id);
+               void *result = glMapBufferRange(GL_ARRAY_BUFFER, 0, size, GL_MAP_READ_BIT|GL_MAP_WRITE_BIT);
+               glBindBuffer(GL_ARRAY_BUFFER, 0);
+               return result;
        }
 }
 
@@ -166,67 +151,15 @@ bool Buffer::unmap()
                return glUnmapNamedBuffer(id);
        else if(OES_mapbuffer)
        {
-               BindRestore _bind(this, ARRAY_BUFFER);
-               return glUnmapBuffer(ARRAY_BUFFER);
+               glBindBuffer(GL_ARRAY_BUFFER, id);
+               bool result = glUnmapBuffer(GL_ARRAY_BUFFER);
+               glBindBuffer(GL_ARRAY_BUFFER, 0);
+               return result;
        }
        else
                return true;
 }
 
-void Buffer::bind_to(BufferType t) const
-{
-       require_buffer_type(t);
-       if(t==ELEMENT_ARRAY_BUFFER)
-               if(const VertexSetup *vs = VertexSetup::current())
-               {
-                       // Don't change the binding in a vertex array object
-                       if(this==vs->get_index_buffer())
-                               return;
-                       throw invalid_operation("Buffer::bind_to(ELEMENT_ARRAY_BUFFER)");
-               }
-       if(set_current(t, this))
-               glBindBuffer(t, id);
-}
-
-const Buffer *Buffer::current(BufferType t)
-{
-       if(t==ELEMENT_ARRAY_BUFFER)
-               if(const VertexSetup *vs = VertexSetup::current())
-                       return vs->get_index_buffer();
-       return binding(t);
-}
-
-void Buffer::unbind_from(BufferType type)
-{
-       if(type==ELEMENT_ARRAY_BUFFER && VertexSetup::current())
-               throw invalid_operation("Buffer::unbind_from(ELEMENT_ARRAY_BUFFER)");
-       if(set_current(type, 0))
-               glBindBuffer(type, 0);
-}
-
-const Buffer *&Buffer::binding(BufferType type)
-{
-       switch(type)
-       {
-       case ARRAY_BUFFER:         return bound[0];
-       case ELEMENT_ARRAY_BUFFER: return bound[1];
-       case PIXEL_PACK_BUFFER:    return bound[2];
-       case PIXEL_UNPACK_BUFFER:  return bound[3];
-       case UNIFORM_BUFFER:       return bound[4];
-       default: throw invalid_argument("Buffer::binding");
-       }
-}
-
-bool Buffer::set_current(BufferType type, const Buffer *buf)
-{
-       const Buffer *&ptr = binding(type);
-       if(ptr==buf)
-               return false;
-
-       ptr = buf;
-       return true;
-}
-
 void Buffer::set_debug_name(const string &name)
 {
 #ifdef DEBUG
@@ -237,83 +170,5 @@ void Buffer::set_debug_name(const string &name)
 #endif
 }
 
-
-vector<const BufferRange *> BufferRange::bound_uniform;
-
-BufferRange::BufferRange(Buffer &b, unsigned o, unsigned s):
-       buffer(b),
-       offset(o),
-       size(s)
-{
-       if(o>buffer.get_size() || o+s>buffer.get_size())
-               throw out_of_range("BufferRange::BufferRange");
-}
-
-BufferRange::~BufferRange()
-{
-       for(unsigned i=0; i<bound_uniform.size(); ++i)
-               if(bound_uniform[i]==this)
-                       unbind_from(UNIFORM_BUFFER, i);
-}
-
-void BufferRange::data(const void *d)
-{
-       buffer.sub_data(offset, size, d);
-}
-
-void BufferRange::bind_to(BufferType t, unsigned i)
-{
-       Buffer::require_buffer_type(t);
-       if(set_current(t, i, this))
-       {
-               // The buffer gets bound as a side effect
-               Buffer::set_current(t, &buffer);
-               glBindBufferRange(t, i, buffer.id, offset, size);
-       }
-}
-
-void BufferRange::unbind_from(BufferType t, unsigned i)
-{
-       if(set_current(t, i, 0))
-       {
-               Buffer::set_current(t, 0);
-               glBindBufferBase(t, i, 0);
-       }
-}
-
-const BufferRange *&BufferRange::binding(BufferType type, unsigned index)
-{
-       if(type==UNIFORM_BUFFER)
-       {
-               if(index>=Limits::get_global().max_uniform_bindings)
-                       throw out_of_range("BufferRange::binding");
-               if(bound_uniform.size()<=index)
-                       bound_uniform.resize(index+1);
-               return bound_uniform[index];
-       }
-       else
-               throw invalid_argument("BufferRange::binding");
-}
-
-bool BufferRange::set_current(BufferType type, unsigned index, const BufferRange *buf)
-{
-       const BufferRange *&ptr = binding(type, index);
-       if(ptr==buf)
-               return false;
-
-       ptr = buf;
-       return true;
-}
-
-unsigned BufferRange::get_n_uniform_buffer_bindings()
-{
-       return Limits::get_global().max_uniform_bindings;
-}
-
-unsigned BufferRange::get_uniform_buffer_alignment()
-{
-       return Limits::get_global().uniform_buffer_alignment;
-}
-
 } // namespace GL
 } // namespace Msp
index 83e75927ae31c3a44cd81420cea8f626a39c605e..a80e52a68b9c34b00e499c6a16fb0b9e85446d39 100644 (file)
@@ -21,15 +21,6 @@ public:
        virtual ~buffer_too_small() throw() { }
 };
 
-enum BufferType
-{
-       ARRAY_BUFFER         = GL_ARRAY_BUFFER,
-       ELEMENT_ARRAY_BUFFER = GL_ELEMENT_ARRAY_BUFFER,
-       PIXEL_PACK_BUFFER    = GL_PIXEL_PACK_BUFFER,
-       PIXEL_UNPACK_BUFFER  = GL_PIXEL_UNPACK_BUFFER,
-       UNIFORM_BUFFER       = GL_UNIFORM_BUFFER
-};
-
 enum BufferUsage
 {
        STREAM_DRAW  = GL_STREAM_DRAW,
@@ -66,16 +57,10 @@ private:
        unsigned size;
        bool allocated;
 
-       static const Buffer *bound[5];
-
 public:
        Buffer();
        ~Buffer();
 
-private:
-       static void require_buffer_type(BufferType);
-
-public:
        /** Returns the OpenGL ID of the buffer.  For internal use only. */
        unsigned get_id() const { return id; }
 
@@ -106,57 +91,13 @@ public:
 
        void require_size(unsigned) const;
 
-       BufferRange *create_range(unsigned, unsigned);
-
        void *map();
        DEPRECATED void *map(BufferAccess) { return map(); }
        bool unmap();
 
-       /** Binds the buffer. */
-       void bind_to(BufferType) const;
-
-       static const Buffer *current(BufferType);
-       static void unbind_from(BufferType);
-private:
-       static const Buffer *&binding(BufferType);
-       static bool set_current(BufferType, const Buffer *);
-
-public:
        void set_debug_name(const std::string &);
 };
 
-
-/**
-A proxy for a subset of a buffer.  Can be bound for use with uniform blocks.
-*/
-class BufferRange
-{
-private:
-       Buffer &buffer;
-       unsigned offset;
-       unsigned size;
-
-       static std::vector<const BufferRange *> bound_uniform;
-
-public:
-       BufferRange(Buffer &, unsigned, unsigned);
-       ~BufferRange();
-
-       void data(const void *);
-
-       void bind_to(BufferType, unsigned);
-
-       static const BufferRange *current(BufferType t, unsigned i) { return binding(t, i); }
-       static void unbind_from(BufferType, unsigned);
-private:
-       static const BufferRange *&binding(BufferType, unsigned);
-       static bool set_current(BufferType, unsigned, const BufferRange *);
-
-public:
-       DEPRECATED static unsigned get_n_uniform_buffer_bindings();
-       DEPRECATED static unsigned get_uniform_buffer_alignment();
-};
-
 } // namespace GL
 } // namespace Msp
 
index cbbde4e1b93f1e07266c097c150774f2b5621d3c..47e2770c58675fd128d16afa6b50446e7f53a62f 100644 (file)
@@ -66,10 +66,10 @@ public:
        /** Returns the buffer in which the data is stored. */
        const Buffer *get_buffer() const { return buffer; }
 
-protected:
-       /** Returns the amount of data to be stored in the buffer, in bytes. */
+       /** Returns the size of the data, in bytes. */
        virtual unsigned get_data_size() const = 0;
 
+protected:
        /** Returns a pointer to the start of data in client memory. */
        virtual const void *get_data_pointer() const = 0;
 
@@ -82,13 +82,14 @@ protected:
        changes. */
        void update_offset();
 
-       /** Returns the offset where the data should be uploaded. */
+public:
+       /** Returns the offset of the data from the beginning of the buffer. */
        unsigned get_offset() const { return offset; }
 
+private:
        /** Called when the target buffer or offset within it has changed. */
        virtual void location_changed(Buffer *, unsigned, unsigned) const { }
 
-private:
        /** Uploads data to the buffer.  Receives pointer to mapped buffer memory as
        parameter, or null to use the buffer upload interface. */
        void upload_data(char *) const;
index b07195231423ca139a174af18c202c80153f6602..5600a38ba9d70f9ef4a96c89b315a22ea485f1f1 100644 (file)
@@ -32,6 +32,8 @@ public:
        void attach(const ClipPlane &);
        void detach(const ClipPlane &);
 
+       unsigned get_n_planes() const { return planes.size(); }
+
        DEPRECATED void attach(unsigned, const ClipPlane &p) { attach(p); }
        DEPRECATED void detach(unsigned);
 
diff --git a/source/core/pipelinestate.cpp b/source/core/pipelinestate.cpp
new file mode 100644 (file)
index 0000000..a3b9e64
--- /dev/null
@@ -0,0 +1,319 @@
+#include <stdexcept>
+#include <msp/core/algorithm.h>
+#include <msp/gl/extensions/arb_direct_state_access.h>
+#include <msp/gl/extensions/arb_sampler_objects.h>
+#include <msp/gl/extensions/arb_shader_objects.h>
+#include <msp/gl/extensions/arb_uniform_buffer_object.h>
+#include <msp/gl/extensions/arb_vertex_array_object.h>
+#include "buffer.h"
+#include "deviceinfo.h"
+#include "pipelinestate.h"
+#include "program.h"
+#include "texture.h"
+#include "uniformblock.h"
+#include "vertexsetup.h"
+#include "windingtest.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+const PipelineState *PipelineState::last_applied = 0;
+vector<int> PipelineState::bound_tex_targets;
+
+PipelineState::PipelineState():
+       shprog(0),
+       vertex_setup(0),
+       winding_test(0),
+       enabled_clip_planes(0),
+       changes(0)
+{
+       if(!ARB_direct_state_access && bound_tex_targets.empty())
+               bound_tex_targets.resize(Limits::get_global().max_texture_bindings);
+}
+
+PipelineState::~PipelineState()
+{
+       if(this==last_applied)
+               last_applied = 0;
+}
+
+void PipelineState::set_shader_program(const Program *p)
+{
+       if(p!=shprog)
+       {
+               shprog = p;
+               changes |= SHPROG;
+       }
+}
+
+void PipelineState::set_vertex_setup(const VertexSetup *s)
+{
+       if(s!=vertex_setup)
+       {
+               vertex_setup = s;
+               changes |= VERTEX_SETUP;
+       }
+}
+
+void PipelineState::set_winding_test(const WindingTest *w)
+{
+       if(w!=winding_test)
+       {
+               winding_test = w;
+               changes |= WINDING_TEST;
+       }
+}
+
+void PipelineState::set_enabled_clip_planes(unsigned p)
+{
+       if(p!=enabled_clip_planes)
+       {
+               enabled_clip_planes = p;
+               changes |= CLIP_PLANES;
+       }
+}
+
+void PipelineState::set_texture(unsigned binding, const Texture *tex, const Sampler *samp)
+{
+       if((tex!=0)!=(samp!=0))
+               throw invalid_argument("PipelineState::set_texture");
+
+       vector<BoundTexture>::iterator i = lower_bound_member(textures, binding, &BoundTexture::binding);
+       if(i==textures.end() || i->binding!=binding)
+               i = textures.insert(i, BoundTexture(binding));
+       if(tex!=i->texture || samp!=i->sampler)
+       {
+               i->texture = tex;
+               i->sampler = samp;
+               i->changed = true;
+               changes |= TEXTURES;
+       }
+}
+
+void PipelineState::set_uniforms(const DefaultUniformBlock *block)
+{
+       set_uniform_block_(-1, block);
+}
+
+void PipelineState::set_uniform_block(unsigned binding, const BufferBackedUniformBlock *block)
+{
+       set_uniform_block_(binding, block);
+}
+
+void PipelineState::set_uniform_block_(int binding, const UniformBlock *block)
+{
+       vector<BoundUniformBlock>::iterator i = lower_bound_member(uniform_blocks, binding, &BoundUniformBlock::binding);
+       if(i==uniform_blocks.end() || i->binding!=binding)
+               i = uniform_blocks.insert(i, BoundUniformBlock(binding));
+       if(block!=i->block || binding<0)
+       {
+               i->block = block;
+               i->changed = true;
+               changes |= UNIFORMS;
+       }
+}
+
+void PipelineState::apply() const
+{
+       apply(this==last_applied ? changes : ~0U);
+}
+
+void PipelineState::apply(unsigned mask) const
+{
+       if(mask&SHPROG)
+               glUseProgram(shprog ? shprog->get_id() : 0);
+
+       if(mask&VERTEX_SETUP)
+       {
+               glBindVertexArray(vertex_setup ? vertex_setup->get_id() : 0);
+               if(vertex_setup)
+                       vertex_setup->refresh();
+       }
+
+       if(mask&WINDING_TEST)
+       {
+               if(winding_test)
+               {
+                       glEnable(GL_CULL_FACE);
+                       glFrontFace(winding_test->get_winding());
+               }
+               else
+                       glDisable(GL_CULL_FACE);
+       }
+
+       if(mask&CLIP_PLANES)
+       {
+               unsigned max_clip_planes = Limits::get_global().max_clip_planes;
+               for(unsigned i=0; i<max_clip_planes; ++i)
+               {
+                       if((enabled_clip_planes>>i)&1)
+                               glEnable(GL_CLIP_PLANE0+i);
+                       else
+                               glDisable(GL_CLIP_PLANE0+i);
+               }
+       }
+
+       if(mask&TEXTURES)
+       {
+               if(last_applied && this!=last_applied)
+               {
+                       vector<BoundTexture>::const_iterator i = textures.begin();
+                       vector<BoundTexture>::const_iterator j = last_applied->textures.begin();
+                       while(j!=last_applied->textures.end())
+                       {
+                               if(i==textures.end() || j->binding<i->binding)
+                               {
+                                       if(bound_tex_targets[j->binding])
+                                       {
+                                               if(ARB_direct_state_access)
+                                                       glBindTextureUnit(j->binding, 0);
+                                               else
+                                               {
+                                                       glActiveTexture(GL_TEXTURE0+j->binding);
+                                                       glBindTexture(bound_tex_targets[j->binding], 0);
+                                               }
+                                       }
+                                       ++j;
+                               }
+                               else
+                               {
+                                       if(i->binding==j->binding)
+                                               ++j;
+                                       ++i;
+                               }
+                       }
+               }
+
+               for(vector<BoundTexture>::const_iterator i=textures.begin(); i!=textures.end(); ++i)
+                       if(i->changed)
+                       {
+                               if(i->texture && i->sampler)
+                               {
+                                       if(ARB_direct_state_access)
+                                               glBindTextureUnit(i->binding, i->texture->get_id());
+                                       else
+                                       {
+                                               glActiveTexture(GL_TEXTURE0+i->binding);
+                                               if(bound_tex_targets[i->binding] && static_cast<int>(i->texture->get_target())!=bound_tex_targets[i->binding])
+                                                       glBindTexture(bound_tex_targets[i->binding], 0);
+                                               glBindTexture(i->texture->get_target(), i->texture->get_id());
+                                               bound_tex_targets[i->binding] = i->texture->get_target();
+                                       }
+
+                                       glBindSampler(i->binding, i->sampler->get_id());
+                                       i->sampler->refresh();
+                               }
+                               else if(bound_tex_targets[i->binding])
+                               {
+                                       if(ARB_direct_state_access)
+                                               glBindTextureUnit(i->binding, 0);
+                                       else
+                                       {
+                                               glActiveTexture(GL_TEXTURE0+i->binding);
+                                               glBindTexture(bound_tex_targets[i->binding], 0);
+                                               bound_tex_targets[i->binding] = 0;
+                                       }
+                               }
+
+                               i->changed = false;
+                       }
+       }
+
+       if(mask&UNIFORMS)
+       {
+               if(last_applied && this!=last_applied)
+               {
+                       vector<BoundUniformBlock>::const_iterator i = uniform_blocks.begin();
+                       vector<BoundUniformBlock>::const_iterator j = last_applied->uniform_blocks.begin();
+                       while(j!=last_applied->uniform_blocks.end())
+                       {
+                               if(i==uniform_blocks.end() || j->binding<i->binding)
+                               {
+                                       glBindBufferBase(GL_UNIFORM_BUFFER, j->binding, 0);
+                                       ++j;
+                               }
+                               else
+                               {
+                                       if(i->binding==j->binding)
+                                               ++j;
+                                       ++i;
+                               }
+                       }
+               }
+
+               for(vector<BoundUniformBlock>::const_iterator i=uniform_blocks.begin(); i!=uniform_blocks.end(); ++i)
+                       if(i->changed)
+                       {
+                               if(i->block)
+                               {
+                                       if(i->binding>=0)
+                                       {
+                                               const BufferBackedUniformBlock *block = static_cast<const BufferBackedUniformBlock *>(i->block);
+                                               glBindBufferRange(GL_UNIFORM_BUFFER, i->binding, block->get_buffer()->get_id(), block->get_offset(), block->get_data_size());
+                                       }
+                                       else
+                                               static_cast<const DefaultUniformBlock *>(i->block)->apply();
+                               }
+                               else
+                                       glBindBufferBase(GL_UNIFORM_BUFFER, i->binding, 0);
+
+                               i->changed = false;
+                       }
+       }
+
+       last_applied = this;
+       changes &= ~mask;
+}
+
+void PipelineState::clear()
+{
+       if(last_applied)
+       {
+               glUseProgram(0);
+               glBindVertexArray(0);
+
+               unsigned max_clip_planes = Limits::get_global().max_clip_planes;
+               for(unsigned i=0; i<max_clip_planes; ++i)
+                       if((last_applied->enabled_clip_planes>>i)&1)
+                               glDisable(GL_CLIP_PLANE0+i);
+
+               for(vector<BoundTexture>::const_iterator i=last_applied->textures.begin(); i!=last_applied->textures.end(); ++i)
+                       if(i->texture && i->sampler)
+                       {
+                               if(ARB_direct_state_access)
+                                       glBindTextureUnit(i->binding, 0);
+                               else
+                               {
+                                       glActiveTexture(GL_TEXTURE0+i->binding);
+                                       glBindTexture(bound_tex_targets[i->binding], 0);
+                                       bound_tex_targets[i->binding] = 0;
+                               }
+                       }
+
+               for(vector<BoundUniformBlock>::const_iterator i=last_applied->uniform_blocks.begin(); i!=last_applied->uniform_blocks.end(); ++i)
+                       if(i->block)
+                               glBindBufferBase(GL_UNIFORM_BUFFER, i->binding, 0);
+
+               last_applied = 0;
+       }
+}
+
+
+PipelineState::BoundTexture::BoundTexture(unsigned b):
+       binding(b),
+       changed(false),
+       texture(0),
+       sampler(0)
+{ }
+
+
+PipelineState::BoundUniformBlock::BoundUniformBlock(int b):
+       binding(b),
+       changed(false),
+       block(0)
+{ }
+
+} // namespace GL
+} // namespace Msp
diff --git a/source/core/pipelinestate.h b/source/core/pipelinestate.h
new file mode 100644 (file)
index 0000000..8d1d1aa
--- /dev/null
@@ -0,0 +1,91 @@
+#ifndef PIPELINESTATE_H_
+#define PIPELINESTATE_H_
+
+#include <vector>
+#include <msp/core/noncopyable.h>
+
+namespace Msp {
+namespace GL {
+
+class BufferBackedUniformBlock;
+class DefaultUniformBlock;
+class Program;
+class Sampler;
+class Texture;
+class UniformBlock;
+class VertexSetup;
+class WindingTest;
+
+class PipelineState: public NonCopyable
+{
+private:
+       struct BoundTexture
+       {
+               unsigned binding;
+               mutable bool changed;
+               const Texture *texture;
+               const Sampler *sampler;
+
+               BoundTexture(unsigned);
+       };
+
+       struct BoundUniformBlock
+       {
+               int binding;
+               mutable bool changed;
+               const UniformBlock *block;
+
+               BoundUniformBlock(int);
+       };
+
+       enum ChangeMask
+       {
+               SHPROG = 1,
+               VERTEX_SETUP = 2,
+               WINDING_TEST = 4,
+               CLIP_PLANES = 8,
+               TEXTURES = 16,
+               UNIFORMS = 32
+       };
+
+       const Program *shprog;
+       const VertexSetup *vertex_setup;
+       const WindingTest *winding_test;
+       unsigned enabled_clip_planes;
+       std::vector<BoundTexture> textures;
+       std::vector<BoundUniformBlock> uniform_blocks;
+       mutable unsigned changes;
+
+       static const PipelineState *last_applied;
+       static std::vector<int> bound_tex_targets;
+
+public:
+       PipelineState();
+       ~PipelineState();
+
+       void set_shader_program(const Program *);
+       void set_vertex_setup(const VertexSetup *);
+       void set_winding_test(const WindingTest *);
+       void set_enabled_clip_planes(unsigned);
+       void set_texture(unsigned, const Texture *, const Sampler *);
+       void set_uniforms(const DefaultUniformBlock *);
+       void set_uniform_block(unsigned, const BufferBackedUniformBlock *);
+private:
+       void set_uniform_block_(int, const UniformBlock *);
+public:
+
+       const Program *get_shader_program() const { return shprog; }
+       const VertexSetup *get_vertex_setup() const { return vertex_setup; }
+       const WindingTest *get_winding_test() const { return winding_test; }
+
+       void apply() const;
+private:
+       void apply(unsigned) const;
+public:
+       static void clear();
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif
index 33c53cd7755fe4f0e4d7b1bd293c2f6af30c8748..ed2455f86aa315ec79f97bf2860563f7d40cc243 100644 (file)
@@ -355,7 +355,8 @@ void Program::link()
                                }
                        }
 
-                       Conditional<BindRestore> _bind(!ARB_separate_shader_objects, this);
+                       if(!ARB_separate_shader_objects)
+                               glUseProgram(id);
                        for(map<string, unsigned>::const_iterator i=transient->textures.begin(); i!=transient->textures.end(); ++i)
                        {
                                int location = get_uniform_location(i->first);
@@ -754,25 +755,6 @@ int Program::get_attribute_location(const string &name) const
        return i!=attributes.end() && i->name==name ? i->location : -1;
 }
 
-void Program::bind() const
-{
-       if(!linked)
-               throw invalid_operation("Program::bind");
-
-       if(!set_current(this))
-               return;
-
-       glUseProgram(id);
-}
-
-void Program::unbind()
-{
-       if(!set_current(0))
-               return;
-
-       glUseProgram(0);
-}
-
 void Program::set_debug_name(const string &name)
 {
 #ifdef DEBUG
index a2324f2329cc0fbaa3c8a4a2ea733384d02e6aeb..a494e0798f5d67ef5ecaf7f770d7e289a06bc150 100644 (file)
@@ -20,7 +20,7 @@ class Shader;
 A complete shader program.  Programs can be assembled of individual Shaders or
 generated with a set of standard features.
 */
-class Program: public Bindable<Program>
+class Program
 {
 public:
        class Loader: public DataFile::CollectionObjectLoader<Program>
@@ -191,8 +191,7 @@ public:
        const AttributeInfo &get_attribute_info(const std::string &) const;
        int get_attribute_location(const std::string &) const;
 
-       void bind() const;
-       static void unbind();
+       unsigned get_id() const { return id; }
 
        void set_debug_name(const std::string &);
 private:
index bb37b0747e7d12c732ac4e57234c6b8bc3836344..ffd7762568f665baf551808558a3231ca8ba93fe 100644 (file)
@@ -8,7 +8,6 @@
 #include "error.h"
 #include "sampler.h"
 #include "texture.h"
-#include "texunit.h"
 
 using namespace std;
 
@@ -34,40 +33,42 @@ Sampler::Sampler():
                glGenSamplers(1, &id);
 }
 
-void Sampler::update_parameter(int mask) const
+void Sampler::update() const
 {
-       if(mask&MIN_FILTER)
+       if(dirty_params&MIN_FILTER)
                glSamplerParameteri(id, GL_TEXTURE_MIN_FILTER, min_filter);
-       if(mask&MAG_FILTER)
+       if(dirty_params&MAG_FILTER)
                glSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, mag_filter);
-       if(mask&MAX_ANISOTROPY)
+       if(dirty_params&MAX_ANISOTROPY)
                glSamplerParameterf(id, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy);
-       if(mask&WRAP_S)
+       if(dirty_params&WRAP_S)
                glSamplerParameteri(id, GL_TEXTURE_WRAP_S, wrap_s);
-       if(mask&WRAP_T)
+       if(dirty_params&WRAP_T)
                glSamplerParameteri(id, GL_TEXTURE_WRAP_T, wrap_t);
-       if(mask&WRAP_R)
+       if(dirty_params&WRAP_R)
                glSamplerParameteri(id, GL_TEXTURE_WRAP_R, wrap_r);
-       if(mask&BORDER_COLOR)
+       if(dirty_params&BORDER_COLOR)
                glSamplerParameterfv(id, GL_TEXTURE_BORDER_COLOR, &border_color.r);
-       if(mask&COMPARE)
+       if(dirty_params&COMPARE)
        {
                glSamplerParameteri(id, GL_TEXTURE_COMPARE_MODE, (compare ? GL_COMPARE_R_TO_TEXTURE : GL_NONE));
                if(compare)
                        glSamplerParameteri(id, GL_TEXTURE_COMPARE_FUNC, cmp_func);
        }
+
+       dirty_params = 0;
 }
 
 void Sampler::set_min_filter(TextureFilter f)
 {
        min_filter = f;
-       update_parameter(MIN_FILTER);
+       dirty_params |= MIN_FILTER;
 }
 
 void Sampler::set_mag_filter(TextureFilter f)
 {
        mag_filter = f;
-       update_parameter(MAG_FILTER);
+       dirty_params |= MAG_FILTER;
 }
 
 void Sampler::set_filter(TextureFilter f)
@@ -84,7 +85,7 @@ void Sampler::set_max_anisotropy(float a)
                static Require _req(EXT_texture_filter_anisotropic);
        max_anisotropy = a;
        if(EXT_texture_filter_anisotropic)
-               update_parameter(MAX_ANISOTROPY);
+               dirty_params |= MAX_ANISOTROPY;
 }
 
 void Sampler::set_wrap(TextureWrap w)
@@ -98,32 +99,32 @@ void Sampler::set_wrap(TextureWrap w)
 void Sampler::set_wrap_s(TextureWrap w)
 {
        wrap_s = w;
-       update_parameter(WRAP_S);
+       dirty_params |= WRAP_S;
 }
 
 void Sampler::set_wrap_t(TextureWrap w)
 {
        wrap_t = w;
-       update_parameter(WRAP_T);
+       dirty_params |= WRAP_T;
 }
 
 void Sampler::set_wrap_r(TextureWrap w)
 {
        static Require _req(EXT_texture3D);
        wrap_r = w;
-       update_parameter(WRAP_R);
+       dirty_params |= WRAP_R;
 }
 
 void Sampler::set_border_color(const Color &c)
 {
        border_color = c;
-       update_parameter(BORDER_COLOR);
+       dirty_params |= BORDER_COLOR;
 }
 
 void Sampler::disable_compare()
 {
        compare = false;
-       update_parameter(COMPARE);
+       dirty_params |= COMPARE;
 }
 
 void Sampler::set_compare(Predicate f)
@@ -134,34 +135,6 @@ void Sampler::set_compare(Predicate f)
        dirty_params |= COMPARE;
 }
 
-void Sampler::bind_to(unsigned i) const
-{
-       TexUnit &unit = TexUnit::get_unit(i);
-
-       if(unit.set_sampler(this))
-       {
-               glBindSampler(i, id);
-
-               if(dirty_params)
-               {
-                       update_parameter(dirty_params);
-                       dirty_params = 0;
-               }
-       }
-}
-
-const Sampler *Sampler::current(unsigned i)
-{
-       return TexUnit::get_unit(i).get_sampler();
-}
-
-void Sampler::unbind_from(unsigned i)
-{
-       TexUnit &unit = TexUnit::get_unit(i);
-       if(unit.set_sampler(0))
-               glBindSampler(i, 0);
-}
-
 void Sampler::set_debug_name(const string &name)
 {
 #ifdef DEBUG
index bb02269f8c0ec9bcfd4408b3e48fa49702b90e06..ff9201860e69bc4c7cc6ed8af2dc512940ac5615 100644 (file)
@@ -114,7 +114,7 @@ public:
        Sampler();
 
 private:
-       void update_parameter(int) const;
+       void update() const;
        void set_parameter_i(unsigned, int) const;
        void set_parameter_f(unsigned, float) const;
        void set_parameter_fv(unsigned, const float *) const;
@@ -155,12 +155,9 @@ public:
        bool is_compare_enabled() const { return compare; }
        Predicate get_compare_function() const { return cmp_func; }
 
-       void bind() const { bind_to(0); }
-       void bind_to(unsigned) const;
+       void refresh() const { if(dirty_params) update(); }
 
-       static const Sampler *current(unsigned = 0);
-       static void unbind() { unbind_from(0); }
-       static void unbind_from(unsigned);
+       unsigned get_id() const { return id; }
 
        void set_debug_name(const std::string &);
 };
index ea503ed1f9d4414f28f200c89be286fdc49f6190..5197b3da4bd7461564305e8d9f7ffa7e8312a794 100644 (file)
@@ -8,7 +8,6 @@
 #include "resourcemanager.h"
 #include "resources.h"
 #include "texture.h"
-#include "texunit.h"
 
 using namespace std;
 
@@ -40,9 +39,6 @@ Texture::Texture(GLenum t, ResourceManager *m):
 
 Texture::~Texture()
 {
-       while(TexUnit *unit = TexUnit::find_unit(this))
-               unbind_from(unit->get_index());
-
        if(id)
                glDeleteTextures(1, &id);
 }
@@ -137,13 +133,22 @@ void Texture::generate_mipmap()
        // glGenerateMipmap is defined here
        static Require _req(EXT_framebuffer_object);
 
+       if(!ARB_direct_state_access)
+       {
+               glActiveTexture(GL_TEXTURE0);
+               glBindTexture(target, id);
+       }
+       generate_mipmap_();
+       if(!ARB_direct_state_access)
+               glBindTexture(target, 0);
+}
+
+void Texture::generate_mipmap_()
+{
        if(ARB_direct_state_access)
                glGenerateTextureMipmap(id);
        else
-       {
-               BindRestore _bind(this);
                glGenerateMipmap(target);
-       }
 }
 
 void Texture::set_auto_generate_mipmap(bool gm)
@@ -172,56 +177,6 @@ void Texture::image(const Graphics::Image &img, bool)
        image(img, 0U);
 }
 
-void Texture::bind_to(unsigned i) const
-{
-       if(!id)
-       {
-               if(manager)
-                       manager->resource_used(*this);
-               if(!id)
-               {
-                       unbind_from(i);
-                       return;
-               }
-       }
-
-       TexUnit &unit = TexUnit::get_unit(i);
-       if(unit.set_texture(this))
-       {
-               if(manager)
-                       manager->resource_used(*this);
-
-               if(ARB_direct_state_access)
-                       glBindTextureUnit(i, id);
-               else
-               {
-                       unit.bind();
-                       glBindTexture(target, id);
-               }
-       }
-}
-
-const Texture *Texture::current(unsigned i)
-{
-       return TexUnit::get_unit(i).get_texture();
-}
-
-void Texture::unbind_from(unsigned i)
-{
-       TexUnit &unit = TexUnit::get_unit(i);
-       const Texture *cur = unit.get_texture();
-       if(unit.set_texture(0))
-       {
-               if(ARB_direct_state_access)
-                       glBindTextureUnit(i, 0);
-               else
-               {
-                       unit.bind();
-                       glBindTexture(cur->target, 0);
-               }
-       }
-}
-
 void Texture::set_debug_name(const string &name)
 {
 #ifdef DEBUG
index 7fb41a622b7b3c7609baea465480603d9b1555f5..58e22d358a6a82f2f321b3ba553b9a5b2ce00fc6 100644 (file)
@@ -89,7 +89,10 @@ public:
        static bool can_generate_mipmap();
 
        void generate_mipmap();
+protected:
+       void generate_mipmap_();
 
+public:
        /** Sets automatic mipmap generation.  If enabled, mipmaps are generated
        when a texture image is uploaded. */
        void set_auto_generate_mipmap(bool);
@@ -112,13 +115,6 @@ public:
        GLenum get_target() const { return target; }
        unsigned get_id() const { return id; }
 
-       void bind() const { bind_to(0); }
-       void bind_to(unsigned) const;
-
-       static const Texture *current(unsigned = 0);
-       static void unbind() { unbind_from(0); }
-       static void unbind_from(unsigned);
-
        virtual UInt64 get_data_size() const { return 0; }
 
        void set_debug_name(const std::string &);
index 71c736f04da4ecb7971d22461434169445614f6b..7685d39e99abaeca025ae1c4750b6a53903ff08a 100644 (file)
@@ -43,12 +43,27 @@ void Texture1D::allocate(unsigned level)
                throw invalid_operation("Texture1D::allocate");
        if(level>=levels)
                throw invalid_argument("Texture1D::allocate");
+
+       bool direct = ARB_texture_storage && ARB_direct_state_access;
+       if(!direct)
+       {
+               glActiveTexture(GL_TEXTURE0);
+               glBindTexture(target, id);
+       }
+
+       allocate_(level);
+
+       if(!direct)
+               glBindTexture(target, 0);
+}
+
+void Texture1D::allocate_(unsigned level)
+{
        if(allocated&(1<<level))
                return;
 
        if(ARB_texture_storage)
        {
-               Conditional<BindRestore> _bind(!ARB_direct_state_access, this);
                if(ARB_direct_state_access)
                        glTextureStorage1D(id, levels, storage_fmt, width);
                else
@@ -57,7 +72,7 @@ void Texture1D::allocate(unsigned level)
                allocated |= (1<<levels)-1;
        }
        else
-               image(level, 0);
+               image_(level, 0);
 }
 
 void Texture1D::image(unsigned level, const void *data)
@@ -67,13 +82,25 @@ void Texture1D::image(unsigned level, const void *data)
        if(level>=levels)
                throw out_of_range("Texture1D::image");
 
-       unsigned w = get_level_size(level);
-
        if(ARB_texture_storage)
-               return sub_image(level, 0, w, data);
+               return sub_image(level, 0, get_level_size(level), data);
+
+       glActiveTexture(GL_TEXTURE0);
+       glBindTexture(target, id);
+
+       image_(level, data);
+
+       if(auto_gen_mipmap && level==0)
+       {
+               generate_mipmap_();
+               allocated |= (1<<levels)-1;
+       }
 
-       BindRestore _bind(this);
+       glBindTexture(target, 0);
+}
 
+void Texture1D::image_(unsigned level, const void *data)
+{
        if(!allocated)
        {
                glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, levels-1);
@@ -82,14 +109,9 @@ void Texture1D::image(unsigned level, const void *data)
 
        PixelComponents comp = get_components(storage_fmt);
        GLenum type = get_gl_type(get_component_type(storage_fmt));
-       glTexImage1D(target, level, storage_fmt, w, 0, comp, type, data);
+       glTexImage1D(target, level, storage_fmt, get_level_size(level), 0, comp, type, data);
 
        allocated |= 1<<level;
-       if(auto_gen_mipmap && level==0)
-       {
-               generate_mipmap();
-               allocated |= (1<<levels)-1;
-       }
 }
 
 void Texture1D::image(unsigned level, PixelComponents comp, DataType type, const void *data)
@@ -106,8 +128,14 @@ void Texture1D::sub_image(unsigned level, int x, unsigned wd, const void *data)
        if(level>=levels)
                throw out_of_range("Texture1D::sub_image");
 
-       Conditional<BindRestore> _bind(!ARB_direct_state_access, this);
-       allocate(level);
+       bool direct = (ARB_direct_state_access && (ARB_texture_storage || (allocated&(1<<level))));
+       if(!direct)
+       {
+               glActiveTexture(GL_TEXTURE0);
+               glBindTexture(target, id);
+       }
+
+       allocate_(level);
 
        PixelComponents comp = get_components(storage_fmt);
        GLenum type = get_gl_type(get_component_type(storage_fmt));
@@ -117,7 +145,10 @@ void Texture1D::sub_image(unsigned level, int x, unsigned wd, const void *data)
                glTexSubImage1D(target, level, x, wd, comp, type, data);
 
        if(auto_gen_mipmap && level==0)
-               generate_mipmap();
+               generate_mipmap_();
+
+       if(!direct)
+               glBindTexture(target, 0);
 }
 
 void Texture1D::sub_image(unsigned level, int x, unsigned wd, PixelComponents comp, DataType type, const void *data)
index b14ff917666f88cb02fc7fbbcd5c55a8330b0075..09d805e7869f8afd2819596bab336a8db23389a8 100644 (file)
@@ -36,7 +36,13 @@ public:
        { storage(make_pixelformat(c, UNSIGNED_BYTE), w, l); }
 
        void allocate(unsigned);
+private:
+       void allocate_(unsigned);
+public:
        void image(unsigned, const void *);
+private:
+       void image_(unsigned, const void *);
+public:
        DEPRECATED void image(unsigned, PixelComponents, DataType, const void *);
        void sub_image(unsigned, int, unsigned, const void *);
        DEPRECATED void sub_image(unsigned, int, unsigned, PixelComponents, DataType, const void *);
index 78f8c9e983034f34eadec903c5c53ffb4ffd6c5d..09831cb3385abcc5eeaf5f9e5404e33a6a427f3f 100644 (file)
@@ -72,12 +72,27 @@ void Texture2D::allocate(unsigned level)
                throw invalid_operation("Texture2D::allocate");
        if(level>=levels)
                throw invalid_argument("Texture2D::allocate");
+
+       bool direct = ARB_texture_storage && ARB_direct_state_access;
+       if(!direct)
+       {
+               glActiveTexture(GL_TEXTURE0);
+               glBindTexture(target, id);
+       }
+
+       allocate_(level);
+
+       if(!direct)
+               glBindTexture(target, 0);
+}
+
+void Texture2D::allocate_(unsigned level)
+{
        if(allocated&(1<<level))
                return;
 
        if(ARB_texture_storage)
        {
-               Conditional<BindRestore> _bind(!ARB_direct_state_access, this);
                if(ARB_direct_state_access)
                        glTextureStorage2D(id, levels, storage_fmt, width, height);
                else
@@ -86,7 +101,7 @@ void Texture2D::allocate(unsigned level)
                allocated |= (1<<levels)-1;
        }
        else
-               image(level, 0);
+               image_(level, 0);
 }
 
 void Texture2D::image(unsigned level, const void *data)
@@ -96,29 +111,40 @@ void Texture2D::image(unsigned level, const void *data)
        if(level>=levels)
                throw out_of_range("Texture2D::image");
 
-       LinAl::Vector<unsigned, 2> size = get_level_size(level);
-
        if(ARB_texture_storage)
+       {
+               LinAl::Vector<unsigned, 2> size = get_level_size(level);
                return sub_image(level, 0, 0, size.x, size.y, data);
+       }
+
+       glActiveTexture(GL_TEXTURE0);
+       glBindTexture(target, id);
+
+       image_(level, data);
+
+       if(auto_gen_mipmap && level==0)
+       {
+               generate_mipmap_();
+               allocated |= (1<<levels)-1;
+       }
 
-       BindRestore _bind(this);
+       glBindTexture(target, 0);
+}
 
+void Texture2D::image_(unsigned level, const void *data)
+{
        if(!allocated)
        {
                glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, levels-1);
                apply_swizzle();
        }
 
+       LinAl::Vector<unsigned, 2> size = get_level_size(level);
        PixelComponents comp = get_components(storage_fmt);
        GLenum type = get_gl_type(get_component_type(storage_fmt));
        glTexImage2D(target, level, storage_fmt, size.x, size.y, 0, comp, type, data);
 
        allocated |= 1<<level;
-       if(auto_gen_mipmap && level==0)
-       {
-               generate_mipmap();
-               allocated |= (1<<levels)-1;
-       }
 }
 
 void Texture2D::image(unsigned level, PixelComponents comp, DataType type, const void *data)
@@ -135,8 +161,14 @@ void Texture2D::sub_image(unsigned level, int x, int y, unsigned wd, unsigned ht
        if(level>=levels)
                throw out_of_range("Texture2D::sub_image");
 
-       Conditional<BindRestore> _bind(!ARB_direct_state_access, this);
-       allocate(level);
+       bool direct = (ARB_direct_state_access && (ARB_texture_storage || (allocated&(1<<level))));
+       if(!direct)
+       {
+               glActiveTexture(GL_TEXTURE0);
+               glBindTexture(target, id);
+       }
+
+       allocate_(level);
 
        PixelComponents comp = get_components(storage_fmt);
        GLenum type = get_gl_type(get_component_type(storage_fmt));
@@ -146,7 +178,10 @@ void Texture2D::sub_image(unsigned level, int x, int y, unsigned wd, unsigned ht
                glTexSubImage2D(target, level, x, y, wd, ht, comp, type, data);
 
        if(auto_gen_mipmap && level==0)
-               generate_mipmap();
+               generate_mipmap_();
+
+       if(!direct)
+               glBindTexture(target, 0);
 }
 
 void Texture2D::sub_image(unsigned level, int x, int y, unsigned wd, unsigned ht, PixelComponents comp, DataType type, const void *data)
@@ -290,7 +325,6 @@ bool Texture2D::AsyncLoader::process()
                image.load_into(*img_loader, mapped_address);
        else if(phase==3)
        {
-               Bind _bind_buf(pixel_buffer, PIXEL_UNPACK_BUFFER);
                mapped_address = 0;
                if(!pixel_buffer.unmap())
                {
@@ -300,7 +334,9 @@ bool Texture2D::AsyncLoader::process()
 
                if(!texture.id)
                        texture.generate_id();
+               glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pixel_buffer.get_id());
                texture.image(image, 0, true);
+               glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
        }
 
        ++phase;
index 877555c0f5ba43d4cdefb5a78af34225cc2e4756..8f5c9b21df7df778559e2f52e40bf10bd841144a 100644 (file)
@@ -56,11 +56,19 @@ public:
        undefined.  If storage has already been allocated, does nothing. */
        void allocate(unsigned level);
 
+private:
+       void allocate_(unsigned level);
+
+public:
        /** Updates the contents of the entire texture.  Storage must be defined
        beforehand.  The image data must have dimensions and format matching the
        defined storage. */
        virtual void image(unsigned level, const void *data);
 
+private:
+       void image_(unsigned level, const void *data);
+
+public:
        DEPRECATED void image(unsigned level, PixelComponents fmt, DataType type, const void *data);
 
        /** Updates a rectangular region of the texture.  Storage must be defined
index f6268d697d6d60c00735c6230e6ff6c701eb8b7c..3c675dbb705847527586b452f414bdc4b49c1fb1 100644 (file)
@@ -62,9 +62,23 @@ void Texture3D::allocate(unsigned level)
        if(allocated&(1<<level))
                return;
 
+       bool direct = ARB_texture_storage && ARB_direct_state_access;
+       if(!direct)
+       {
+               glActiveTexture(GL_TEXTURE0);
+               glBindTexture(target, id);
+       }
+
+       allocate_(level);
+
+       if(!direct)
+               glBindTexture(target, 0);
+}
+
+void Texture3D::allocate_(unsigned level)
+{
        if(ARB_texture_storage)
        {
-               Conditional<BindRestore> _bind(!ARB_direct_state_access, this);
                if(ARB_direct_state_access)
                        glTextureStorage3D(id, levels, storage_fmt, width, height, depth);
                else
@@ -73,7 +87,7 @@ void Texture3D::allocate(unsigned level)
                allocated |= (1<<levels)-1;
        }
        else
-               image(level, 0);
+               image_(level, 0);
 }
 
 void Texture3D::image(unsigned level, const void *data)
@@ -83,29 +97,40 @@ void Texture3D::image(unsigned level, const void *data)
        if(level>=levels)
                throw out_of_range("Texture3D::image");
 
-       LinAl::Vector<unsigned, 3> size = get_level_size(level);
-
        if(ARB_texture_storage)
+       {
+               LinAl::Vector<unsigned, 3> size = get_level_size(level);
                return sub_image(level, 0, 0, 0, size.x, size.y, size.z, data);
+       }
+
+       glActiveTexture(GL_TEXTURE0);
+       glBindTexture(target, id);
 
-       BindRestore _bind(this);
+       image_(level, data);
 
+       if(auto_gen_mipmap && level==0)
+       {
+               generate_mipmap_();
+               allocated |= (1<<levels)-1;
+       }
+
+       glBindTexture(target, 0);
+}
+
+void Texture3D::image_(unsigned level, const void *data)
+{
        if(!allocated)
        {
                glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, levels-1);
                apply_swizzle();
        }
 
+       LinAl::Vector<unsigned, 3> size = get_level_size(level);
        PixelComponents comp = get_components(storage_fmt);
        GLenum type = get_gl_type(get_component_type(storage_fmt));
        glTexImage3D(target, level, storage_fmt, size.x, size.y, size.z, 0, comp, type, data);
 
        allocated |= 1<<level;
-       if(auto_gen_mipmap && level==0)
-       {
-               generate_mipmap();
-               allocated |= (1<<levels)-1;
-       }
 }
 
 void Texture3D::image(unsigned level, PixelComponents comp, DataType type, const void *data)
@@ -122,8 +147,14 @@ void Texture3D::sub_image(unsigned level, int x, int y, int z, unsigned wd, unsi
        if(level>=levels)
                throw out_of_range("Texture3D::sub_image");
 
-       Conditional<BindRestore> _bind(!ARB_direct_state_access, this);
-       allocate(level);
+       bool direct = (ARB_direct_state_access && (ARB_texture_storage || (allocated&(1<<level))));
+       if(!direct)
+       {
+               glActiveTexture(GL_TEXTURE0);
+               glBindTexture(target, id);
+       }
+
+       allocate_(level);
 
        PixelComponents comp = get_components(storage_fmt);
        GLenum type = get_gl_type(get_component_type(storage_fmt));
@@ -133,7 +164,10 @@ void Texture3D::sub_image(unsigned level, int x, int y, int z, unsigned wd, unsi
                glTexSubImage3D(target, level, x, y, z, wd, ht, dp, comp, type, data);
 
        if(auto_gen_mipmap && level==0)
-               generate_mipmap();
+               generate_mipmap_();
+
+       if(!direct)
+               glBindTexture(target, 0);
 }
 
 void Texture3D::sub_image(unsigned level, int x, int y, int z, unsigned wd, unsigned ht, unsigned dp, PixelComponents comp, DataType type, const void *data)
index df52bf66ee8daeb1e1a879440c63ed52ab799833..2a8f653cd04422c333a1dcb81e937978dee38fda 100644 (file)
@@ -53,11 +53,19 @@ public:
        undefined.  If storage has already been allocated, does nothing. */
        void allocate(unsigned level);
 
+private:
+       void allocate_(unsigned);
+
+public:
        /** Updates the contents of the entire texture.  Storage must be defined
        beforehand.  The image data must have dimensions and format matching the
        defined storage. */
        void image(unsigned level, const void *data);
 
+private:
+       void image_(unsigned, const void *);
+
+public:
        DEPRECATED void image(unsigned level, PixelComponents comp, DataType type, const void *data);
 
        /** Updates a cuboid-shaped region of the texture.  Storage must be defined
index 543bb9d40ec00e954ce894d9699e86c364405dd8..4984985c807489b28d6f5737c2f2ba03286488d3 100644 (file)
@@ -82,9 +82,23 @@ void TextureCube::allocate(unsigned level)
        if(allocated&(64<<level))
                return;
 
+       bool direct = ARB_texture_storage && ARB_direct_state_access;
+       if(!direct)
+       {
+               glActiveTexture(GL_TEXTURE0);
+               glBindTexture(target, id);
+       }
+
+       allocate_(level);
+
+       if(!direct)
+               glBindTexture(target, 0);
+}
+
+void TextureCube::allocate_(unsigned level)
+{
        if(ARB_texture_storage)
        {
-               Conditional<BindRestore> _bind(!ARB_direct_state_access, this);
                if(ARB_direct_state_access)
                        glTextureStorage2D(id, levels, storage_fmt, size, size);
                else
@@ -95,7 +109,7 @@ void TextureCube::allocate(unsigned level)
        else
        {
                for(unsigned i=0; i<6; ++i)
-                       image(enumerate_faces(i), level, 0);
+                       image_(enumerate_faces(i), level, 0);
        }
 }
 
@@ -106,41 +120,50 @@ void TextureCube::image(TextureCubeFace face, unsigned level, const void *data)
        if(level>=levels)
                throw out_of_range("TextureCube::image");
 
-       unsigned s = get_level_size(level);
-
        if(ARB_texture_storage)
-               return sub_image(face, level, 0, 0, s, s, data);
+       {
+               unsigned lsz = get_level_size(level);
+               return sub_image(face, level, 0, 0, lsz, lsz, data);
+       }
+
+       glActiveTexture(GL_TEXTURE0);
+       glBindTexture(target, id);
 
-       BindRestore _bind(this);
+       image_(face, level, data);
 
+       if(auto_gen_mipmap && level==0 && (allocated&63)==63)
+       {
+               generate_mipmap_();
+               allocated |= (64<<levels)-1;
+       }
+
+       glBindTexture(target, 0);
+}
+
+void TextureCube::image_(TextureCubeFace face, unsigned level, const void *data)
+{
        if(!allocated)
        {
                glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, levels-1);
                apply_swizzle();
        }
 
+       unsigned lsz = get_level_size(level);
        PixelComponents comp = get_components(storage_fmt);
        GLenum type = get_gl_type(get_component_type(storage_fmt));
-       glTexImage2D(face, level, storage_fmt, s, s, 0, comp, type, data);
+       glTexImage2D(face, level, storage_fmt, lsz, lsz, 0, comp, type, data);
 
        if(level==0)
        {
                allocated |= 1<<get_face_index(face);
                if((allocated&63)==63)
-               {
                        allocated |= 64;
-                       if(auto_gen_mipmap)
-                       {
-                               generate_mipmap();
-                               allocated |= (64<<levels)-1;
-                       }
-               }
        }
        else if(!(allocated&(64<<level)))
        {
                for(unsigned i=0; i<6; ++i)
                        if(enumerate_faces(i)!=face)
-                               glTexImage2D(enumerate_faces(i), level, storage_fmt, s, s, 0, comp, type, 0);
+                               glTexImage2D(enumerate_faces(i), level, storage_fmt, lsz, lsz, 0, comp, type, 0);
 
                allocated |= 64<<level;
        }
@@ -160,8 +183,14 @@ void TextureCube::sub_image(TextureCubeFace face, unsigned level, int x, int y,
        if(level>=levels)
                throw out_of_range("TextureCube::sub_image");
 
-       Conditional<BindRestore> _bind(!ARB_direct_state_acess, this);
-       allocate(level);
+       bool direct = (ARB_direct_state_access && (ARB_texture_storage || (allocated&(1<<level))));
+       if(!direct)
+       {
+               glActiveTexture(GL_TEXTURE0);
+               glBindTexture(target, id);
+       }
+
+       allocate_(level);
 
        PixelComponents comp = get_components(storage_fmt);
        GLenum type = get_gl_type(get_component_type(storage_fmt));
@@ -171,7 +200,10 @@ void TextureCube::sub_image(TextureCubeFace face, unsigned level, int x, int y,
                glTexSubImage2D(face, level, x, y, wd, ht, comp, type, data);
 
        if(auto_gen_mipmap && level==0)
-               generate_mipmap();
+               generate_mipmap_();
+
+       if(!direct)
+               glBindTexture(target, 0);
 }
 
 void TextureCube::sub_image(TextureCubeFace face, unsigned level, int x, int y, unsigned wd, unsigned ht, PixelComponents comp, DataType type, const void *data)
index ae305153fec6860a8f37e3128f037214f07d5e25..39fe0c699b4b6358fa9efe6c7348504450690742 100644 (file)
@@ -77,11 +77,19 @@ public:
        undefined.  If storage has already been allocated, does nothing. */
        void allocate(unsigned level);
 
+private:
+       void allocate_(unsigned);
+
+public:
        /** Updates the contents of a face.  Storage must be defined beforehand.
        The image data must have dimensions and format matching the defined
        storage. */
        void image(TextureCubeFace face, unsigned level, const void *data);
 
+private:
+       void image_(TextureCubeFace, unsigned, const void *);
+
+public:
        DEPRECATED void image(TextureCubeFace face, unsigned level,
                PixelComponents comp, DataType type, const void *data);
 
diff --git a/source/core/texunit.cpp b/source/core/texunit.cpp
deleted file mode 100644 (file)
index 7405d8d..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-#include <stdexcept>
-#include <msp/gl/extensions/arb_multitexture.h>
-#include <msp/gl/extensions/arb_vertex_shader.h>
-#include "deviceinfo.h"
-#include "gl.h"
-#include "misc.h"
-#include "texture.h"
-#include "texunit.h"
-
-using namespace std;
-
-namespace Msp {
-namespace GL {
-
-vector<TexUnit> TexUnit::units;
-TexUnit *TexUnit::cur_unit = 0;
-
-TexUnit::TexUnit():
-       texture(0),
-       sampler(0)
-{ }
-
-bool TexUnit::set_texture(const Texture *tex)
-{
-       bool result = (tex!=texture);
-       texture = tex;
-       return result;
-}
-
-bool TexUnit::set_sampler(const Sampler *samp)
-{
-       bool result = (samp!=sampler);
-       sampler = samp;
-       return result;
-}
-
-void TexUnit::bind()
-{
-       if(cur_unit!=this && (cur_unit || index))
-               glActiveTexture(GL_TEXTURE0+index);
-       cur_unit = this;
-}
-
-unsigned TexUnit::get_n_units()
-{
-       return Limits::get_global().max_texture_bindings;
-}
-
-TexUnit &TexUnit::get_unit(unsigned n)
-{
-       if(n>0)
-               static Require _req(ARB_multitexture);
-       if(n>=Limits::get_global().max_texture_bindings)
-               throw out_of_range("TexUnit::get_unit");
-
-       if(units.size()<=n)
-       {
-               unsigned i = units.size();
-               units.resize(n+1, TexUnit());
-               for(; i<units.size(); ++i)
-                       units[i].index = i;
-       }
-
-       return units[n];
-}
-
-TexUnit &TexUnit::current()
-{
-       if(!cur_unit)
-               get_unit(0).bind();
-       return *cur_unit;
-}
-
-TexUnit *TexUnit::find_unit(const Texture *tex)
-{
-       for(vector<TexUnit>::iterator i=units.begin(); i!=units.end(); ++i)
-               if(i->texture==tex)
-                       return &*i;
-       return 0;
-}
-
-} // namespace GL
-} // namespace Msp
diff --git a/source/core/texunit.h b/source/core/texunit.h
deleted file mode 100644 (file)
index 8fefc3a..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef MSP_GL_TEXUNIT_H_
-#define MSP_GL_TEXUNIT_H_
-
-#include <vector>
-
-namespace Msp {
-namespace GL {
-
-class Sampler;
-class Texture;
-
-/**
-Keeps track of texture unit related state.  Intended for internal use.
-*/
-class TexUnit
-{
-private:
-       unsigned index;
-       const Texture *texture;
-       const Sampler *sampler;
-
-       static std::vector<TexUnit> units;
-       static TexUnit *cur_unit;
-
-       TexUnit();
-
-public:
-       unsigned get_index() const { return index; }
-       bool set_texture(const Texture *);
-       const Texture *get_texture() const { return texture; }
-       bool set_sampler(const Sampler *);
-       const Sampler *get_sampler() const { return sampler; }
-       void bind();
-
-       DEPRECATED static unsigned get_n_units();
-       static TexUnit &get_unit(unsigned);
-       static TexUnit &current();
-       static TexUnit *find_unit(const Texture *);
-};
-
-} // namespace GL
-} // namespace Msp
-
-#endif
index 59871cdde8249b3b90e0dd03a89db66963e2efd6..af4016ee5da8b32ad926689e0c211a3b0dbc4042 100644 (file)
@@ -38,11 +38,8 @@ void DefaultUniformBlock::attach(int index, const Uniform &uni)
        uniforms[index] = &uni;
 }
 
-void DefaultUniformBlock::apply(int index) const
+void DefaultUniformBlock::apply() const
 {
-       if(index>=0)
-               throw invalid_argument("DefaultUniformBlock::apply");
-
        for(unsigned i=0; i<uniforms.size(); ++i)
                if(uniforms[i])
                        uniforms[i]->apply(i);
@@ -51,8 +48,7 @@ void DefaultUniformBlock::apply(int index) const
 
 BufferBackedUniformBlock::BufferBackedUniformBlock(unsigned s):
        size(s),
-       data(size),
-       buf_range(0)
+       data(size)
 {
        static Require _req(ARB_shader_objects);
        static Require _req2(ARB_uniform_buffer_object);
@@ -61,22 +57,11 @@ BufferBackedUniformBlock::BufferBackedUniformBlock(unsigned s):
                throw invalid_argument("BufferBackedUniformBlock::BufferBackedUniformBlock");
 }
 
-BufferBackedUniformBlock::~BufferBackedUniformBlock()
-{
-       delete buf_range;
-}
-
 unsigned BufferBackedUniformBlock::get_alignment() const
 {
        return Limits::get_global().uniform_buffer_alignment;
 }
 
-void BufferBackedUniformBlock::location_changed(Buffer *buf, unsigned off, unsigned) const
-{
-       delete buf_range;
-       buf_range = buf->create_range(off, size);
-}
-
 void BufferBackedUniformBlock::attach(const Program::UniformInfo &info, const Uniform &uni)
 {
        if(info.block->bind_point<0)
@@ -86,16 +71,5 @@ void BufferBackedUniformBlock::attach(const Program::UniformInfo &info, const Un
        dirty = true;
 }
 
-void BufferBackedUniformBlock::apply(int index) const
-{
-       if(index<0)
-               throw invalid_argument("BufferBackedUniformBlock::apply");
-       if(!get_buffer())
-               throw invalid_operation("UniformBlock::apply");
-
-       refresh();
-       buf_range->bind_to(UNIFORM_BUFFER, index);
-}
-
 } // namespace GL
 } // namespace Msp
index bc0b933b01666f3a8e4df77fb1e179f1a8123652..18b651c7b4e498c12f2bdccba4c190dbe5c30663 100644 (file)
@@ -27,7 +27,6 @@ public:
        virtual ~UniformBlock() { }
 
        virtual void attach(const Program::UniformInfo &, const Uniform &) = 0;
-       virtual void apply(int) const = 0;
 };
 
 /** Stores uniforms for the default uniform block.  Uniforms are associated
@@ -42,7 +41,7 @@ public:
 
        virtual void attach(const Program::UniformInfo &, const Uniform &);
        void attach(int, const Uniform &);
-       virtual void apply(int) const;
+       void apply() const;
 };
 
 /** Stores uniforms for a buffer-backed uniform block.  Uniform values are
@@ -53,21 +52,17 @@ class BufferBackedUniformBlock: public UniformBlock, public Bufferable
 private:
        unsigned size;
        std::vector<char> data;
-       mutable BufferRange *buf_range;
 
 public:
        BufferBackedUniformBlock(unsigned);
-       virtual ~BufferBackedUniformBlock();
 
-private:
        virtual unsigned get_data_size() const { return size; }
+private:
        virtual const void *get_data_pointer() const { return &data[0]; }
        virtual unsigned get_alignment() const;
-       virtual void location_changed(Buffer *, unsigned, unsigned) const;
 
 public:
        void attach(const Program::UniformInfo &, const Uniform &);
-       virtual void apply(int) const;
 };
 
 } // namespace GL
index 1094bb21c9ef229359a09f70b35435c32f6e8444..f077ad2e00260ac675efcd191a214b8820eb3554 100644 (file)
@@ -34,8 +34,6 @@ VertexSetup::VertexSetup():
 
 VertexSetup::~VertexSetup()
 {
-       if(current()==this)
-               unbind();
        glDeleteVertexArrays(1, &id);
 }
 
@@ -70,7 +68,7 @@ void VertexSetup::set_vertex_array(const VertexArray &a)
                throw invalid_argument("VertexSetup::set_vertex_array");
 
        vertex_array = &a;
-       update(VERTEX_ARRAY);
+       dirty |= VERTEX_ARRAY;
 }
 
 void VertexSetup::set_instance_array(const VertexArray &a)
@@ -85,13 +83,13 @@ void VertexSetup::set_instance_array(const VertexArray &a)
        static Require req(ARB_instanced_arrays);
 
        inst_array = &a;
-       update(INSTANCE_ARRAY);
+       dirty |= INSTANCE_ARRAY;
 }
 
 void VertexSetup::set_index_buffer(const Buffer &ibuf)
 {
        index_buffer = &ibuf;
-       update(INDEX_BUFFER);
+       dirty |= INDEX_BUFFER;
 }
 
 bool VertexSetup::verify_format(const VertexFormat &fmt)
@@ -108,33 +106,31 @@ bool VertexSetup::verify_format(const VertexFormat &fmt)
        return true;
 }
 
-void VertexSetup::update(unsigned mask) const
+void VertexSetup::update() const
 {
        static bool direct = ARB_direct_state_access && ARB_vertex_attrib_binding;
-       if(!direct && current()!=this)
-       {
-               dirty |= mask;
-               return;
-       }
 
-       if(mask&VERTEX_ARRAY)
+       if(dirty&VERTEX_ARRAY)
                update_vertex_array(*vertex_array, 0, 0, direct);
 
-       if((mask&INSTANCE_ARRAY) && inst_array)
+       if(dirty&INSTANCE_ARRAY)
                update_vertex_array(*inst_array, 1, 1, direct);
 
-       if(mask&INDEX_BUFFER)
+       if(dirty&INDEX_BUFFER)
        {
                if(direct)
                        glVertexArrayElementBuffer(id, index_buffer->get_id());
                else
-                       glBindBuffer(ELEMENT_ARRAY_BUFFER, index_buffer->get_id());
+                       glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer->get_id());
        }
+
+       dirty = 0;
 }
 
 void VertexSetup::update_vertex_array(const VertexArray &array, unsigned binding, unsigned divisor, bool direct) const
 {
-       Conditional<Bind> bind_vbuf(!direct, array.get_buffer(), ARRAY_BUFFER);
+       if(!direct)
+               glBindBuffer(GL_ARRAY_BUFFER, array.get_buffer()->get_id());
 
        const VertexFormat &fmt = array.get_format();
        unsigned stride = fmt.stride()*sizeof(float);
@@ -170,31 +166,9 @@ void VertexSetup::update_vertex_array(const VertexArray &array, unsigned binding
                }
                offset += sz*sizeof(float);
        }
-}
 
-void VertexSetup::bind() const
-{
-       if(!vertex_array || !index_buffer)
-               throw invalid_operation("VertexSetup::bind");
-
-       if(set_current(this))
-       {
-               vertex_array->refresh();
-               if(inst_array)
-                       inst_array->refresh();
-               glBindVertexArray(id);
-               if(dirty)
-               {
-                       update(dirty);
-                       dirty = 0;
-               }
-       }
-}
-
-void VertexSetup::unbind()
-{
-       if(set_current(0))
-               glBindVertexArray(0);
+       if(!direct)
+               glBindBuffer(GL_ARRAY_BUFFER, 0);
 }
 
 void VertexSetup::unload()
@@ -207,8 +181,8 @@ void VertexSetup::unload()
        }
        else
        {
-               BindRestore _bind(*this);
-               Buffer::unbind_from(ARRAY_BUFFER);
+               glBindVertexArray(id);
+               glBindBuffer(GL_ARRAY_BUFFER, 0);
 
                for(const unsigned char *a=vertex_format.begin(); a!=vertex_format.end(); ++a)
                {
@@ -223,7 +197,7 @@ void VertexSetup::unload()
                        glVertexAttribPointer(sem, 1, GL_FLOAT, false, 0, 0);
                }
 
-               glBindBuffer(ELEMENT_ARRAY_BUFFER, 0);
+               glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        }
 
        vertex_array = 0;
index 3b18006af04918661150d285ea6563664db51b32..408d738012fb196be44555c3bb25b9fe9672582a 100644 (file)
@@ -7,13 +7,14 @@
 namespace Msp {
 namespace GL {
 
+class Buffer;
 class VertexArray;
 
 /**
 Combines a VertexArray with an index buffer.  This wraps OpenGL's vertex array
 objects.  Intended for internal use.
 */
-class VertexSetup: public Bindable<VertexSetup>
+class VertexSetup
 {
 private:
        enum ComponentMask
@@ -47,12 +48,13 @@ public:
 
 private:
        static bool verify_format(const VertexFormat &);
-       void update(unsigned) const;
+       void update() const;
        void update_vertex_array(const VertexArray &, unsigned, unsigned, bool) const;
 
 public:
-       void bind() const;
-       static void unbind();
+       void refresh() const { if(dirty) update(); }
+
+       unsigned get_id() const { return id; }
 
        void unload();
 
index ffc52556bfaa5e9b6df35c5345e1afb212fdacab..ff5b417d5a0a28ee77ccc502e481e9ff23fd6229 100644 (file)
@@ -29,6 +29,8 @@ public:
        WindingTest();
        WindingTest(FaceWinding);
 
+       FaceWinding get_winding() const { return winding; }
+
        void bind() const;
 
        static void unbind();
index 8612ec06e8e10d6ba871143bc58568336c7aa38e..6e6301151e87e02c00263b01d875d00ba8970d7d 100644 (file)
@@ -7,7 +7,6 @@
 #include "resources.h"
 #include "shader.h"
 #include "tests.h"
-#include "texunit.h"
 
 using namespace std;
 
index e33295dabba94249c75f75812efd855dc0e00160..465e4fee74fc65dd2ab462710c46ac2f6922d45e 100644 (file)
@@ -4,7 +4,6 @@
 #include "mesh.h"
 #include "renderer.h"
 #include "resources.h"
-#include "texunit.h"
 
 using namespace std;
 
index b21c395cf04c27f1084492294dbd2635993af5df..79b559019d116b196502267222e5c37e6985642d 100644 (file)
@@ -7,6 +7,7 @@
 #include "color.h"
 #include "error.h"
 #include "matrix.h"
+#include "pipelinestate.h"
 #include "program.h"
 #include "programdata.h"
 #include "uniform.h"
@@ -596,15 +597,10 @@ void ProgramData::update_block(SharedBlock &block, const Program::UniformBlockIn
        }
 }
 
-void ProgramData::apply() const
+vector<ProgramData::ProgramBlock>::const_iterator ProgramData::prepare_program(const Program &prog) const
 {
-       const Program *prog = Program::current();
-       if(!prog)
-               throw invalid_operation("ProgramData::apply");
-
        BufferBackedUniformBlock *old_last_block = last_buffer_block;
-       vector<ProgramBlock>::iterator prog_begin = get_program(*prog);
-       Program::LayoutHash prog_hash = prog->get_uniform_layout_hash();
+       vector<ProgramBlock>::iterator prog_begin = get_program(prog);
 
        Mask force_dirty = (dirty==ALL_ONES ? ALL_ONES : 0U);
        Mask affected = (dirty&prog_begin->masks.used) | force_dirty;
@@ -623,7 +619,7 @@ void ProgramData::apply() const
                        dirty = 0;
                }
 
-               const vector<Program::UniformBlockInfo> &block_infos = prog->get_uniform_blocks();
+               const vector<Program::UniformBlockInfo> &block_infos = prog.get_uniform_blocks();
 
                if(prog_begin->masks.dirty==ALL_ONES)
                {
@@ -679,9 +675,25 @@ void ProgramData::apply() const
                }
        }
 
-       for(vector<ProgramBlock>::iterator i=prog_begin+1; (i!=programs.end() && i->prog_hash==prog_hash); ++i)
+       return prog_begin;
+}
+
+void ProgramData::apply(const Program &prog, PipelineState &state) const
+{
+       vector<ProgramBlock>::const_iterator prog_begin = prepare_program(prog);
+       Program::LayoutHash prog_hash = prog_begin->prog_hash;
+       for(vector<ProgramBlock>::const_iterator i=prog_begin+1; (i!=programs.end() && i->prog_hash==prog_hash); ++i)
                if(i->block)
-                       i->block->apply(i->bind_point);
+               {
+                       if(i->bind_point<0)
+                               state.set_uniforms(static_cast<const DefaultUniformBlock *>(i->block));
+                       else
+                       {
+                               const BufferBackedUniformBlock *block = static_cast<const BufferBackedUniformBlock *>(i->block);
+                               block->refresh();
+                               state.set_uniform_block(i->bind_point, block);
+                       }
+               }
 }
 
 void ProgramData::set_debug_name(const string &name)
index a05674dd21927304d3755aa5f0118870ef81729e..93eb3be89e1dc66e7ad85061d75752a4fe080a9a 100644 (file)
@@ -23,6 +23,7 @@ public:
 
 class Buffer;
 class BufferBackedUniformBlock;
+class PipelineState;
 class UniformBlock;
 struct Color;
 
@@ -249,10 +250,9 @@ private:
        void update_block_uniform_indices(SharedBlock &, const Program::UniformBlockInfo &) const;
        void update_block(SharedBlock &, const Program::UniformBlockInfo &) const;
 
+       std::vector<ProgramBlock>::const_iterator prepare_program(const Program &) const;
 public:
-       /** Applies uniform blocks for the currently bound program, creating them
-       if needed. */
-       void apply() const;
+       void apply(const Program &, PipelineState &) const;
 
        void set_debug_name(const std::string &);
 };
index d86b78046eb24454f954155f687d0c2ec9c710c0..4acf3deda9dded4cabc903e5bfc42d718f0c2f3d 100644 (file)
@@ -10,9 +10,9 @@
 #include "programdata.h"
 #include "renderable.h"
 #include "renderer.h"
+#include "resourcemanager.h"
 #include "sampler.h"
 #include "texture.h"
-#include "texunit.h"
 #include "vertexarray.h"
 #include "vertexsetup.h"
 #include "windingtest.h"
@@ -57,6 +57,10 @@ void Renderer::transform(const Matrix &matrix)
 
 void Renderer::set_texture(Tag tag, const Texture *tex, const Sampler *samp)
 {
+       if(tex)
+               if(ResourceManager *res_mgr = tex->get_manager())
+                       res_mgr->resource_used(*tex);
+
        if(texture_stack.size()>state->texture_count)
        {
                BoundTexture &bt = texture_stack[state->texture_count];
@@ -86,17 +90,9 @@ void Renderer::set_texture(Tag tag, const Texture *tex, const Sampler *samp)
 
 void Renderer::flush_textures()
 {
-       for(unsigned i=0; i<texture_stack.size(); ++i)
-       {
-               BoundTexture &bt = texture_stack[i];
-               if(i>=state->texture_count && bt.unit>=0)
-               {
-                       Texture::unbind_from(bt.unit);
-                       Sampler::unbind_from(bt.unit);
-               }
-               else if(bt.replaced>=static_cast<int>(state->texture_count))
-                       bt.replaced = -1;
-       }
+       for(unsigned i=0; i<state->texture_count; ++i)
+               if(texture_stack[i].replaced>=static_cast<int>(state->texture_count))
+                       texture_stack[i].replaced = -1;
 
        texture_stack.erase(texture_stack.begin()+state->texture_count, texture_stack.end());
 }
@@ -194,19 +190,10 @@ void Renderer::end()
 
        *state = State();
        shdata_stack.clear();
+       add_shader_data(standard_shdata);
        excluded.clear();
 
-       for(vector<BoundTexture>::iterator i=texture_stack.begin(); i!=texture_stack.end(); ++i)
-               if(i->unit>=0)
-               {
-                       Texture::unbind_from(i->unit);
-                       Sampler::unbind_from(i->unit);
-               }
-       Clipping::unbind();
-       Program::unbind();
-       VertexSetup::unbind();
-       Buffer::unbind_from(ELEMENT_ARRAY_BUFFER);
-       WindingTest::unbind();
+       PipelineState::clear();
 }
 
 void Renderer::exclude(const Renderable &renderable)
@@ -244,40 +231,38 @@ void Renderer::apply_state()
        if(!state->shprog)
                throw invalid_operation("Renderer::apply_state");
 
-       /* We (mostly) let the objects themselves figure out if the binding has
-       changed */
+       if(changed&MATRIX)
+       {
+               standard_shdata.uniform("world_obj_matrix", state->model_matrix);
+               LinAl::SquareMatrix<float, 3> nm = state->model_matrix.block<3, 3>(0, 0);
+               nm = transpose(invert(nm));
+               standard_shdata.uniform("world_obj_normal_matrix", nm);
+               changed &= ~MATRIX;
+       }
 
-       if(state->texture_count<texture_stack.size())
-               flush_textures();
+       bool shprog_changed = (state->shprog!=pipeline_state.get_shader_program());
+       pipeline_state.set_shader_program(state->shprog);
 
-       for(vector<BoundTexture>::const_iterator i=texture_stack.begin(); i!=texture_stack.end(); ++i)
+       if(state->vertex_setup)
        {
-               int unit = state->shprog->get_uniform_binding(i->tag);
-               if(unit>=0)
-               {
-                       if(i->texture)
-                               i->texture->bind_to(unit);
-                       if(i->sampler)
-                               i->sampler->bind_to(unit);
-                       i->unit = unit;
-               }
+               if(const VertexArray *array = state->vertex_setup->get_vertex_array())
+                       array->refresh();
+               if(const VertexArray *array = state->vertex_setup->get_instance_array())
+                       array->refresh();
        }
+       pipeline_state.set_vertex_setup(state->vertex_setup);
 
-       if(state->clipping)
-               state->clipping->bind();
-       else
-               Clipping::unbind();
+       pipeline_state.set_winding_test((state->winding_test && state->reverse_winding) ? &state->winding_test->get_reverse() : state->winding_test);
+       pipeline_state.set_enabled_clip_planes(state->clipping ? (1<<state->clipping->get_n_planes())-1 : 0);
 
-       bool shprog_changed = (state->shprog!=Program::current());
-       state->shprog->bind();
+       if(state->texture_count<texture_stack.size())
+               flush_textures();
 
-       if(changed&MATRIX)
+       for(vector<BoundTexture>::const_iterator i=texture_stack.begin(); i!=texture_stack.end(); ++i)
        {
-               standard_shdata.uniform("world_obj_matrix", state->model_matrix);
-               LinAl::SquareMatrix<float, 3> nm = state->model_matrix.block<3, 3>(0, 0);
-               nm = transpose(invert(nm));
-               standard_shdata.uniform("world_obj_normal_matrix", nm);
-               changed &= ~MATRIX;
+               int unit = (i->tag.id ? state->shprog->get_uniform_binding(i->tag) : i->unit);
+               if(unit>=0)
+                       pipeline_state.set_texture(unit, i->texture, i->sampler);
        }
 
        bool shdata_changed = changed&SHADER_DATA;
@@ -291,26 +276,13 @@ void Renderer::apply_state()
                        shdata_stack.erase(shdata_stack.begin()+state->shdata_count, shdata_stack.end());
                for(vector<BoundProgramData>::const_iterator i=shdata_stack.begin(); i!=shdata_stack.end(); ++i)
                {
-                       i->shdata->apply();
+                       i->shdata->apply(*state->shprog, pipeline_state);
                        i->generation = i->shdata->get_generation();
                }
                changed &= ~SHADER_DATA;
        }
 
-       if(state->vertex_setup)
-               state->vertex_setup->bind();
-       else
-               VertexSetup::unbind();
-
-       if(state->winding_test)
-       {
-               if(state->reverse_winding)
-                       state->winding_test->get_reverse().bind();
-               else
-                       state->winding_test->bind();
-       }
-       else
-               WindingTest::unbind();
+       pipeline_state.apply();
 }
 
 
index b5cbe5bcab7a32b1182f9f2aa90ca6f88c93cb68..5f069197453501fa097ccc261cb20b4383c84cb0 100644 (file)
@@ -4,6 +4,7 @@
 #include <set>
 #include <vector>
 #include "matrix.h"
+#include "pipelinestate.h"
 #include "programdata.h"
 #include "tag.h"
 
@@ -112,6 +113,7 @@ private:
        ProgramData standard_shdata;
        std::vector<BoundProgramData> shdata_stack;
        std::set<const Renderable *> excluded;
+       PipelineState pipeline_state;
 
 public:
        Renderer();
index 005904f284b74cbb6c6e9b4343584f882eca70fe..db06bb33fb51f8db7c0fd1a78055ff50ba4d9f42 100644 (file)
@@ -35,6 +35,7 @@ void View::render()
        if(!internal_renderer)
                internal_renderer = new Renderer;
        render(*internal_renderer);
+       internal_renderer->end();
 }
 
 void View::render(Renderer &renderer)