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)
43 void PipelineState::set(T &target, T value, unsigned flag)
52 void PipelineState::set_shader_program(const Program *p)
54 set(shprog, p, SHPROG);
57 void PipelineState::set_vertex_setup(const VertexSetup *s)
59 set(vertex_setup, s, VERTEX_SETUP);
62 void PipelineState::set_front_face(FaceWinding w)
64 set(front_face, w, FACE_CULL);
67 void PipelineState::set_face_cull(CullMode c)
69 set(face_cull, c, FACE_CULL);
72 void PipelineState::set_enabled_clip_planes(unsigned p)
74 set(enabled_clip_planes, p, CLIP_PLANES);
77 void PipelineState::set_texture(unsigned binding, const Texture *tex, const Sampler *samp)
79 if((tex!=0)!=(samp!=0))
80 throw invalid_argument("PipelineState::set_texture");
82 vector<BoundTexture>::iterator i = lower_bound_member(textures, binding, &BoundTexture::binding);
83 if(i==textures.end() || i->binding!=binding)
84 i = textures.insert(i, BoundTexture(binding));
85 if(tex!=i->texture || samp!=i->sampler)
94 void PipelineState::set_uniforms(const DefaultUniformBlock *block)
96 set_uniform_block_(-1, block);
99 void PipelineState::set_uniform_block(unsigned binding, const BufferBackedUniformBlock *block)
101 set_uniform_block_(binding, block);
104 void PipelineState::set_uniform_block_(int binding, const UniformBlock *block)
106 vector<BoundUniformBlock>::iterator i = lower_bound_member(uniform_blocks, binding, &BoundUniformBlock::binding);
107 if(i==uniform_blocks.end() || i->binding!=binding)
108 i = uniform_blocks.insert(i, BoundUniformBlock(binding));
109 if(block!=i->block || binding<0)
117 void PipelineState::apply() const
119 apply(this==last_applied ? changes : ~0U);
122 void PipelineState::apply(unsigned mask) const
125 glUseProgram(shprog ? shprog->get_id() : 0);
127 if(mask&VERTEX_SETUP)
129 glBindVertexArray(vertex_setup ? vertex_setup->get_id() : 0);
131 vertex_setup->refresh();
136 glFrontFace(front_face==CLOCKWISE ? GL_CW : GL_CCW);
138 if(face_cull!=NO_CULL && front_face!=NON_MANIFOLD)
140 glEnable(GL_CULL_FACE);
141 glCullFace(face_cull==CULL_FRONT ? GL_FRONT : GL_BACK);
144 glDisable(GL_CULL_FACE);
149 unsigned max_clip_planes = Limits::get_global().max_clip_planes;
150 for(unsigned i=0; i<max_clip_planes; ++i)
152 if((enabled_clip_planes>>i)&1)
153 glEnable(GL_CLIP_PLANE0+i);
155 glDisable(GL_CLIP_PLANE0+i);
161 if(last_applied && this!=last_applied)
163 vector<BoundTexture>::const_iterator i = textures.begin();
164 vector<BoundTexture>::const_iterator j = last_applied->textures.begin();
165 while(j!=last_applied->textures.end())
167 if(i==textures.end() || j->binding<i->binding)
169 if(bound_tex_targets[j->binding])
171 if(ARB_direct_state_access)
172 glBindTextureUnit(j->binding, 0);
175 glActiveTexture(GL_TEXTURE0+j->binding);
176 glBindTexture(bound_tex_targets[j->binding], 0);
183 if(i->binding==j->binding)
190 for(vector<BoundTexture>::const_iterator i=textures.begin(); i!=textures.end(); ++i)
191 if(i->changed || mask==~0U)
193 if(i->texture && i->sampler)
195 if(ARB_direct_state_access)
196 glBindTextureUnit(i->binding, i->texture->get_id());
199 glActiveTexture(GL_TEXTURE0+i->binding);
200 if(bound_tex_targets[i->binding] && static_cast<int>(i->texture->get_target())!=bound_tex_targets[i->binding])
201 glBindTexture(bound_tex_targets[i->binding], 0);
202 glBindTexture(i->texture->get_target(), i->texture->get_id());
203 bound_tex_targets[i->binding] = i->texture->get_target();
206 glBindSampler(i->binding, i->sampler->get_id());
207 i->sampler->refresh();
209 else if(bound_tex_targets[i->binding])
211 if(ARB_direct_state_access)
212 glBindTextureUnit(i->binding, 0);
215 glActiveTexture(GL_TEXTURE0+i->binding);
216 glBindTexture(bound_tex_targets[i->binding], 0);
217 bound_tex_targets[i->binding] = 0;
227 if(last_applied && this!=last_applied)
229 vector<BoundUniformBlock>::const_iterator i = uniform_blocks.begin();
230 vector<BoundUniformBlock>::const_iterator j = last_applied->uniform_blocks.begin();
231 while(j!=last_applied->uniform_blocks.end())
233 if(i==uniform_blocks.end() || j->binding<i->binding)
235 glBindBufferBase(GL_UNIFORM_BUFFER, j->binding, 0);
240 if(i->binding==j->binding)
247 for(vector<BoundUniformBlock>::const_iterator i=uniform_blocks.begin(); i!=uniform_blocks.end(); ++i)
248 if(i->changed || mask==~0U)
254 const BufferBackedUniformBlock *block = static_cast<const BufferBackedUniformBlock *>(i->block);
255 glBindBufferRange(GL_UNIFORM_BUFFER, i->binding, block->get_buffer()->get_id(), block->get_offset(), block->get_data_size());
258 static_cast<const DefaultUniformBlock *>(i->block)->apply();
261 glBindBufferBase(GL_UNIFORM_BUFFER, i->binding, 0);
271 void PipelineState::clear()
276 glBindVertexArray(0);
278 unsigned max_clip_planes = Limits::get_global().max_clip_planes;
279 for(unsigned i=0; i<max_clip_planes; ++i)
280 if((last_applied->enabled_clip_planes>>i)&1)
281 glDisable(GL_CLIP_PLANE0+i);
283 for(vector<BoundTexture>::const_iterator i=last_applied->textures.begin(); i!=last_applied->textures.end(); ++i)
284 if(i->texture && i->sampler)
286 if(ARB_direct_state_access)
287 glBindTextureUnit(i->binding, 0);
290 glActiveTexture(GL_TEXTURE0+i->binding);
291 glBindTexture(bound_tex_targets[i->binding], 0);
292 bound_tex_targets[i->binding] = 0;
296 for(vector<BoundUniformBlock>::const_iterator i=last_applied->uniform_blocks.begin(); i!=last_applied->uniform_blocks.end(); ++i)
298 glBindBufferBase(GL_UNIFORM_BUFFER, i->binding, 0);
305 PipelineState::BoundTexture::BoundTexture(unsigned b):
313 PipelineState::BoundUniformBlock::BoundUniformBlock(int b):