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"
21 const PipelineState *PipelineState::last_applied = 0;
22 vector<int> PipelineState::bound_tex_targets;
24 PipelineState::PipelineState():
27 front_face(COUNTERCLOCKWISE),
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_front_face(FaceWinding w)
69 void PipelineState::set_face_cull(CullMode c)
78 void PipelineState::set_enabled_clip_planes(unsigned p)
80 if(p!=enabled_clip_planes)
82 enabled_clip_planes = p;
83 changes |= CLIP_PLANES;
87 void PipelineState::set_texture(unsigned binding, const Texture *tex, const Sampler *samp)
89 if((tex!=0)!=(samp!=0))
90 throw invalid_argument("PipelineState::set_texture");
92 vector<BoundTexture>::iterator i = lower_bound_member(textures, binding, &BoundTexture::binding);
93 if(i==textures.end() || i->binding!=binding)
94 i = textures.insert(i, BoundTexture(binding));
95 if(tex!=i->texture || samp!=i->sampler)
104 void PipelineState::set_uniforms(const DefaultUniformBlock *block)
106 set_uniform_block_(-1, block);
109 void PipelineState::set_uniform_block(unsigned binding, const BufferBackedUniformBlock *block)
111 set_uniform_block_(binding, block);
114 void PipelineState::set_uniform_block_(int binding, const UniformBlock *block)
116 vector<BoundUniformBlock>::iterator i = lower_bound_member(uniform_blocks, binding, &BoundUniformBlock::binding);
117 if(i==uniform_blocks.end() || i->binding!=binding)
118 i = uniform_blocks.insert(i, BoundUniformBlock(binding));
119 if(block!=i->block || binding<0)
127 void PipelineState::apply() const
129 apply(this==last_applied ? changes : ~0U);
132 void PipelineState::apply(unsigned mask) const
135 glUseProgram(shprog ? shprog->get_id() : 0);
137 if(mask&VERTEX_SETUP)
139 glBindVertexArray(vertex_setup ? vertex_setup->get_id() : 0);
141 vertex_setup->refresh();
146 glFrontFace(front_face==CLOCKWISE ? GL_CW : GL_CCW);
148 if(face_cull!=NO_CULL)
150 glEnable(GL_CULL_FACE);
151 glCullFace(face_cull==CULL_FRONT ? GL_FRONT : GL_BACK);
154 glDisable(GL_CULL_FACE);
159 unsigned max_clip_planes = Limits::get_global().max_clip_planes;
160 for(unsigned i=0; i<max_clip_planes; ++i)
162 if((enabled_clip_planes>>i)&1)
163 glEnable(GL_CLIP_PLANE0+i);
165 glDisable(GL_CLIP_PLANE0+i);
171 if(last_applied && this!=last_applied)
173 vector<BoundTexture>::const_iterator i = textures.begin();
174 vector<BoundTexture>::const_iterator j = last_applied->textures.begin();
175 while(j!=last_applied->textures.end())
177 if(i==textures.end() || j->binding<i->binding)
179 if(bound_tex_targets[j->binding])
181 if(ARB_direct_state_access)
182 glBindTextureUnit(j->binding, 0);
185 glActiveTexture(GL_TEXTURE0+j->binding);
186 glBindTexture(bound_tex_targets[j->binding], 0);
193 if(i->binding==j->binding)
200 for(vector<BoundTexture>::const_iterator i=textures.begin(); i!=textures.end(); ++i)
203 if(i->texture && i->sampler)
205 if(ARB_direct_state_access)
206 glBindTextureUnit(i->binding, i->texture->get_id());
209 glActiveTexture(GL_TEXTURE0+i->binding);
210 if(bound_tex_targets[i->binding] && static_cast<int>(i->texture->get_target())!=bound_tex_targets[i->binding])
211 glBindTexture(bound_tex_targets[i->binding], 0);
212 glBindTexture(i->texture->get_target(), i->texture->get_id());
213 bound_tex_targets[i->binding] = i->texture->get_target();
216 glBindSampler(i->binding, i->sampler->get_id());
217 i->sampler->refresh();
219 else if(bound_tex_targets[i->binding])
221 if(ARB_direct_state_access)
222 glBindTextureUnit(i->binding, 0);
225 glActiveTexture(GL_TEXTURE0+i->binding);
226 glBindTexture(bound_tex_targets[i->binding], 0);
227 bound_tex_targets[i->binding] = 0;
237 if(last_applied && this!=last_applied)
239 vector<BoundUniformBlock>::const_iterator i = uniform_blocks.begin();
240 vector<BoundUniformBlock>::const_iterator j = last_applied->uniform_blocks.begin();
241 while(j!=last_applied->uniform_blocks.end())
243 if(i==uniform_blocks.end() || j->binding<i->binding)
245 glBindBufferBase(GL_UNIFORM_BUFFER, j->binding, 0);
250 if(i->binding==j->binding)
257 for(vector<BoundUniformBlock>::const_iterator i=uniform_blocks.begin(); i!=uniform_blocks.end(); ++i)
264 const BufferBackedUniformBlock *block = static_cast<const BufferBackedUniformBlock *>(i->block);
265 glBindBufferRange(GL_UNIFORM_BUFFER, i->binding, block->get_buffer()->get_id(), block->get_offset(), block->get_data_size());
268 static_cast<const DefaultUniformBlock *>(i->block)->apply();
271 glBindBufferBase(GL_UNIFORM_BUFFER, i->binding, 0);
281 void PipelineState::clear()
286 glBindVertexArray(0);
288 unsigned max_clip_planes = Limits::get_global().max_clip_planes;
289 for(unsigned i=0; i<max_clip_planes; ++i)
290 if((last_applied->enabled_clip_planes>>i)&1)
291 glDisable(GL_CLIP_PLANE0+i);
293 for(vector<BoundTexture>::const_iterator i=last_applied->textures.begin(); i!=last_applied->textures.end(); ++i)
294 if(i->texture && i->sampler)
296 if(ARB_direct_state_access)
297 glBindTextureUnit(i->binding, 0);
300 glActiveTexture(GL_TEXTURE0+i->binding);
301 glBindTexture(bound_tex_targets[i->binding], 0);
302 bound_tex_targets[i->binding] = 0;
306 for(vector<BoundUniformBlock>::const_iterator i=last_applied->uniform_blocks.begin(); i!=last_applied->uniform_blocks.end(); ++i)
308 glBindBufferBase(GL_UNIFORM_BUFFER, i->binding, 0);
315 PipelineState::BoundTexture::BoundTexture(unsigned b):
323 PipelineState::BoundUniformBlock::BoundUniformBlock(int b):