]> git.cworth.org Git - vogl/blob - src/voglcommon/vogl_msaa_texture.cpp
Initial vogl checkin
[vogl] / src / voglcommon / vogl_msaa_texture.cpp
1 /**************************************************************************
2  *
3  * Copyright 2013-2014 RAD Game Tools and Valve Software
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26 // File: vogl_msaa_texture.cpp
27 #include "vogl_msaa_texture.h"
28 #include "vogl_vec.h"
29 #include "vogl_texture_format.h"
30
31 // Requires GL 3.2, GL_ARB_explicit_attrib_location, GL_ARB_separate_shader_objects, GL_ARB_sample_shading
32
33 // Passthrough vertex shader
34
35 // Requires GL 3.2, GL_ARB_explicit_attrib_location, GL_ARB_separate_shader_objects
36 static const char *g_passthrough_vert_shader =
37     "#version 150 core\n"
38     "#extension GL_ARB_explicit_attrib_location : enable\n"
39     "#extension GL_ARB_separate_shader_objects : enable\n"
40     "layout(location = 0) in vec4 vVertex;\n"
41     "layout(location = 1) in vec3 vTexCoord0;\n"
42     "layout(location = 0) out vec3 vTex;\n"
43     "void main(void)\n"
44     "{ vTex = vTexCoord0;\n"
45     "gl_Position = vVertex;\n"
46     "}";
47
48 // Reading fragment shaders
49
50 static const char *g_read_color_frag_shader =
51     "#version 150 core\n"
52     "#extension GL_ARB_explicit_attrib_location : enable\n"
53     "#extension GL_ARB_separate_shader_objects : enable\n"
54     "layout(location = 0) in vec3 vTex0;\n"
55     "layout(location = 0) out vec4 fragColor0;\n"
56     "uniform sampler2DMS tex;\n"
57     "uniform int tex_sample;\n"
58     "void main(void) { fragColor0 = texelFetch(tex, ivec2(int(vTex0.x), int(vTex0.y)), tex_sample); }";
59
60 static const char *g_read_color_array_frag_shader =
61     "#version 150 core\n"
62     "#extension GL_ARB_explicit_attrib_location : enable\n"
63     "#extension GL_ARB_separate_shader_objects : enable\n"
64     "layout(location = 0) in vec3 vTex0;\n"
65     "layout(location = 0) out vec4 fragColor0;\n"
66     "uniform sampler2DMSArray tex;\n"
67     "uniform int tex_sample;\n"
68     "void main(void) { fragColor0 = texelFetch(tex, ivec3(int(vTex0.x), int(vTex0.y), int(vTex0.z)), tex_sample); }";
69
70 static const char *g_read_depth_frag_shader =
71     "#version 150 core\n"
72     "#extension GL_ARB_explicit_attrib_location : enable\n"
73     "#extension GL_ARB_separate_shader_objects : enable\n"
74     "layout(location = 0) in vec3 vTex0;\n"
75     "layout(location = 0) out vec4 fragColor0;\n"
76     "uniform sampler2DMS tex;\n"
77     "uniform int tex_sample;\n"
78     "void main(void) { fragColor0 = vec4(0,0,0,0); gl_FragDepth = texelFetch(tex, ivec2(int(vTex0.x), int(vTex0.y)), tex_sample).x; }";
79
80 static const char *g_read_depth_array_frag_shader =
81     "#version 150 core\n"
82     "#extension GL_ARB_explicit_attrib_location : enable\n"
83     "#extension GL_ARB_separate_shader_objects : enable\n"
84     "layout(location = 0) in vec3 vTex0;\n"
85     "layout(location = 0) out vec4 fragColor0;\n"
86     "uniform sampler2DMSArray tex;\n"
87     "uniform int tex_sample;\n"
88     "void main(void) { fragColor0 = vec4(0,0,0,1); gl_FragDepth = texelFetch(tex, ivec3(int(vTex0.x), int(vTex0.y), int(vTex0.z)), tex_sample).x; }";
89
90 // Writing fragment shaders
91
92 static const char *g_write_color_frag_shader =
93     "#version 150 core\n"
94     "#extension GL_ARB_explicit_attrib_location : enable\n"
95     "#extension GL_ARB_separate_shader_objects : enable\n"
96     "#extension GL_ARB_sample_shading : enable\n"
97     "layout(location = 0) in vec3 vTex0;\n"
98     "layout(location = 0) out vec4 fragColor0;\n"
99     "uniform sampler2D tex;\n"
100     "uniform int sample_mask;\n"
101     "void main(void)\n"
102     "{\n"
103     "fragColor0 = texelFetch(tex, ivec2(int(vTex0.x), int(vTex0.y)), 0);\n"
104     "gl_SampleMask[0] = sample_mask;\n"
105     "}";
106
107 static const char *g_write_color_array_frag_shader =
108     "#version 150 core\n"
109     "#extension GL_ARB_explicit_attrib_location : enable\n"
110     "#extension GL_ARB_separate_shader_objects : enable\n"
111     "#extension GL_ARB_sample_shading : enable\n"
112     "layout(location = 0) in vec3 vTex0;\n"
113     "layout(location = 0) out vec4 fragColor0;\n"
114     "uniform sampler2DArray tex;\n"
115     "uniform int sample_mask;\n"
116     "void main(void)\n"
117     "{\n"
118     "fragColor0 = texelFetch(tex, ivec3(int(vTex0.x), int(vTex0.y), int(vTex0.z)), 0);\n"
119     "gl_SampleMask[0] = sample_mask;\n"
120     "}";
121
122 static const char *g_write_depth_frag_shader =
123     "#version 150 core\n"
124     "#extension GL_ARB_explicit_attrib_location : enable\n"
125     "#extension GL_ARB_separate_shader_objects : enable\n"
126     "#extension GL_ARB_sample_shading : enable\n"
127     "layout(location = 0) in vec3 vTex0;\n"
128     "layout(location = 0) out vec4 fragColor0;\n"
129     "uniform sampler2D tex;\n"
130     "uniform int sample_mask;\n"
131     "void main(void)\n"
132     "{\n"
133     "fragColor0 = vec4(0,0,0,1);\n"
134     "gl_FragDepth = texelFetch(tex, ivec2(int(vTex0.x), int(vTex0.y)), 0).x;\n"
135     "gl_SampleMask[0] = sample_mask;\n"
136     "}";
137
138 static const char *g_write_depth_array_frag_shader =
139     "#version 150 core\n"
140     "#extension GL_ARB_explicit_attrib_location : enable\n"
141     "#extension GL_ARB_separate_shader_objects : enable\n"
142     "#extension GL_ARB_sample_shading : enable\n"
143     "layout(location = 0) in vec3 vTex0;\n"
144     "layout(location = 0) out vec4 fragColor0;\n"
145     "uniform sampler2DArray tex;\n"
146     "uniform int sample_mask;\n"
147     "void main(void)\n"
148     "{\n"
149     "fragColor0 = vec4(0,0,0,1);\n"
150     "gl_FragDepth = texelFetch(tex, ivec3(int(vTex0.x), int(vTex0.y), int(vTex0.z)), 0).x;\n"
151     "gl_SampleMask[0] = sample_mask;\n"
152     "}";
153
154 static const char *g_const_color_frag_shader =
155     "#version 150 core\n"
156     "#extension GL_ARB_explicit_attrib_location : enable\n"
157     "#extension GL_ARB_separate_shader_objects : enable\n"
158     "#extension GL_ARB_sample_shading : enable\n"
159     "layout(location = 0) out vec4 fragColor0;\n"
160     "uniform vec4 color;\n"
161     "void main(void)\n"
162     "{\n"
163     "fragColor0 = color;\n"
164     "}";
165
166 static const char *g_write_stencil_frag_shader =
167     "#version 150 core\n"
168     "#extension GL_ARB_explicit_attrib_location : enable\n"
169     "#extension GL_ARB_separate_shader_objects : enable\n"
170     "#extension GL_ARB_sample_shading : enable\n"
171     "layout(location = 0) in vec3 vTex0;\n"
172     "layout(location = 0) out vec4 fragColor0;\n"
173     "uniform sampler2D tex;\n"
174     "uniform float stencil_comp_val;\n"
175     "uniform int sample_mask;\n"
176     "void main(void)\n"
177     "{\n"
178     "float stencil_val = texelFetch(tex, ivec2(int(vTex0.x), int(vTex0.y)), 0).x;\n"
179     "if (abs(stencil_val - stencil_comp_val) > 0.125/255.0) discard;\n"
180     "fragColor0 = vec4(0,0,0,1);\n"
181     "gl_SampleMask[0] = sample_mask;\n"
182     "}";
183
184 static const char *g_write_stencil_array_frag_shader =
185     "#version 150 core\n"
186     "#extension GL_ARB_explicit_attrib_location : enable\n"
187     "#extension GL_ARB_separate_shader_objects : enable\n"
188     "#extension GL_ARB_sample_shading : enable\n"
189     "layout(location = 0) in vec3 vTex0;\n"
190     "layout(location = 0) out vec4 fragColor0;\n"
191     "uniform sampler2DArray tex;\n"
192     "uniform float stencil_comp_val;\n"
193     "uniform int sample_mask;\n"
194     "void main(void)\n"
195     "{\n"
196     "float stencil_val = texelFetch(tex, ivec3(int(vTex0.x), int(vTex0.y), int(vTex0.z)), 0).x;\n"
197     "if (abs(stencil_val - stencil_comp_val) > 0.125/255.0) discard;\n"
198     "fragColor0 = vec4(0,0,0,1);\n"
199     "gl_SampleMask[0] = sample_mask;\n"
200     "}";
201
202 struct vogl_quad_vertex
203 {
204     vec4F m_pos;
205     vec3F m_uv0;
206
207     vogl_quad_vertex() { }
208
209     vogl_quad_vertex(float x, float y, float z, float w, float u, float v, float q) :
210         m_pos(x, y, z, w), m_uv0(u, v, q)
211     {
212     }
213 };
214
215 static const vogl_quad_vertex g_quad_tri_verts[3*2] =
216 {
217     vogl_quad_vertex(-1.0f,  1.0f, 0.0f, 1.0f,  0.0f, 1.0f, 0.0f ), // top left
218     vogl_quad_vertex( 1.0f,  1.0f, 0.0f, 1.0f,  1.0f, 1.0f, 0.0f ), // top right
219     vogl_quad_vertex( 1.0f, -1.0f, 0.0f, 1.0f,  1.0f, 0.0f, 0.0f ), // bottom right
220
221     vogl_quad_vertex(-1.0f,  1.0f, 0.0f, 1.0f,  0.0f, 1.0f, 0.0f ), // top left
222     vogl_quad_vertex( 1.0f, -1.0f, 0.0f, 1.0f,  1.0f, 0.0f, 0.0f ), // bottom right
223     vogl_quad_vertex(-1.0f, -1.0f, 0.0f, 1.0f,  0.0f, 0.0f, 0.0f )  // bottom left
224 };
225
226 vogl_msaa_texture_splitter::vogl_msaa_texture_splitter() :
227     m_vao_handle(0),
228     m_vertex_buffer(0),
229     m_orig_context(0),
230     m_work_context(0),
231     m_cur_display(0),
232     m_cur_fb_config(0),
233     m_cur_drawable(0),
234     m_valid(false)
235 {
236 }
237
238 bool vogl_msaa_texture_splitter::init()
239 {
240     deinit();
241
242     // Create work context
243     m_orig_context = vogl_get_current_context();
244     m_cur_display = vogl_get_current_display();
245     m_cur_fb_config = vogl_get_current_fb_config();
246     m_cur_drawable = vogl_get_current_drawable();
247
248     vogl_context_desc context_desc;
249     m_work_context = vogl_create_context(m_cur_display, m_cur_fb_config, m_orig_context, 3, 2, eCHCDebugContextFlag | cCHCCoreProfileFlag, &context_desc);
250     if (!m_work_context)
251     {
252         vogl_error_printf("%s: Failed creating temporary context!\n", VOGL_METHOD_NAME);
253         return false;
254     }
255
256     vogl_make_current(m_cur_display, m_cur_drawable, m_work_context);
257
258     vogl_enable_generic_context_debug_messages();
259
260     m_context_info.init(context_desc);
261
262     GL_ENTRYPOINT(glGenVertexArrays)(1, &m_vao_handle);
263     VOGL_CHECK_GL_ERROR;
264
265     GL_ENTRYPOINT(glBindVertexArray)(m_vao_handle);
266     VOGL_CHECK_GL_ERROR;
267
268     // Create programs
269
270     // Reading from MSAA
271     if (!m_read_color_program.init(g_passthrough_vert_shader, g_read_color_frag_shader))
272         return false;
273     m_read_color_program.set_uniform("tex", 0);
274
275     if (!m_read_color_array_program.init(g_passthrough_vert_shader, g_read_color_array_frag_shader))
276         return false;
277     m_read_color_array_program.set_uniform("tex", 0);
278
279     if (!m_read_depth_program.init(g_passthrough_vert_shader, g_read_depth_frag_shader))
280         return false;
281     m_read_depth_program.set_uniform("tex", 0);
282
283     if (!m_read_depth_array_program.init(g_passthrough_vert_shader, g_read_depth_array_frag_shader))
284         return false;
285     m_read_depth_array_program.set_uniform("tex", 0);
286
287     // Writing to MSAA
288     if (!m_write_color_program.init(g_passthrough_vert_shader, g_write_color_frag_shader))
289         return false;
290     m_write_color_program.set_uniform("tex", 0);
291
292     if (!m_write_color_array_program.init(g_passthrough_vert_shader, g_write_color_array_frag_shader))
293         return false;
294     m_write_color_array_program.set_uniform("tex", 0);
295
296     if (!m_write_depth_program.init(g_passthrough_vert_shader, g_write_depth_frag_shader))
297         return false;
298     m_write_depth_program.set_uniform("tex", 0);
299
300     if (!m_write_depth_array_program.init(g_passthrough_vert_shader, g_write_depth_array_frag_shader))
301         return false;
302     m_write_depth_array_program.set_uniform("tex", 0);
303
304     // Copying stencil to color
305     if (!m_const_color_program.init(g_passthrough_vert_shader, g_const_color_frag_shader))
306         return false;
307
308     // Copying color to stencil
309     if (!m_write_stencil_program.init(g_passthrough_vert_shader, g_write_stencil_frag_shader))
310         return false;
311     m_write_stencil_program.set_uniform("tex", 0);
312
313     if (!m_write_stencil_array_program.init(g_passthrough_vert_shader, g_write_stencil_array_frag_shader))
314         return false;
315     m_write_stencil_array_program.set_uniform("tex", 0);
316
317     // Create vertex buffer and bind it
318     GL_ENTRYPOINT(glGenBuffers)(1, &m_vertex_buffer);
319     VOGL_CHECK_GL_ERROR;
320
321     GL_ENTRYPOINT(glBindBuffer)(GL_ARRAY_BUFFER, m_vertex_buffer);
322     VOGL_CHECK_GL_ERROR;
323
324     GL_ENTRYPOINT(glVertexAttribPointer)(0, 4, GL_FLOAT, GL_FALSE, sizeof(vogl_quad_vertex), (const GLvoid *)(uint64_t)VOGL_OFFSETOF(vogl_quad_vertex, m_pos));
325     VOGL_CHECK_GL_ERROR;
326
327     GL_ENTRYPOINT(glVertexAttribPointer)(1, 3, GL_FLOAT, GL_FALSE, sizeof(vogl_quad_vertex), (const GLvoid *)(uint64_t)VOGL_OFFSETOF(vogl_quad_vertex, m_uv0));
328     VOGL_CHECK_GL_ERROR;
329
330     GL_ENTRYPOINT(glEnableVertexAttribArray)(0);
331     VOGL_CHECK_GL_ERROR;
332
333     GL_ENTRYPOINT(glEnableVertexAttribArray)(1);
334     VOGL_CHECK_GL_ERROR;
335
336     vogl_reset_pixel_store_states();
337
338     // Set state (some of this is probably not necessary)
339     GL_ENTRYPOINT(glDisable)(GL_BLEND);
340     GL_ENTRYPOINT(glDisable)(GL_CULL_FACE);
341     GL_ENTRYPOINT(glDisable)(GL_DEPTH_TEST);
342     GL_ENTRYPOINT(glDisable)(GL_STENCIL_TEST);
343     GL_ENTRYPOINT(glDepthMask)(GL_FALSE);
344     GL_ENTRYPOINT(glStencilMask)(0);
345     GL_ENTRYPOINT(glActiveTexture)(GL_TEXTURE0);
346     VOGL_CHECK_GL_ERROR;
347
348     m_valid = true;
349
350     return true;
351 }
352
353 void vogl_msaa_texture_splitter::deinit()
354 {
355     if (!m_work_context)
356         return;
357
358     // We're switching contexts so serialize here (not sure if this is necessary, best to be safe).
359     GL_ENTRYPOINT(glFinish)();
360     VOGL_CHECK_GL_ERROR;
361
362     GL_ENTRYPOINT(glBindVertexArray)(0);
363     VOGL_CHECK_GL_ERROR;
364
365     GL_ENTRYPOINT(glUseProgram)(0);
366     VOGL_CHECK_GL_ERROR;
367
368     GL_ENTRYPOINT(glBindTexture)(GL_TEXTURE_2D, 0);
369     VOGL_CHECK_GL_ERROR;
370
371     GL_ENTRYPOINT(glBindTexture)(GL_TEXTURE_2D_MULTISAMPLE, 0);
372     VOGL_CHECK_GL_ERROR;
373
374     GL_ENTRYPOINT(glBindTexture)(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, 0);
375     VOGL_CHECK_GL_ERROR;
376
377     GL_ENTRYPOINT(glBindBuffer)(GL_ARRAY_BUFFER, 0);
378     VOGL_CHECK_GL_ERROR;
379
380     if (m_vao_handle)
381     {
382         GL_ENTRYPOINT(glDeleteVertexArrays)(1, &m_vao_handle);
383         VOGL_CHECK_GL_ERROR;
384
385         m_vao_handle = 0;
386     }
387
388     if (m_vertex_buffer)
389     {
390         GL_ENTRYPOINT(glDeleteBuffers)(1, &m_vertex_buffer);
391         VOGL_CHECK_GL_ERROR;
392
393         m_vertex_buffer = 0;
394     }
395
396     m_read_color_program.deinit();
397     m_read_color_array_program.deinit();
398     m_read_depth_program.deinit();
399     m_read_depth_array_program.deinit();
400
401     m_write_color_program.deinit();
402     m_write_color_array_program.deinit();
403     m_write_depth_program.deinit();
404     m_write_depth_array_program.deinit();
405
406     m_const_color_program.deinit();
407
408     m_write_stencil_program.deinit();
409     m_write_stencil_array_program.deinit();
410
411     vogl_make_current(m_cur_display, m_cur_drawable, m_orig_context);
412
413     vogl_destroy_context(m_cur_display, m_work_context);
414     m_work_context = 0;
415
416     m_orig_context = 0;
417     m_cur_display = 0;
418     m_cur_fb_config = 0;
419     m_cur_drawable = 0;
420
421     m_valid = false;
422 }
423
424 vogl_msaa_texture_splitter::~vogl_msaa_texture_splitter()
425 {
426     deinit();
427 }
428
429 // One multisampled source, multiple non-multisampled destinations created by method.
430 bool vogl_msaa_texture_splitter::split(GLenum src_target, GLuint src_texture, vogl::vector<GLuint> &dest_textures)
431 {
432     dest_textures.resize(0);
433
434     if (!m_valid)
435         return false;
436
437     if ((src_target != GL_TEXTURE_2D_MULTISAMPLE) && (src_target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY))
438         return false;
439
440     GLenum dest_target = (src_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
441
442     GL_ENTRYPOINT(glBindTexture)(src_target, src_texture);
443     VOGL_CHECK_GL_ERROR;
444
445     GLint mip_level = 0, base_level = 0, max_level = 0;
446
447     GLenum internal_fmt = 0;
448     int base_width = 0, base_height = 0, base_depth = 0, samples = 0;
449     GL_ENTRYPOINT(glGetTexLevelParameteriv)(src_target, base_level, GL_TEXTURE_INTERNAL_FORMAT, reinterpret_cast<GLint *>(&internal_fmt));
450     GL_ENTRYPOINT(glGetTexLevelParameteriv)(src_target, base_level, GL_TEXTURE_WIDTH, &base_width);
451     GL_ENTRYPOINT(glGetTexLevelParameteriv)(src_target, base_level, GL_TEXTURE_HEIGHT, &base_height);
452     GL_ENTRYPOINT(glGetTexLevelParameteriv)(src_target, base_level, GL_TEXTURE_DEPTH, &base_depth);
453     GL_ENTRYPOINT(glGetTexLevelParameteriv)(src_target, base_level, GL_TEXTURE_SAMPLES, &samples);
454     VOGL_CHECK_GL_ERROR;
455
456     if ((base_width < 1) || (base_height < 1) || (base_depth < 1) || (samples < 1))
457         return false;
458
459     const vogl_internal_tex_format *pInternal_tex_fmt = vogl_find_internal_texture_format(internal_fmt);
460     if ((!pInternal_tex_fmt) || (pInternal_tex_fmt->m_optimum_get_image_fmt == GL_NONE) || (pInternal_tex_fmt->m_optimum_get_image_type == GL_NONE))
461         return false;
462
463     GLenum attachment_target = GL_COLOR_ATTACHMENT0;
464
465     if ((pInternal_tex_fmt->m_comp_sizes[cTCDepth]) && (pInternal_tex_fmt->m_comp_sizes[cTCStencil]))
466         attachment_target = GL_DEPTH_STENCIL_ATTACHMENT;
467     else if (pInternal_tex_fmt->m_comp_sizes[cTCDepth])
468         attachment_target = GL_DEPTH_ATTACHMENT;
469     else if (pInternal_tex_fmt->m_comp_sizes[cTCStencil])
470         return false;
471
472     if (attachment_target == GL_COLOR_ATTACHMENT0)
473     {
474         GL_ENTRYPOINT(glDepthMask)(GL_FALSE);
475         VOGL_CHECK_GL_ERROR;
476
477         GL_ENTRYPOINT(glDisable)(GL_DEPTH_TEST);
478         VOGL_CHECK_GL_ERROR;
479     }
480     else
481     {
482         GL_ENTRYPOINT(glDepthMask)(GL_TRUE);
483         VOGL_CHECK_GL_ERROR;
484
485         GL_ENTRYPOINT(glEnable)(GL_DEPTH_TEST);
486         VOGL_CHECK_GL_ERROR;
487
488         GL_ENTRYPOINT(glDepthFunc)(GL_ALWAYS);
489         VOGL_CHECK_GL_ERROR;
490     }
491
492     GL_ENTRYPOINT(glDisable)(GL_STENCIL_TEST);
493     VOGL_CHECK_GL_ERROR;
494
495     uint width = base_width << base_level;
496     uint height = base_height << base_level;
497     uint depth = base_depth;
498
499     uint max_possible_mip_levels = utils::compute_max_mips(width, height, depth);
500     int num_actual_mip_levels = math::minimum<int>(max_possible_mip_levels, max_level + 1);
501
502     for (int sample_index = 0; sample_index < samples; sample_index++)
503     {
504         m_read_color_program.set_uniform("tex_sample", sample_index);
505         m_read_color_array_program.set_uniform("tex_sample", sample_index);
506         m_read_depth_program.set_uniform("tex_sample", sample_index);
507         m_read_depth_array_program.set_uniform("tex_sample", sample_index);
508
509         GLuint dest_texture = 0;
510         GL_ENTRYPOINT(glGenTextures)(1, &dest_texture);
511         VOGL_CHECK_GL_ERROR;
512
513         dest_textures.push_back(dest_texture);
514
515         GL_ENTRYPOINT(glBindTexture)(dest_target, dest_texture);
516         VOGL_CHECK_GL_ERROR;
517
518         GL_ENTRYPOINT(glTexParameteri)(dest_target, GL_TEXTURE_BASE_LEVEL, base_level);
519         VOGL_CHECK_GL_ERROR;
520
521         GL_ENTRYPOINT(glTexParameteri)(dest_target, GL_TEXTURE_MAX_LEVEL, num_actual_mip_levels - 1);
522         VOGL_CHECK_GL_ERROR;
523
524         int mip_width = 0, mip_height = 0, mip_depth = 0;
525         GL_ENTRYPOINT(glGetTexLevelParameteriv)(src_target, mip_level, GL_TEXTURE_WIDTH, &mip_width);
526         GL_ENTRYPOINT(glGetTexLevelParameteriv)(src_target, mip_level, GL_TEXTURE_HEIGHT, &mip_height);
527         GL_ENTRYPOINT(glGetTexLevelParameteriv)(src_target, mip_level, GL_TEXTURE_DEPTH, &mip_depth);
528         if ((vogl_check_gl_error()) || (mip_width < 1) || (mip_height < 1) || (mip_depth < 1))
529             goto failure;
530
531         VOGL_ASSERT(mip_depth == base_depth);
532         VOGL_NOTE_UNUSED(mip_depth);
533
534         vogl::vector<uint8> ones;
535         ones.resize(static_cast<uint>(vogl_get_image_size(pInternal_tex_fmt->m_optimum_get_image_fmt, pInternal_tex_fmt->m_optimum_get_image_type, mip_width, mip_height, mip_depth)));
536         ones.set_all(255);
537
538         if (src_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)
539         {
540             GL_ENTRYPOINT(glTexImage3D)(dest_target,
541                 mip_level,
542                 internal_fmt,
543                 mip_width,
544                 mip_height,
545                 base_depth,
546                 0,
547                 pInternal_tex_fmt->m_optimum_get_image_fmt,
548                 pInternal_tex_fmt->m_optimum_get_image_type,
549                 ones.get_ptr());
550             VOGL_CHECK_GL_ERROR;
551         }
552         else
553         {
554             GL_ENTRYPOINT(glTexImage2D)(dest_target,
555                 mip_level,
556                 internal_fmt,
557                 mip_width,
558                 mip_height,
559                 0,
560                 pInternal_tex_fmt->m_optimum_get_image_fmt,
561                 pInternal_tex_fmt->m_optimum_get_image_type,
562                 ones.get_ptr());
563             VOGL_CHECK_GL_ERROR;
564         }
565
566         for (int layer = 0; layer < base_depth; layer++)
567         {
568             // Create FBO
569             GLuint fbo_handle = 0;
570             GL_ENTRYPOINT(glGenFramebuffers)(1, &fbo_handle);
571             VOGL_CHECK_GL_ERROR;
572
573             GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, fbo_handle);
574             VOGL_CHECK_GL_ERROR;
575
576             if (dest_target == GL_TEXTURE_2D_ARRAY)
577             {
578                 GL_ENTRYPOINT(glFramebufferTextureLayer)(GL_DRAW_FRAMEBUFFER, attachment_target, dest_texture, mip_level, layer);
579                 VOGL_CHECK_GL_ERROR;
580             }
581             else
582             {
583                 GL_ENTRYPOINT(glFramebufferTexture2D)(GL_DRAW_FRAMEBUFFER, attachment_target, dest_target, dest_texture, mip_level);
584                 VOGL_CHECK_GL_ERROR;
585             }
586
587             if (attachment_target == GL_COLOR_ATTACHMENT0)
588             {
589                 GLenum draw_buf = GL_COLOR_ATTACHMENT0;
590                 GL_ENTRYPOINT(glDrawBuffers)(1, &draw_buf);
591                 VOGL_CHECK_GL_ERROR;
592             }
593             else
594             {
595                 GL_ENTRYPOINT(glDrawBuffer)(GL_NONE);
596                 VOGL_CHECK_GL_ERROR;
597             }
598
599             GLenum fbo_status = GL_ENTRYPOINT(glCheckFramebufferStatus)(GL_DRAW_FRAMEBUFFER);
600             VOGL_CHECK_GL_ERROR;
601
602             bool status = false;
603
604             if (fbo_status == GL_FRAMEBUFFER_COMPLETE)
605             {
606                 // This method reads from a multisampled texture, which does NOT support GL_SKIP_DECODE_EXT on these targets.
607                 // Instead, we enable sRGB writes to work around this. The source and dest use the same formats, and if the dest is not sRGB then the source shouldn't be.
608                 GL_ENTRYPOINT(glDisable)(GL_FRAMEBUFFER_SRGB);
609                 VOGL_CHECK_GL_ERROR;
610
611                 if (attachment_target == GL_COLOR_ATTACHMENT0)
612                 {
613                     GLint encoding = 0;
614                     GL_ENTRYPOINT(glGetFramebufferAttachmentParameteriv)(GL_DRAW_FRAMEBUFFER, attachment_target, GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING, &encoding);
615                     VOGL_CHECK_GL_ERROR;
616
617                     if (encoding == GL_SRGB)
618                     {
619                         GL_ENTRYPOINT(glEnable)(GL_FRAMEBUFFER_SRGB);
620                         VOGL_CHECK_GL_ERROR;
621                     }
622                 }
623
624                 // Render quad to FBO
625                 GL_ENTRYPOINT(glViewport)(0, 0, mip_width, mip_height);
626                 VOGL_CHECK_GL_ERROR;
627
628                 GL_ENTRYPOINT(glClearColor)(1.0f, 0.3f, 1.0f, 1.0f);
629                 VOGL_CHECK_GL_ERROR;
630
631                 GL_ENTRYPOINT(glClearDepth)(.25f);
632                 VOGL_CHECK_GL_ERROR;
633
634                 GL_ENTRYPOINT(glClearStencil)(64);
635                 VOGL_CHECK_GL_ERROR;
636
637                 if (attachment_target == GL_COLOR_ATTACHMENT0)
638                 {
639                     GL_ENTRYPOINT(glClear)(GL_COLOR_BUFFER_BIT);
640                     VOGL_CHECK_GL_ERROR;
641                 }
642                 else if (attachment_target == GL_DEPTH_ATTACHMENT)
643                 {
644                     GL_ENTRYPOINT(glClear)(GL_DEPTH_BUFFER_BIT);
645                     VOGL_CHECK_GL_ERROR;
646                 }
647                 else
648                 {
649                     GL_ENTRYPOINT(glClear)(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
650                     VOGL_CHECK_GL_ERROR;
651                 }
652
653                 vogl_quad_vertex quad_tri_verts[3*2];
654                 memcpy(quad_tri_verts, g_quad_tri_verts, sizeof(quad_tri_verts));
655
656                 for (uint i = 0; i < 6; i++)
657                 {
658                     quad_tri_verts[i].m_uv0[0] *= mip_width;
659                     quad_tri_verts[i].m_uv0[1] *= mip_height;
660                     quad_tri_verts[i].m_uv0[2] = layer;
661                 }
662
663                 GL_ENTRYPOINT(glBufferData)(GL_ARRAY_BUFFER, sizeof(quad_tri_verts), quad_tri_verts, GL_STATIC_DRAW);
664                 VOGL_CHECK_GL_ERROR;
665
666                 if (attachment_target == GL_COLOR_ATTACHMENT0)
667                 {
668                     GL_ENTRYPOINT(glUseProgram)((src_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) ? m_read_color_array_program.get_handle() : m_read_color_program.get_handle());
669                     VOGL_CHECK_GL_ERROR;
670                 }
671                 else
672                 {
673                     GL_ENTRYPOINT(glUseProgram)((src_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) ? m_read_depth_array_program.get_handle() : m_read_depth_program.get_handle());
674                     VOGL_CHECK_GL_ERROR;
675                 }
676
677                 GL_ENTRYPOINT(glDrawArrays)(GL_TRIANGLES, 0, 6);
678                 VOGL_CHECK_GL_ERROR;
679
680                 status = true;
681             } // fbo_status
682
683             // Delete FBO
684             GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, 0);
685             VOGL_CHECK_GL_ERROR;
686
687             GL_ENTRYPOINT(glDeleteFramebuffers)(1, &fbo_handle);
688             VOGL_CHECK_GL_ERROR;
689
690             GL_ENTRYPOINT(glDrawBuffer)(GL_FRONT_LEFT);
691             VOGL_CHECK_GL_ERROR;
692
693             if (!status)
694                 goto failure;
695         } // layer
696     } // sample_index
697
698     GL_ENTRYPOINT(glBindTexture)(src_target, 0);
699     VOGL_CHECK_GL_ERROR;
700
701     GL_ENTRYPOINT(glBindTexture)(dest_target, 0);
702     VOGL_CHECK_GL_ERROR;
703
704     return true;
705
706 failure:
707     GL_ENTRYPOINT(glBindTexture)(src_target, 0);
708     VOGL_CHECK_GL_ERROR;
709
710     GL_ENTRYPOINT(glBindTexture)(dest_target, 0);
711     VOGL_CHECK_GL_ERROR;
712
713     if (dest_textures.size())
714     {
715         GL_ENTRYPOINT(glDeleteTextures)(dest_textures.size(), dest_textures.get_ptr());
716         VOGL_CHECK_GL_ERROR;
717
718         dest_textures.resize(0);
719     }
720
721     return false;
722 }
723
724 // Multiple sources, one multisampled destination. Caller creates destination.
725 bool vogl_msaa_texture_splitter::combine(GLuint src_texture, uint dest_sample_index, GLenum dest_target, GLuint dest_texture)
726 {
727     if (!m_valid)
728     {
729         VOGL_ASSERT_ALWAYS;
730         return false;
731     }
732
733     if ((dest_target != GL_TEXTURE_2D_MULTISAMPLE) && (dest_target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY))
734     {
735         VOGL_ASSERT_ALWAYS;
736         return false;
737     }
738
739     m_write_color_program.set_uniform("sample_mask", static_cast<int>(1U << dest_sample_index));
740     m_write_color_array_program.set_uniform("sample_mask", static_cast<int>(1U << dest_sample_index));
741     m_write_depth_program.set_uniform("sample_mask", static_cast<int>(1U << dest_sample_index));
742     m_write_depth_array_program.set_uniform("sample_mask", static_cast<int>(1U << dest_sample_index));
743
744     const GLenum src_target = (dest_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
745
746     GL_ENTRYPOINT(glBindTexture)(src_target, src_texture);
747     VOGL_CHECK_GL_ERROR;
748
749     GL_ENTRYPOINT(glBindTexture)(dest_target, dest_texture);
750     VOGL_CHECK_GL_ERROR;
751
752     const int mip_level = 0;
753
754     GLenum internal_fmt = 0;
755     GL_ENTRYPOINT(glGetTexLevelParameteriv)(src_target, mip_level, GL_TEXTURE_INTERNAL_FORMAT, reinterpret_cast<GLint *>(&internal_fmt));
756
757     int mip_width = 0, mip_height = 0, mip_depth = 0;
758     GL_ENTRYPOINT(glGetTexLevelParameteriv)(src_target, mip_level, GL_TEXTURE_WIDTH, &mip_width);
759     GL_ENTRYPOINT(glGetTexLevelParameteriv)(src_target, mip_level, GL_TEXTURE_HEIGHT, &mip_height);
760     GL_ENTRYPOINT(glGetTexLevelParameteriv)(src_target, mip_level, GL_TEXTURE_DEPTH, &mip_depth);
761
762     if ((vogl_check_gl_error()) || (mip_width < 1) || (mip_height < 1) || (mip_depth < 1))
763         return false;
764
765     const vogl_internal_tex_format *pInternal_tex_fmt = vogl_find_internal_texture_format(internal_fmt);
766     if ((!pInternal_tex_fmt) || (pInternal_tex_fmt->m_optimum_get_image_fmt == GL_NONE) || (pInternal_tex_fmt->m_optimum_get_image_type == GL_NONE))
767         return false;
768
769     GLenum attachment_target = GL_COLOR_ATTACHMENT0;
770     if ((pInternal_tex_fmt->m_comp_sizes[cTCDepth]) && (pInternal_tex_fmt->m_comp_sizes[cTCStencil]))
771         attachment_target = GL_DEPTH_STENCIL_ATTACHMENT;
772     else if (pInternal_tex_fmt->m_comp_sizes[cTCDepth])
773         attachment_target = GL_DEPTH_ATTACHMENT;
774     else if (pInternal_tex_fmt->m_comp_sizes[cTCStencil])
775         return false;
776
777     if (attachment_target == GL_COLOR_ATTACHMENT0)
778     {
779         GL_ENTRYPOINT(glDepthMask)(GL_FALSE);
780         VOGL_CHECK_GL_ERROR;
781
782         GL_ENTRYPOINT(glDisable)(GL_DEPTH_TEST);
783         VOGL_CHECK_GL_ERROR;
784     }
785     else
786     {
787         GL_ENTRYPOINT(glDepthMask)(GL_TRUE);
788         VOGL_CHECK_GL_ERROR;
789
790         GL_ENTRYPOINT(glEnable)(GL_DEPTH_TEST);
791         VOGL_CHECK_GL_ERROR;
792
793         GL_ENTRYPOINT(glDepthFunc)(GL_ALWAYS);
794         VOGL_CHECK_GL_ERROR;
795     }
796
797     GL_ENTRYPOINT(glDisable)(GL_STENCIL_TEST);
798     VOGL_CHECK_GL_ERROR;
799
800     // This method disables sRGB reads and writes (we can do this because the source is non-multisampled and the dest is a multisampled render target.)
801     GLint orig_srgb_decode = 0;
802     if (m_context_info.supports_extension("GL_EXT_texture_sRGB_decode"))
803     {
804         GL_ENTRYPOINT(glGetTexParameteriv)(src_target, GL_TEXTURE_SRGB_DECODE_EXT, &orig_srgb_decode);
805         VOGL_CHECK_GL_ERROR;
806
807         GL_ENTRYPOINT(glTexParameteri)(src_target, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
808         VOGL_CHECK_GL_ERROR;
809     }
810
811     for (int layer = 0; layer < mip_depth; layer++)
812     {
813         // Create FBO
814         GLuint fbo_handle = 0;
815         GL_ENTRYPOINT(glGenFramebuffers)(1, &fbo_handle);
816         VOGL_CHECK_GL_ERROR;
817
818         GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, fbo_handle);
819         VOGL_CHECK_GL_ERROR;
820
821         if (dest_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)
822         {
823             GL_ENTRYPOINT(glFramebufferTextureLayer)(GL_DRAW_FRAMEBUFFER, attachment_target, dest_texture, mip_level, layer);
824             VOGL_CHECK_GL_ERROR;
825         }
826         else
827         {
828             GL_ENTRYPOINT(glFramebufferTexture2D)(GL_DRAW_FRAMEBUFFER, attachment_target, dest_target, dest_texture, mip_level);
829             VOGL_CHECK_GL_ERROR;
830         }
831
832         if (attachment_target == GL_COLOR_ATTACHMENT0)
833         {
834             GLenum draw_buf = GL_COLOR_ATTACHMENT0;
835             GL_ENTRYPOINT(glDrawBuffers)(1, &draw_buf);
836             VOGL_CHECK_GL_ERROR;
837         }
838         else
839         {
840             GL_ENTRYPOINT(glDrawBuffer)(GL_NONE);
841             VOGL_CHECK_GL_ERROR;
842         }
843
844         GLenum fbo_status = GL_ENTRYPOINT(glCheckFramebufferStatus)(GL_DRAW_FRAMEBUFFER);
845         VOGL_CHECK_GL_ERROR;
846
847         bool status = false;
848
849         if (fbo_status == GL_FRAMEBUFFER_COMPLETE)
850         {
851             // Render quad to FBO
852             GL_ENTRYPOINT(glViewport)(0, 0, mip_width, mip_height);
853             VOGL_CHECK_GL_ERROR;
854
855             vogl_quad_vertex quad_tri_verts[3*2];
856             memcpy(quad_tri_verts, g_quad_tri_verts, sizeof(quad_tri_verts));
857
858             for (uint i = 0; i < 6; i++)
859             {
860                 quad_tri_verts[i].m_uv0[0] *= mip_width;
861                 quad_tri_verts[i].m_uv0[1] *= mip_height;
862                 quad_tri_verts[i].m_uv0[2] = layer;
863             }
864
865             GL_ENTRYPOINT(glBufferData)(GL_ARRAY_BUFFER, sizeof(quad_tri_verts), quad_tri_verts, GL_STATIC_DRAW);
866             VOGL_CHECK_GL_ERROR;
867
868             if (attachment_target == GL_COLOR_ATTACHMENT0)
869             {
870                 GL_ENTRYPOINT(glUseProgram)((src_target == GL_TEXTURE_2D_ARRAY) ? m_write_color_array_program.get_handle() : m_write_color_program.get_handle());
871                 VOGL_CHECK_GL_ERROR;
872             }
873             else
874             {
875                 GL_ENTRYPOINT(glUseProgram)((src_target == GL_TEXTURE_2D_ARRAY) ? m_write_depth_array_program.get_handle() : m_write_depth_program.get_handle());
876                 VOGL_CHECK_GL_ERROR;
877             }
878
879             GL_ENTRYPOINT(glDisable)(GL_FRAMEBUFFER_SRGB);
880             VOGL_CHECK_GL_ERROR;
881
882             GL_ENTRYPOINT(glDrawArrays)(GL_TRIANGLES, 0, 6);
883             VOGL_CHECK_GL_ERROR;
884
885             status = true;
886         } // fbo_status
887
888         // Delete FBO
889         GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, 0);
890         VOGL_CHECK_GL_ERROR;
891
892         GL_ENTRYPOINT(glDeleteFramebuffers)(1, &fbo_handle);
893         VOGL_CHECK_GL_ERROR;
894
895         GL_ENTRYPOINT(glDrawBuffer)(GL_FRONT_LEFT);
896         VOGL_CHECK_GL_ERROR;
897
898         if (!status)
899             goto failure;
900     } // layer
901
902     GL_ENTRYPOINT(glBindTexture)(src_target, 0);
903     VOGL_CHECK_GL_ERROR;
904
905     GL_ENTRYPOINT(glBindTexture)(dest_target, 0);
906     VOGL_CHECK_GL_ERROR;
907
908     return true;
909
910 failure:
911     GL_ENTRYPOINT(glBindTexture)(src_target, 0);
912     VOGL_CHECK_GL_ERROR;
913
914     GL_ENTRYPOINT(glBindTexture)(dest_target, 0);
915     VOGL_CHECK_GL_ERROR;
916
917     if (m_context_info.supports_extension("GL_EXT_texture_sRGB_decode"))
918     {
919         GL_ENTRYPOINT(glTexParameteri)(src_target, GL_TEXTURE_SRGB_DECODE_EXT, orig_srgb_decode);
920         VOGL_CHECK_GL_ERROR;
921     }
922
923     return false;
924 }
925
926 // How to retrieve MSAA stencil info:
927 // Step 1: Get MSAA depth/stencil texture info
928 // Step 2: Create new MSAA color texture - same res and # of samples, 32-bit RGBA format
929 // Step 3: Create new temp FBO, attach new MSAA color texture + MSAA depth/stencil texture
930 // Step 4: Clear FBO's color attachment
931 // Step 5: Disable depth mask, set depth func to always
932 // Step 6: For i = 0 to 255:
933 //  Enable stencil testing, set ref to i, reject when stencil != i
934 //  Draw a quad, have it output color value i
935 // Step 7: Now split this MSAA color texture into sep non-MSAA textures
936 // Step 8: Return these MSAA color textures to the caller
937 // Step 9: The caller now can combine the stencil data with the retrieved depth data
938
939 // Also see http://www.opengl.org/wiki/Texture#Stencil_texturing, but this is GL v4.3
940
941 bool vogl_msaa_texture_splitter::copy_stencil_samples_to_color(GLenum target, GLuint src_texture, GLuint &dest_texture)
942 {
943     dest_texture = 0;
944
945     if (!m_valid)
946     {
947         VOGL_ASSERT_ALWAYS;
948         return false;
949     }
950
951     if ((target != GL_TEXTURE_2D_MULTISAMPLE) && (target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY))
952     {
953         VOGL_ASSERT_ALWAYS;
954         return false;
955     }
956
957     GL_ENTRYPOINT(glBindTexture)(target, src_texture);
958     VOGL_CHECK_GL_ERROR;
959
960     const int mip_level = 0;
961
962     GLenum internal_fmt = 0;
963     GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, mip_level, GL_TEXTURE_INTERNAL_FORMAT, reinterpret_cast<GLint *>(&internal_fmt));
964
965     int width = 0, height = 0, depth = 0, samples = 0;
966     GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, mip_level, GL_TEXTURE_WIDTH, &width);
967     GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, mip_level, GL_TEXTURE_HEIGHT, &height);
968     GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, mip_level, GL_TEXTURE_DEPTH, &depth);
969     GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, mip_level, GL_TEXTURE_SAMPLES, &samples);
970
971     if ((vogl_check_gl_error()) || (width < 1) || (height < 1) || (depth < 1) || (samples < 1))
972         return false;
973
974     const vogl_internal_tex_format *pInternal_tex_fmt = vogl_find_internal_texture_format(internal_fmt);
975     if ((!pInternal_tex_fmt) || (pInternal_tex_fmt->m_optimum_get_image_fmt == GL_NONE) || (pInternal_tex_fmt->m_optimum_get_image_type == GL_NONE))
976         return false;
977
978     if (!pInternal_tex_fmt->m_comp_sizes[cTCStencil])
979         return false;
980
981     GLenum fbo_attachment_target = GL_STENCIL_ATTACHMENT;
982     if (pInternal_tex_fmt->m_comp_sizes[cTCDepth])
983         fbo_attachment_target = GL_DEPTH_STENCIL_ATTACHMENT;
984
985     GL_ENTRYPOINT(glGenTextures)(1, &dest_texture);
986     VOGL_CHECK_GL_ERROR;
987
988     GL_ENTRYPOINT(glBindTexture)(target, dest_texture);
989     VOGL_CHECK_GL_ERROR;
990
991     const GLenum dest_internal_fmt = GL_RGBA;
992     const GLboolean fixed_sample_locations = GL_TRUE;
993
994     if (target == GL_TEXTURE_2D_MULTISAMPLE)
995     {
996         GL_ENTRYPOINT(glTexImage2DMultisample)(target, samples, dest_internal_fmt, width, height, fixed_sample_locations);
997         VOGL_CHECK_GL_ERROR;
998     }
999     else
1000     {
1001         GL_ENTRYPOINT(glTexImage3DMultisample)(target, samples, dest_internal_fmt, width, height, depth, fixed_sample_locations);
1002         VOGL_CHECK_GL_ERROR;
1003     }
1004
1005     GL_ENTRYPOINT(glUseProgram)(m_const_color_program.get_handle());
1006     VOGL_CHECK_GL_ERROR;
1007
1008     for (int layer = 0; layer < depth; layer++)
1009     {
1010         GLuint temp_fbo = 0;
1011         GL_ENTRYPOINT(glGenFramebuffers)(1, &temp_fbo);
1012         VOGL_CHECK_GL_ERROR;
1013
1014         GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, temp_fbo);
1015         VOGL_CHECK_GL_ERROR;
1016
1017         if (target == GL_TEXTURE_2D_MULTISAMPLE)
1018         {
1019             GL_ENTRYPOINT(glFramebufferTexture2D)(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, dest_texture, mip_level);
1020             VOGL_CHECK_GL_ERROR;
1021
1022             GL_ENTRYPOINT(glFramebufferTexture2D)(GL_DRAW_FRAMEBUFFER, fbo_attachment_target, target, src_texture, mip_level);
1023             VOGL_CHECK_GL_ERROR;
1024         }
1025         else
1026         {
1027             GL_ENTRYPOINT(glFramebufferTextureLayer)(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dest_texture, mip_level, layer);
1028             VOGL_CHECK_GL_ERROR;
1029
1030             GL_ENTRYPOINT(glFramebufferTextureLayer)(GL_DRAW_FRAMEBUFFER, fbo_attachment_target, src_texture, mip_level, layer);
1031             VOGL_CHECK_GL_ERROR;
1032         }
1033
1034         GLenum draw_buf = GL_COLOR_ATTACHMENT0;
1035         GL_ENTRYPOINT(glDrawBuffers)(1, &draw_buf);
1036         VOGL_CHECK_GL_ERROR;
1037
1038         GLenum fbo_status = GL_ENTRYPOINT(glCheckFramebufferStatus)(GL_DRAW_FRAMEBUFFER);
1039         VOGL_CHECK_GL_ERROR;
1040
1041         bool status = false;
1042
1043         if (fbo_status == GL_FRAMEBUFFER_COMPLETE)
1044         {
1045             GL_ENTRYPOINT(glDisable)(GL_FRAMEBUFFER_SRGB);
1046             VOGL_CHECK_GL_ERROR;
1047
1048             GL_ENTRYPOINT(glViewport)(0, 0, width, height);
1049             VOGL_CHECK_GL_ERROR;
1050
1051             GL_ENTRYPOINT(glClearColor)(0, 0, 0, 0);
1052             VOGL_CHECK_GL_ERROR;
1053
1054             GL_ENTRYPOINT(glClear)(GL_COLOR_BUFFER_BIT);
1055             VOGL_CHECK_GL_ERROR;
1056
1057             GL_ENTRYPOINT(glColorMask)(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1058             VOGL_CHECK_GL_ERROR;
1059
1060             GL_ENTRYPOINT(glEnable)(GL_DEPTH_TEST);
1061             VOGL_CHECK_GL_ERROR;
1062
1063             GL_ENTRYPOINT(glDepthMask)(GL_FALSE);
1064             VOGL_CHECK_GL_ERROR;
1065
1066             GL_ENTRYPOINT(glDepthFunc)(GL_ALWAYS);
1067             VOGL_CHECK_GL_ERROR;
1068
1069             GL_ENTRYPOINT(glEnable)(GL_STENCIL_TEST);
1070             VOGL_CHECK_GL_ERROR;
1071
1072             GL_ENTRYPOINT(glStencilOp)(GL_KEEP, GL_KEEP, GL_REPLACE);
1073             VOGL_CHECK_GL_ERROR;
1074
1075             vogl_quad_vertex quad_tri_verts[3*2];
1076             memcpy(quad_tri_verts, g_quad_tri_verts, sizeof(quad_tri_verts));
1077
1078             for (uint i = 0; i < 6; i++)
1079             {
1080                 quad_tri_verts[i].m_uv0[0] *= width;
1081                 quad_tri_verts[i].m_uv0[1] *= height;
1082                 quad_tri_verts[i].m_uv0[2] = layer;
1083             }
1084
1085             GL_ENTRYPOINT(glBufferData)(GL_ARRAY_BUFFER, sizeof(quad_tri_verts), quad_tri_verts, GL_STATIC_DRAW);
1086             VOGL_CHECK_GL_ERROR;
1087
1088             for (uint stencil_val = 0; stencil_val <= 255; stencil_val++)
1089             {
1090                 m_const_color_program.set_uniform("color", vec4F(stencil_val * (1.0f / 255.0f)));
1091
1092                 GL_ENTRYPOINT(glStencilFunc)(GL_EQUAL, stencil_val, 0xFF);
1093                 VOGL_CHECK_GL_ERROR;
1094
1095                 GL_ENTRYPOINT(glDrawArrays)(GL_TRIANGLES, 0, 6);
1096                 VOGL_CHECK_GL_ERROR;
1097
1098             } // stencil_val
1099
1100             status = true;
1101         } // fbo_status
1102
1103         GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, 0);
1104         VOGL_CHECK_GL_ERROR;
1105
1106         GL_ENTRYPOINT(glDeleteFramebuffers)(1, &temp_fbo);
1107         VOGL_CHECK_GL_ERROR;
1108
1109         temp_fbo = 0;
1110
1111         if (!status)
1112             goto failure;
1113
1114     } // layer
1115
1116     GL_ENTRYPOINT(glBindTexture)(target, 0);
1117     VOGL_CHECK_GL_ERROR;
1118
1119     GL_ENTRYPOINT(glDisable)(GL_STENCIL_TEST);
1120     VOGL_CHECK_GL_ERROR;
1121     return true;
1122
1123 failure:
1124     GL_ENTRYPOINT(glBindTexture)(target, 0);
1125     VOGL_CHECK_GL_ERROR;
1126
1127     if (dest_texture)
1128     {
1129         GL_ENTRYPOINT(glDeleteTextures)(1, &dest_texture);
1130         VOGL_CHECK_GL_ERROR;
1131
1132         dest_texture = 0;
1133     }
1134
1135     GL_ENTRYPOINT(glDisable)(GL_STENCIL_TEST);
1136     VOGL_CHECK_GL_ERROR;
1137
1138     return false;
1139 }
1140
1141 // Copies MSAA color samples from an MSAA 2D to 2D_ARRAY texture to the stencil buffer of a MSAA 2D or 2D_ARRAY depth/stencil texture.
1142 // Source is NOT multisampled, dest is multisampled.
1143 bool vogl_msaa_texture_splitter::copy_color_sample_to_stencil(
1144         GLuint src_texture, uint dest_sample_index, GLenum dest_target, GLuint dest_texture)
1145 {
1146     bool exit_status = false;
1147
1148     if (!m_valid)
1149     {
1150         VOGL_ASSERT_ALWAYS;
1151         return false;
1152     }
1153
1154     if ((dest_target != GL_TEXTURE_2D_MULTISAMPLE) && (dest_target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY))
1155     {
1156         VOGL_ASSERT_ALWAYS;
1157         return false;
1158     }
1159
1160     const GLenum src_target = (dest_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
1161
1162     GL_ENTRYPOINT(glBindTexture)(src_target, src_texture);
1163     VOGL_CHECK_GL_ERROR;
1164
1165     GL_ENTRYPOINT(glBindTexture)(dest_target, dest_texture);
1166     VOGL_CHECK_GL_ERROR;
1167
1168     const int mip_level = 0;
1169
1170     GLenum internal_fmt = 0;
1171     GL_ENTRYPOINT(glGetTexLevelParameteriv)(dest_target, mip_level, GL_TEXTURE_INTERNAL_FORMAT, reinterpret_cast<GLint *>(&internal_fmt));
1172
1173     int width = 0, height = 0, depth = 0, samples = 0;
1174     GL_ENTRYPOINT(glGetTexLevelParameteriv)(dest_target, mip_level, GL_TEXTURE_WIDTH, &width);
1175     GL_ENTRYPOINT(glGetTexLevelParameteriv)(dest_target, mip_level, GL_TEXTURE_HEIGHT, &height);
1176     GL_ENTRYPOINT(glGetTexLevelParameteriv)(dest_target, mip_level, GL_TEXTURE_DEPTH, &depth);
1177     GL_ENTRYPOINT(glGetTexLevelParameteriv)(dest_target, mip_level, GL_TEXTURE_SAMPLES, &samples);
1178
1179     GL_ENTRYPOINT(glBindTexture)(dest_target, 0);
1180     VOGL_CHECK_GL_ERROR;
1181
1182     if ((vogl_check_gl_error()) || (width < 1) || (height < 1) || (depth < 1) || (samples < 1))
1183         return false;
1184
1185     const vogl_internal_tex_format *pInternal_tex_fmt = vogl_find_internal_texture_format(internal_fmt);
1186     if ((!pInternal_tex_fmt) || (pInternal_tex_fmt->m_optimum_get_image_fmt == GL_NONE) || (pInternal_tex_fmt->m_optimum_get_image_type == GL_NONE))
1187         return false;
1188
1189     if (!pInternal_tex_fmt->m_comp_sizes[cTCStencil])
1190         return false;
1191
1192     GLenum fbo_attachment_target = GL_STENCIL_ATTACHMENT;
1193     if (pInternal_tex_fmt->m_comp_sizes[cTCDepth])
1194         fbo_attachment_target = GL_DEPTH_STENCIL_ATTACHMENT;
1195
1196     vogl_simple_gl_program &program = (dest_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) ? m_write_stencil_array_program : m_write_stencil_program;
1197     GL_ENTRYPOINT(glUseProgram)(program.get_handle());
1198     VOGL_CHECK_GL_ERROR;
1199
1200     program.set_uniform("sample_mask", static_cast<int>(1 << dest_sample_index));
1201
1202     GL_ENTRYPOINT(glColorMask)(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
1203     VOGL_CHECK_GL_ERROR;
1204
1205     GL_ENTRYPOINT(glStencilMask)(255);
1206     VOGL_CHECK_GL_ERROR;
1207
1208     for (int layer = 0; layer < depth; layer++)
1209     {
1210         // Create FBO
1211         GLuint fbo_handle = 0;
1212         GL_ENTRYPOINT(glGenFramebuffers)(1, &fbo_handle);
1213         VOGL_CHECK_GL_ERROR;
1214
1215         GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, fbo_handle);
1216         VOGL_CHECK_GL_ERROR;
1217
1218         if (dest_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)
1219         {
1220             GL_ENTRYPOINT(glFramebufferTextureLayer)(GL_DRAW_FRAMEBUFFER, fbo_attachment_target, dest_texture, mip_level, layer);
1221             VOGL_CHECK_GL_ERROR;
1222         }
1223         else
1224         {
1225             GL_ENTRYPOINT(glFramebufferTexture2D)(GL_DRAW_FRAMEBUFFER, fbo_attachment_target, dest_target, dest_texture, mip_level);
1226             VOGL_CHECK_GL_ERROR;
1227         }
1228
1229         GLenum draw_bufs[1] = { GL_NONE };
1230         GL_ENTRYPOINT(glDrawBuffers)(1, draw_bufs);
1231         VOGL_CHECK_GL_ERROR;
1232
1233         GLenum fbo_status = GL_ENTRYPOINT(glCheckFramebufferStatus)(GL_DRAW_FRAMEBUFFER);
1234         VOGL_CHECK_GL_ERROR;
1235
1236         bool status = false;
1237
1238         if (fbo_status == GL_FRAMEBUFFER_COMPLETE)
1239         {
1240             // Render quad to FBO
1241             GL_ENTRYPOINT(glViewport)(0, 0, width, height);
1242             VOGL_CHECK_GL_ERROR;
1243
1244             if (!dest_sample_index)
1245             {
1246                 GL_ENTRYPOINT(glClearStencil)(0);
1247                 VOGL_CHECK_GL_ERROR;
1248
1249                 GL_ENTRYPOINT(glClear)(GL_STENCIL_BUFFER_BIT);
1250                 VOGL_CHECK_GL_ERROR;
1251             }
1252
1253             vogl_quad_vertex quad_tri_verts[3*2];
1254             memcpy(quad_tri_verts, g_quad_tri_verts, sizeof(quad_tri_verts));
1255
1256             for (uint i = 0; i < 6; i++)
1257             {
1258                 quad_tri_verts[i].m_uv0[0] *= width;
1259                 quad_tri_verts[i].m_uv0[1] *= height;
1260                 quad_tri_verts[i].m_uv0[2] = layer;
1261             }
1262
1263             GL_ENTRYPOINT(glBufferData)(GL_ARRAY_BUFFER, sizeof(quad_tri_verts), quad_tri_verts, GL_STATIC_DRAW);
1264             VOGL_CHECK_GL_ERROR;
1265
1266             GL_ENTRYPOINT(glEnable)(GL_DEPTH_TEST);
1267             VOGL_CHECK_GL_ERROR;
1268
1269             GL_ENTRYPOINT(glDepthMask)(GL_FALSE);
1270             VOGL_CHECK_GL_ERROR;
1271
1272             GL_ENTRYPOINT(glDepthFunc)(GL_ALWAYS);
1273             VOGL_CHECK_GL_ERROR;
1274
1275             GL_ENTRYPOINT(glEnable)(GL_STENCIL_TEST);
1276             VOGL_CHECK_GL_ERROR;
1277
1278             GL_ENTRYPOINT(glStencilOp)(GL_KEEP, GL_KEEP, GL_REPLACE);
1279             VOGL_CHECK_GL_ERROR;
1280
1281             for (uint stencil_val = 0; stencil_val <= 255; stencil_val++)
1282             {
1283                 program.set_uniform("stencil_comp_val", stencil_val / 255.0f);
1284
1285                 GL_ENTRYPOINT(glStencilFunc)(GL_ALWAYS, stencil_val, 0xFF);
1286                 VOGL_CHECK_GL_ERROR;
1287
1288                 GL_ENTRYPOINT(glDrawArrays)(GL_TRIANGLES, 0, 6);
1289                 VOGL_CHECK_GL_ERROR;
1290
1291             } // stencil_val
1292
1293             status = true;
1294         } // fbo_status
1295
1296         // Delete FBO
1297         GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, 0);
1298         VOGL_CHECK_GL_ERROR;
1299
1300         GL_ENTRYPOINT(glDeleteFramebuffers)(1, &fbo_handle);
1301         VOGL_CHECK_GL_ERROR;
1302
1303         GL_ENTRYPOINT(glDrawBuffer)(GL_FRONT_LEFT);
1304         VOGL_CHECK_GL_ERROR;
1305
1306         if (!status)
1307             goto failure;
1308
1309     } // layer
1310
1311     exit_status = true;
1312
1313 failure:
1314     GL_ENTRYPOINT(glBindTexture)(src_target, 0);
1315     VOGL_CHECK_GL_ERROR;
1316
1317     GL_ENTRYPOINT(glBindTexture)(dest_target, 0);
1318     VOGL_CHECK_GL_ERROR;
1319
1320     GL_ENTRYPOINT(glColorMask)(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1321     VOGL_CHECK_GL_ERROR;
1322
1323     GL_ENTRYPOINT(glDisable)(GL_STENCIL_TEST);
1324     VOGL_CHECK_GL_ERROR;
1325
1326     GL_ENTRYPOINT(glStencilMask)(0);
1327     VOGL_CHECK_GL_ERROR;
1328
1329     return exit_status;
1330 }
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372