]> git.cworth.org Git - vogl/blob - src/voglcommon/vogl_gl_utils.cpp
Initial vogl checkin
[vogl] / src / voglcommon / vogl_gl_utils.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_gl_utils.cpp
27 #include "vogl_common.h"
28 #include <stdarg.h>
29 #include "vogl_console.h"
30 #include "vogl_json.h"
31 #include "vogl_image.h"
32 #include "vogl_context_info.h"
33 #include "vogl_backtrace.h"
34
35 #define VOGL_DECLARE_PNAME_DEF_TABLE
36 #include "gl_pname_defs.inc"
37
38 #define VOGL_NAMESPACES_IMPLEMENTATION
39 #include "vogl_namespaces.h"
40 #undef VOGL_NAMESPACES_IMPLEMENTATION
41
42 //----------------------------------------------------------------------------------------------------------------------
43 // Globals
44 //----------------------------------------------------------------------------------------------------------------------
45 gl_enums g_gl_enums;
46 bool g_gl_get_error_enabled = true;
47
48 //----------------------------------------------------------------------------------------------------------------------
49 // client side array tables
50 //----------------------------------------------------------------------------------------------------------------------
51 const vogl_client_side_array_desc_t g_vogl_client_side_array_descs[] =
52     {
53 #define VOGL_CLIENT_SIDE_ARRAY_DESC(id, entrypoint, is_enabled, get_binding, get_pointer, get_size, get_stride, get_type) \
54     {                                                                                                                    \
55         entrypoint, is_enabled, get_binding, get_pointer, get_size, get_stride, get_type                                 \
56     }                                                                                                                    \
57     ,
58 #include "vogl_client_side_array_descs.inc"
59 #undef VOGL_CLIENT_SIDE_ARRAY_DESC
60     };
61
62 //----------------------------------------------------------------------------------------------------------------------
63 // vogl_get_gl_integer
64 //----------------------------------------------------------------------------------------------------------------------
65 GLint vogl_get_gl_integer(GLenum pname)
66 {
67     VOGL_FUNC_TRACER
68
69     VOGL_ASSERT(g_gl_enums.get_pname_count(pname) <= 4);
70
71     GLint values[4] = { 0, 0, 0, 0 };
72     GL_ENTRYPOINT(glGetIntegerv)(pname, values);
73     return values[0];
74 }
75
76 //----------------------------------------------------------------------------------------------------------------------
77 // vogl_get_gl_vec4I
78 //----------------------------------------------------------------------------------------------------------------------
79 vec4I vogl_get_gl_vec4I(GLenum pname)
80 {
81     VOGL_FUNC_TRACER
82
83     VOGL_ASSERT(g_gl_enums.get_pname_count(pname) <= 4);
84
85     vec4I result(0);
86     GL_ENTRYPOINT(glGetIntegerv)(pname, &result[0]);
87     return result;
88 }
89
90 //----------------------------------------------------------------------------------------------------------------------
91 // vogl_get_gl_integer_indexed
92 //----------------------------------------------------------------------------------------------------------------------
93 GLint vogl_get_gl_integer_indexed(GLenum pname, uint index)
94 {
95     VOGL_FUNC_TRACER
96
97     VOGL_ASSERT(g_gl_enums.get_pname_count(pname) <= 4);
98
99     GLint values[4] = { 0, 0, 0, 0 };
100     GL_ENTRYPOINT(glGetIntegeri_v)(pname, index, values);
101     return values[0];
102 }
103
104 //----------------------------------------------------------------------------------------------------------------------
105 // vogl_get_gl_integer64
106 //----------------------------------------------------------------------------------------------------------------------
107 GLint64 vogl_get_gl_integer64(GLenum pname)
108 {
109     VOGL_FUNC_TRACER
110
111     VOGL_ASSERT(g_gl_enums.get_pname_count(pname) <= 4);
112
113     GLint64 values[4] = { 0, 0, 0, 0 };
114     GL_ENTRYPOINT(glGetInteger64v)(pname, values);
115     return values[0];
116 }
117
118 //----------------------------------------------------------------------------------------------------------------------
119 // vogl_get_gl_integer64_indexed
120 //----------------------------------------------------------------------------------------------------------------------
121 GLint64 vogl_get_gl_integer64_indexed(GLenum pname, uint index)
122 {
123     VOGL_FUNC_TRACER
124
125     VOGL_ASSERT(g_gl_enums.get_pname_count(pname) <= 4);
126
127     GLint64 values[4] = { 0, 0, 0, 0 };
128     GL_ENTRYPOINT(glGetInteger64i_v)(pname, index, values);
129     return values[0];
130 }
131
132 //----------------------------------------------------------------------------------------------------------------------
133 // vogl_get_gl_boolean
134 //----------------------------------------------------------------------------------------------------------------------
135 GLboolean vogl_get_gl_boolean(GLenum pname)
136 {
137     VOGL_FUNC_TRACER
138
139     VOGL_ASSERT(g_gl_enums.get_pname_count(pname) <= 4);
140
141     GLboolean values[4] = { 0, 0, 0, 0 };
142     GL_ENTRYPOINT(glGetBooleanv)(pname, values);
143     return values[0];
144 }
145
146 //----------------------------------------------------------------------------------------------------------------------
147 // vogl_get_gl_boolean_indexed
148 //----------------------------------------------------------------------------------------------------------------------
149 GLboolean vogl_get_gl_boolean_indexed(GLenum pname, uint index)
150 {
151     VOGL_FUNC_TRACER
152
153     VOGL_ASSERT(g_gl_enums.get_pname_count(pname) <= 4);
154
155     GLboolean values[4] = { 0, 0, 0, 0 };
156     GL_ENTRYPOINT(glGetBooleani_v)(pname, index, values);
157     return values[0];
158 }
159
160 //----------------------------------------------------------------------------------------------------------------------
161 // vogl_get_gl_float
162 //----------------------------------------------------------------------------------------------------------------------
163 GLfloat vogl_get_gl_float(GLenum pname)
164 {
165     VOGL_FUNC_TRACER
166
167     VOGL_ASSERT(g_gl_enums.get_pname_count(pname) <= 4);
168
169     GLfloat values[4] = { 0, 0, 0, 0 };
170     GL_ENTRYPOINT(glGetFloatv)(pname, values);
171     return values[0];
172 }
173
174 //----------------------------------------------------------------------------------------------------------------------
175 // vogl_get_gl_vec4F
176 //----------------------------------------------------------------------------------------------------------------------
177 vec4F vogl_get_gl_vec4F(GLenum pname)
178 {
179     VOGL_FUNC_TRACER
180
181     VOGL_ASSERT(g_gl_enums.get_pname_count(pname) <= 4);
182
183     vec4F values(0);
184     GL_ENTRYPOINT(glGetFloatv)(pname, &values[0]);
185     return values;
186 }
187
188 //----------------------------------------------------------------------------------------------------------------------
189 // vogl_get_gl_matrix44F
190 //----------------------------------------------------------------------------------------------------------------------
191 matrix44F vogl_get_gl_matrix44F(GLenum pname)
192 {
193     VOGL_FUNC_TRACER
194
195     VOGL_ASSERT(g_gl_enums.get_pname_count(pname) <= 16);
196
197     matrix44F values(cClear);
198     GL_ENTRYPOINT(glGetFloatv)(pname, &values[0][0]);
199     return values;
200 }
201
202 //----------------------------------------------------------------------------------------------------------------------
203 // vogl_get_gl_double
204 //----------------------------------------------------------------------------------------------------------------------
205 GLdouble vogl_get_gl_double(GLenum pname)
206 {
207     VOGL_FUNC_TRACER
208
209     VOGL_ASSERT(g_gl_enums.get_pname_count(pname) <= 4);
210
211     GLdouble values[4] = { 0, 0, 0, 0 };
212     GL_ENTRYPOINT(glGetDoublev)(pname, values);
213     return values[0];
214 }
215
216 //----------------------------------------------------------------------------------------------------------------------
217 // vogl_get_gl_vec4D
218 //----------------------------------------------------------------------------------------------------------------------
219 vec4D vogl_get_gl_vec4D(GLenum pname)
220 {
221     VOGL_FUNC_TRACER
222
223     VOGL_ASSERT(g_gl_enums.get_pname_count(pname) <= 4);
224
225     vec4D values(0);
226     GL_ENTRYPOINT(glGetDoublev)(pname, &values[0]);
227     return values;
228 }
229
230 //----------------------------------------------------------------------------------------------------------------------
231 // vogl_get_gl_matrix44D
232 //----------------------------------------------------------------------------------------------------------------------
233 matrix44D vogl_get_gl_matrix44D(GLenum pname)
234 {
235     VOGL_FUNC_TRACER
236
237     VOGL_ASSERT(g_gl_enums.get_pname_count(pname) <= 16);
238
239     matrix44D values(cClear);
240     GL_ENTRYPOINT(glGetDoublev)(pname, &values[0][0]);
241     return values;
242 }
243
244 //----------------------------------------------------------------------------------------------------------------------
245 // vogl_get_gl_type_size (derived from apitrace)
246 //----------------------------------------------------------------------------------------------------------------------
247 uint32_t vogl_get_gl_type_size(uint32_t ogl_type)
248 {
249     VOGL_FUNC_TRACER
250
251     switch (ogl_type)
252     {
253         case GL_BOOL:
254         case GL_UNSIGNED_BYTE:
255         case GL_BYTE:
256         case GL_UNSIGNED_BYTE_3_3_2:
257         case GL_UNSIGNED_BYTE_2_3_3_REV:
258             return 1;
259         case GL_HALF_FLOAT:
260         case GL_UNSIGNED_SHORT:
261         case GL_SHORT:
262         case GL_UNSIGNED_SHORT_5_6_5:
263         case GL_UNSIGNED_SHORT_5_6_5_REV:
264         case GL_UNSIGNED_SHORT_4_4_4_4:
265         case GL_UNSIGNED_SHORT_4_4_4_4_REV:
266         case GL_UNSIGNED_SHORT_5_5_5_1:
267         case GL_UNSIGNED_SHORT_1_5_5_5_REV:
268         case GL_2_BYTES:
269             return 2;
270         case GL_3_BYTES:
271             return 3;
272         case GL_FLOAT:
273         case GL_UNSIGNED_INT:
274         case GL_INT:
275         case GL_FIXED:
276         case GL_UNSIGNED_INT_8_8_8_8:
277         case GL_UNSIGNED_INT_8_8_8_8_REV:
278         case GL_UNSIGNED_INT_10_10_10_2:
279         case GL_UNSIGNED_INT_2_10_10_10_REV:
280         case GL_UNSIGNED_INT_24_8:
281         case GL_UNSIGNED_INT_10F_11F_11F_REV:
282         case GL_UNSIGNED_INT_5_9_9_9_REV:
283         case GL_INT_2_10_10_10_REV:
284         case GL_4_BYTES:
285             return 4;
286         case GL_DOUBLE:
287             return 8;
288         default:
289             vogl_warning_printf("%s: unknown GL type: 0x%04X\n", VOGL_FUNCTION_NAME, ogl_type);
290             break;
291     }
292     return 0;
293 }
294
295 //----------------------------------------------------------------------------------------------------------------------
296 // vogl_get_image_format_channels (derived from apitrace)
297 //----------------------------------------------------------------------------------------------------------------------
298 uint vogl_get_image_format_channels(GLenum format)
299 {
300     VOGL_FUNC_TRACER
301
302     switch (format)
303     {
304         case GL_COLOR_INDEX:
305         case GL_RED:
306         case GL_RED_INTEGER:
307         case GL_GREEN:
308         case GL_GREEN_INTEGER:
309         case GL_BLUE:
310         case GL_BLUE_INTEGER:
311         case GL_ALPHA:
312         case GL_ALPHA_INTEGER:
313         case GL_INTENSITY:
314         case GL_LUMINANCE:
315         case GL_LUMINANCE_INTEGER_EXT:
316         case GL_DEPTH_COMPONENT:
317         case GL_STENCIL_INDEX:
318             return 1;
319         case GL_DEPTH_STENCIL:
320         case GL_LUMINANCE_ALPHA:
321         case GL_LUMINANCE_ALPHA_INTEGER_EXT:
322         case GL_RG:
323         case GL_RG_INTEGER:
324         case GL_422_EXT:             // (luminance, chrominance)
325         case GL_422_REV_EXT:         // (luminance, chrominance)
326         case GL_422_AVERAGE_EXT:     // (luminance, chrominance)
327         case GL_422_REV_AVERAGE_EXT: // (luminance, chrominance)
328         case GL_HILO_NV:             // (hi, lo)
329         case GL_DSDT_NV:             // (ds, dt)
330         case GL_YCBCR_422_APPLE:     // (luminance, chroma)
331         case GL_RGB_422_APPLE:       // (G, B) on even pixels, (G, R) on odd pixels
332         case GL_YCRCB_422_SGIX:      // (Y, [Cb,Cr])
333             return 2;
334         case GL_RGB:
335         case GL_RGB_INTEGER:
336         case GL_BGR:
337         case GL_BGR_INTEGER:
338         case GL_DSDT_MAG_NV:    // (ds, dt, magnitude)
339         case GL_YCRCB_444_SGIX: // (Cb, Y, Cr)
340             return 3;
341         case GL_RGBA:
342         case GL_RGBA_INTEGER:
343         case GL_BGRA:
344         case GL_BGRA_INTEGER:
345         case GL_ABGR_EXT:
346         case GL_CMYK_EXT:
347         case GL_DSDT_MAG_VIB_NV: // (ds, dt, magnitude, vibrance)
348             return 4;
349         case GL_CMYKA_EXT:
350             return 5;
351         case GL_FORMAT_SUBSAMPLE_24_24_OML:
352         case GL_FORMAT_SUBSAMPLE_244_244_OML:
353             // requires UNSIGNED_INT_10_10_10_2, so this value will be ignored
354             return 0;
355         default:
356             vogl_warning_printf("%s: unknown format 0x%04X\n", VOGL_FUNCTION_NAME, format);
357             break;
358     }
359     return 0;
360 }
361
362 //----------------------------------------------------------------------------------------------------------------------
363 // vogl_get_image_format_info (derived from apitrace)
364 //----------------------------------------------------------------------------------------------------------------------
365 void vogl_get_image_format_info(GLenum format, GLenum type, uint &num_channels, uint &bits_per_element, uint &bits_per_pixel)
366 {
367     VOGL_FUNC_TRACER
368
369     num_channels = vogl_get_image_format_channels(format);
370
371     switch (type)
372     {
373         case GL_BITMAP:
374             bits_per_pixel = bits_per_element = 1;
375             break;
376         case GL_BYTE:
377         case GL_UNSIGNED_BYTE:
378             bits_per_element = 8;
379             bits_per_pixel = bits_per_element * num_channels;
380             break;
381         case GL_SHORT:
382         case GL_UNSIGNED_SHORT:
383         case GL_HALF_FLOAT:
384             bits_per_element = 16;
385             bits_per_pixel = bits_per_element * num_channels;
386             break;
387         case GL_INT:
388         case GL_UNSIGNED_INT:
389         case GL_FLOAT:
390             bits_per_element = 32;
391             bits_per_pixel = bits_per_element * num_channels;
392             break;
393         case GL_UNSIGNED_BYTE_3_3_2:
394         case GL_UNSIGNED_BYTE_2_3_3_REV:
395             bits_per_pixel = bits_per_element = 8;
396             break;
397         case GL_UNSIGNED_SHORT_4_4_4_4:
398         case GL_UNSIGNED_SHORT_4_4_4_4_REV:
399         case GL_UNSIGNED_SHORT_5_5_5_1:
400         case GL_UNSIGNED_SHORT_1_5_5_5_REV:
401         case GL_UNSIGNED_SHORT_5_6_5:
402         case GL_UNSIGNED_SHORT_5_6_5_REV:
403         case GL_UNSIGNED_SHORT_8_8_MESA:
404         case GL_UNSIGNED_SHORT_8_8_REV_MESA:
405             bits_per_pixel = bits_per_element = 16;
406             break;
407         case GL_UNSIGNED_INT_8_8_8_8:
408         case GL_UNSIGNED_INT_8_8_8_8_REV:
409         case GL_UNSIGNED_INT_10_10_10_2:
410         case GL_UNSIGNED_INT_2_10_10_10_REV:
411         case GL_UNSIGNED_INT_24_8:
412         case GL_UNSIGNED_INT_10F_11F_11F_REV:
413         case GL_UNSIGNED_INT_5_9_9_9_REV:
414         case GL_UNSIGNED_INT_S8_S8_8_8_NV:
415         case GL_UNSIGNED_INT_8_8_S8_S8_REV_NV:
416             bits_per_pixel = bits_per_element = 32;
417             break;
418         case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
419             bits_per_pixel = bits_per_element = 64;
420             break;
421         default:
422             vogl_warning_printf("%s: unknown type 0x%04X\n", VOGL_FUNCTION_NAME, type);
423             bits_per_pixel = bits_per_element = 0;
424             break;
425     }
426 }
427
428 //----------------------------------------------------------------------------------------------------------------------
429 // vogl_get_image_format_size_in_bytes
430 //----------------------------------------------------------------------------------------------------------------------
431 uint vogl_get_image_format_size_in_bytes(GLenum format, GLenum type)
432 {
433     VOGL_FUNC_TRACER
434
435     uint num_channels, bits_per_element, bits_per_pixel;
436     vogl_get_image_format_info(format, type, num_channels, bits_per_element, bits_per_pixel);
437     return (bits_per_pixel + 7) >> 3;
438 }
439
440 //----------------------------------------------------------------------------------------------------------------------
441 // vogl_has_active_context
442 //----------------------------------------------------------------------------------------------------------------------
443 bool vogl_has_active_context()
444 {
445     VOGL_FUNC_TRACER
446
447     if (!GL_ENTRYPOINT(glXGetCurrentContext))
448         return false;
449
450     if (!GL_ENTRYPOINT(glXGetCurrentContext)())
451         return false;
452
453     return true;
454 }
455
456 //----------------------------------------------------------------------------------------------------------------------
457 // vogl_get_image_size (derived from apitrace)
458 //----------------------------------------------------------------------------------------------------------------------
459 size_t vogl_get_image_size(GLenum format, GLenum type, GLsizei width, GLsizei height, GLsizei depth)
460 {
461     VOGL_FUNC_TRACER
462
463     if (!vogl_has_active_context())
464     {
465         vogl_error_printf("%s: vogl_get_image_size() called without an active context!\n", VOGL_FUNCTION_NAME);
466         return 0;
467     }
468
469     uint num_channels;
470     uint bits_per_element;
471     uint bits_per_pixel;
472     vogl_get_image_format_info(format, type, num_channels, bits_per_element, bits_per_pixel);
473
474     GLint alignment = vogl_get_gl_integer(GL_UNPACK_ALIGNMENT);
475     GLint row_length = vogl_get_gl_integer(GL_UNPACK_ROW_LENGTH);
476     GLint image_height = vogl_get_gl_integer(GL_UNPACK_IMAGE_HEIGHT);
477     GLint skip_rows = vogl_get_gl_integer(GL_UNPACK_SKIP_ROWS);
478     GLint skip_pixels = vogl_get_gl_integer(GL_UNPACK_SKIP_PIXELS);
479     GLint skip_images = vogl_get_gl_integer(GL_UNPACK_SKIP_IMAGES);
480
481     if (row_length <= 0)
482     {
483         row_length = width;
484     }
485
486     size_t row_stride = (row_length * bits_per_pixel + 7) / 8;
487
488     if (((bits_per_element == 1 * 8) ||
489          (bits_per_element == 2 * 8) ||
490          (bits_per_element == 4 * 8) ||
491          (bits_per_element == 8 * 8)) &&
492         ((GLint)bits_per_element < alignment * 8))
493     {
494         row_stride = math::align_up_value(row_stride, alignment);
495     }
496
497     if (image_height <= 0)
498     {
499         image_height = height;
500     }
501
502     // GL_UNPACK_IMAGE_HEIGHT and GL_UNPACK_SKIP_IMAGES should probably not be considered for pixel rectangles
503
504     size_t image_stride = image_height * row_stride;
505
506     size_t size = depth * image_stride;
507
508     size += (skip_pixels * bits_per_pixel + 7) / 8;
509     size += skip_rows * row_stride;
510     size += skip_images * image_stride;
511
512     return size;
513 }
514
515 //----------------------------------------------------------------------------------------------------------------------
516 // vogl_get_tex_target_image_size
517 //----------------------------------------------------------------------------------------------------------------------
518 size_t vogl_get_tex_target_image_size(GLenum target, GLint level, GLenum format, GLenum type)
519 {
520     VOGL_FUNC_TRACER
521
522     GLint width = 0, height = 0, depth = 0;
523
524     if (!vogl_has_active_context())
525     {
526         vogl_error_printf("%s: vogl_get_tex_target_image_size() called without an active context!\n", VOGL_FUNCTION_NAME);
527         return 0;
528     }
529
530     if (!GL_ENTRYPOINT(glGetTexLevelParameteriv))
531     {
532         vogl_error_printf("%s: vogl_get_tex_target_image_size() called but the glGetTexLevelParameteriv function ptr is NULL!\n", VOGL_FUNCTION_NAME);
533         return 0;
534     }
535
536     if (g_vogl_actual_gl_entrypoints.m_glGetTexLevelParameteriv)
537     {
538         GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, level, GL_TEXTURE_WIDTH, &width);
539         GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, level, GL_TEXTURE_HEIGHT, &height);
540         GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, level, GL_TEXTURE_DEPTH, &depth);
541     }
542
543     if ((!width) || (!height) || (!depth))
544         return 0;
545
546     return vogl_get_image_size(format, type, width, height, depth);
547 }
548
549 //----------------------------------------------------------------------------------------------------------------------
550 // vogl_determine_glMap1_size (originally from apitrace)
551 //----------------------------------------------------------------------------------------------------------------------
552 size_t vogl_determine_glMap1_size(GLenum target, GLint stride, GLint order)
553 {
554     VOGL_FUNC_TRACER
555
556     if (order < 1)
557         return 0;
558
559     GLint channels;
560     switch (target)
561     {
562         case GL_MAP1_INDEX:
563         case GL_MAP1_TEXTURE_COORD_1:
564             channels = 1;
565             break;
566         case GL_MAP1_TEXTURE_COORD_2:
567             channels = 2;
568             break;
569         case GL_MAP1_NORMAL:
570         case GL_MAP1_TEXTURE_COORD_3:
571         case GL_MAP1_VERTEX_3:
572             channels = 3;
573             break;
574         case GL_MAP1_COLOR_4:
575         case GL_MAP1_TEXTURE_COORD_4:
576         case GL_MAP1_VERTEX_4:
577             channels = 4;
578             break;
579         default:
580             vogl_warning_printf("%s: unknown GLenum 0x%04X\n", VOGL_FUNCTION_NAME, target);
581             return 0;
582     }
583
584     if (stride < channels)
585         return 0;
586
587     return channels + stride * (order - 1);
588 }
589
590 //----------------------------------------------------------------------------------------------------------------------
591 // vogl_determine_glMap2_size (originally from apitrace)
592 //----------------------------------------------------------------------------------------------------------------------
593 size_t vogl_determine_glMap2_size(GLenum target, GLint ustride, GLint uorder, GLint vstride, GLint vorder)
594 {
595     VOGL_FUNC_TRACER
596
597     if (uorder < 1 || vorder < 1)
598         return 0;
599
600     GLint channels;
601     switch (target)
602     {
603         case GL_MAP2_INDEX:
604         case GL_MAP2_TEXTURE_COORD_1:
605             channels = 1;
606             break;
607         case GL_MAP2_TEXTURE_COORD_2:
608             channels = 2;
609             break;
610         case GL_MAP2_NORMAL:
611         case GL_MAP2_TEXTURE_COORD_3:
612         case GL_MAP2_VERTEX_3:
613             channels = 3;
614             break;
615         case GL_MAP2_COLOR_4:
616         case GL_MAP2_TEXTURE_COORD_4:
617         case GL_MAP2_VERTEX_4:
618             channels = 4;
619             break;
620         default:
621             vogl_warning_printf("%s: unknown GLenum 0x%04X\n", VOGL_FUNCTION_NAME, target);
622             return 0;
623     }
624
625     if (ustride < channels || vstride < channels)
626         return 0;
627
628     return channels +
629            ustride * (uorder - 1) +
630            vstride * (vorder - 1);
631 }
632
633 //----------------------------------------------------------------------------------------------------------------------
634 // vogl_enum_desc::init_sort_priority
635 //----------------------------------------------------------------------------------------------------------------------
636 void vogl_enum_desc::init_sort_priority()
637 {
638     VOGL_FUNC_TRACER
639
640     m_sort_priority = cSCNone;
641
642     if (m_macro_name.ends_with("_EXT"))
643         m_sort_priority = cSCEXT;
644     else if (m_macro_name.ends_with("_ARB"))
645         m_sort_priority = cSCARB;
646     else if (m_macro_name.ends_with("_OES"))
647         m_sort_priority = cSCOES;
648     else
649     {
650         static const char *s_vendor_suffixes[] = { "_NV", "_AMD", "_INTEL", "_QCOM", "_ATI", "_SGIS", "_SGIX", "_ANGLE", "_APPLE", "_MESA", "_IBM" };
651         for (uint i = 0; i < VOGL_ARRAY_SIZE(s_vendor_suffixes); i++)
652         {
653             if (m_macro_name.ends_with(s_vendor_suffixes[i]))
654             {
655                 m_sort_priority = cSCVendor;
656                 break;
657             }
658         }
659     }
660 }
661
662 //----------------------------------------------------------------------------------------------------------------------
663 // vogl_enum_desc::operator <
664 //----------------------------------------------------------------------------------------------------------------------
665 bool vogl_enum_desc::operator<(const vogl_enum_desc &rhs) const
666 {
667     VOGL_FUNC_TRACER
668
669     if (m_sort_priority < rhs.m_sort_priority)
670         return true;
671     else if (m_sort_priority == rhs.m_sort_priority)
672     {
673         int comp_result = m_prefix.compare_using_length(rhs.m_prefix, true);
674         if (comp_result < 0)
675             return true;
676         else if (comp_result == 0)
677             return m_macro_name.compare_using_length(rhs.m_macro_name, true) < 0;
678     }
679     return false;
680 }
681
682 //----------------------------------------------------------------------------------------------------------------------
683 // gl_enums::gl_enums
684 //----------------------------------------------------------------------------------------------------------------------
685 gl_enums::gl_enums()
686 {
687     VOGL_FUNC_TRACER
688
689     memset(m_gl_enum_to_pname_def_index, 0xFF, sizeof(m_gl_enum_to_pname_def_index));
690
691     for (uint i = 0; i < GL_PNAME_DEFS_ARRAY_SIZE; i++)
692     {
693         if (g_gl_pname_defs[i].m_gl_enum < 0x10000)
694         {
695             if (m_gl_enum_to_pname_def_index[g_gl_pname_defs[i].m_gl_enum] != 0xFFFF)
696             {
697                 vogl_debug_printf("%s: duplicate GL enum in g_gl_pname_defs table: 0x%04X %s\n", VOGL_METHOD_NAME, i, g_gl_pname_defs[i].m_pName);
698                 continue;
699             }
700
701             m_gl_enum_to_pname_def_index[g_gl_pname_defs[i].m_gl_enum] = i;
702
703             m_enum_name_hash_map.insert(g_gl_pname_defs[i].m_pName, g_gl_pname_defs[i].m_gl_enum);
704         }
705     }
706
707     init_enum_descs();
708     init_image_formats();
709 }
710
711 //----------------------------------------------------------------------------------------------------------------------
712 // gl_enums::add_enum
713 //----------------------------------------------------------------------------------------------------------------------
714 void gl_enums::add_enum(const char *pPrefix, const char *pSpec_type, const char *pGL_type, const char *pName, uint64_t value)
715 {
716     VOGL_FUNC_TRACER
717
718     {
719         gl_enum_value_to_enum_desc_hash_map::insert_result ins_result(m_enum_value_hash_map.insert(value, vogl_enum_desc_vec()));
720         vogl_enum_desc_vec &vec = ins_result.first->second;
721         vogl_enum_desc *pDesc = vec.enlarge(1);
722         pDesc->m_value = value;
723         pDesc->m_prefix = pPrefix;
724         pDesc->m_spec_type = pSpec_type;
725         pDesc->m_gl_type = pGL_type;
726         pDesc->m_macro_name = pName;
727         pDesc->init_sort_priority();
728     }
729
730     {
731         gl_spec_type_and_value_to_enum_desc_hash_map_t::insert_result ins_result(m_spec_type_and_enum_value_hash_map.insert(vogl_spec_type_and_value_enum_key(pSpec_type, value), vogl_enum_desc_vec()));
732         vogl_enum_desc_vec &vec = ins_result.first->second;
733
734         vogl_enum_desc *pDesc = vec.enlarge(1);
735         pDesc->m_value = value;
736         pDesc->m_prefix = pPrefix;
737         pDesc->m_spec_type = pSpec_type;
738         pDesc->m_gl_type = pGL_type;
739         pDesc->m_macro_name = pName;
740         pDesc->init_sort_priority();
741     }
742
743     {
744         gl_enum_name_hash_map::insert_result res(m_enum_name_hash_map.insert(pName, value));
745
746         // Check for duplicate definitions with different values (compare apitrace's pname table vs. the spec)
747         uint64_t value_in_map = res.first->second;
748         VOGL_ASSERT(value_in_map == value);
749         VOGL_NOTE_UNUSED(value_in_map);
750     }
751 }
752
753 //----------------------------------------------------------------------------------------------------------------------
754 // gl_enums::init_enum_descs
755 //----------------------------------------------------------------------------------------------------------------------
756 void gl_enums::init_enum_descs()
757 {
758     VOGL_FUNC_TRACER
759
760 #define DEFINE_GL_ENUM_CATEGORY_BEGIN(spectype)
761 #define DEFINE_GL_DEFINE_MEMBER(prefix, spec_type, enum_name)
762 #define DEFINE_GL_ENUM_MEMBER(prefix, spec_type, gl_type, enum_name, value) add_enum(#prefix, #spec_type, gl_type, enum_name, value);
763 #define DEFINE_GL_ENUM_CATEGORY_END(x)
764
765 #include "gl_enum_desc.inc"
766 #include "glx_enum_desc.inc"
767
768 #undef DEFINE_GL_ENUM_CATEGORY_BEGIN
769 #undef DEFINE_GL_DEFINE_MEMBER
770 #undef DEFINE_GL_ENUM_MEMBER
771 #undef DEFINE_GL_ENUM_CATEGORY_END
772
773     for (gl_enum_value_to_enum_desc_hash_map::iterator it = m_enum_value_hash_map.begin(); it != m_enum_value_hash_map.end(); ++it)
774     {
775         vogl_enum_desc_vec &vec = it->second;
776         vec.sort();
777     }
778
779     for (gl_spec_type_and_value_to_enum_desc_hash_map_t::iterator it = m_spec_type_and_enum_value_hash_map.begin(); it != m_spec_type_and_enum_value_hash_map.end(); ++it)
780     {
781         vogl_enum_desc_vec &vec = it->second;
782         vec.sort();
783     }
784 }
785
786 //----------------------------------------------------------------------------------------------------------------------
787 // gl_enums::get_name
788 //----------------------------------------------------------------------------------------------------------------------
789 const char *gl_enums::find_name(uint64_t gl_enum, const char *pPreferred_prefix) const
790 {
791     VOGL_FUNC_TRACER
792
793     gl_enum_value_to_enum_desc_hash_map::const_iterator it(m_enum_value_hash_map.find(gl_enum));
794     if (it != m_enum_value_hash_map.end())
795     {
796         const vogl_enum_desc_vec &desc_vec = it->second;
797
798         if (pPreferred_prefix)
799         {
800             for (uint i = 0; i < desc_vec.size(); i++)
801                 if (!desc_vec[i].m_prefix.compare(pPreferred_prefix, false)) // purposely not case sensitive
802                     return desc_vec[i].m_macro_name.get_ptr();
803         }
804
805         return desc_vec[0].m_macro_name.get_ptr();
806     }
807
808     // Try falling back to the pname table - some of the extension enums are not in the .spec files but are in apitrace's pname table.
809     int pname_index = find_pname_def_index(gl_enum);
810     if ((pname_index >= 0) && (g_gl_pname_defs[pname_index].m_pName))
811         return g_gl_pname_defs[pname_index].m_pName;
812
813     if (g_command_line_params.get_value_as_bool("debug"))
814     {
815         vogl_debug_printf("%s: Failed finding GL enum 0x%08" PRIX64 ", API prefix \"%s\"\n", VOGL_METHOD_NAME, gl_enum, pPreferred_prefix ? pPreferred_prefix : "");
816     }
817
818     return NULL;
819 }
820
821 //----------------------------------------------------------------------------------------------------------------------
822 // gl_enums::find_gl_image_format_name
823 //----------------------------------------------------------------------------------------------------------------------
824 const char *gl_enums::find_gl_image_format_name(GLenum gl_enum) const
825 {
826     VOGL_FUNC_TRACER
827
828     const char *const *ppName = m_image_formats.find_value(gl_enum);
829     if (ppName)
830         return *ppName;
831     return find_gl_name(gl_enum);
832 }
833
834 //----------------------------------------------------------------------------------------------------------------------
835 // gl_enums::find_name
836 //----------------------------------------------------------------------------------------------------------------------
837 const char *gl_enums::find_name(const char *pSpec_type, uint64_t gl_enum, const char *pPreferred_prefix) const
838 {
839     VOGL_FUNC_TRACER
840
841     // The spec type search is fuzzy but it does guide the search to saner enums in many common cases.
842     // The spec types in the enum table don't always match up with the spec types in the GL API param desc's.
843     // This isn't critical but it would be nice to try resolving this crap.
844     if (pSpec_type)
845     {
846         gl_spec_type_and_value_to_enum_desc_hash_map_t::const_iterator it(m_spec_type_and_enum_value_hash_map.find(vogl_spec_type_and_value_enum_key(pSpec_type, gl_enum)));
847         if (it != m_spec_type_and_enum_value_hash_map.end())
848         {
849             const vogl_enum_desc_vec &desc_vec = it->second;
850
851             if (pPreferred_prefix)
852             {
853                 for (uint i = 0; i < desc_vec.size(); i++)
854                     if (!desc_vec[i].m_prefix.compare(pPreferred_prefix, false)) // purposely not case sensitive
855                         return desc_vec[i].m_macro_name.get_ptr();
856             }
857
858             return desc_vec[0].m_macro_name.get_ptr();
859         }
860         else
861         {
862             if (g_command_line_params.get_value_as_bool("debug"))
863             {
864                 vogl_debug_printf("%s: Failed finding GL enum with spec type %s, enum 0x%08" PRIX64 ", API prefix \"%s\", falling back to non-spec type search\n",
865                                  VOGL_METHOD_NAME, pSpec_type, gl_enum, pPreferred_prefix ? pPreferred_prefix : "");
866             }
867         }
868     }
869
870     return find_name(gl_enum, pPreferred_prefix);
871 }
872
873 //----------------------------------------------------------------------------------------------------------------------
874 // gl_enums::find_enum
875 //----------------------------------------------------------------------------------------------------------------------
876 const char *gl_enums::find_name(uint64_t gl_enum, gl_entrypoint_id_t entrypoint_id, int param_index) const
877 {
878     VOGL_ASSERT(entrypoint_id < VOGL_NUM_ENTRYPOINTS);
879
880     const gl_entrypoint_desc_t &entrypoint_desc = g_vogl_entrypoint_descs[entrypoint_id];
881
882     const char *pSpec_type = NULL;
883     if (param_index < 0)
884     {
885         pSpec_type = entrypoint_desc.m_pReturn_spec_type;
886     }
887     else
888     {
889         VOGL_ASSERT(param_index < static_cast<int>(entrypoint_desc.m_num_params));
890
891         pSpec_type = g_vogl_entrypoint_param_descs[entrypoint_id][param_index].m_pSpec_type;
892     }
893
894     return find_name(pSpec_type, gl_enum, entrypoint_desc.m_pAPI_prefix);
895 }
896
897 //----------------------------------------------------------------------------------------------------------------------
898 // gl_enums::find_enum
899 //----------------------------------------------------------------------------------------------------------------------
900 uint64_t gl_enums::find_enum(const dynamic_string &str) const
901 {
902     VOGL_FUNC_TRACER
903
904     gl_enum_name_hash_map::const_iterator it(m_enum_name_hash_map.find(str));
905     return (it == m_enum_name_hash_map.end()) ? static_cast<uint64_t>(cUnknownEnum) : it->second;
906 }
907
908 //----------------------------------------------------------------------------------------------------------------------
909 // gl_enums::get_pname_count
910 //----------------------------------------------------------------------------------------------------------------------
911 int gl_enums::get_pname_count(uint64_t gl_enum) const
912 {
913     VOGL_FUNC_TRACER
914
915     if (GL_ENTRYPOINT(glGetIntegerv))
916     {
917         if (gl_enum == GL_COMPRESSED_TEXTURE_FORMATS)
918         {
919             GLint value;
920             GL_ENTRYPOINT(glGetIntegerv)(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &value);
921             return value;
922         }
923         else if (gl_enum == GL_PROGRAM_BINARY_FORMATS)
924         {
925             GLint value;
926             GL_ENTRYPOINT(glGetIntegerv)(GL_NUM_PROGRAM_BINARY_FORMATS, &value);
927             return value;
928         }
929     }
930
931     int pname_index = find_pname_def_index(gl_enum);
932     if (pname_index >= 0)
933         return g_gl_pname_defs[pname_index].m_count;
934
935     vogl_warning_printf("%s: Unknown GL enum: 0x%08" PRIX64 "\n", VOGL_METHOD_NAME, gl_enum);
936     return -1;
937 }
938
939 //----------------------------------------------------------------------------------------------------------------------
940 // gl_enums::get_pname_type
941 //----------------------------------------------------------------------------------------------------------------------
942 int gl_enums::get_pname_type(uint64_t gl_enum) const
943 {
944     VOGL_FUNC_TRACER
945     int pname_index = find_pname_def_index(gl_enum);
946     if (pname_index >= 0)
947         return g_gl_pname_defs[pname_index].m_type;
948
949     vogl_warning_printf("%s: Unknown GL enum: 0x%08" PRIX64 "\n", VOGL_METHOD_NAME, gl_enum);
950     return cSTInt32;
951 }
952
953 //----------------------------------------------------------------------------------------------------------------------
954 // gl_enums::find_pname_def_index
955 //----------------------------------------------------------------------------------------------------------------------
956 int gl_enums::find_pname_def_index(uint64_t gl_enum) const
957 {
958     VOGL_FUNC_TRACER
959
960     if (gl_enum < 0x10000)
961     {
962         int pname_index = m_gl_enum_to_pname_def_index[static_cast<uint>(gl_enum)];
963         if (pname_index != 0xFFFF)
964             return pname_index;
965     }
966     return vogl::cInvalidIndex;
967 }
968
969 //----------------------------------------------------------------------------------------------------------------------
970 // GL image format to enum helpers
971 //----------------------------------------------------------------------------------------------------------------------
972 void gl_enums::init_image_formats()
973 {
974     VOGL_FUNC_TRACER
975
976 #define IMG_FMT(x) m_image_formats.insert(x, #x);
977 #include "vogl_image_formats.inc"
978 #undef IMG_FMT
979 }
980
981 //----------------------------------------------------------------------------------------------------------------------
982 // vogl_get_bound_gl_buffer
983 //----------------------------------------------------------------------------------------------------------------------
984 GLuint vogl_get_bound_gl_buffer(GLenum target)
985 {
986     VOGL_FUNC_TRACER
987
988     GLenum t = 0;
989     switch (target)
990     {
991         case GL_ARRAY_BUFFER:
992             t = GL_ARRAY_BUFFER_BINDING;
993             break;
994         case GL_ATOMIC_COUNTER_BUFFER:
995             t = GL_ATOMIC_COUNTER_BUFFER_BINDING;
996             break;
997         case GL_COPY_READ_BUFFER:
998             t = GL_COPY_READ_BUFFER_BINDING;
999             break;
1000         case GL_COPY_WRITE_BUFFER:
1001             t = GL_COPY_WRITE_BUFFER_BINDING;
1002             break;
1003         case GL_DRAW_INDIRECT_BUFFER:
1004             t = GL_DRAW_INDIRECT_BUFFER_BINDING;
1005             break;
1006         case GL_DISPATCH_INDIRECT_BUFFER:
1007             t = GL_DISPATCH_INDIRECT_BUFFER_BINDING;
1008             break;
1009         case GL_ELEMENT_ARRAY_BUFFER:
1010             t = GL_ELEMENT_ARRAY_BUFFER_BINDING;
1011             break;
1012         case GL_PIXEL_PACK_BUFFER:
1013             t = GL_PIXEL_PACK_BUFFER_BINDING;
1014             break;
1015         case GL_PIXEL_UNPACK_BUFFER:
1016             t = GL_PIXEL_UNPACK_BUFFER_BINDING;
1017             break;
1018         case GL_SHADER_STORAGE_BUFFER:
1019             t = GL_SHADER_STORAGE_BUFFER_BINDING;
1020             break;
1021         case GL_TRANSFORM_FEEDBACK_BUFFER:
1022             t = GL_TRANSFORM_FEEDBACK_BUFFER_BINDING;
1023             break;
1024         case GL_UNIFORM_BUFFER:
1025             t = GL_UNIFORM_BUFFER_BINDING;
1026             break;
1027         case GL_TEXTURE_BUFFER:
1028             t = GL_TEXTURE_BINDING_BUFFER;
1029             break;
1030         default:
1031         {
1032             console::warning("%s: Unknown buffer GL enum 0x%08X\n", VOGL_FUNCTION_NAME, target);
1033             return 0;
1034         }
1035     }
1036     GLint id = 0;
1037     GL_ENTRYPOINT(glGetIntegerv)(t, &id);
1038     return id;
1039 }
1040
1041 //----------------------------------------------------------------------------------------------------------------------
1042 // vogl_reset_pixel_store_states
1043 //----------------------------------------------------------------------------------------------------------------------
1044 void vogl_reset_pixel_store_states()
1045 {
1046     VOGL_FUNC_TRACER
1047
1048     GL_ENTRYPOINT(glPixelStorei)(GL_PACK_SWAP_BYTES, false);
1049     GL_ENTRYPOINT(glPixelStorei)(GL_PACK_LSB_FIRST, false);
1050     GL_ENTRYPOINT(glPixelStorei)(GL_PACK_ROW_LENGTH, 0);
1051     GL_ENTRYPOINT(glPixelStorei)(GL_PACK_IMAGE_HEIGHT, 0);
1052     GL_ENTRYPOINT(glPixelStorei)(GL_PACK_SKIP_ROWS, 0);
1053     GL_ENTRYPOINT(glPixelStorei)(GL_PACK_SKIP_PIXELS, 0);
1054     GL_ENTRYPOINT(glPixelStorei)(GL_PACK_SKIP_IMAGES, 0);
1055     GL_ENTRYPOINT(glPixelStorei)(GL_PACK_ALIGNMENT, 1);
1056     GL_ENTRYPOINT(glPixelStorei)(GL_UNPACK_SWAP_BYTES, false);
1057     GL_ENTRYPOINT(glPixelStorei)(GL_UNPACK_LSB_FIRST, false);
1058     GL_ENTRYPOINT(glPixelStorei)(GL_UNPACK_ROW_LENGTH, 0);
1059     GL_ENTRYPOINT(glPixelStorei)(GL_UNPACK_IMAGE_HEIGHT, 0);
1060     GL_ENTRYPOINT(glPixelStorei)(GL_UNPACK_SKIP_ROWS, 0);
1061     GL_ENTRYPOINT(glPixelStorei)(GL_UNPACK_SKIP_PIXELS, 0);
1062     GL_ENTRYPOINT(glPixelStorei)(GL_UNPACK_SKIP_IMAGES, 0);
1063     GL_ENTRYPOINT(glPixelStorei)(GL_UNPACK_ALIGNMENT, 1);
1064 }
1065
1066 //----------------------------------------------------------------------------------------------------------------------
1067 // vogl_reset_pixel_transfer_states
1068 //----------------------------------------------------------------------------------------------------------------------
1069 void vogl_reset_pixel_transfer_states()
1070 {
1071     VOGL_FUNC_TRACER
1072
1073     GL_ENTRYPOINT(glPixelTransferi)(GL_MAP_COLOR, GL_FALSE);
1074
1075     GL_ENTRYPOINT(glPixelTransferi)(GL_MAP_STENCIL, GL_FALSE);
1076     GL_ENTRYPOINT(glPixelTransferi)(GL_INDEX_SHIFT, 0);
1077     GL_ENTRYPOINT(glPixelTransferi)(GL_INDEX_OFFSET, 0);
1078
1079     GL_ENTRYPOINT(glPixelTransferf)(GL_RED_SCALE, 1.0f);
1080     GL_ENTRYPOINT(glPixelTransferf)(GL_GREEN_SCALE, 1.0f);
1081     GL_ENTRYPOINT(glPixelTransferf)(GL_BLUE_SCALE, 1.0f);
1082     GL_ENTRYPOINT(glPixelTransferf)(GL_ALPHA_SCALE, 1.0f);
1083     GL_ENTRYPOINT(glPixelTransferf)(GL_DEPTH_SCALE, 1.0f);
1084
1085     GL_ENTRYPOINT(glPixelTransferf)(GL_RED_BIAS, 0.0f);
1086     GL_ENTRYPOINT(glPixelTransferf)(GL_GREEN_BIAS, 0.0f);
1087     GL_ENTRYPOINT(glPixelTransferf)(GL_BLUE_BIAS, 0.0f);
1088     GL_ENTRYPOINT(glPixelTransferf)(GL_ALPHA_BIAS, 0.0f);
1089     GL_ENTRYPOINT(glPixelTransferf)(GL_DEPTH_BIAS, 0.0f);
1090
1091     GL_ENTRYPOINT(glPixelTransferf)(GL_POST_CONVOLUTION_RED_SCALE, 1.0f);
1092     GL_ENTRYPOINT(glPixelTransferf)(GL_POST_CONVOLUTION_GREEN_SCALE, 1.0f);
1093     GL_ENTRYPOINT(glPixelTransferf)(GL_POST_CONVOLUTION_BLUE_SCALE, 1.0f);
1094     GL_ENTRYPOINT(glPixelTransferf)(GL_POST_CONVOLUTION_ALPHA_SCALE, 1.0f);
1095
1096     GL_ENTRYPOINT(glPixelTransferf)(GL_POST_CONVOLUTION_RED_BIAS, 0.0f);
1097     GL_ENTRYPOINT(glPixelTransferf)(GL_POST_CONVOLUTION_GREEN_BIAS, 0.0f);
1098     GL_ENTRYPOINT(glPixelTransferf)(GL_POST_CONVOLUTION_BLUE_BIAS, 0.0f);
1099     GL_ENTRYPOINT(glPixelTransferf)(GL_POST_CONVOLUTION_ALPHA_BIAS, 0.0f);
1100
1101     GL_ENTRYPOINT(glPixelTransferf)(GL_POST_COLOR_MATRIX_RED_SCALE, 1.0f);
1102     GL_ENTRYPOINT(glPixelTransferf)(GL_POST_COLOR_MATRIX_GREEN_SCALE, 1.0f);
1103     GL_ENTRYPOINT(glPixelTransferf)(GL_POST_COLOR_MATRIX_BLUE_SCALE, 1.0f);
1104     GL_ENTRYPOINT(glPixelTransferf)(GL_POST_COLOR_MATRIX_ALPHA_SCALE, 1.0f);
1105
1106     GL_ENTRYPOINT(glPixelTransferf)(GL_POST_COLOR_MATRIX_RED_BIAS, 0.0f);
1107     GL_ENTRYPOINT(glPixelTransferf)(GL_POST_COLOR_MATRIX_GREEN_BIAS, 0.0f);
1108     GL_ENTRYPOINT(glPixelTransferf)(GL_POST_COLOR_MATRIX_BLUE_BIAS, 0.0f);
1109     GL_ENTRYPOINT(glPixelTransferf)(GL_POST_COLOR_MATRIX_ALPHA_BIAS, 0.0f);
1110 }
1111
1112 #include "vogl_general_context_state.h"
1113
1114 //----------------------------------------------------------------------------------------------------------------------
1115 // vogl_copy_buffer_to_image
1116 //----------------------------------------------------------------------------------------------------------------------
1117 bool vogl_copy_buffer_to_image(void *pDst, uint dst_size, uint width, uint height, GLuint format, GLuint type, bool flip_image, GLuint framebuffer, GLuint read_buffer, GLuint pixel_pack_buffer)
1118 {
1119     VOGL_FUNC_TRACER
1120
1121     if ((!width) || (!height))
1122     {
1123         VOGL_ASSERT_ALWAYS;
1124         return false;
1125     }
1126
1127     // Forceably discard any errors up to here, even in benchmark mode, because glReadPixels() is going to be slow as hell anyway
1128     GL_ENTRYPOINT(glGetError)();
1129
1130     // Save the state we'll be changing
1131     vogl_scoped_state_saver state_saver(cGSTPixelStore);
1132     vogl_scoped_binding_state orig_framebuffers(GL_DRAW_FRAMEBUFFER, GL_READ_FRAMEBUFFER, GL_PIXEL_PACK_BUFFER);
1133
1134     // Set the state we need to do a glReadPixels()
1135     vogl_reset_pixel_store_states();
1136
1137     GL_ENTRYPOINT(glBindBuffer)(GL_PIXEL_PACK_BUFFER, pixel_pack_buffer);
1138     GL_ENTRYPOINT(glBindFramebuffer)(GL_FRAMEBUFFER, framebuffer);
1139
1140     vogl_scoped_state_saver framebuffer_state_saver(cGSTReadBuffer, cGSTDrawBuffer);
1141
1142     GL_ENTRYPOINT(glReadBuffer)(read_buffer);
1143
1144     VOGL_CHECK_GL_ERROR;
1145
1146     // Now read the pixels
1147     GLenum err = GL_INVALID_VALUE;
1148
1149     // Ensure the destination buffer is big enough
1150     size_t image_size = vogl_get_image_size(format, type, width, height, 1);
1151     if ((pDst) && ((!image_size) || (dst_size < image_size)))
1152     {
1153         VOGL_ASSERT_ALWAYS;
1154     }
1155     else
1156     {
1157         GL_ENTRYPOINT(glReadPixels)(0, 0, width, height, format, type, pDst);
1158
1159         err = GL_ENTRYPOINT(glGetError());
1160     }
1161
1162     if (err)
1163     {
1164         console::warning("%s: GL error 0x%X while calling glReadPixels()!\n", VOGL_FUNCTION_NAME, err);
1165     }
1166
1167     // Optionally flip the image
1168     if ((flip_image) && (err == GL_NO_ERROR) && (pDst))
1169     {
1170         size_t pitch = vogl_get_image_size(format, type, width, 1, 1);
1171         if (pitch > cUINT32_MAX)
1172         {
1173             VOGL_ASSERT_ALWAYS;
1174             return false;
1175         }
1176
1177         if ((pitch) && ((image_size / pitch) == height))
1178         {
1179             vogl::vector<uint8> row_buf(static_cast<uint>(pitch));
1180
1181             for (uint y = 0; y < (height / 2); y++)
1182             {
1183                 uint8 *pA = reinterpret_cast<uint8 *>(pDst) + y * pitch;
1184                 uint8 *pB = reinterpret_cast<uint8 *>(pDst) + (height - 1 - y) * pitch;
1185                 memcpy(row_buf.get_ptr(), pA, pitch);
1186                 memcpy(pA, pB, pitch);
1187                 memcpy(pB, row_buf.get_ptr(), pitch);
1188             }
1189         }
1190         else
1191         {
1192             // Don't know how to flip it
1193             VOGL_ASSERT_ALWAYS;
1194         }
1195     }
1196
1197     // Restore previous state - order is critical here!
1198     framebuffer_state_saver.restore();
1199     orig_framebuffers.restore();
1200     state_saver.restore();
1201
1202     VOGL_CHECK_GL_ERROR;
1203
1204     return (err == GL_NO_ERROR);
1205 }
1206
1207 //----------------------------------------------------------------------------------------------------------------------
1208 // vogl_check_gl_error_internal
1209 // Returns *true* on error
1210 //----------------------------------------------------------------------------------------------------------------------
1211 bool vogl_check_gl_error_internal(bool suppress_error_message, const char *pFile, uint line, const char *pFunc)
1212 {
1213     VOGL_FUNC_TRACER
1214
1215     bool status = false;
1216     for (;;)
1217     {
1218         // http://www.opengl.org/sdk/docs/man/xhtml/glGetError.xml
1219         // "Thus, glGetError should always be called in a loop, until it returns GL_NO_ERROR, if all error flags are to be reset."
1220         GLenum gl_err = GL_ENTRYPOINT(glGetError)();
1221         if (gl_err == GL_NO_ERROR)
1222             break;
1223
1224         if (!suppress_error_message)
1225         {
1226             console::error("%s: GL error: 0x%08X (%u): %s (Called From File: %s, line: %u, func: %s)\n", VOGL_FUNCTION_NAME, gl_err, gl_err, g_gl_enums.find_name("ErrorCode", gl_err), pFile ? pFile : "?", line, pFunc ? pFunc : "?");
1227
1228 #if 0
1229                         dynamic_string_array backtrace;
1230                         if (get_printable_backtrace(backtrace))
1231                         {
1232                                 console::error("Backtrace:\n");
1233                                 for (uint i = 0; i < backtrace.size(); i++)
1234                                         console::error("%s\n", backtrace[i].get_ptr());
1235                         }
1236 #endif
1237         }
1238         status = true;
1239     }
1240
1241     return status;
1242 }
1243
1244 //----------------------------------------------------------------------------------------------------------------------
1245 // vogl_enable_gl_get_errors
1246 //----------------------------------------------------------------------------------------------------------------------
1247 void vogl_enable_gl_get_error()
1248 {
1249     g_gl_get_error_enabled = true;
1250 }
1251
1252 //----------------------------------------------------------------------------------------------------------------------
1253 // vogl_disable_gl_get_errors
1254 //----------------------------------------------------------------------------------------------------------------------
1255 void vogl_disable_gl_get_error()
1256 {
1257     g_gl_get_error_enabled = false;
1258 }
1259
1260 //----------------------------------------------------------------------------------------------------------------------
1261 // vogl_is_gl_get_error_enabled
1262 //----------------------------------------------------------------------------------------------------------------------
1263 bool vogl_is_gl_get_error_enabled()
1264 {
1265     return g_gl_get_error_enabled;
1266 }
1267
1268 //----------------------------------------------------------------------------------------------------------------------
1269 // vogl_is_draw_entrypoint
1270 //----------------------------------------------------------------------------------------------------------------------
1271 bool vogl_is_draw_entrypoint(gl_entrypoint_id_t id)
1272 {
1273     VOGL_FUNC_TRACER
1274
1275     switch (id)
1276     {
1277         case VOGL_ENTRYPOINT_glDrawRangeElements:
1278         case VOGL_ENTRYPOINT_glDrawRangeElementsBaseVertex:
1279         case VOGL_ENTRYPOINT_glDrawElements:
1280         case VOGL_ENTRYPOINT_glDrawArrays:
1281         case VOGL_ENTRYPOINT_glDrawArraysEXT:
1282         case VOGL_ENTRYPOINT_glDrawElementsBaseVertex:
1283         case VOGL_ENTRYPOINT_glDrawElementsInstanced:
1284         case VOGL_ENTRYPOINT_glDrawElementsInstancedARB:
1285         case VOGL_ENTRYPOINT_glDrawElementsInstancedBaseVertex:
1286         case VOGL_ENTRYPOINT_glDrawArraysIndirect:
1287         case VOGL_ENTRYPOINT_glDrawArraysInstanced:
1288         case VOGL_ENTRYPOINT_glDrawArraysInstancedARB:
1289         case VOGL_ENTRYPOINT_glDrawArraysInstancedBaseInstance:
1290         case VOGL_ENTRYPOINT_glDrawArraysInstancedEXT:
1291         case VOGL_ENTRYPOINT_glMultiDrawArrays:
1292         case VOGL_ENTRYPOINT_glMultiDrawArraysEXT:
1293         case VOGL_ENTRYPOINT_glMultiDrawElements:
1294         case VOGL_ENTRYPOINT_glMultiDrawElementsEXT:
1295         case VOGL_ENTRYPOINT_glMultiDrawElementsBaseVertex:
1296         case VOGL_ENTRYPOINT_glDrawElementArrayAPPLE:
1297         case VOGL_ENTRYPOINT_glDrawElementArrayATI:
1298         case VOGL_ENTRYPOINT_glDrawElementsIndirect:
1299         case VOGL_ENTRYPOINT_glDrawElementsInstancedBaseInstance:
1300         case VOGL_ENTRYPOINT_glDrawElementsInstancedBaseVertexBaseInstance:
1301         case VOGL_ENTRYPOINT_glDrawElementsInstancedEXT:
1302         case VOGL_ENTRYPOINT_glDrawRangeElementArrayAPPLE:
1303         case VOGL_ENTRYPOINT_glDrawRangeElementArrayATI:
1304         case VOGL_ENTRYPOINT_glDrawRangeElementsEXT:
1305         case VOGL_ENTRYPOINT_glDrawTransformFeedback:
1306         case VOGL_ENTRYPOINT_glDrawTransformFeedbackInstanced:
1307         case VOGL_ENTRYPOINT_glDrawTransformFeedbackNV:
1308         case VOGL_ENTRYPOINT_glDrawTransformFeedbackStream:
1309         case VOGL_ENTRYPOINT_glDrawTransformFeedbackStreamInstanced:
1310         case VOGL_ENTRYPOINT_glMultiDrawArraysIndirect:
1311         case VOGL_ENTRYPOINT_glMultiDrawArraysIndirectAMD:
1312         case VOGL_ENTRYPOINT_glMultiDrawElementArrayAPPLE:
1313         case VOGL_ENTRYPOINT_glMultiDrawElementsIndirect:
1314         case VOGL_ENTRYPOINT_glMultiDrawElementsIndirectAMD:
1315         case VOGL_ENTRYPOINT_glMultiDrawRangeElementArrayAPPLE:
1316             return true;
1317         default:
1318             break;
1319     }
1320     return false;
1321 }
1322
1323 //----------------------------------------------------------------------------------------------------------------------
1324 // vogl_is_clear_entrypoint
1325 //----------------------------------------------------------------------------------------------------------------------
1326 bool vogl_is_clear_entrypoint(gl_entrypoint_id_t id)
1327 {
1328     VOGL_FUNC_TRACER
1329
1330     switch (id)
1331     {
1332         case VOGL_ENTRYPOINT_glClear:
1333         case VOGL_ENTRYPOINT_glClearBufferiv:
1334         case VOGL_ENTRYPOINT_glClearBufferfv:
1335         case VOGL_ENTRYPOINT_glClearBufferuiv:
1336         case VOGL_ENTRYPOINT_glClearBufferfi:
1337             return true;
1338         default:
1339             break;
1340     }
1341     return false;
1342 }
1343
1344 //----------------------------------------------------------------------------------------------------------------------
1345 // vogl_get_json_value_as_enum
1346 //----------------------------------------------------------------------------------------------------------------------
1347 GLenum vogl_get_json_value_as_enum(const json_node &node, const char *pKey, GLenum def)
1348 {
1349     VOGL_FUNC_TRACER
1350
1351     uint64_t v = g_gl_enums.find_enum(node.value_as_string(pKey));
1352     if (v == gl_enums::cUnknownEnum)
1353         return def;
1354     VOGL_ASSERT(v <= cUINT32_MAX);
1355     return static_cast<GLenum>(v);
1356 }
1357
1358 //----------------------------------------------------------------------------------------------------------------------
1359 // vogl_get_json_value_as_enum
1360 //----------------------------------------------------------------------------------------------------------------------
1361 GLenum vogl_get_json_value_as_enum(const json_value &val, GLenum def)
1362 {
1363     VOGL_FUNC_TRACER
1364
1365     uint64_t v = g_gl_enums.find_enum(val.as_string());
1366     if (v == gl_enums::cUnknownEnum)
1367         return def;
1368     VOGL_ASSERT(v <= cUINT32_MAX);
1369     return static_cast<GLenum>(v);
1370 }
1371
1372 //----------------------------------------------------------------------------------------------------------------------
1373 // vogl_get_binding_from_target
1374 //----------------------------------------------------------------------------------------------------------------------
1375 GLenum vogl_get_binding_from_target(GLenum target)
1376 {
1377     VOGL_FUNC_TRACER
1378
1379     switch (target)
1380     {
1381 #define DEFINE_BINDING(c, t, b) \
1382     case t:                     \
1383         return b;
1384 #include "gl_buffer_bindings.inc"
1385 #undef DEFINE_BINDING
1386
1387         default:
1388         {
1389             console::warning("%s: Unknown target GL enum 0x%08X\n", VOGL_FUNCTION_NAME, target);
1390             return GL_NONE;
1391         }
1392     }
1393 }
1394
1395 //----------------------------------------------------------------------------------------------------------------------
1396 // vogl_get_object_category_from_binding
1397 //----------------------------------------------------------------------------------------------------------------------
1398 GLenum vogl_get_object_category_from_binding(GLenum binding)
1399 {
1400     VOGL_FUNC_TRACER
1401
1402     switch (binding)
1403     {
1404 #define DEFINE_BINDING(c, t, b) \
1405     case b:                     \
1406         return c;
1407 #include "gl_buffer_bindings.inc"
1408 #undef DEFINE_BINDING
1409
1410         default:
1411         {
1412             console::warning("%s: Unknown binding GL enum 0x%08X\n", VOGL_FUNCTION_NAME, binding);
1413             return GL_NONE;
1414         }
1415     }
1416 }
1417
1418 //----------------------------------------------------------------------------------------------------------------------
1419 // vogl_get_object_category_from_target
1420 //----------------------------------------------------------------------------------------------------------------------
1421 GLenum vogl_get_object_category_from_target(GLenum target)
1422 {
1423     VOGL_FUNC_TRACER
1424
1425     switch (target)
1426     {
1427 #define DEFINE_BINDING(c, t, b) \
1428     case t:                     \
1429         return c;
1430 #include "gl_buffer_bindings.inc"
1431 #undef DEFINE_BINDING
1432
1433         default:
1434         {
1435             console::warning("%s: Unknown target GL enum 0x%08X\n", VOGL_FUNCTION_NAME, target);
1436             return GL_NONE;
1437         }
1438     }
1439 }
1440
1441 //----------------------------------------------------------------------------------------------------------------------
1442 // vogl_get_target_from_binding
1443 //----------------------------------------------------------------------------------------------------------------------
1444 GLenum vogl_get_target_from_binding(GLenum binding)
1445 {
1446     VOGL_FUNC_TRACER
1447
1448     switch (binding)
1449     {
1450 #define DEFINE_BINDING(c, t, b) \
1451     case b:                     \
1452         return t;
1453 #include "gl_buffer_bindings.inc"
1454 #undef DEFINE_BINDING
1455
1456         default:
1457         {
1458             console::warning("%s: Unknown binding GL enum 0x%08X\n", VOGL_FUNCTION_NAME, binding);
1459             return GL_NONE;
1460         }
1461     }
1462 }
1463
1464 //----------------------------------------------------------------------------------------------------------------------
1465 // vogl_bind_object
1466 //----------------------------------------------------------------------------------------------------------------------
1467 void vogl_bind_object(GLenum target, GLuint handle)
1468 {
1469     VOGL_FUNC_TRACER
1470
1471     GLenum category = vogl_get_object_category_from_target(target);
1472
1473     switch (category)
1474     {
1475         case GL_TEXTURE:
1476         {
1477             GL_ENTRYPOINT(glBindTexture)(target, handle);
1478             break;
1479         }
1480         case GL_BUFFER:
1481         {
1482             GL_ENTRYPOINT(glBindBuffer)(target, handle);
1483             break;
1484         }
1485         case GL_FRAMEBUFFER:
1486         {
1487             GL_ENTRYPOINT(glBindFramebuffer)(target, handle);
1488             break;
1489         }
1490         case GL_RENDERBUFFER:
1491         {
1492             GL_ENTRYPOINT(glBindRenderbuffer)(target, handle);
1493             break;
1494         }
1495         case GL_SAMPLER:
1496         {
1497             GL_ENTRYPOINT(glBindSampler)(target, handle);
1498             break;
1499         }
1500         case GL_VERTEX_ARRAY:
1501         {
1502             GL_ENTRYPOINT(glBindVertexArray)(handle);
1503             break;
1504         }
1505         case GL_ACTIVE_TEXTURE:
1506         {
1507             // not really a binding, exactly, but seems useful
1508             GL_ENTRYPOINT(glActiveTexture)(handle);
1509             break;
1510         }
1511         case GL_PROGRAM:
1512         {
1513             GL_ENTRYPOINT(glUseProgram)(handle);
1514             break;
1515         }
1516         default:
1517         {
1518             VOGL_ASSERT_ALWAYS;
1519             break;
1520         }
1521     }
1522
1523     VOGL_CHECK_GL_ERROR;
1524 }
1525
1526 //----------------------------------------------------------------------------------------------------------------------
1527 // vogl_get_bound_object
1528 //----------------------------------------------------------------------------------------------------------------------
1529 GLuint vogl_get_bound_object(GLenum target)
1530 {
1531     VOGL_FUNC_TRACER
1532
1533     GLenum binding = vogl_get_binding_from_target(target);
1534     if (binding == GL_NONE)
1535     {
1536         VOGL_ASSERT_ALWAYS;
1537         return 0;
1538     }
1539
1540     GLint handle = 0;
1541     GL_ENTRYPOINT(glGetIntegerv)(binding, &handle);
1542     VOGL_CHECK_GL_ERROR;
1543
1544     return handle;
1545 }
1546
1547 //----------------------------------------------------------------------------------------------------------------------
1548 // vogl_debug_message_control
1549 //----------------------------------------------------------------------------------------------------------------------
1550 void vogl_debug_message_control(const vogl_context_info &context_info, GLenum err_code, bool enabled)
1551 {
1552     VOGL_FUNC_TRACER
1553
1554     if (!context_info.is_debug_context())
1555         return;
1556
1557     if (!context_info.supports_extension("GL_ARB_debug_output") || (!GL_ENTRYPOINT(glDebugMessageControlARB)))
1558         return;
1559
1560     GL_ENTRYPOINT(glDebugMessageControlARB)(GL_DEBUG_SOURCE_API_ARB, GL_DEBUG_TYPE_ERROR_ARB, GL_DONT_CARE, 1, &err_code, enabled);
1561 }
1562
1563 //----------------------------------------------------------------------------------------------------------------------
1564 // vogl_determine_texture_target
1565 // NOTE: Don't use this for anything other than debugging!
1566 //----------------------------------------------------------------------------------------------------------------------
1567 GLenum vogl_determine_texture_target(const vogl_context_info &context_info, GLuint handle)
1568 {
1569     VOGL_FUNC_TRACER
1570
1571     GLboolean is_texture = GL_ENTRYPOINT(glIsTexture)(handle);
1572     if (!is_texture)
1573         return GL_NONE;
1574
1575     vogl_scoped_binding_state orig_texture_state;
1576     orig_texture_state.save_textures();
1577
1578     VOGL_CHECK_GL_ERROR;
1579
1580     // roughly sorted by most likely to least
1581     static const GLenum s_possible_targets[] =
1582         {
1583             GL_TEXTURE_2D, GL_TEXTURE_CUBE_MAP,
1584             GL_TEXTURE_3D, GL_TEXTURE_2D_ARRAY, GL_TEXTURE_1D, GL_TEXTURE_1D_ARRAY,
1585             GL_TEXTURE_RECTANGLE, GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_BUFFER, GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_2D_MULTISAMPLE_ARRAY
1586         };
1587
1588     vogl_debug_message_control(context_info, GL_INVALID_OPERATION, false);
1589
1590     uint i;
1591     for (i = 0; i < VOGL_ARRAY_SIZE(s_possible_targets); i++)
1592     {
1593         GL_ENTRYPOINT(glBindTexture)(s_possible_targets[i], handle);
1594         if (!vogl_check_gl_error_suppress_message())
1595             break;
1596     }
1597
1598     if (i == VOGL_ARRAY_SIZE(s_possible_targets))
1599         vogl_check_gl_error_suppress_message();
1600
1601     vogl_debug_message_control(context_info, GL_INVALID_OPERATION, true);
1602
1603     return (i < VOGL_ARRAY_SIZE(s_possible_targets)) ? s_possible_targets[i] : GL_NONE;
1604 }
1605
1606 //----------------------------------------------------------------------------------------------------------------------
1607 // vogl_state_saver::save
1608 //----------------------------------------------------------------------------------------------------------------------
1609 void vogl_state_saver::save(vogl_generic_state_type type)
1610 {
1611     VOGL_FUNC_TRACER
1612
1613 #define SAVE_INT_STATE(type, pname)                                              \
1614     do                                                                           \
1615     {                                                                            \
1616         m_states.push_back(saved_state(type, pname, vogl_get_gl_integer(pname))); \
1617     } while (0)
1618 #define SAVE_FLOAT_STATE(type, pname)                                          \
1619     do                                                                         \
1620     {                                                                          \
1621         m_states.push_back(saved_state(type, pname, vogl_get_gl_float(pname))); \
1622     } while (0)
1623
1624     switch (type)
1625     {
1626         case cGSTPixelStore:
1627         {
1628             static const GLenum s_pixel_store_enums[] =
1629                 {
1630                     GL_PACK_SWAP_BYTES, GL_PACK_LSB_FIRST, GL_PACK_ROW_LENGTH, GL_PACK_IMAGE_HEIGHT, GL_PACK_SKIP_ROWS, GL_PACK_SKIP_PIXELS, GL_PACK_SKIP_IMAGES, GL_PACK_ALIGNMENT,
1631                     GL_UNPACK_SWAP_BYTES, GL_UNPACK_LSB_FIRST, GL_UNPACK_ROW_LENGTH, GL_UNPACK_IMAGE_HEIGHT, GL_UNPACK_SKIP_ROWS, GL_UNPACK_SKIP_PIXELS, GL_UNPACK_SKIP_IMAGES, GL_UNPACK_ALIGNMENT
1632                 };
1633
1634             for (uint i = 0; i < VOGL_ARRAY_SIZE(s_pixel_store_enums); i++)
1635                 SAVE_INT_STATE(cGSTPixelStore, s_pixel_store_enums[i]);
1636
1637             break;
1638         }
1639         case cGSTPixelTransfer:
1640         {
1641             // FIXME: All pixel transfer was marked deprecated and not available in a Core Profile (let the caller worry about it)
1642             static const GLenum s_pixel_transfer_int_enums[] =
1643                 {
1644                     GL_MAP_COLOR, GL_MAP_STENCIL, GL_INDEX_SHIFT, GL_INDEX_OFFSET
1645                 };
1646
1647             for (uint i = 0; i < VOGL_ARRAY_SIZE(s_pixel_transfer_int_enums); i++)
1648                 SAVE_INT_STATE(cGSTPixelTransfer, s_pixel_transfer_int_enums[i]);
1649
1650             static const GLfloat s_pixel_transfer_float_enums[] =
1651                 {
1652                     GL_INDEX_OFFSET, GL_RED_SCALE, GL_GREEN_SCALE, GL_BLUE_SCALE, GL_ALPHA_SCALE, GL_DEPTH_SCALE, GL_RED_BIAS, GL_GREEN_BIAS,
1653                     GL_BLUE_BIAS, GL_ALPHA_BIAS, GL_DEPTH_BIAS, GL_POST_COLOR_MATRIX_RED_SCALE, GL_POST_COLOR_MATRIX_GREEN_SCALE, GL_POST_COLOR_MATRIX_BLUE_SCALE,
1654                     GL_POST_COLOR_MATRIX_ALPHA_SCALE, GL_POST_COLOR_MATRIX_RED_BIAS, GL_POST_COLOR_MATRIX_GREEN_BIAS, GL_POST_COLOR_MATRIX_BLUE_BIAS, GL_POST_COLOR_MATRIX_ALPHA_BIAS,
1655                     GL_POST_CONVOLUTION_RED_SCALE, GL_POST_CONVOLUTION_GREEN_SCALE, GL_POST_CONVOLUTION_BLUE_SCALE, GL_POST_CONVOLUTION_ALPHA_SCALE, GL_POST_CONVOLUTION_RED_BIAS,
1656                     GL_POST_CONVOLUTION_GREEN_BIAS, GL_POST_CONVOLUTION_BLUE_BIAS, GL_POST_CONVOLUTION_ALPHA_BIAS
1657                 };
1658
1659             for (uint i = 0; i < VOGL_ARRAY_SIZE(s_pixel_transfer_float_enums); i++)
1660                 SAVE_FLOAT_STATE(cGSTPixelTransfer, s_pixel_transfer_float_enums[i]);
1661
1662             break;
1663         }
1664         case cGSTReadBuffer:
1665         {
1666             SAVE_INT_STATE(type, GL_READ_BUFFER);
1667             break;
1668         }
1669         case cGSTDrawBuffer:
1670         {
1671             uint max_draw_buffers = vogl_get_gl_integer(GL_MAX_DRAW_BUFFERS);
1672             m_draw_buffers.resize(max_draw_buffers);
1673
1674             for (uint i = 0; i < max_draw_buffers; i++)
1675                 m_draw_buffers[i] = vogl_get_gl_integer(GL_DRAW_BUFFER0 + i);
1676
1677             break;
1678         }
1679         case cGSTActiveTexture:
1680         {
1681             GLint active_texture = 0;
1682             GL_ENTRYPOINT(glGetIntegerv)(GL_ACTIVE_TEXTURE, &active_texture);
1683             m_states.push_back(saved_state(type, GL_ACTIVE_TEXTURE, active_texture));
1684             break;
1685         }
1686         case cGSTClientActiveTexture:
1687         {
1688             // FIXME: Don't think this is available in core (let the caller worry about it)
1689             GLint client_active_texture = 0;
1690             GL_ENTRYPOINT(glGetIntegerv)(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);
1691             m_states.push_back(saved_state(type, GL_CLIENT_ACTIVE_TEXTURE, client_active_texture));
1692             break;
1693         }
1694         case cGSTMatrixMode:
1695         {
1696             SAVE_INT_STATE(type, GL_MATRIX_MODE);
1697             break;
1698         }
1699         case cGSTARBVertexProgram:
1700         {
1701             GLint cur_arb_vertex_program = 0;
1702             GL_ENTRYPOINT(glGetProgramivARB)(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_BINDING_ARB, &cur_arb_vertex_program);
1703             m_states.push_back(saved_state(type, GL_VERTEX_PROGRAM_ARB, cur_arb_vertex_program));
1704             break;
1705         }
1706         case cGSTARBFragmentProgram:
1707         {
1708             GLint cur_arb_fragment_program = 0;
1709             GL_ENTRYPOINT(glGetProgramivARB)(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_BINDING_ARB, &cur_arb_fragment_program);
1710             m_states.push_back(saved_state(type, GL_FRAGMENT_PROGRAM_ARB, cur_arb_fragment_program));
1711             break;
1712         }
1713         default:
1714         {
1715             VOGL_ASSERT_ALWAYS;
1716             break;
1717         }
1718     }
1719
1720 #undef SAVE_INT_STATE
1721 #undef SAVE_FLOAT_STATE
1722
1723     VOGL_CHECK_GL_ERROR;
1724 }
1725
1726 //----------------------------------------------------------------------------------------------------------------------
1727 // vogl_state_saver::restore
1728 //----------------------------------------------------------------------------------------------------------------------
1729 void vogl_state_saver::restore()
1730 {
1731     VOGL_FUNC_TRACER
1732
1733     if (m_draw_buffers.size())
1734     {
1735         int i;
1736         for (i = m_draw_buffers.size() - 1; i >= 0; --i)
1737             if (m_draw_buffers[i] != GL_NONE)
1738                 break;
1739
1740         VOGL_ASSERT(i >= 0);
1741
1742         // On NV, we can cvall glDrawBuffers() with a single GL_BACK, etc. and it's fine. On AMD it barfs.
1743         if (!i)
1744         {
1745             GL_ENTRYPOINT(glDrawBuffer)(m_draw_buffers[0]);
1746             VOGL_CHECK_GL_ERROR;
1747         }
1748         else
1749         {
1750             GL_ENTRYPOINT(glDrawBuffers)(i + 1, m_draw_buffers.get_ptr());
1751             VOGL_CHECK_GL_ERROR;
1752         }
1753     }
1754
1755     for (uint i = 0; i < m_states.size(); i++)
1756     {
1757         const vogl::value_data_type value_type = m_states[i].m_value.get_data_type();
1758
1759         switch (m_states[i].m_state_type)
1760         {
1761             case cGSTPixelStore:
1762             {
1763                 VOGL_ASSERT(value_type == cDTInt);
1764                 GL_ENTRYPOINT(glPixelStorei)(m_states[i].m_pname, m_states[i].m_value.get_int());
1765                 VOGL_CHECK_GL_ERROR;
1766                 break;
1767             }
1768             case cGSTPixelTransfer:
1769             {
1770                 if (value_type == cDTFloat)
1771                 {
1772                     GL_ENTRYPOINT(glPixelTransferf)(m_states[i].m_pname, m_states[i].m_value.get_float());
1773                     VOGL_CHECK_GL_ERROR;
1774                 }
1775                 else if (value_type == cDTInt)
1776                 {
1777                     GL_ENTRYPOINT(glPixelTransferi)(m_states[i].m_pname, m_states[i].m_value.get_int());
1778                     VOGL_CHECK_GL_ERROR;
1779                 }
1780                 else
1781                 {
1782                     VOGL_ASSERT_ALWAYS;
1783                     break;
1784                 }
1785                 break;
1786             }
1787             case cGSTReadBuffer:
1788             {
1789                 VOGL_ASSERT(m_states[i].m_pname == GL_READ_BUFFER);
1790                 VOGL_ASSERT(value_type == cDTInt);
1791                 GL_ENTRYPOINT(glReadBuffer)(m_states[i].m_value.get_int());
1792                 VOGL_CHECK_GL_ERROR;
1793                 break;
1794             }
1795             case cGSTDrawBuffer:
1796             {
1797                 VOGL_ASSERT_ALWAYS;
1798                 break;
1799             }
1800             case cGSTActiveTexture:
1801             {
1802                 VOGL_ASSERT(m_states[i].m_pname == GL_ACTIVE_TEXTURE);
1803                 VOGL_ASSERT(value_type == cDTInt);
1804                 GL_ENTRYPOINT(glActiveTexture)(m_states[i].m_value.get_int());
1805                 VOGL_CHECK_GL_ERROR;
1806                 break;
1807             }
1808             case cGSTClientActiveTexture:
1809             {
1810                 VOGL_ASSERT(m_states[i].m_pname == GL_CLIENT_ACTIVE_TEXTURE);
1811                 VOGL_ASSERT(value_type == cDTInt);
1812                 GL_ENTRYPOINT(glClientActiveTexture)(m_states[i].m_value.get_int());
1813                 VOGL_CHECK_GL_ERROR;
1814                 break;
1815             }
1816             case cGSTMatrixMode:
1817             {
1818                 VOGL_ASSERT(m_states[i].m_pname == GL_MATRIX_MODE);
1819                 VOGL_ASSERT(value_type == cDTInt);
1820                 GL_ENTRYPOINT(glMatrixMode)(m_states[i].m_value.get_int());
1821                 VOGL_CHECK_GL_ERROR;
1822                 break;
1823             }
1824             case cGSTARBVertexProgram:
1825             {
1826                 VOGL_ASSERT(m_states[i].m_pname == GL_VERTEX_PROGRAM_ARB);
1827                 VOGL_ASSERT(value_type == cDTInt);
1828                 GL_ENTRYPOINT(glBindProgramARB)(GL_VERTEX_PROGRAM_ARB, m_states[i].m_value.get_int());
1829                 VOGL_CHECK_GL_ERROR;
1830                 break;
1831             }
1832             case cGSTARBFragmentProgram:
1833             {
1834                 VOGL_ASSERT(m_states[i].m_pname == GL_FRAGMENT_PROGRAM_ARB);
1835                 VOGL_ASSERT(value_type == cDTInt);
1836                 GL_ENTRYPOINT(glBindProgramARB)(GL_FRAGMENT_PROGRAM_ARB, m_states[i].m_value.get_int());
1837                 VOGL_CHECK_GL_ERROR;
1838                 break;
1839             }
1840             default:
1841             {
1842                 VOGL_ASSERT_ALWAYS;
1843                 break;
1844             }
1845         }
1846     }
1847 }
1848
1849 //----------------------------------------------------------------------------------------------------------------------
1850 // vogl_gl_get_uniform_size_in_GLints
1851 //----------------------------------------------------------------------------------------------------------------------
1852 int vogl_gl_get_uniform_size_in_GLints(GLenum type)
1853 {
1854     VOGL_FUNC_TRACER
1855
1856     switch (type)
1857     {
1858         case GL_FLOAT:
1859         case GL_INT:
1860         case GL_UNSIGNED_INT:
1861         case GL_BOOL:
1862
1863         case GL_SAMPLER_1D:
1864         case GL_SAMPLER_2D:
1865         case GL_SAMPLER_3D:
1866         case GL_SAMPLER_CUBE:
1867         case GL_SAMPLER_1D_SHADOW:
1868         case GL_SAMPLER_2D_SHADOW:
1869         case GL_SAMPLER_1D_ARRAY:
1870         case GL_SAMPLER_2D_ARRAY:
1871         case GL_SAMPLER_1D_ARRAY_SHADOW:
1872         case GL_SAMPLER_2D_ARRAY_SHADOW:
1873         case GL_SAMPLER_2D_MULTISAMPLE:
1874         case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
1875         case GL_SAMPLER_CUBE_SHADOW:
1876         case GL_SAMPLER_BUFFER:
1877         case GL_SAMPLER_2D_RECT:
1878         case GL_SAMPLER_2D_RECT_SHADOW:
1879         case GL_INT_SAMPLER_1D:
1880         case GL_INT_SAMPLER_2D:
1881         case GL_INT_SAMPLER_3D:
1882         case GL_INT_SAMPLER_CUBE:
1883         case GL_INT_SAMPLER_1D_ARRAY:
1884         case GL_INT_SAMPLER_2D_ARRAY:
1885         case GL_INT_SAMPLER_2D_MULTISAMPLE:
1886         case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
1887         case GL_INT_SAMPLER_BUFFER:
1888         case GL_INT_SAMPLER_2D_RECT:
1889         case GL_UNSIGNED_INT_SAMPLER_1D:
1890         case GL_UNSIGNED_INT_SAMPLER_2D:
1891         case GL_UNSIGNED_INT_SAMPLER_3D:
1892         case GL_UNSIGNED_INT_SAMPLER_CUBE:
1893         case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
1894         case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
1895         case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
1896         case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
1897         case GL_UNSIGNED_INT_SAMPLER_BUFFER:
1898         case GL_UNSIGNED_INT_SAMPLER_2D_RECT:
1899
1900         case GL_IMAGE_1D:
1901         case GL_IMAGE_2D:
1902         case GL_IMAGE_3D:
1903         case GL_IMAGE_2D_RECT:
1904         case GL_IMAGE_CUBE:
1905         case GL_IMAGE_BUFFER:
1906         case GL_IMAGE_1D_ARRAY:
1907         case GL_IMAGE_2D_ARRAY:
1908         case GL_IMAGE_2D_MULTISAMPLE:
1909         case GL_IMAGE_2D_MULTISAMPLE_ARRAY:
1910         case GL_INT_IMAGE_1D:
1911         case GL_INT_IMAGE_2D:
1912         case GL_INT_IMAGE_3D:
1913         case GL_INT_IMAGE_2D_RECT:
1914         case GL_INT_IMAGE_CUBE:
1915         case GL_INT_IMAGE_BUFFER:
1916         case GL_INT_IMAGE_1D_ARRAY:
1917         case GL_INT_IMAGE_2D_ARRAY:
1918         case GL_INT_IMAGE_2D_MULTISAMPLE:
1919         case GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY:
1920         case GL_UNSIGNED_INT_IMAGE_1D:
1921         case GL_UNSIGNED_INT_IMAGE_2D:
1922         case GL_UNSIGNED_INT_IMAGE_3D:
1923         case GL_UNSIGNED_INT_IMAGE_2D_RECT:
1924         case GL_UNSIGNED_INT_IMAGE_CUBE:
1925         case GL_UNSIGNED_INT_IMAGE_BUFFER:
1926         case GL_UNSIGNED_INT_IMAGE_1D_ARRAY:
1927         case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
1928         case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE:
1929         case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY:
1930
1931         case GL_UNSIGNED_INT_ATOMIC_COUNTER:
1932
1933             return 1;
1934
1935         case GL_DOUBLE:
1936         case GL_FLOAT_VEC2:
1937         case GL_INT_VEC2:
1938         case GL_UNSIGNED_INT_VEC2:
1939         case GL_BOOL_VEC2:
1940             return 2;
1941
1942         case GL_FLOAT_VEC3:
1943         case GL_INT_VEC3:
1944         case GL_UNSIGNED_INT_VEC3:
1945         case GL_BOOL_VEC3:
1946             return 3;
1947
1948         case GL_DOUBLE_VEC2:
1949         case GL_FLOAT_VEC4:
1950         case GL_INT_VEC4:
1951         case GL_UNSIGNED_INT_VEC4:
1952         case GL_BOOL_VEC4:
1953         case GL_FLOAT_MAT2:
1954             return 4;
1955
1956         case GL_FLOAT_MAT3:
1957             return 9;
1958
1959         case GL_FLOAT_MAT4:
1960             return 16;
1961
1962         case GL_DOUBLE_VEC3:
1963         case GL_FLOAT_MAT2x3:
1964         case GL_FLOAT_MAT3x2:
1965             return 6;
1966
1967         case GL_DOUBLE_VEC4:
1968         case GL_DOUBLE_MAT2:
1969         case GL_FLOAT_MAT2x4:
1970         case GL_FLOAT_MAT4x2:
1971             return 8;
1972
1973         case GL_DOUBLE_MAT2x3:
1974         case GL_DOUBLE_MAT3x2:
1975         case GL_FLOAT_MAT3x4:
1976         case GL_FLOAT_MAT4x3:
1977             return 12;
1978
1979         case GL_DOUBLE_MAT2x4:
1980         case GL_DOUBLE_MAT4x2:
1981             return 16;
1982
1983         case GL_DOUBLE_MAT3:
1984             return 18;
1985
1986         case GL_DOUBLE_MAT3x4:
1987         case GL_DOUBLE_MAT4x3:
1988             return 24;
1989
1990         case GL_DOUBLE_MAT4:
1991             return 32;
1992
1993         default:
1994         {
1995             VOGL_ASSERT_ALWAYS;
1996             vogl_warning_printf("%s: Unknown uniform type 0x%04X\n", VOGL_FUNCTION_NAME, type);
1997             return 0;
1998         }
1999     }
2000 }
2001
2002 //----------------------------------------------------------------------------------------------------------------------
2003 // vogl_gl_get_uniform_size_in_bytes
2004 //----------------------------------------------------------------------------------------------------------------------
2005 int vogl_gl_get_uniform_size_in_bytes(GLenum type)
2006 {
2007     VOGL_FUNC_TRACER
2008
2009     return vogl_gl_get_uniform_size_in_GLints(type) * sizeof(GLint);
2010 }
2011
2012 //----------------------------------------------------------------------------------------------------------------------
2013 // vogl_gl_get_uniform_base_type
2014 //----------------------------------------------------------------------------------------------------------------------
2015 int vogl_gl_get_uniform_base_type(GLenum type)
2016 {
2017     VOGL_FUNC_TRACER
2018
2019     switch (type)
2020     {
2021         case GL_FLOAT:
2022         case GL_FLOAT_VEC2:
2023         case GL_FLOAT_VEC3:
2024         case GL_FLOAT_VEC4:
2025         case GL_FLOAT_MAT2:
2026         case GL_FLOAT_MAT3:
2027         case GL_FLOAT_MAT4:
2028         case GL_FLOAT_MAT2x3:
2029         case GL_FLOAT_MAT3x2:
2030         case GL_FLOAT_MAT2x4:
2031         case GL_FLOAT_MAT4x2:
2032         case GL_FLOAT_MAT3x4:
2033         case GL_FLOAT_MAT4x3:
2034             return GL_FLOAT;
2035
2036         case GL_DOUBLE:
2037         case GL_DOUBLE_VEC2:
2038         case GL_DOUBLE_VEC3:
2039         case GL_DOUBLE_VEC4:
2040         case GL_DOUBLE_MAT2:
2041         case GL_DOUBLE_MAT3:
2042         case GL_DOUBLE_MAT4:
2043         case GL_DOUBLE_MAT2x3:
2044         case GL_DOUBLE_MAT3x2:
2045         case GL_DOUBLE_MAT2x4:
2046         case GL_DOUBLE_MAT4x2:
2047         case GL_DOUBLE_MAT3x4:
2048         case GL_DOUBLE_MAT4x3:
2049             return GL_DOUBLE;
2050
2051         case GL_INT:
2052         case GL_INT_VEC2:
2053         case GL_INT_VEC3:
2054         case GL_INT_VEC4:
2055             return GL_INT;
2056
2057         case GL_UNSIGNED_INT:
2058         case GL_UNSIGNED_INT_VEC2:
2059         case GL_UNSIGNED_INT_VEC3:
2060         case GL_UNSIGNED_INT_VEC4:
2061         case GL_UNSIGNED_INT_ATOMIC_COUNTER:
2062             return GL_UNSIGNED_INT;
2063
2064         case GL_BOOL:
2065         case GL_BOOL_VEC2:
2066         case GL_BOOL_VEC3:
2067         case GL_BOOL_VEC4:
2068             return GL_BOOL;
2069
2070         case GL_SAMPLER_1D:
2071         case GL_SAMPLER_2D:
2072         case GL_SAMPLER_3D:
2073         case GL_SAMPLER_CUBE:
2074         case GL_SAMPLER_1D_SHADOW:
2075         case GL_SAMPLER_2D_SHADOW:
2076         case GL_SAMPLER_1D_ARRAY:
2077         case GL_SAMPLER_2D_ARRAY:
2078         case GL_SAMPLER_1D_ARRAY_SHADOW:
2079         case GL_SAMPLER_2D_ARRAY_SHADOW:
2080         case GL_SAMPLER_2D_MULTISAMPLE:
2081         case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
2082         case GL_SAMPLER_CUBE_SHADOW:
2083         case GL_SAMPLER_BUFFER:
2084         case GL_SAMPLER_2D_RECT:
2085         case GL_SAMPLER_2D_RECT_SHADOW:
2086         case GL_INT_SAMPLER_1D:
2087         case GL_INT_SAMPLER_2D:
2088         case GL_INT_SAMPLER_3D:
2089         case GL_INT_SAMPLER_CUBE:
2090         case GL_INT_SAMPLER_1D_ARRAY:
2091         case GL_INT_SAMPLER_2D_ARRAY:
2092         case GL_INT_SAMPLER_2D_MULTISAMPLE:
2093         case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
2094         case GL_INT_SAMPLER_BUFFER:
2095         case GL_INT_SAMPLER_2D_RECT:
2096         case GL_UNSIGNED_INT_SAMPLER_1D:
2097         case GL_UNSIGNED_INT_SAMPLER_2D:
2098         case GL_UNSIGNED_INT_SAMPLER_3D:
2099         case GL_UNSIGNED_INT_SAMPLER_CUBE:
2100         case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
2101         case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
2102         case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
2103         case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
2104         case GL_UNSIGNED_INT_SAMPLER_BUFFER:
2105         case GL_UNSIGNED_INT_SAMPLER_2D_RECT:
2106             return GL_SAMPLER;
2107
2108         case GL_IMAGE_1D:
2109         case GL_IMAGE_2D:
2110         case GL_IMAGE_3D:
2111         case GL_IMAGE_2D_RECT:
2112         case GL_IMAGE_CUBE:
2113         case GL_IMAGE_BUFFER:
2114         case GL_IMAGE_1D_ARRAY:
2115         case GL_IMAGE_2D_ARRAY:
2116         case GL_IMAGE_2D_MULTISAMPLE:
2117         case GL_IMAGE_2D_MULTISAMPLE_ARRAY:
2118         case GL_INT_IMAGE_1D:
2119         case GL_INT_IMAGE_2D:
2120         case GL_INT_IMAGE_3D:
2121         case GL_INT_IMAGE_2D_RECT:
2122         case GL_INT_IMAGE_CUBE:
2123         case GL_INT_IMAGE_BUFFER:
2124         case GL_INT_IMAGE_1D_ARRAY:
2125         case GL_INT_IMAGE_2D_ARRAY:
2126         case GL_INT_IMAGE_2D_MULTISAMPLE:
2127         case GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY:
2128         case GL_UNSIGNED_INT_IMAGE_1D:
2129         case GL_UNSIGNED_INT_IMAGE_2D:
2130         case GL_UNSIGNED_INT_IMAGE_3D:
2131         case GL_UNSIGNED_INT_IMAGE_2D_RECT:
2132         case GL_UNSIGNED_INT_IMAGE_CUBE:
2133         case GL_UNSIGNED_INT_IMAGE_BUFFER:
2134         case GL_UNSIGNED_INT_IMAGE_1D_ARRAY:
2135         case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
2136         case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE:
2137         case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY:
2138             return GL_IMAGE_1D; // what do we return??
2139
2140         default:
2141         {
2142             VOGL_ASSERT_ALWAYS;
2143             vogl_warning_printf("%s: Unknown uniform type 0x%04X\n", VOGL_FUNCTION_NAME, type);
2144             return GL_NONE;
2145         }
2146     }
2147 }
2148
2149 //----------------------------------------------------------------------------------------------------------------------
2150 // vogl_format_debug_output_arb
2151 // Loosely derived from http://www.altdevblogaday.com/2011/06/23/improving-opengl-error-messages/
2152 //----------------------------------------------------------------------------------------------------------------------
2153 void vogl_format_debug_output_arb(char out_str[], size_t out_str_size, GLenum source, GLenum type, GLuint id, GLenum severity, const char *msg)
2154 {
2155     VOGL_FUNC_TRACER
2156
2157     char source_str[32];
2158     const char *source_fmt = "UNDEFINED(0x%04X)";
2159
2160     switch (source)
2161     {
2162         case GL_DEBUG_SOURCE_API_ARB:
2163             source_fmt = "API";
2164             break;
2165         case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB:
2166             source_fmt = "WINDOW_SYSTEM";
2167             break;
2168         case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB:
2169             source_fmt = "SHADER_COMPILER";
2170             break;
2171         case GL_DEBUG_SOURCE_THIRD_PARTY_ARB:
2172             source_fmt = "THIRD_PARTY";
2173             break;
2174         case GL_DEBUG_SOURCE_APPLICATION_ARB:
2175             source_fmt = "APPLICATION";
2176             break;
2177         case GL_DEBUG_SOURCE_OTHER_ARB:
2178             source_fmt = "OTHER";
2179             break;
2180         default:
2181             break;
2182     }
2183
2184     vogl_sprintf_s(source_str, sizeof(source_str), source_fmt, source);
2185
2186     char type_str[32];
2187     const char *type_fmt = "UNDEFINED(0x%04X)";
2188     switch (type)
2189     {
2190         case GL_DEBUG_TYPE_ERROR_ARB:
2191             type_fmt = "ERROR";
2192             break;
2193         case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB:
2194             type_fmt = "DEPRECATED_BEHAVIOR";
2195             break;
2196         case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB:
2197             type_fmt = "UNDEFINED_BEHAVIOR";
2198             break;
2199         case GL_DEBUG_TYPE_PORTABILITY_ARB:
2200             type_fmt = "PORTABILITY";
2201             break;
2202         case GL_DEBUG_TYPE_PERFORMANCE_ARB:
2203             type_fmt = "PERFORMANCE";
2204             break;
2205         case GL_DEBUG_TYPE_OTHER_ARB:
2206             type_fmt = "OTHER";
2207             break;
2208         default:
2209             break;
2210     }
2211     vogl_sprintf_s(type_str, sizeof(type_str), type_fmt, type);
2212
2213     char severity_str[32];
2214     const char *severity_fmt = "UNDEFINED";
2215     switch (severity)
2216     {
2217         case GL_DEBUG_SEVERITY_HIGH_ARB:
2218             severity_fmt = "HIGH";
2219             break;
2220         case GL_DEBUG_SEVERITY_MEDIUM_ARB:
2221             severity_fmt = "MEDIUM";
2222             break;
2223         case GL_DEBUG_SEVERITY_LOW_ARB:
2224             severity_fmt = "LOW";
2225             break;
2226         default:
2227             break;
2228     }
2229
2230     vogl_sprintf_s(severity_str, sizeof(severity_str), severity_fmt, severity);
2231
2232     vogl_sprintf_s(out_str, out_str_size, "OpenGL: %s [source=%s type=%s severity=%s id=%d]", msg, source_str, type_str, severity_str, id);
2233 }
2234
2235 //----------------------------------------------------------------------------------------------------------------------
2236 // vogl_generic_arb_debug_callback
2237 //----------------------------------------------------------------------------------------------------------------------
2238 void vogl_generic_arb_debug_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, GLvoid *pUser_param)
2239 {
2240     VOGL_FUNC_TRACER
2241
2242     VOGL_NOTE_UNUSED(length);
2243     VOGL_NOTE_UNUSED(pUser_param);
2244
2245     char final_message[4096];
2246
2247     vogl_format_debug_output_arb(final_message, sizeof(final_message), source, type, id, severity, reinterpret_cast<const char *>(message));
2248
2249     vogl_warning_printf("%s: %s\n", VOGL_FUNCTION_NAME, final_message);
2250 }
2251
2252 //----------------------------------------------------------------------------------------------------------------------
2253 // vogl_enable_generic_context_debug_messages
2254 //----------------------------------------------------------------------------------------------------------------------
2255 void vogl_enable_generic_context_debug_messages()
2256 {
2257     GL_ENTRYPOINT(glDebugMessageCallbackARB)(vogl_generic_arb_debug_callback, NULL);
2258     GL_ENTRYPOINT(glEnable)(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
2259     VOGL_CHECK_GL_ERROR;
2260 }
2261
2262 //----------------------------------------------------------------------------------------------------------------------
2263 // vogl_create_context
2264 //----------------------------------------------------------------------------------------------------------------------
2265 vogl_gl_context vogl_create_context(vogl_gl_display display, vogl_gl_fb_config fb_config, vogl_gl_context share_context, uint major_ver, uint minor_ver, uint flags, vogl_context_desc *pDesc)
2266 {
2267     vogl_context_attribs attribs;
2268     attribs.add_key(GLX_CONTEXT_MAJOR_VERSION_ARB, major_ver);
2269     attribs.add_key(GLX_CONTEXT_MINOR_VERSION_ARB, minor_ver);
2270
2271     if (flags & (cCHCCoreProfileFlag | cCHCCompatProfileFlag))
2272     {
2273         uint profile_mask = 0;
2274         if (flags & cCHCCoreProfileFlag)
2275             profile_mask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
2276
2277         if (flags & cCHCCompatProfileFlag)
2278             profile_mask |= GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
2279
2280         attribs.add_key(GLX_CONTEXT_PROFILE_MASK_ARB, profile_mask);
2281     }
2282     if (flags & eCHCDebugContextFlag)
2283     {
2284         attribs.add_key(GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB);
2285     }
2286
2287     GLXContext context = GL_ENTRYPOINT(glXCreateContextAttribsARB)(display, fb_config, share_context, GL_TRUE, attribs.get_ptr());
2288
2289     if (pDesc)
2290     {
2291         if (!context)
2292             pDesc->clear();
2293         else
2294             pDesc->init(VOGL_ENTRYPOINT_glXCreateContextAttribsARB, GL_TRUE, (vogl_trace_ptr_value)context, (vogl_trace_ptr_value)share_context, attribs);
2295     }
2296
2297     return context;
2298 }
2299
2300 //----------------------------------------------------------------------------------------------------------------------
2301 // vogl_get_current_context
2302 //----------------------------------------------------------------------------------------------------------------------
2303 vogl_gl_context vogl_get_current_context()
2304 {
2305     return GL_ENTRYPOINT(glXGetCurrentContext)();
2306 }
2307
2308 //----------------------------------------------------------------------------------------------------------------------
2309 // vogl_get_current_display
2310 //----------------------------------------------------------------------------------------------------------------------
2311 vogl_gl_display vogl_get_current_display()
2312 {
2313     return GL_ENTRYPOINT(glXGetCurrentDisplay)();
2314 }
2315
2316 //----------------------------------------------------------------------------------------------------------------------
2317 // vogl_get_current_drawable
2318 //----------------------------------------------------------------------------------------------------------------------
2319 vogl_gl_drawable vogl_get_current_drawable()
2320 {
2321     return GL_ENTRYPOINT(glXGetCurrentDrawable)();
2322 }
2323
2324 //----------------------------------------------------------------------------------------------------------------------
2325 // vogl_get_current_fb_config
2326 //----------------------------------------------------------------------------------------------------------------------
2327 vogl_gl_fb_config vogl_get_current_fb_config(uint screen)
2328 {
2329     GLXDrawable pDrawable = GL_ENTRYPOINT(glXGetCurrentDrawable)();
2330     Display *pDisplay = GL_ENTRYPOINT(glXGetCurrentDisplay)();
2331     if ((!pDrawable) || (!pDisplay))
2332         return 0;
2333
2334     GLuint fbconfig_id = 0;
2335     GL_ENTRYPOINT(glXQueryDrawable)(pDisplay, pDrawable, GLX_FBCONFIG_ID, &fbconfig_id);
2336
2337     GLint attrib_list[3] = { GLX_FBCONFIG_ID, static_cast<GLint>(fbconfig_id), None };
2338     GLint nelements = 0;
2339     GLXFBConfig *pConfigs = GL_ENTRYPOINT(glXChooseFBConfig)(pDisplay, screen, attrib_list, &nelements);
2340
2341     if ((pConfigs) && (nelements > 0))
2342         return pConfigs[0];
2343
2344     return 0;
2345 }
2346
2347 //----------------------------------------------------------------------------------------------------------------------
2348 // vogl_make_current
2349 //----------------------------------------------------------------------------------------------------------------------
2350 void vogl_make_current(vogl_gl_display display, vogl_gl_drawable drawable, vogl_gl_context context)
2351 {
2352     GL_ENTRYPOINT(glXMakeCurrent)(display, drawable, context);
2353 }
2354
2355 //----------------------------------------------------------------------------------------------------------------------
2356 // vogl_destroy_context
2357 //----------------------------------------------------------------------------------------------------------------------
2358 void vogl_destroy_context(vogl_gl_display display, vogl_gl_context context)
2359 {
2360     GL_ENTRYPOINT(glXDestroyContext)(display, context);
2361 }
2362
2363 //----------------------------------------------------------------------------------------------------------------------
2364 // vogl_get_max_supported_mip_levels
2365 //----------------------------------------------------------------------------------------------------------------------
2366 int vogl_get_max_supported_mip_levels()
2367 {
2368     int max_texture_size = vogl_get_gl_integer(GL_MAX_TEXTURE_SIZE);
2369     return math::floor_log2i(max_texture_size);
2370 }
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408