From: Mikko Rasa Date: Mon, 16 Aug 2021 16:11:25 +0000 (+0300) Subject: Rewrite state management X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=9b3bce7ae76ff8c0c81315d2505ea96bf422a318;p=libs%2Fgl.git Rewrite state management 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. --- diff --git a/source/core/batch.cpp b/source/core/batch.cpp index 68e232ba..2bc44c9d 100644 --- a/source/core/batch.cpp +++ b/source/core/batch.cpp @@ -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); } diff --git a/source/core/buffer.cpp b/source/core/buffer.cpp index 4750846a..ecf7b49a 100644 --- a/source/core/buffer.cpp +++ b/source/core/buffer.cpp @@ -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 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=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 diff --git a/source/core/buffer.h b/source/core/buffer.h index 83e75927..a80e52a6 100644 --- a/source/core/buffer.h +++ b/source/core/buffer.h @@ -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 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 diff --git a/source/core/bufferable.h b/source/core/bufferable.h index cbbde4e1..47e2770c 100644 --- a/source/core/bufferable.h +++ b/source/core/bufferable.h @@ -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; diff --git a/source/core/clipping.h b/source/core/clipping.h index b0719523..5600a38b 100644 --- a/source/core/clipping.h +++ b/source/core/clipping.h @@ -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 index 00000000..a3b9e640 --- /dev/null +++ b/source/core/pipelinestate.cpp @@ -0,0 +1,319 @@ +#include +#include +#include +#include +#include +#include +#include +#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 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::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::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>i)&1) + glEnable(GL_CLIP_PLANE0+i); + else + glDisable(GL_CLIP_PLANE0+i); + } + } + + if(mask&TEXTURES) + { + if(last_applied && this!=last_applied) + { + vector::const_iterator i = textures.begin(); + vector::const_iterator j = last_applied->textures.begin(); + while(j!=last_applied->textures.end()) + { + if(i==textures.end() || j->bindingbinding) + { + 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::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(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::const_iterator i = uniform_blocks.begin(); + vector::const_iterator j = last_applied->uniform_blocks.begin(); + while(j!=last_applied->uniform_blocks.end()) + { + if(i==uniform_blocks.end() || j->bindingbinding) + { + glBindBufferBase(GL_UNIFORM_BUFFER, j->binding, 0); + ++j; + } + else + { + if(i->binding==j->binding) + ++j; + ++i; + } + } + } + + for(vector::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(i->block); + glBindBufferRange(GL_UNIFORM_BUFFER, i->binding, block->get_buffer()->get_id(), block->get_offset(), block->get_data_size()); + } + else + static_cast(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; ienabled_clip_planes>>i)&1) + glDisable(GL_CLIP_PLANE0+i); + + for(vector::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::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 index 00000000..8d1d1aaa --- /dev/null +++ b/source/core/pipelinestate.h @@ -0,0 +1,91 @@ +#ifndef PIPELINESTATE_H_ +#define PIPELINESTATE_H_ + +#include +#include + +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 textures; + std::vector uniform_blocks; + mutable unsigned changes; + + static const PipelineState *last_applied; + static std::vector 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 diff --git a/source/core/program.cpp b/source/core/program.cpp index 33c53cd7..ed2455f8 100644 --- a/source/core/program.cpp +++ b/source/core/program.cpp @@ -355,7 +355,8 @@ void Program::link() } } - Conditional _bind(!ARB_separate_shader_objects, this); + if(!ARB_separate_shader_objects) + glUseProgram(id); for(map::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 diff --git a/source/core/program.h b/source/core/program.h index a2324f23..a494e079 100644 --- a/source/core/program.h +++ b/source/core/program.h @@ -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 +class Program { public: class Loader: public DataFile::CollectionObjectLoader @@ -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: diff --git a/source/core/sampler.cpp b/source/core/sampler.cpp index bb37b074..ffd77625 100644 --- a/source/core/sampler.cpp +++ b/source/core/sampler.cpp @@ -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 diff --git a/source/core/sampler.h b/source/core/sampler.h index bb02269f..ff920186 100644 --- a/source/core/sampler.h +++ b/source/core/sampler.h @@ -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 &); }; diff --git a/source/core/texture.cpp b/source/core/texture.cpp index ea503ed1..5197b3da 100644 --- a/source/core/texture.cpp +++ b/source/core/texture.cpp @@ -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 diff --git a/source/core/texture.h b/source/core/texture.h index 7fb41a62..58e22d35 100644 --- a/source/core/texture.h +++ b/source/core/texture.h @@ -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 &); diff --git a/source/core/texture1d.cpp b/source/core/texture1d.cpp index 71c736f0..7685d39e 100644 --- a/source/core/texture1d.cpp +++ b/source/core/texture1d.cpp @@ -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< _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) 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) throw out_of_range("Texture1D::sub_image"); - Conditional _bind(!ARB_direct_state_access, this); - allocate(level); + bool direct = (ARB_direct_state_access && (ARB_texture_storage || (allocated&(1<=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< _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) throw out_of_range("Texture2D::image"); - LinAl::Vector size = get_level_size(level); - if(ARB_texture_storage) + { + LinAl::Vector 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< 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<=levels) throw out_of_range("Texture2D::sub_image"); - Conditional _bind(!ARB_direct_state_access, this); - allocate(level); + bool direct = (ARB_direct_state_access && (ARB_texture_storage || (allocated&(1< _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) throw out_of_range("Texture3D::image"); - LinAl::Vector size = get_level_size(level); - if(ARB_texture_storage) + { + LinAl::Vector 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< 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<=levels) throw out_of_range("Texture3D::sub_image"); - Conditional _bind(!ARB_direct_state_access, this); - allocate(level); + bool direct = (ARB_direct_state_access && (ARB_texture_storage || (allocated&(1< _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) throw out_of_range("TextureCube::sub_image"); - Conditional _bind(!ARB_direct_state_acess, this); - allocate(level); + bool direct = (ARB_direct_state_access && (ARB_texture_storage || (allocated&(1< -#include -#include -#include "deviceinfo.h" -#include "gl.h" -#include "misc.h" -#include "texture.h" -#include "texunit.h" - -using namespace std; - -namespace Msp { -namespace GL { - -vector 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::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 index 8fefc3a8..00000000 --- a/source/core/texunit.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef MSP_GL_TEXUNIT_H_ -#define MSP_GL_TEXUNIT_H_ - -#include - -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 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 ¤t(); - static TexUnit *find_unit(const Texture *); -}; - -} // namespace GL -} // namespace Msp - -#endif diff --git a/source/core/uniformblock.cpp b/source/core/uniformblock.cpp index 59871cdd..af4016ee 100644 --- a/source/core/uniformblock.cpp +++ b/source/core/uniformblock.cpp @@ -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; iapply(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 diff --git a/source/core/uniformblock.h b/source/core/uniformblock.h index bc0b933b..18b651c7 100644 --- a/source/core/uniformblock.h +++ b/source/core/uniformblock.h @@ -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 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 diff --git a/source/core/vertexsetup.cpp b/source/core/vertexsetup.cpp index 1094bb21..f077ad2e 100644 --- a/source/core/vertexsetup.cpp +++ b/source/core/vertexsetup.cpp @@ -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_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; diff --git a/source/core/vertexsetup.h b/source/core/vertexsetup.h index 3b18006a..408d7380 100644 --- a/source/core/vertexsetup.h +++ b/source/core/vertexsetup.h @@ -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 +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(); diff --git a/source/core/windingtest.h b/source/core/windingtest.h index ffc52556..ff5b417d 100644 --- a/source/core/windingtest.h +++ b/source/core/windingtest.h @@ -29,6 +29,8 @@ public: WindingTest(); WindingTest(FaceWinding); + FaceWinding get_winding() const { return winding; } + void bind() const; static void unbind(); diff --git a/source/effects/bloom.cpp b/source/effects/bloom.cpp index 8612ec06..6e630115 100644 --- a/source/effects/bloom.cpp +++ b/source/effects/bloom.cpp @@ -7,7 +7,6 @@ #include "resources.h" #include "shader.h" #include "tests.h" -#include "texunit.h" using namespace std; diff --git a/source/effects/environmentmap.cpp b/source/effects/environmentmap.cpp index e33295da..465e4fee 100644 --- a/source/effects/environmentmap.cpp +++ b/source/effects/environmentmap.cpp @@ -4,7 +4,6 @@ #include "mesh.h" #include "renderer.h" #include "resources.h" -#include "texunit.h" using namespace std; diff --git a/source/render/programdata.cpp b/source/render/programdata.cpp index b21c395c..79b55901 100644 --- a/source/render/programdata.cpp +++ b/source/render/programdata.cpp @@ -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::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::iterator prog_begin = get_program(*prog); - Program::LayoutHash prog_hash = prog->get_uniform_layout_hash(); + vector::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 &block_infos = prog->get_uniform_blocks(); + const vector &block_infos = prog.get_uniform_blocks(); if(prog_begin->masks.dirty==ALL_ONES) { @@ -679,9 +675,25 @@ void ProgramData::apply() const } } - for(vector::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::const_iterator prog_begin = prepare_program(prog); + Program::LayoutHash prog_hash = prog_begin->prog_hash; + for(vector::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(i->block)); + else + { + const BufferBackedUniformBlock *block = static_cast(i->block); + block->refresh(); + state.set_uniform_block(i->bind_point, block); + } + } } void ProgramData::set_debug_name(const string &name) diff --git a/source/render/programdata.h b/source/render/programdata.h index a05674dd..93eb3be8 100644 --- a/source/render/programdata.h +++ b/source/render/programdata.h @@ -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::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 &); }; diff --git a/source/render/renderer.cpp b/source/render/renderer.cpp index d86b7804..4acf3ded 100644 --- a/source/render/renderer.cpp +++ b/source/render/renderer.cpp @@ -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=state->texture_count && bt.unit>=0) - { - Texture::unbind_from(bt.unit); - Sampler::unbind_from(bt.unit); - } - else if(bt.replaced>=static_cast(state->texture_count)) - bt.replaced = -1; - } + for(unsigned i=0; itexture_count; ++i) + if(texture_stack[i].replaced>=static_cast(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::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 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_countshprog!=pipeline_state.get_shader_program()); + pipeline_state.set_shader_program(state->shprog); - for(vector::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<clipping->get_n_planes())-1 : 0); - bool shprog_changed = (state->shprog!=Program::current()); - state->shprog->bind(); + if(state->texture_count::const_iterator i=texture_stack.begin(); i!=texture_stack.end(); ++i) { - standard_shdata.uniform("world_obj_matrix", state->model_matrix); - LinAl::SquareMatrix 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::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(); } diff --git a/source/render/renderer.h b/source/render/renderer.h index b5cbe5bc..5f069197 100644 --- a/source/render/renderer.h +++ b/source/render/renderer.h @@ -4,6 +4,7 @@ #include #include #include "matrix.h" +#include "pipelinestate.h" #include "programdata.h" #include "tag.h" @@ -112,6 +113,7 @@ private: ProgramData standard_shdata; std::vector shdata_stack; std::set excluded; + PipelineState pipeline_state; public: Renderer(); diff --git a/source/render/view.cpp b/source/render/view.cpp index 005904f2..db06bb33 100644 --- a/source/render/view.cpp +++ b/source/render/view.cpp @@ -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)