]> git.tdb.fi Git - libs/gl.git/blob - source/backends/opengl/pipelinestate_backend.cpp
Check the flat qualifier from the correct member
[libs/gl.git] / source / backends / opengl / pipelinestate_backend.cpp
1 #include <msp/gl/extensions/arb_direct_state_access.h>
2 #include <msp/gl/extensions/arb_sampler_objects.h>
3 #include <msp/gl/extensions/arb_shader_image_load_store.h>
4 #include <msp/gl/extensions/arb_shader_objects.h>
5 #include <msp/gl/extensions/arb_uniform_buffer_object.h>
6 #include <msp/gl/extensions/arb_vertex_array_object.h>
7 #include <msp/gl/extensions/arb_tessellation_shader.h>
8 #include <msp/gl/extensions/ext_framebuffer_object.h>
9 #include <msp/gl/extensions/msp_primitive_restart.h>
10 #include "blend.h"
11 #include "buffer.h"
12 #include "depthtest.h"
13 #include "device.h"
14 #include "framebuffer.h"
15 #include "gl.h"
16 #include "pipelinestate.h"
17 #include "pipelinestate_backend.h"
18 #include "program.h"
19 #include "rect.h"
20 #include "sampler.h"
21 #include "stenciltest.h"
22 #include "texture.h"
23 #include "uniformblock.h"
24 #include "vertexsetup.h"
25
26 using namespace std;
27
28 namespace Msp {
29 namespace GL {
30
31 OpenGLPipelineState::~OpenGLPipelineState()
32 {
33         if(applied_to)
34                 applied_to->get_state().last_pipeline = 0;
35 }
36
37 void OpenGLPipelineState::apply() const
38 {
39         const PipelineState &self = *static_cast<const PipelineState *>(this);
40         Device &device = Device::get_current();
41
42         if(applied_to && applied_to!=&device)
43         {
44                 applied_to->get_state().last_pipeline = 0;
45                 changes = ~0U;
46         }
47
48         OpenGLDeviceState &dev_state = device.get_state();
49         if(!dev_state.last_pipeline)
50                 OpenGLTexture::unbind_scratch();
51         
52         if(this!=dev_state.last_pipeline)
53         {
54                 if(dev_state.last_pipeline)
55                         dev_state.last_pipeline->applied_to = 0;
56                 changes = ~0U;
57         }
58
59         if(changes&PipelineState::FRAMEBUFFER)
60         {
61                 const Framebuffer *framebuffer = self.framebuffer;
62                 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer ? framebuffer->id : 0);
63                 if(framebuffer)
64                 {
65                         framebuffer->refresh();
66                         framebuffer->require_complete();
67                 }
68         }
69
70         if(changes&(PipelineState::VIEWPORT|PipelineState::SCISSOR|PipelineState::FRAMEBUFFER))
71                 if(const Framebuffer *framebuffer = self.framebuffer)
72                 {
73                         Rect fb_rect = framebuffer->get_rect();
74                         if(changes&(PipelineState::VIEWPORT|PipelineState::FRAMEBUFFER))
75                         {
76                                 Rect viewport = fb_rect.intersect(self.viewport);
77                                 glViewport(viewport.left, viewport.bottom, viewport.width, viewport.height);
78                         }
79                         if(changes&(PipelineState::SCISSOR|PipelineState::FRAMEBUFFER))
80                         {
81                                 Rect scissor = fb_rect.intersect(self.scissor);
82                                 if(scissor!=fb_rect)
83                                 {
84                                         glEnable(GL_SCISSOR_TEST);
85                                         glScissor(scissor.left, scissor.bottom, scissor.width, scissor.height);
86                                 }
87                                 else
88                                         glDisable(GL_SCISSOR_TEST);
89                         }
90                 }
91
92         if(changes&PipelineState::SHPROG)
93         {
94                 glUseProgram(self.shprog ? self.shprog->id : 0);
95
96                 unsigned ncd = (self.shprog ? self.shprog->get_n_clip_distances() : 0);
97                 if(ncd!=dev_state.n_clip_distances)
98                 {
99                         for(unsigned i=0; (i<ncd || i<dev_state.n_clip_distances); ++i)
100                         {
101                                 if(i<ncd)
102                                         glEnable(GL_CLIP_PLANE0+i);
103                                 else
104                                         glDisable(GL_CLIP_PLANE0+i);
105                         }
106                         dev_state.n_clip_distances = ncd;
107                 }
108         }
109
110         if(changes&PipelineState::RESOURCES)
111         {
112                 for(const PipelineState::BoundResource &r: self.resources)
113                 {
114                         if(!r.changed && changes!=~0U)
115                                 continue;
116
117                         if(r.used)
118                         {
119                                 if(r.type==PipelineState::UNIFORM_BLOCK)
120                                 {
121                                         if(r.binding>=0)
122                                         {
123                                                 glBindBufferRange(GL_UNIFORM_BUFFER, r.binding, r.buffer->id, r.block->get_offset(), r.block->get_data_size());
124                                                 dev_state.bound_uniform_blocks[r.binding] = 1;
125                                         }
126                                         else if(r.binding==ReflectData::DEFAULT_BLOCK && self.shprog)
127                                         {
128                                                 const char *data = static_cast<const char *>(r.block->get_data_pointer());
129                                                 for(const Program::UniformCall &call: self.shprog->uniform_calls)
130                                                         call.func(call.location, call.size, data+call.location*16);
131                                         }
132                                 }
133                                 else if(r.type==PipelineState::SAMPLED_TEXTURE)
134                                 {
135                                         if(ARB_direct_state_access)
136                                                 glBindTextureUnit(r.binding, r.texture->id);
137                                         else
138                                         {
139                                                 glActiveTexture(GL_TEXTURE0+r.binding);
140                                                 if(dev_state.bound_tex_targets[r.binding] && static_cast<int>(r.texture->target)!=dev_state.bound_tex_targets[r.binding])
141                                                         glBindTexture(dev_state.bound_tex_targets[r.binding], 0);
142                                                 glBindTexture(r.texture->target, r.texture->id);
143                                         }
144
145                                         dev_state.bound_tex_targets[r.binding] = r.texture->target;
146
147                                         glBindSampler(r.binding, r.sampler->id);
148                                         r.sampler->refresh();
149                                 }
150                                 else if(r.type==PipelineState::STORAGE_TEXTURE)
151                                 {
152                                         static Require _req(ARB_shader_image_load_store);
153                                         GLenum gl_format = get_gl_pixelformat(r.texture->get_format());
154                                         glBindImageTexture(r.binding, r.texture->id, 0, true, 0, GL_READ_WRITE, gl_format);
155
156                                         dev_state.bound_storage_textures[r.binding] = 1;
157                                 }
158                         }
159
160                         r.changed = false;
161                 }
162         }
163
164         if(changes&PipelineState::VERTEX_SETUP)
165         {
166                 const VertexSetup *vertex_setup = self.vertex_setup;
167                 glBindVertexArray(vertex_setup ? vertex_setup->id : 0);
168                 if(vertex_setup)
169                 {
170                         static Require _req(MSP_primitive_restart);
171
172                         vertex_setup->refresh();
173                         unsigned ri = (vertex_setup->get_index_type()==UNSIGNED_INT ? 0xFFFFFFFF : 0xFFFF);
174                         if(ri!=dev_state.restart_index)
175                         {
176                                 if(!dev_state.restart_index)
177                                         glEnable(GL_PRIMITIVE_RESTART);
178                                 glPrimitiveRestartIndex(ri);
179                                 dev_state.restart_index = ri;
180                         }
181                 }
182         }
183
184         if(changes&PipelineState::PATCH_SIZE)
185                 if(self.patch_size)
186                 {
187                         static Require _req(ARB_tessellation_shader);
188                         glPatchParameteri(GL_PATCH_VERTICES, self.patch_size);
189                 }
190
191         if(changes&PipelineState::FACE_CULL)
192         {
193                 glFrontFace(self.front_face==CLOCKWISE ? GL_CW : GL_CCW);
194
195                 if(self.face_cull!=NO_CULL && self.front_face!=NON_MANIFOLD)
196                 {
197                         glEnable(GL_CULL_FACE);
198                         glCullFace(self.face_cull==CULL_FRONT ? GL_FRONT : GL_BACK);
199                 }
200                 else
201                         glDisable(GL_CULL_FACE);
202         }
203
204         if(changes&PipelineState::DEPTH_TEST)
205         {
206                 const DepthTest &depth_test = self.depth_test;
207                 if(depth_test.enabled)
208                 {
209                         glEnable(GL_DEPTH_TEST);
210                         glDepthFunc(get_gl_predicate(depth_test.compare));
211                 }
212                 else
213                         glDisable(GL_DEPTH_TEST);
214
215                 glDepthMask(depth_test.write);
216         }
217
218         if(changes&PipelineState::STENCIL_TEST)
219         {
220                 const StencilTest &stencil_test = self.stencil_test;
221                 if(stencil_test.enabled)
222                 {
223                         glEnable(GL_STENCIL_TEST);
224                         glStencilFunc(get_gl_predicate(stencil_test.compare), stencil_test.reference, 0xFFFFFFFF);
225                         glStencilOp(get_gl_stencil_op(stencil_test.stencil_fail_op), get_gl_stencil_op(stencil_test.depth_fail_op), get_gl_stencil_op(stencil_test.depth_pass_op));
226                 }
227                 else
228                         glDisable(GL_STENCIL_TEST);
229         }
230
231         if(changes&PipelineState::BLEND)
232         {
233                 const Blend &blend = self.blend;
234                 if(blend.enabled)
235                 {
236                         glEnable(GL_BLEND);
237                         glBlendEquation(get_gl_blend_equation(blend.equation));
238                         glBlendFunc(get_gl_blend_factor(blend.src_factor), get_gl_blend_factor(blend.dst_factor));
239                         glBlendColor(blend.constant.r, blend.constant.g, blend.constant.b, blend.constant.a);
240                         ColorWriteMask cw = blend.write_mask;
241                         glColorMask((cw&WRITE_RED)!=0, (cw&WRITE_GREEN)!=0, (cw&WRITE_BLUE)!=0, (cw&WRITE_ALPHA)!=0);
242                 }
243                 else
244                 {
245                         glDisable(GL_BLEND);
246                         glColorMask(true, true, true, true);
247                 }
248
249                 if(blend.alpha_to_coverage && self.framebuffer && self.framebuffer->get_format().get_samples()>1)
250                         glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);
251                 else
252                         glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
253         }
254
255 #ifdef DEBUG
256         if(changes&(PipelineState::SHPROG|PipelineState::RESOURCES))
257                 self.check_bound_resources();
258 #endif
259
260         applied_to = &device;
261         dev_state.last_pipeline = this;
262         changes = 0;
263 }
264
265 void OpenGLPipelineState::clear()
266 {
267         OpenGLDeviceState &dev_state = Device::get_current().get_state();
268         if(dev_state.last_pipeline)
269         {
270                 glUseProgram(0);
271                 glBindVertexArray(0);
272
273                 for(unsigned i=0; i<dev_state.n_clip_distances; ++i)
274                         glDisable(GL_CLIP_PLANE0+i);
275                 dev_state.n_clip_distances = 0;
276
277                 for(unsigned i=0; i<dev_state.bound_tex_targets.size(); ++i)
278                         if(dev_state.bound_tex_targets[i])
279                         {
280                                 if(ARB_direct_state_access)
281                                         glBindTextureUnit(i, 0);
282                                 else
283                                 {
284                                         glActiveTexture(GL_TEXTURE0+i);
285                                         glBindTexture(dev_state.bound_tex_targets[i], 0);
286                                 }
287                                 dev_state.bound_tex_targets[i] = 0;
288                         }
289
290                 for(unsigned i=0; i<dev_state.bound_storage_textures.size(); ++i)
291                         if(dev_state.bound_storage_textures[i])
292                         {
293                                 glBindImageTexture(i, 0, 0, true, 0, GL_READ_ONLY, GL_RGBA8);
294                                 dev_state.bound_storage_textures[i] = 0;
295                         }
296
297                 for(unsigned i=0; i<dev_state.bound_uniform_blocks.size(); ++i)
298                         if(dev_state.bound_uniform_blocks[i])
299                         {
300                                 glBindBufferBase(GL_UNIFORM_BUFFER, i, 0);
301                                 dev_state.bound_uniform_blocks[i] = 0;
302                         }
303
304                 glDisable(GL_DEPTH_TEST);
305                 glDepthMask(true);
306                 glDisable(GL_STENCIL_TEST);
307                 glDisable(GL_BLEND);
308
309                 dev_state.last_pipeline->applied_to = 0;
310                 dev_state.last_pipeline = 0;
311         }
312 }
313
314 } // namespace GL
315 } // namespace Msp