]> git.cworth.org Git - vogl/blob - src/voglcommon/vogl_texture_format.cpp
Initial vogl checkin
[vogl] / src / voglcommon / vogl_texture_format.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_texture_format.cpp
27 #include "vogl_common.h"
28 #include "vogl_texture_format.h"
29 #include "vogl_ktx_texture.h"
30
31 //----------------------------------------------------------------------------------------------------------------------
32 // Globals
33 //----------------------------------------------------------------------------------------------------------------------
34 vogl_internal_tex_format g_vogl_internal_texture_formats[] =
35     {
36 // TODO: Test ALL of these format mappings on AMD and Intel Mesa.
37 // TODO: This table mapping internal texture formats was composed by calling NVidia's driver.
38 // We should also compose tables for other drivers, and a generic table.
39 #include "vogl_internal_texture_formats.inc"
40     };
41 uint g_vogl_total_internal_texture_formats = VOGL_ARRAY_SIZE(g_vogl_internal_texture_formats);
42
43 typedef vogl::hash_map<GLenum, vogl_internal_tex_format *> vogl_internal_texture_format_hash_map;
44
45 vogl_internal_texture_format_hash_map g_internal_format_hash_map;
46
47 //----------------------------------------------------------------------------------------------------------------------
48 // vogl_devel_dump_internal_texture_formats
49 // This func is only for testing various internal GL format related API's
50 // This func is used to generate vogl_internal_texture_formats.inc
51 //----------------------------------------------------------------------------------------------------------------------
52 void vogl_devel_dump_internal_texture_formats(const vogl_context_info &context_info)
53 {
54     VOGL_FUNC_TRACER
55
56     VOGL_CHECK_GL_ERROR;
57
58     vogl_scoped_binding_state orig_texture;
59     orig_texture.save_textures();
60
61     vogl_scoped_state_saver state_saver(cGSTPixelStore, cGSTPixelTransfer);
62
63     vogl_reset_pixel_store_states();
64     vogl_reset_pixel_transfer_states();
65
66 #if 0
67         // silly experiment
68         {
69                 GLuint handle;
70                 ACTUAL_GL_ENTRYPOINT(glGenTextures)(1, &handle);
71                 VOGL_CHECK_GL_ERROR;
72
73                 ACTUAL_GL_ENTRYPOINT(glBindTexture)(GL_TEXTURE_2D, handle);
74                 VOGL_CHECK_GL_ERROR;
75
76                 for (uint i = 0; i < 256; i++)
77                 {
78                         uint8 vals[4] = { i, 0, 0, 0 };
79                         //ACTUAL_GL_ENTRYPOINT(glTexImage2D)(GL_TEXTURE_2D, 0, GL_R8_SNORM, 1, 1, 0, GL_RED, GL_BYTE, vals);
80
81                         //float vals[1] = { ( i - 128.0f) / 127.0f };
82                         //float vals[1] = { i / 255.0f };
83
84                         //ACTUAL_GL_ENTRYPOINT(glPixelTransferf)(GL_RED_SCALE, .5f);
85                         //ACTUAL_GL_ENTRYPOINT(glPixelTransferf)(GL_RED_BIAS, 0.5f);
86
87                         ACTUAL_GL_ENTRYPOINT(glTexImage2D)(GL_TEXTURE_2D, 0, GL_RGB8UI, 1, 1, 0, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, vals);
88
89                         //ACTUAL_GL_ENTRYPOINT(glPixelTransferf)(GL_RED_SCALE, 1.0f);
90                         //ACTUAL_GL_ENTRYPOINT(glPixelTransferf)(GL_RED_BIAS, 0.0f);
91
92                         VOGL_CHECK_GL_ERROR;
93
94                         uint16 gvals[4] = { 0, 0, 0, 0 };
95                         ACTUAL_GL_ENTRYPOINT(glGetTexImage)(GL_TEXTURE_2D, 0, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, gvals);
96                         VOGL_CHECK_GL_ERROR;
97
98                         printf("%u %u %u %u, %u %u %u %u\n", vals[0], vals[1], vals[2], vals[3],
99                                gvals[0], gvals[1], gvals[2], gvals[3]);
100                 }
101
102
103                 ACTUAL_GL_ENTRYPOINT(glDeleteTextures)(1, &handle);
104         }
105 #endif
106
107     typedef vogl::map<GLenum, vogl_internal_tex_format> tex_format_map;
108     tex_format_map internal_formats;
109
110     // Iterate through the base internal fmts, which need some special handling (argh) because the actual internal fmt != the requested internal fmt
111     GLenum base_internal_formats[] =
112         {
113             GL_DEPTH_COMPONENT,
114             GL_DEPTH_STENCIL,
115             GL_ALPHA,
116             GL_RED,
117             GL_RG,
118             GL_RGB,
119             GL_RGBA,
120             GL_LUMINANCE,
121             GL_LUMINANCE_ALPHA,
122             GL_INTENSITY,
123             GL_SLUMINANCE,
124             GL_SLUMINANCE_ALPHA,
125             GL_SRGB,
126             GL_SRGB_ALPHA
127         };
128
129     for (uint i = 0; i < VOGL_ARRAY_SIZE(base_internal_formats); i++)
130     {
131         printf("%s\n", g_gl_enums.find_gl_name(base_internal_formats[i]));
132
133         GLuint handle;
134         GL_ENTRYPOINT(glGenTextures)(1, &handle);
135         VOGL_CHECK_GL_ERROR;
136
137         GLenum target = GL_TEXTURE_2D;
138
139         GL_ENTRYPOINT(glBindTexture)(target, handle);
140
141         GLenum base_internal_fmt = base_internal_formats[i];
142
143         vogl_internal_tex_format f;
144         GL_ENTRYPOINT(glGetInternalformativ)(target, base_internal_fmt, GL_GET_TEXTURE_IMAGE_TYPE, sizeof(f.m_optimum_get_image_type), (GLint *)&f.m_optimum_get_image_type);
145         GL_ENTRYPOINT(glGetInternalformativ)(target, base_internal_fmt, GL_GET_TEXTURE_IMAGE_FORMAT, sizeof(f.m_optimum_get_image_fmt), (GLint *)&f.m_optimum_get_image_fmt);
146         VOGL_CHECK_GL_ERROR;
147
148         GLenum &get_fmt = f.m_optimum_get_image_fmt;
149         GLenum &get_type = f.m_optimum_get_image_type;
150
151         // manual fixups, ARGH
152         switch (base_internal_fmt)
153         {
154             case GL_DEPTH_COMPONENT:
155             {
156                 get_fmt = GL_DEPTH_COMPONENT;
157                 get_type = GL_FLOAT;
158                 break;
159             }
160             case GL_RG:
161             {
162                 get_fmt = GL_RG;
163                 get_type = GL_UNSIGNED_BYTE;
164                 break;
165             }
166             case GL_RGB:
167             {
168                 get_fmt = GL_RGB;
169                 get_type = GL_UNSIGNED_BYTE;
170                 break;
171             }
172             case GL_RED:
173             {
174                 get_fmt = GL_RED;
175                 get_type = GL_UNSIGNED_BYTE;
176                 break;
177             }
178             case GL_COMPRESSED_LUMINANCE:
179             {
180                 get_fmt = GL_LUMINANCE;
181                 get_type = GL_UNSIGNED_BYTE;
182                 break;
183             }
184             case GL_COMPRESSED_LUMINANCE_ALPHA:
185             {
186                 get_fmt = GL_LUMINANCE_ALPHA;
187                 get_type = GL_UNSIGNED_BYTE;
188                 break;
189             }
190             case GL_COMPRESSED_RGB:
191             {
192                 get_fmt = GL_RGBA;
193                 get_type = GL_UNSIGNED_BYTE;
194                 break;
195             }
196             case GL_COMPRESSED_RGBA:
197             {
198                 get_fmt = GL_RGBA;
199                 get_type = GL_UNSIGNED_BYTE;
200                 break;
201             }
202             case GL_LUMINANCE_ALPHA:
203             {
204                 get_fmt = GL_LUMINANCE_ALPHA;
205                 get_type = GL_UNSIGNED_BYTE;
206                 break;
207             }
208             case GL_SLUMINANCE_ALPHA:
209             {
210                 get_fmt = GL_LUMINANCE_ALPHA;
211                 get_type = GL_UNSIGNED_BYTE;
212                 break;
213             }
214             case GL_SRGB:
215             {
216                 get_fmt = GL_RGB;
217                 get_type = GL_UNSIGNED_BYTE;
218                 break;
219             }
220             case GL_SRGB_ALPHA:
221             {
222                 get_fmt = GL_RGBA;
223                 get_type = GL_UNSIGNED_BYTE;
224                 break;
225             }
226             default:
227             {
228                 break;
229             }
230         }
231
232         VOGL_VERIFY(get_fmt != GL_NONE);
233         VOGL_VERIFY(get_type != GL_NONE);
234
235         GL_ENTRYPOINT(glTexImage2D)(target, 0, base_internal_fmt, 32, 32, 0, get_fmt, get_type, NULL);
236         VOGL_VERIFY(!vogl_check_gl_error());
237
238 //bool any_gl_errors = false;
239
240 #define GET_INT(dst, gl_enum)                                                  \
241     do                                                                         \
242     {                                                                          \
243         int values[4];                                                         \
244         utils::zero_object(values);                                            \
245         GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, 0, (gl_enum), values); \
246         (dst) = values[0];                                                     \
247     } while (0)
248         GLenum actual_internal_fmt;
249         GET_INT(actual_internal_fmt, GL_TEXTURE_INTERNAL_FORMAT);
250
251         f.m_tex_image_flags = ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4));
252         f.m_fmt = base_internal_fmt;
253         f.m_actual_internal_fmt = actual_internal_fmt;
254         f.m_name = g_gl_enums.find_name(base_internal_fmt, "gl");
255
256         GET_INT(f.m_comp_sizes[cTCRed], GL_TEXTURE_RED_SIZE);
257         GET_INT(f.m_comp_sizes[cTCGreen], GL_TEXTURE_GREEN_SIZE);
258         GET_INT(f.m_comp_sizes[cTCBlue], GL_TEXTURE_BLUE_SIZE);
259         GET_INT(f.m_comp_sizes[cTCAlpha], GL_TEXTURE_ALPHA_SIZE);
260         GET_INT(f.m_comp_sizes[cTCStencil], GL_TEXTURE_STENCIL_SIZE);
261         GET_INT(f.m_comp_sizes[cTCDepth], GL_TEXTURE_DEPTH_SIZE);
262         GET_INT(f.m_comp_sizes[cTCIntensity], GL_TEXTURE_INTENSITY_SIZE);
263         GET_INT(f.m_comp_sizes[cTCLuminance], GL_TEXTURE_LUMINANCE_SIZE);
264
265         GET_INT(f.m_comp_types[cTCRed], GL_TEXTURE_RED_TYPE);
266         GET_INT(f.m_comp_types[cTCGreen], GL_TEXTURE_GREEN_TYPE);
267         GET_INT(f.m_comp_types[cTCBlue], GL_TEXTURE_BLUE_TYPE);
268         GET_INT(f.m_comp_types[cTCAlpha], GL_TEXTURE_ALPHA_TYPE);
269         GET_INT(f.m_comp_types[cTCDepth], GL_TEXTURE_DEPTH_TYPE);
270         GET_INT(f.m_comp_types[cTCIntensity], GL_TEXTURE_INTENSITY_TYPE);
271         GET_INT(f.m_comp_types[cTCLuminance], GL_TEXTURE_LUMINANCE_TYPE);
272
273         GET_INT(f.m_shared_size, GL_TEXTURE_SHARED_SIZE);
274         GET_INT(f.m_compressed, GL_TEXTURE_COMPRESSED);
275
276         printf("base_internal_fmt: %s get_fmt: %s get_type: %s, actual_internal_fmt: %s compressed: %u\n",
277                g_gl_enums.find_gl_name(base_internal_fmt), g_gl_enums.find_gl_name(get_fmt), g_gl_enums.find_gl_name(get_type),
278                g_gl_enums.find_gl_name(actual_internal_fmt),
279                f.m_compressed);
280 #undef GET_INT
281
282         //VOGL_ASSERT(!any_gl_errors);
283
284         VOGL_ASSERT(f.m_actual_internal_fmt != GL_NONE);
285         VOGL_ASSERT(f.m_optimum_get_image_fmt != GL_NONE);
286         VOGL_ASSERT(f.m_optimum_get_image_type != GL_NONE);
287
288         VOGL_ASSERT(!f.m_compressed);
289         VOGL_ASSERT(!ktx_is_compressed_ogl_fmt(f.m_fmt) && !ktx_is_compressed_ogl_fmt(f.m_actual_internal_fmt));
290         VOGL_ASSERT(ktx_get_ogl_compressed_base_internal_fmt(f.m_fmt) == 0 && ktx_get_ogl_compressed_base_internal_fmt(f.m_actual_internal_fmt) == 0);
291
292         if (!internal_formats.insert(base_internal_fmt, f).second)
293         {
294             internal_formats.find_value(base_internal_fmt)->m_tex_image_flags |= ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4));
295         }
296
297         GL_ENTRYPOINT(glBindTexture)(target, 0);
298         VOGL_CHECK_GL_ERROR;
299
300         GL_ENTRYPOINT(glDeleteTextures)(1, &handle);
301         VOGL_CHECK_GL_ERROR;
302     }
303
304     for (uint t = 0; t < 5; t++)
305     {
306         GLenum target = GL_NONE;
307         switch (t)
308         {
309             case 0:
310             {
311                 target = GL_TEXTURE_1D;
312                 break;
313             }
314             case 1:
315             {
316                 target = GL_TEXTURE_2D;
317                 break;
318             }
319             case 2:
320             {
321                 target = GL_TEXTURE_3D;
322                 break;
323             }
324             case 3:
325             {
326                 target = GL_TEXTURE_2D_MULTISAMPLE;
327                 break;
328             }
329             case 4:
330             {
331                 target = GL_TEXTURE_2D_MULTISAMPLE_ARRAY;
332                 break;
333             }
334             default:
335             {
336                 VOGL_ASSERT_ALWAYS;
337                 break;
338             }
339         }
340
341         for (uint fmt = 0; fmt <= 0xFFFF; fmt++)
342         {
343             GLuint handle;
344             GL_ENTRYPOINT(glGenTextures)(1, &handle);
345             VOGL_CHECK_GL_ERROR;
346
347             GL_ENTRYPOINT(glBindTexture)(target, handle);
348
349             vogl_debug_message_control(context_info, GL_INVALID_ENUM, false);
350             vogl_debug_message_control(context_info, GL_INVALID_OPERATION, false);
351
352             bool failed = false;
353
354             switch (t)
355             {
356                 case 0:
357                 {
358                     GL_ENTRYPOINT(glTexStorage1D)(target, 1, fmt, 32);
359                     failed = vogl_check_gl_error_suppress_message();
360                     break;
361                 }
362                 case 1:
363                 {
364                     GL_ENTRYPOINT(glTexStorage2D)(target, 1, fmt, 32, 32);
365                     failed = vogl_check_gl_error_suppress_message();
366                     break;
367                 }
368                 case 2:
369                 {
370                     GL_ENTRYPOINT(glTexStorage3D)(target, 1, fmt, 32, 32, 32);
371                     failed = vogl_check_gl_error_suppress_message();
372                     break;
373                 }
374                 case 3:
375                 {
376                     GL_ENTRYPOINT(glTexStorage2DMultisample)(target, 2, fmt, 32, 32, GL_TRUE);
377                     failed = vogl_check_gl_error_suppress_message();
378                     break;
379                 }
380                 case 4:
381                 {
382                     GL_ENTRYPOINT(glTexStorage3DMultisample)(target, 2, fmt, 32, 32, 2, GL_TRUE);
383                     failed = vogl_check_gl_error_suppress_message();
384                     break;
385                 }
386             }
387
388             vogl_debug_message_control(context_info, GL_INVALID_ENUM, true);
389             vogl_debug_message_control(context_info, GL_INVALID_OPERATION, true);
390
391             if (failed)
392                 continue;
393
394             bool any_gl_errors = false;
395             VOGL_NOTE_UNUSED(any_gl_errors);
396
397             vogl_internal_tex_format f;
398             f.m_tex_image_flags = (1 << t);
399             f.m_fmt = fmt;
400             f.m_actual_internal_fmt = fmt; // this assumes the actual internal fmt will match here!
401             f.m_name = g_gl_enums.find_name(fmt, "gl");
402
403 #define GET_INT(dst, gl_enum)                                                  \
404     do                                                                         \
405     {                                                                          \
406         int values[4];                                                         \
407         utils::zero_object(values);                                            \
408         GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, 0, (gl_enum), values); \
409         (dst) = values[0];                                                     \
410     } while (0)
411
412             GLenum internal_fmt;
413             GET_INT(internal_fmt, GL_TEXTURE_INTERNAL_FORMAT);
414             VOGL_ASSERT(internal_fmt == fmt);
415             GET_INT(f.m_comp_sizes[cTCRed], GL_TEXTURE_RED_SIZE);
416             GET_INT(f.m_comp_sizes[cTCGreen], GL_TEXTURE_GREEN_SIZE);
417             GET_INT(f.m_comp_sizes[cTCBlue], GL_TEXTURE_BLUE_SIZE);
418             GET_INT(f.m_comp_sizes[cTCAlpha], GL_TEXTURE_ALPHA_SIZE);
419             GET_INT(f.m_comp_sizes[cTCStencil], GL_TEXTURE_STENCIL_SIZE);
420             GET_INT(f.m_comp_sizes[cTCDepth], GL_TEXTURE_DEPTH_SIZE);
421             GET_INT(f.m_comp_sizes[cTCIntensity], GL_TEXTURE_INTENSITY_SIZE);
422             GET_INT(f.m_comp_sizes[cTCLuminance], GL_TEXTURE_LUMINANCE_SIZE);
423
424             GET_INT(f.m_comp_types[cTCRed], GL_TEXTURE_RED_TYPE);
425             GET_INT(f.m_comp_types[cTCGreen], GL_TEXTURE_GREEN_TYPE);
426             GET_INT(f.m_comp_types[cTCBlue], GL_TEXTURE_BLUE_TYPE);
427             GET_INT(f.m_comp_types[cTCAlpha], GL_TEXTURE_ALPHA_TYPE);
428             GET_INT(f.m_comp_types[cTCDepth], GL_TEXTURE_DEPTH_TYPE);
429             GET_INT(f.m_comp_types[cTCIntensity], GL_TEXTURE_INTENSITY_TYPE);
430             GET_INT(f.m_comp_types[cTCLuminance], GL_TEXTURE_LUMINANCE_TYPE);
431
432             GET_INT(f.m_shared_size, GL_TEXTURE_SHARED_SIZE);
433             GET_INT(f.m_compressed, GL_TEXTURE_COMPRESSED);
434 #undef GET_INT
435
436             VOGL_ASSERT(!any_gl_errors);
437
438             GL_ENTRYPOINT(glGetInternalformativ)(target, fmt, GL_GET_TEXTURE_IMAGE_TYPE, sizeof(f.m_optimum_get_image_type), (GLint *)&f.m_optimum_get_image_type);
439             GL_ENTRYPOINT(glGetInternalformativ)(target, fmt, GL_GET_TEXTURE_IMAGE_FORMAT, sizeof(f.m_optimum_get_image_fmt), (GLint *)&f.m_optimum_get_image_fmt);
440             VOGL_CHECK_GL_ERROR;
441
442             if (f.m_compressed)
443             {
444                 f.m_optimum_get_image_fmt = GL_RGBA;
445                 f.m_optimum_get_image_type = GL_UNSIGNED_BYTE;
446             }
447             else
448             {
449 #define HANDLE_FMT(gl_enum, fmt, type)     \
450     case gl_enum:                          \
451     {                                      \
452         f.m_optimum_get_image_fmt = fmt;   \
453         f.m_optimum_get_image_type = type; \
454         break;                             \
455     }
456                 bool unhandled = false;
457                 switch (fmt)
458                 {
459                     HANDLE_FMT(GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV);
460                     HANDLE_FMT(GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV);
461                     HANDLE_FMT(GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT);
462                     HANDLE_FMT(GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT);
463                     HANDLE_FMT(GL_INTENSITY32F_ARB, GL_RED, GL_FLOAT);
464
465                     HANDLE_FMT(2, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE);
466                     HANDLE_FMT(3, GL_RGB, GL_UNSIGNED_BYTE);
467                     HANDLE_FMT(GL_LUMINANCE4_ALPHA4, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE);
468                     HANDLE_FMT(GL_LUMINANCE6_ALPHA2, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE);
469                     HANDLE_FMT(GL_LUMINANCE8_ALPHA8, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE);
470                     HANDLE_FMT(GL_LUMINANCE12_ALPHA4, GL_LUMINANCE_ALPHA, GL_UNSIGNED_SHORT);
471                     HANDLE_FMT(GL_LUMINANCE12_ALPHA12, GL_LUMINANCE_ALPHA, GL_UNSIGNED_SHORT);
472                     HANDLE_FMT(GL_LUMINANCE16_ALPHA16, GL_LUMINANCE_ALPHA, GL_UNSIGNED_SHORT);
473
474                     HANDLE_FMT(GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE);
475                     HANDLE_FMT(GL_RGB8I, GL_RGB_INTEGER, GL_BYTE);
476                     HANDLE_FMT(GL_RGB10, GL_RGB, GL_UNSIGNED_SHORT);
477                     HANDLE_FMT(GL_RGB12, GL_RGB, GL_UNSIGNED_SHORT);
478                     HANDLE_FMT(GL_RGB16, GL_RGB, GL_UNSIGNED_SHORT);
479                     HANDLE_FMT(GL_RGBA12, GL_RGB, GL_UNSIGNED_SHORT);
480                     HANDLE_FMT(GL_RG8, GL_RG, GL_UNSIGNED_BYTE);
481                     HANDLE_FMT(GL_RG16, GL_RG, GL_UNSIGNED_SHORT);
482                     HANDLE_FMT(GL_RG16F, GL_RG, GL_HALF_FLOAT);
483                     HANDLE_FMT(GL_RG32F, GL_RG, GL_FLOAT);
484
485                     HANDLE_FMT(GL_SRGB8, GL_RGB, GL_UNSIGNED_BYTE);
486                     HANDLE_FMT(GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE);
487                     HANDLE_FMT(GL_SLUMINANCE8_ALPHA8, GL_LUMINANCE_ALPHA, GL_BYTE);
488
489                     HANDLE_FMT(GL_RGB32I, GL_RGB_INTEGER, GL_INT);
490                     HANDLE_FMT(GL_RGB16I, GL_RGB_INTEGER, GL_SHORT);
491
492                     HANDLE_FMT(GL_RGB32UI, GL_RGB_INTEGER, GL_UNSIGNED_INT);
493                     HANDLE_FMT(GL_RGB16UI, GL_RGB_INTEGER, GL_UNSIGNED_SHORT);
494                     HANDLE_FMT(GL_RGB8UI, GL_RGB_INTEGER, GL_UNSIGNED_INT);
495                     HANDLE_FMT(GL_SIGNED_RGBA8_NV, GL_RGBA, GL_BYTE);
496                     HANDLE_FMT(GL_SIGNED_RGB8_NV, GL_RGB, GL_BYTE);
497                     HANDLE_FMT(GL_SIGNED_LUMINANCE8_ALPHA8_NV, GL_LUMINANCE_ALPHA, GL_BYTE);
498                     HANDLE_FMT(GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV, GL_RGBA, GL_BYTE);
499                     HANDLE_FMT(GL_RG8_SNORM, GL_RG, GL_BYTE);
500                     HANDLE_FMT(GL_RGB8_SNORM, GL_RGB, GL_BYTE);
501                     HANDLE_FMT(GL_RG16_SNORM, GL_RG, GL_SHORT);
502                     HANDLE_FMT(GL_RGB16_SNORM, GL_RGB, GL_SHORT);
503
504                     HANDLE_FMT(GL_RGB32F, GL_RGB, GL_FLOAT);
505                     HANDLE_FMT(GL_RGB16F, GL_RGB, GL_HALF_FLOAT);
506
507                     // TODO: Research oddball formats
508                     HANDLE_FMT(GL_PALETTE4_RGB8_OES, GL_RGB, GL_UNSIGNED_BYTE);
509                     HANDLE_FMT(GL_PALETTE4_R5_G6_B5_OES, GL_RGB, GL_UNSIGNED_BYTE);
510                     HANDLE_FMT(GL_PALETTE8_RGB8_OES, GL_RGB, GL_UNSIGNED_BYTE);
511                     HANDLE_FMT(GL_PALETTE8_R5_G6_B5_OES, GL_RGB, GL_UNSIGNED_BYTE);
512
513                     HANDLE_FMT(GL_HILO16_NV, GL_NONE, GL_NONE);
514                     HANDLE_FMT(GL_SIGNED_HILO16_NV, GL_NONE, GL_NONE);
515                     HANDLE_FMT(GL_DSDT8_MAG8_INTENSITY8_NV, GL_NONE, GL_NONE);
516                     HANDLE_FMT(GL_HILO8_NV, GL_NONE, GL_NONE);
517                     HANDLE_FMT(GL_SIGNED_HILO8_NV, GL_NONE, GL_NONE);
518                     HANDLE_FMT(GL_DSDT8_NV, GL_NONE, GL_NONE);
519                     HANDLE_FMT(GL_DSDT8_MAG8_NV, GL_NONE, GL_NONE);
520
521                     default:
522                         unhandled = true;
523                         break;
524                 }
525
526                 if ((unhandled) && ((f.m_optimum_get_image_fmt == GL_NONE) || (f.m_optimum_get_image_type == GL_NONE)))
527                 {
528                     printf("INVALID: %s %s %s\n", f.m_name.get_ptr(), g_gl_enums.find_name(f.m_optimum_get_image_fmt, "gl"), g_gl_enums.find_name(f.m_optimum_get_image_type, "gl"));
529                 }
530             }
531
532 #undef HANDLE_FMT
533
534             VOGL_ASSERT(f.m_actual_internal_fmt != GL_NONE);
535
536             if ((f.m_optimum_get_image_fmt == GL_NONE) || (f.m_optimum_get_image_type == GL_NONE))
537                 vogl_warning_printf("%s: Don't have an optimal get format/type for internal format %s\n", VOGL_FUNCTION_NAME, g_gl_enums.find_gl_name(fmt));
538
539             VOGL_ASSERT(fmt != GL_LUMINANCE);
540
541             VOGL_ASSERT(f.m_fmt == f.m_actual_internal_fmt);
542             if (!f.m_compressed)
543             {
544                 VOGL_ASSERT(!ktx_is_compressed_ogl_fmt(f.m_fmt) && !ktx_is_compressed_ogl_fmt(f.m_actual_internal_fmt));
545                 VOGL_ASSERT(ktx_get_ogl_compressed_base_internal_fmt(f.m_fmt) == 0 && ktx_get_ogl_compressed_base_internal_fmt(f.m_actual_internal_fmt) == 0);
546             }
547             else
548             {
549                 VOGL_ASSERT(ktx_is_compressed_ogl_fmt(f.m_actual_internal_fmt));
550                 VOGL_ASSERT(ktx_get_ogl_compressed_base_internal_fmt(f.m_actual_internal_fmt) != 0);
551             }
552
553             if (!internal_formats.insert(fmt, f).second)
554             {
555                 internal_formats.find_value(fmt)->m_tex_image_flags |= (1 << t);
556             }
557
558             GL_ENTRYPOINT(glBindTexture)(target, 0);
559             VOGL_CHECK_GL_ERROR;
560
561             GL_ENTRYPOINT(glDeleteTextures)(1, &handle);
562             VOGL_CHECK_GL_ERROR;
563         }
564     }
565
566     const char *pOutput_filename = "internal_texture_formats.inc";
567     FILE *pFile = vogl_fopen(pOutput_filename, "w");
568     VOGL_VERIFY(pFile);
569     if (!pFile)
570         return;
571
572     for (tex_format_map::const_iterator it = internal_formats.begin(); it != internal_formats.end(); ++it)
573     {
574         vogl_internal_tex_format fmt(it->second);
575
576         uint actual_size = 0;
577
578         if (!fmt.m_compressed)
579         {
580             VOGL_ASSERT(!ktx_is_compressed_ogl_fmt(fmt.m_fmt));
581             VOGL_ASSERT(ktx_get_ogl_compressed_base_internal_fmt(fmt.m_fmt) == 0);
582         }
583         else
584         {
585             VOGL_ASSERT(ktx_is_compressed_ogl_fmt(fmt.m_fmt));
586             VOGL_ASSERT(ktx_get_ogl_compressed_base_internal_fmt(fmt.m_fmt) != 0);
587         }
588
589         if ((!fmt.m_compressed) && (fmt.m_optimum_get_image_fmt != GL_NONE) && (fmt.m_optimum_get_image_type != GL_NONE))
590         {
591             GLuint handle;
592             GL_ENTRYPOINT(glGenTextures)(1, &handle);
593             VOGL_CHECK_GL_ERROR;
594
595             GL_ENTRYPOINT(glBindTexture)(GL_TEXTURE_2D, handle);
596             VOGL_CHECK_GL_ERROR;
597
598             uint8 vals[128];
599             utils::zero_object(vals);
600             vals[1] = 64;
601             GL_ENTRYPOINT(glTexImage2D)(GL_TEXTURE_2D, 0, fmt.m_fmt, 1, 1, 0, fmt.m_optimum_get_image_fmt, fmt.m_optimum_get_image_type, vals);
602             if (vogl_check_gl_error())
603             {
604                 printf("glTexImage2D FAILED: %s %s %s\n", fmt.m_name.get_ptr(), g_gl_enums.find_name(fmt.m_optimum_get_image_fmt, "gl"), g_gl_enums.find_name(fmt.m_optimum_get_image_type, "gl"));
605             }
606
607             uint8 gvals[128];
608             memset(gvals, 0xCD, sizeof(gvals));
609             GL_ENTRYPOINT(glGetTexImage)(GL_TEXTURE_2D, 0, fmt.m_optimum_get_image_fmt, fmt.m_optimum_get_image_type, gvals);
610
611             uint actual_size0 = 0;
612             for (actual_size0 = 0; actual_size0 < sizeof(gvals); actual_size0++)
613                 if (gvals[actual_size0] == 0xCD)
614                     break;
615
616             memset(gvals, 0x12, sizeof(gvals));
617             GL_ENTRYPOINT(glGetTexImage)(GL_TEXTURE_2D, 0, fmt.m_optimum_get_image_fmt, fmt.m_optimum_get_image_type, gvals);
618
619             uint actual_size1 = 0;
620             for (actual_size1 = 0; actual_size1 < sizeof(gvals); actual_size1++)
621                 if (gvals[actual_size1] == 0x12)
622                     break;
623
624             VOGL_VERIFY(actual_size0 == actual_size1);
625
626             //printf("glGetTexImage() wrote %u bytes\n", actual_size0);
627
628             if (vogl_check_gl_error()) // || gvals[1] != vals[1])
629             {
630                 printf("glGetTexImage() failed: %s %s %s\n", fmt.m_name.get_ptr(), g_gl_enums.find_name(fmt.m_optimum_get_image_fmt, "gl"), g_gl_enums.find_name(fmt.m_optimum_get_image_type, "gl"));
631             }
632
633             GL_ENTRYPOINT(glBindTexture)(GL_TEXTURE_2D, 0);
634             VOGL_CHECK_GL_ERROR;
635
636             GL_ENTRYPOINT(glDeleteTextures)(1, &handle);
637
638             actual_size = actual_size0;
639
640             uint s = vogl_get_image_format_size_in_bytes(fmt.m_optimum_get_image_fmt, fmt.m_optimum_get_image_type);
641             VOGL_VERIFY(s);
642             if (s != actual_size0)
643             {
644                 VOGL_VERIFY(0);
645             }
646
647             vogl::ktx_texture ktx_tex;
648             GLenum img_fmt;
649             GLenum img_type;
650             img_fmt = fmt.m_optimum_get_image_fmt;
651             img_type = fmt.m_optimum_get_image_type;
652
653             uint block_dim, bytes_per_block;
654             bool success = ktx_get_ogl_fmt_desc(img_fmt, img_type, block_dim, bytes_per_block);
655             VOGL_VERIFY(success);
656             VOGL_VERIFY(block_dim == 1);
657             VOGL_VERIFY(bytes_per_block == actual_size);
658
659             if (!ktx_tex.init_2D(1, 1, 1, fmt.m_fmt, img_fmt, img_type))
660             {
661                 printf("ktx_texture::init_2D() failed: %s %s %s\n", fmt.m_name.get_ptr(), g_gl_enums.find_name(fmt.m_optimum_get_image_fmt, "gl"), g_gl_enums.find_name(fmt.m_optimum_get_image_type, "gl"));
662             }
663         }
664         else if (fmt.m_compressed)
665         {
666             GLuint handle;
667             GL_ENTRYPOINT(glGenTextures)(1, &handle);
668             VOGL_CHECK_GL_ERROR;
669
670             GL_ENTRYPOINT(glBindTexture)(GL_TEXTURE_2D, handle);
671             VOGL_CHECK_GL_ERROR;
672
673             GL_ENTRYPOINT(glTexStorage2D)(GL_TEXTURE_2D, 1, fmt.m_fmt, 1, 1);
674             VOGL_CHECK_GL_ERROR;
675
676             GL_ENTRYPOINT(glGetTexLevelParameteriv)(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, (GLint *)&actual_size);
677             VOGL_CHECK_GL_ERROR;
678
679             GL_ENTRYPOINT(glBindTexture)(GL_TEXTURE_2D, 0);
680             VOGL_CHECK_GL_ERROR;
681
682             GL_ENTRYPOINT(glDeleteTextures)(1, &handle);
683             VOGL_CHECK_GL_ERROR;
684
685             uint block_width = 0, block_height = 0, block_size = 0;
686             GL_ENTRYPOINT(glGetInternalformativ)(GL_TEXTURE_2D, fmt.m_fmt, GL_TEXTURE_COMPRESSED_BLOCK_WIDTH, sizeof(int), reinterpret_cast<GLint *>(&block_width));
687             GL_ENTRYPOINT(glGetInternalformativ)(GL_TEXTURE_2D, fmt.m_fmt, GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT, sizeof(int), reinterpret_cast<GLint *>(&block_height));
688             GL_ENTRYPOINT(glGetInternalformativ)(GL_TEXTURE_2D, fmt.m_fmt, GL_TEXTURE_COMPRESSED_BLOCK_SIZE, sizeof(int), reinterpret_cast<GLint *>(&block_size));
689             VOGL_CHECK_GL_ERROR;
690
691             if (block_size == actual_size * 8U)
692                 block_size /= 8;
693
694             uint block_dim, bytes_per_block;
695             bool success = ktx_get_ogl_fmt_desc(fmt.m_fmt, GL_UNSIGNED_BYTE, block_dim, bytes_per_block);
696             if ((!success) || (block_dim != block_width) || (block_dim != block_height) || (bytes_per_block != actual_size) || (bytes_per_block != block_size))
697             {
698                 printf("ktx_get_ogl_fmt_desc on compressed format failed: %s %s %s %u %i %i %i\n", fmt.m_name.get_ptr(), g_gl_enums.find_name(fmt.m_optimum_get_image_fmt, "gl"), g_gl_enums.find_name(fmt.m_optimum_get_image_type, "gl"), actual_size, block_width, block_height, block_size);
699             }
700
701             fmt.m_block_width = block_width;
702             fmt.m_block_height = block_height;
703
704             vogl::ktx_texture ktx_tex;
705             if (!ktx_tex.init_2D(1, 1, 1, fmt.m_fmt, GL_NONE, GL_NONE))
706             {
707                 printf("ktx_texture::init_2D() compressed failed: %s %s %s\n", fmt.m_name.get_ptr(), g_gl_enums.find_name(fmt.m_optimum_get_image_fmt, "gl"), g_gl_enums.find_name(fmt.m_optimum_get_image_type, "gl"));
708             }
709         }
710
711         fmt.m_image_bytes_per_pixel_or_block = actual_size;
712
713         fprintf(pFile, "   vogl_internal_tex_format(0x%04X, \"%s\", 0x%04X,\n", fmt.m_fmt, fmt.m_name.get_ptr(), fmt.m_actual_internal_fmt);
714
715         fprintf(pFile, "      ");
716         for (uint i = 0; i < cTCTotalComponents; i++)
717             fprintf(pFile, "%u, ", fmt.m_comp_sizes[i]);
718         fprintf(pFile, "\n");
719
720         fprintf(pFile, "      ");
721         for (uint i = 0; i < cTCTotalComponents; i++)
722             fprintf(pFile, "%s, ", g_gl_enums.find_name(fmt.m_comp_types[i], "gl"));
723         fprintf(pFile, "\n");
724
725         fprintf(pFile, "      %u, 0x%02X, %u, \n", fmt.m_shared_size, fmt.m_tex_image_flags, fmt.m_compressed);
726         fprintf(pFile, "      %s, %s, %u, %u, %u),\n",
727                 g_gl_enums.find_name(fmt.m_optimum_get_image_fmt, "gl"),
728                 g_gl_enums.find_name(fmt.m_optimum_get_image_type, "gl"),
729                 fmt.m_image_bytes_per_pixel_or_block,
730                 fmt.m_block_width, fmt.m_block_height);
731
732 #if 0
733                 uint q;
734                 for (q = 0; q < g_vogl_total_internal_texture_formats; q++)
735                 {
736                         if (g_vogl_internal_texture_formats[q].m_fmt == fmt.m_fmt)
737                         {
738                                 if (!g_vogl_internal_texture_formats[q].compare(fmt))
739                                 {
740                                         VOGL_ASSERT_ALWAYS;
741                                 }
742                                 break;
743                         }
744                 }
745                 if (q == g_vogl_total_internal_texture_formats)
746                 {
747                         VOGL_ASSERT_ALWAYS;
748                 }
749 #endif
750     }
751
752     vogl_fclose(pFile);
753
754     printf("Wrote file %s\n", pOutput_filename);
755 }
756
757 //----------------------------------------------------------------------------------------------------------------------
758 // vogl_internal_tex_format::vogl_internal_tex_format
759 //----------------------------------------------------------------------------------------------------------------------
760 vogl_internal_tex_format::vogl_internal_tex_format(
761     GLenum fmt, const char *pName, GLenum actual_fmt,
762     int s0, int s1, int s2, int s3, int s4, int s5, int s6, int s7,
763     GLenum t0, GLenum t1, GLenum t2, GLenum t3, GLenum t4, GLenum t5, GLenum t6, GLenum t7,
764     int shared_size, int tex_storage_type_flags, bool compressed, GLenum optimum_get_fmt, GLenum optimum_get_type,
765     uint image_bytes_per_pixel_or_block, uint block_width, uint block_height)
766 {
767     VOGL_FUNC_TRACER
768
769     //VOGL_VERIFY(optimum_get_fmt != GL_NONE);
770     //VOGL_VERIFY(optimum_get_type != GL_NONE);
771
772     m_fmt = fmt;
773     m_name = pName;
774     m_actual_internal_fmt = actual_fmt;
775     m_comp_sizes[0] = s0;
776     m_comp_sizes[1] = s1;
777     m_comp_sizes[2] = s2;
778     m_comp_sizes[3] = s3;
779     m_comp_sizes[4] = s4;
780     m_comp_sizes[5] = s5;
781     m_comp_sizes[6] = s6;
782     m_comp_sizes[7] = s7;
783     m_comp_types[0] = t0;
784     m_comp_types[1] = t1;
785     m_comp_types[2] = t2;
786     m_comp_types[3] = t3;
787     m_comp_types[4] = t4;
788     m_comp_types[5] = t5;
789     m_comp_types[6] = t6;
790     m_comp_types[7] = t7;
791     m_shared_size = shared_size;
792     m_tex_image_flags = tex_storage_type_flags;
793     m_compressed = compressed;
794     m_optimum_get_image_fmt = optimum_get_fmt;
795     m_optimum_get_image_type = optimum_get_type;
796     m_image_bytes_per_pixel_or_block = image_bytes_per_pixel_or_block;
797     m_block_width = block_width;
798     m_block_height = block_height;
799 }
800
801 //----------------------------------------------------------------------------------------------------------------------
802 // vogl_internal_tex_format::compare
803 //----------------------------------------------------------------------------------------------------------------------
804 bool vogl_internal_tex_format::compare(const vogl_internal_tex_format &rhs) const
805 {
806     VOGL_FUNC_TRACER
807
808 #define CMP(x)      \
809     if (x != rhs.x) \
810         return false;
811     CMP(m_fmt);
812     CMP(m_name);
813     CMP(m_actual_internal_fmt);
814     for (uint i = 0; i < cTCTotalComponents; i++)
815     {
816         CMP(m_comp_sizes[i]);
817         CMP(m_comp_types[i]);
818     }
819     CMP(m_shared_size);
820     CMP(m_tex_image_flags);
821     CMP(m_optimum_get_image_fmt);
822     CMP(m_optimum_get_image_type);
823     CMP(m_image_bytes_per_pixel_or_block);
824     CMP(m_block_width);
825     CMP(m_block_height);
826     CMP(m_compressed);
827 #undef CMP
828
829     return true;
830 }
831
832 //----------------------------------------------------------------------------------------------------------------------
833 // vogl_texture_format_init
834 //----------------------------------------------------------------------------------------------------------------------
835 void vogl_texture_format_init()
836 {
837     VOGL_FUNC_TRACER
838
839     VOGL_ASSERT(g_vogl_internal_texture_formats[0].m_fmt);
840
841     g_internal_format_hash_map.reserve(g_vogl_total_internal_texture_formats);
842
843     for (uint i = 0; i < g_vogl_total_internal_texture_formats; i++)
844     {
845         bool success = g_internal_format_hash_map.insert(g_vogl_internal_texture_formats[i].m_fmt, &g_vogl_internal_texture_formats[i]).second;
846         VOGL_VERIFY(success);
847     }
848 }
849
850 //----------------------------------------------------------------------------------------------------------------------
851 // vogl_find_internal_texture_format
852 //----------------------------------------------------------------------------------------------------------------------
853 const vogl_internal_tex_format *vogl_find_internal_texture_format(GLenum internal_format)
854 {
855     VOGL_FUNC_TRACER
856
857     VOGL_ASSERT(g_internal_format_hash_map.size());
858
859     vogl_internal_tex_format **ppFmt = g_internal_format_hash_map.find_value(internal_format);
860     return ppFmt ? *ppFmt : NULL;
861 }