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