2 #include <msp/core/algorithm.h>
3 #include <msp/gl/extensions/arb_direct_state_access.h>
4 #include <msp/gl/extensions/arb_sampler_objects.h>
5 #include <msp/gl/extensions/arb_shader_objects.h>
6 #include <msp/gl/extensions/arb_uniform_buffer_object.h>
7 #include <msp/gl/extensions/arb_vertex_array_object.h>
9 #include "deviceinfo.h"
10 #include "pipelinestate.h"
13 #include "uniformblock.h"
14 #include "vertexsetup.h"
15 #include "windingtest.h"
22 const PipelineState *PipelineState::last_applied = 0;
23 vector<int> PipelineState::bound_tex_targets;
25 PipelineState::PipelineState():
29 enabled_clip_planes(0),
32 if(!ARB_direct_state_access && bound_tex_targets.empty())
33 bound_tex_targets.resize(Limits::get_global().max_texture_bindings);
36 PipelineState::~PipelineState()
38 if(this==last_applied)
42 void PipelineState::set_shader_program(const Program *p)
51 void PipelineState::set_vertex_setup(const VertexSetup *s)
56 changes |= VERTEX_SETUP;
60 void PipelineState::set_winding_test(const WindingTest *w)
65 changes |= WINDING_TEST;
69 void PipelineState::set_enabled_clip_planes(unsigned p)
71 if(p!=enabled_clip_planes)
73 enabled_clip_planes = p;
74 changes |= CLIP_PLANES;
78 void PipelineState::set_texture(unsigned binding, const Texture *tex, const Sampler *samp)
80 if((tex!=0)!=(samp!=0))
81 throw invalid_argument("PipelineState::set_texture");
83 vector<BoundTexture>::iterator i = lower_bound_member(textures, binding, &BoundTexture::binding);
84 if(i==textures.end() || i->binding!=binding)
85 i = textures.insert(i, BoundTexture(binding));
86 if(tex!=i->texture || samp!=i->sampler)
95 void PipelineState::set_uniforms(const DefaultUniformBlock *block)
97 set_uniform_block_(-1, block);
100 void PipelineState::set_uniform_block(unsigned binding, const BufferBackedUniformBlock *block)
102 set_uniform_block_(binding, block);
105 void PipelineState::set_uniform_block_(int binding, const UniformBlock *block)
107 vector<BoundUniformBlock>::iterator i = lower_bound_member(uniform_blocks, binding, &BoundUniformBlock::binding);
108 if(i==uniform_blocks.end() || i->binding!=binding)
109 i = uniform_blocks.insert(i, BoundUniformBlock(binding));
110 if(block!=i->block || binding<0)
118 void PipelineState::apply() const
120 apply(this==last_applied ? changes : ~0U);
123 void PipelineState::apply(unsigned mask) const
126 glUseProgram(shprog ? shprog->get_id() : 0);
128 if(mask&VERTEX_SETUP)
130 glBindVertexArray(vertex_setup ? vertex_setup->get_id() : 0);
132 vertex_setup->refresh();
135 if(mask&WINDING_TEST)
139 glEnable(GL_CULL_FACE);
140 glFrontFace(winding_test->get_winding());
143 glDisable(GL_CULL_FACE);
148 unsigned max_clip_planes = Limits::get_global().max_clip_planes;
149 for(unsigned i=0; i<max_clip_planes; ++i)
151 if((enabled_clip_planes>>i)&1)
152 glEnable(GL_CLIP_PLANE0+i);
154 glDisable(GL_CLIP_PLANE0+i);
160 if(last_applied && this!=last_applied)
162 vector<BoundTexture>::const_iterator i = textures.begin();
163 vector<BoundTexture>::const_iterator j = last_applied->textures.begin();
164 while(j!=last_applied->textures.end())
166 if(i==textures.end() || j->binding<i->binding)
168 if(bound_tex_targets[j->binding])
170 if(ARB_direct_state_access)
171 glBindTextureUnit(j->binding, 0);
174 glActiveTexture(GL_TEXTURE0+j->binding);
175 glBindTexture(bound_tex_targets[j->binding], 0);
182 if(i->binding==j->binding)
189 for(vector<BoundTexture>::const_iterator i=textures.begin(); i!=textures.end(); ++i)
192 if(i->texture && i->sampler)
194 if(ARB_direct_state_access)
195 glBindTextureUnit(i->binding, i->texture->get_id());
198 glActiveTexture(GL_TEXTURE0+i->binding);
199 if(bound_tex_targets[i->binding] && static_cast<int>(i->texture->get_target())!=bound_tex_targets[i->binding])
200 glBindTexture(bound_tex_targets[i->binding], 0);
201 glBindTexture(i->texture->get_target(), i->texture->get_id());
202 bound_tex_targets[i->binding] = i->texture->get_target();
205 glBindSampler(i->binding, i->sampler->get_id());
206 i->sampler->refresh();
208 else if(bound_tex_targets[i->binding])
210 if(ARB_direct_state_access)
211 glBindTextureUnit(i->binding, 0);
214 glActiveTexture(GL_TEXTURE0+i->binding);
215 glBindTexture(bound_tex_targets[i->binding], 0);
216 bound_tex_targets[i->binding] = 0;
226 if(last_applied && this!=last_applied)
228 vector<BoundUniformBlock>::const_iterator i = uniform_blocks.begin();
229 vector<BoundUniformBlock>::const_iterator j = last_applied->uniform_blocks.begin();
230 while(j!=last_applied->uniform_blocks.end())
232 if(i==uniform_blocks.end() || j->binding<i->binding)
234 glBindBufferBase(GL_UNIFORM_BUFFER, j->binding, 0);
239 if(i->binding==j->binding)
246 for(vector<BoundUniformBlock>::const_iterator i=uniform_blocks.begin(); i!=uniform_blocks.end(); ++i)
253 const BufferBackedUniformBlock *block = static_cast<const BufferBackedUniformBlock *>(i->block);
254 glBindBufferRange(GL_UNIFORM_BUFFER, i->binding, block->get_buffer()->get_id(), block->get_offset(), block->get_data_size());
257 static_cast<const DefaultUniformBlock *>(i->block)->apply();
260 glBindBufferBase(GL_UNIFORM_BUFFER, i->binding, 0);
270 void PipelineState::clear()
275 glBindVertexArray(0);
277 unsigned max_clip_planes = Limits::get_global().max_clip_planes;
278 for(unsigned i=0; i<max_clip_planes; ++i)
279 if((last_applied->enabled_clip_planes>>i)&1)
280 glDisable(GL_CLIP_PLANE0+i);
282 for(vector<BoundTexture>::const_iterator i=last_applied->textures.begin(); i!=last_applied->textures.end(); ++i)
283 if(i->texture && i->sampler)
285 if(ARB_direct_state_access)
286 glBindTextureUnit(i->binding, 0);
289 glActiveTexture(GL_TEXTURE0+i->binding);
290 glBindTexture(bound_tex_targets[i->binding], 0);
291 bound_tex_targets[i->binding] = 0;
295 for(vector<BoundUniformBlock>::const_iterator i=last_applied->uniform_blocks.begin(); i!=last_applied->uniform_blocks.end(); ++i)
297 glBindBufferBase(GL_UNIFORM_BUFFER, i->binding, 0);
304 PipelineState::BoundTexture::BoundTexture(unsigned b):
312 PipelineState::BoundUniformBlock::BoundUniformBlock(int b):