]> git.cworth.org Git - vogl/blob - src/voglcommon/vogl_context_info.cpp
- regression test now works on AMD
[vogl] / src / voglcommon / vogl_context_info.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_context_info.cpp
27 #include "vogl_context_info.h"
28 #include "vogl_entrypoints.h"
29
30 #include "vogl_console.h"
31
32 #include "btrace.h"
33
34 int vogl_determine_attrib_list_array_size(const int *attrib_list)
35 {
36     VOGL_FUNC_TRACER
37
38     if (!attrib_list)
39         return 0;
40
41     int n = 0;
42
43     if (attrib_list)
44     {
45         for (;;)
46         {
47             int key = attrib_list[n];
48             n++;
49             if (!key)
50                 break;
51
52             int val = attrib_list[n];
53             VOGL_NOTE_UNUSED(val);
54             n++;
55         }
56     }
57
58     return n;
59 }
60
61 vogl_context_attribs::vogl_context_attribs()
62 {
63     VOGL_FUNC_TRACER
64 }
65
66 vogl_context_attribs::vogl_context_attribs(const int *pAttribs)
67 {
68     VOGL_FUNC_TRACER
69
70     init(pAttribs);
71 }
72
73 vogl_context_attribs::vogl_context_attribs(const int *pAttribs, uint num_attribs)
74 {
75     VOGL_FUNC_TRACER
76
77     init(pAttribs, num_attribs);
78 }
79
80 vogl_context_attribs::vogl_context_attribs(const attrib_vec &vec)
81 {
82     VOGL_FUNC_TRACER
83
84     init(vec.get_ptr(), vec.size());
85 }
86
87 void vogl_context_attribs::init(const int *pAttribs)
88 {
89     VOGL_FUNC_TRACER
90
91     init(pAttribs, vogl_determine_attrib_list_array_size(pAttribs));
92 }
93
94 void vogl_context_attribs::init(const int *pAttribs, uint num_attribs)
95 {
96     VOGL_FUNC_TRACER
97
98     m_attribs.clear();
99
100     if ((pAttribs) && (num_attribs))
101     {
102         m_attribs.append(pAttribs, num_attribs);
103     }
104 }
105
106 void vogl_context_attribs::init(const attrib_vec &vec)
107 {
108     VOGL_FUNC_TRACER
109
110     init(vec.get_ptr(), vec.size());
111 }
112
113 int vogl_context_attribs::find_value_ofs(int key_to_find) const
114 {
115     VOGL_FUNC_TRACER
116
117     uint ofs = 0;
118     while (ofs < m_attribs.size())
119     {
120         int key = m_attribs[ofs];
121         if (!key)
122             break;
123
124         if (++ofs >= m_attribs.size())
125             break;
126
127         if (key == key_to_find)
128             return ofs;
129
130         ofs++;
131     }
132
133     return -1;
134 }
135
136 bool vogl_context_attribs::get_value(int key_to_find, int &val) const
137 {
138     VOGL_FUNC_TRACER
139
140     int ofs = find_value_ofs(key_to_find);
141     if (ofs < 0)
142     {
143         val = 0;
144         return false;
145     }
146
147     val = m_attribs[ofs];
148     return true;
149 }
150
151 bool vogl_context_attribs::check() const
152 {
153     VOGL_FUNC_TRACER
154
155     if (!m_attribs.size())
156         return true;
157
158     if (m_attribs.back() != 0)
159         return false;
160
161     uint ofs = 0;
162     do
163     {
164         int key = m_attribs[ofs];
165         if (!key)
166             return true;
167         ofs++;
168
169         if (ofs >= m_attribs.size())
170             return false;
171
172         ofs++;
173     } while (ofs < m_attribs.size());
174
175     return false;
176 }
177
178 bool vogl_context_attribs::serialize(vogl::json_node &node) const
179 {
180     VOGL_FUNC_TRACER
181
182     json_node &attribs_array = node.add_array("attribs");
183     for (uint i = 0; i < m_attribs.size(); i++)
184         attribs_array.add_value(m_attribs[i]);
185
186     return true;
187 }
188
189 bool vogl_context_attribs::deserialize(const vogl::json_node &node)
190 {
191     VOGL_FUNC_TRACER
192
193     const json_node *pAttribs_array = node.find_child_array("attribs");
194     if (!pAttribs_array)
195         return false;
196
197     m_attribs.resize(pAttribs_array->size());
198     for (uint i = 0; i < pAttribs_array->size(); i++)
199         m_attribs[i] = pAttribs_array->value_as_int(i);
200
201     return true;
202 }
203
204 void vogl_context_attribs::add_key(int key, int value)
205 {
206     VOGL_FUNC_TRACER
207
208     if (m_attribs.size())
209     {
210         VOGL_ASSERT(m_attribs.back() == 0);
211         if (m_attribs.back() == 0)
212             m_attribs.resize(m_attribs.size() - 1);
213     }
214
215     m_attribs.push_back(key);
216     m_attribs.push_back(value);
217     m_attribs.push_back(0);
218 }
219
220 vogl_context_info::vogl_context_info()
221     : m_version(VOGL_GL_VERSION_UNKNOWN),
222       m_forward_compatible(false),
223       m_core_profile(false),
224       m_debug_context(false),
225       m_max_vertex_attribs(0),
226       m_max_texture_coords(0),
227       m_max_texture_units(0),
228       m_max_texture_image_units(0),
229       m_max_combined_texture_coords(0),
230       m_max_draw_buffers(0),
231       m_max_lights(0),
232       m_max_uniform_buffer_bindings(0),
233       m_max_arb_program_matrices(0),
234       m_max_arb_vertex_program_env_params(0),
235       m_max_arb_fragment_program_env_params(0),
236       m_max_transform_feedback_separate_attribs(0),
237       m_is_valid(false)
238 {
239     VOGL_FUNC_TRACER
240 }
241
242 vogl_context_info::vogl_context_info(const vogl_context_desc &desc)
243     : m_version(VOGL_GL_VERSION_UNKNOWN),
244       m_forward_compatible(false),
245       m_core_profile(false),
246       m_debug_context(false),
247       m_max_vertex_attribs(0),
248       m_max_texture_coords(0),
249       m_max_texture_units(0),
250       m_max_texture_image_units(0),
251       m_max_combined_texture_coords(0),
252       m_max_draw_buffers(0),
253       m_max_lights(0),
254       m_max_uniform_buffer_bindings(0),
255       m_max_arb_program_matrices(0),
256       m_max_arb_vertex_program_env_params(0),
257       m_max_arb_fragment_program_env_params(0),
258       m_max_transform_feedback_separate_attribs(0),
259       m_is_valid(false)
260 {
261     VOGL_FUNC_TRACER
262
263     init(desc);
264 }
265
266 void vogl_context_info::query_string(vogl::dynamic_string &str, GLenum name)
267 {
268     VOGL_FUNC_TRACER
269
270     const char *pStr = reinterpret_cast<const char *>(GL_ENTRYPOINT(glGetString)(name));
271     str.set(pStr ? pStr : "");
272
273     vogl_check_gl_error();
274 }
275
276 vogl_gl_version_t vogl_context_info::parse_version_string(const vogl::dynamic_string &str)
277 {
278     VOGL_FUNC_TRACER
279
280     if (str.size() < 3)
281         return VOGL_GL_VERSION_UNKNOWN;
282
283     // major_number.minor_number major_number.minor_number.release_number
284     // release_number can be very large (tens of thousands)
285     // optionally followed by vendor/driver info
286
287     int major = 0, minor = 0;
288     uint n = sscanf(str.get_ptr(), "%d.%d", &major, &minor);
289     if ((n < 2) || (major < 1) || (minor < 0) || (minor > 255))
290     {
291         console::error("%s: Failed parsing GL/GLSL version string \"%s\"!\n", VOGL_METHOD_NAME, str.get_ptr());
292
293         return VOGL_GL_VERSION_UNKNOWN;
294     }
295
296     return VOGL_CREATE_GL_VERSION(major, minor, 0);
297 }
298
299 // See http://www.opengl.org/registry/specs/ARB/glx_create_context.txt
300 bool vogl_context_info::init(const vogl_context_desc &desc)
301 {
302     VOGL_FUNC_TRACER
303
304     clear();
305
306     if (!GL_ENTRYPOINT(glGetString))
307         return false;
308
309     m_desc = desc;
310
311     vogl_check_gl_error();
312
313     query_string(m_version_str, GL_VERSION);
314     query_string(m_glsl_version_str, GL_SHADING_LANGUAGE_VERSION);
315     query_string(m_vendor_str, GL_VENDOR);
316     query_string(m_renderer_str, GL_RENDERER);
317
318     // Update btrace with our gl info.
319     btrace_get_glinfo().version_str = m_version_str;
320     btrace_get_glinfo().glsl_version_str = m_glsl_version_str;
321     btrace_get_glinfo().vendor_str = m_vendor_str;
322     btrace_get_glinfo().renderer_str = m_renderer_str;
323
324     m_version = parse_version_string(m_version_str);
325     m_glsl_version = parse_version_string(m_glsl_version_str);
326
327     if (vogl_check_gl_error())
328     {
329         console::warning("%s: GL error querying context vendor/renderer/version strings!\n", VOGL_METHOD_NAME);
330     }
331
332     m_forward_compatible = false;
333     m_core_profile = false;
334     m_debug_context = false;
335
336     // glGetInteger is GL >= 3.0 (even if glGetIntegerv can still be non-null on lower version contexts)
337     if ((GL_ENTRYPOINT(glGetIntegerv)) && (m_version >= VOGL_GL_VERSION_3_0))
338     {
339         GLint major_vers = -1, minor_vers = -1;
340         GL_ENTRYPOINT(glGetIntegerv)(GL_MAJOR_VERSION, &major_vers);
341         GL_ENTRYPOINT(glGetIntegerv)(GL_MINOR_VERSION, &minor_vers);
342
343         if (!vogl_check_gl_error())
344         {
345             if ((major_vers > 0) && (minor_vers >= 0))
346             {
347                 vogl_gl_version_t context_version = VOGL_CREATE_GL_VERSION(major_vers, minor_vers, 0);
348                 VOGL_ASSERT(m_version == context_version);
349                 m_version = context_version;
350             }
351         }
352
353         GLint context_flags = 0;
354         GL_ENTRYPOINT(glGetIntegerv)(GL_CONTEXT_FLAGS, &context_flags);
355         if (!vogl_check_gl_error())
356         {
357             if (context_flags & GL_CONTEXT_FLAG_DEBUG_BIT)
358                 m_debug_context = true;
359
360             // forward compat is GL >= 3.0
361             if (context_flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT)
362                 m_forward_compatible = true;
363         }
364
365         // GL_CONTEXT_PROFILE_MASK is GL 3.2 or greater - (the core profile bit is ignored for context versions requested <v3.2)
366         if (m_version >= VOGL_GL_VERSION_3_2)
367         {
368             GLint profile_mask = 0;
369             GL_ENTRYPOINT(glGetIntegerv)(GL_CONTEXT_PROFILE_MASK, &profile_mask);
370
371             if (!vogl_check_gl_error())
372             {
373                 if (profile_mask & GL_CONTEXT_CORE_PROFILE_BIT)
374                 {
375                     VOGL_ASSERT((profile_mask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) == 0);
376                     m_core_profile = true;
377                 }
378             }
379         }
380     }
381
382     determine_core_extensions();
383
384     bool success = query_extensions();
385
386     m_is_valid = success && (m_version >= VOGL_GL_VERSION_1_0);
387
388     init_context_limits();
389
390     vogl_check_gl_error();
391
392     return m_is_valid;
393 }
394
395 void vogl_context_info::init_context_limits()
396 {
397     VOGL_FUNC_TRACER
398
399     VOGL_CHECK_GL_ERROR;
400
401     m_max_vertex_attribs = vogl_get_gl_integer(GL_MAX_VERTEX_ATTRIBS);
402     VOGL_CHECK_GL_ERROR;
403
404     m_max_texture_coords = is_core_profile() ? 0 : vogl_get_gl_integer(GL_MAX_TEXTURE_COORDS);
405     VOGL_CHECK_GL_ERROR;
406
407     m_max_texture_units = is_core_profile() ? 0 : vogl_get_gl_integer(GL_MAX_TEXTURE_UNITS);
408     VOGL_CHECK_GL_ERROR;
409
410     m_max_texture_image_units = vogl_get_gl_integer(GL_MAX_TEXTURE_IMAGE_UNITS);
411     VOGL_CHECK_GL_ERROR;
412
413     m_max_combined_texture_coords = vogl_get_gl_integer(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS);
414     VOGL_CHECK_GL_ERROR;
415
416     m_max_draw_buffers = (get_version() >= VOGL_GL_VERSION_2_0) ? vogl_get_gl_integer(GL_MAX_DRAW_BUFFERS) : 0;
417     VOGL_CHECK_GL_ERROR;
418
419     m_max_lights = is_core_profile() ? 0 : vogl_get_gl_integer(GL_MAX_LIGHTS);
420     VOGL_CHECK_GL_ERROR;
421
422     m_max_uniform_buffer_bindings = vogl_get_gl_integer(GL_MAX_UNIFORM_BUFFER_BINDINGS);
423     VOGL_CHECK_GL_ERROR;
424
425     m_max_transform_feedback_separate_attribs = (get_version() >= VOGL_GL_VERSION_3_0) ? vogl_get_gl_integer(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS) : 0;
426     VOGL_CHECK_GL_ERROR;
427
428     if (!is_core_profile() && supports_extension("GL_ARB_vertex_program") && GL_ENTRYPOINT(glGetProgramivARB))
429     {
430         m_max_arb_program_matrices = vogl_get_gl_integer(GL_MAX_PROGRAM_MATRICES_ARB);
431
432         GL_ENTRYPOINT(glGetProgramivARB)(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_ENV_PARAMETERS_ARB, reinterpret_cast<GLint *>(&m_max_arb_vertex_program_env_params));
433         VOGL_CHECK_GL_ERROR;
434
435         GL_ENTRYPOINT(glGetProgramivARB)(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_ENV_PARAMETERS_ARB, reinterpret_cast<GLint *>(&m_max_arb_fragment_program_env_params));
436         VOGL_CHECK_GL_ERROR;
437     }
438 }
439
440 bool vogl_context_info::query_extensions()
441 {
442     VOGL_FUNC_TRACER
443
444     // glGetStringi is available in OpenGL3.0 and newer
445     if (GL_ENTRYPOINT(glGetStringi))
446     {
447         GLint num_extensions = 0;
448         GL_ENTRYPOINT(glGetIntegerv)(GL_NUM_EXTENSIONS, &num_extensions);
449
450         m_extensions.reserve(num_extensions + 200);
451
452         for (int i = 0; i < num_extensions; i++)
453         {
454             const GLubyte *pGLExt = reinterpret_cast<const GLubyte *>(GL_ENTRYPOINT(glGetStringi)(GL_EXTENSIONS, i));
455             if (pGLExt)
456             {
457                 m_extensions.enlarge(1)->set(reinterpret_cast<const char *>(pGLExt));
458                 m_extensions.back().tolower();
459             }
460         }
461     }
462
463     // glGetString(GL_EXTENSIONS) is only supported in OpenGL3.0 and older.
464     // It was deprecrated in 3.1, so it is available in a compatibility profile (GL_ARB_compatibility).
465     if (get_version() <= VOGL_GL_VERSION_3_0 || is_compatibility_profile())
466     {
467         const char *pExtensions = reinterpret_cast<const char *>(GL_ENTRYPOINT(glGetString)(GL_EXTENSIONS));
468         if (pExtensions)
469         {
470             dynamic_string extensions(pExtensions);
471             dynamic_string_array tokens;
472             extensions.tokenize(" \t", tokens, true);
473             m_extensions.append(tokens);
474         }
475     }
476
477     if (GL_ENTRYPOINT(glXQueryExtensionsString))
478     {
479         const char *pExtensions = reinterpret_cast<const char *>(GL_ENTRYPOINT(glXQueryExtensionsString)(GL_ENTRYPOINT(glXGetCurrentDisplay)(), 0));
480         if (pExtensions)
481         {
482             dynamic_string extensions(pExtensions);
483             dynamic_string_array tokens;
484             extensions.tokenize(" \t", tokens, true);
485             m_extensions.append(tokens);
486         }
487     }
488
489     m_extensions.unique();
490
491     return true;
492 }
493
494 void vogl_context_info::clear()
495 {
496     VOGL_FUNC_TRACER
497
498     m_desc.clear();
499
500     m_version = VOGL_GL_VERSION_UNKNOWN;
501     m_glsl_version = VOGL_GL_VERSION_UNKNOWN;
502
503     m_forward_compatible = false;
504     m_core_profile = false;
505     m_debug_context = false;
506
507     m_version_str.clear();
508     m_glsl_version_str.clear();
509     m_vendor_str.clear();
510     m_renderer_str.clear();
511     m_extensions.clear();
512     m_core_extensions.clear();
513
514     m_max_vertex_attribs = 0;
515     m_max_texture_coords = 0;
516     m_max_texture_units = 0;
517     m_max_texture_image_units = 0;
518     m_max_combined_texture_coords = 0;
519     m_max_draw_buffers = 0;
520     m_max_lights = 0;
521     m_max_uniform_buffer_bindings = 0;
522     m_max_arb_program_matrices = 0;
523     m_max_arb_vertex_program_env_params = 0;
524     m_max_arb_fragment_program_env_params = 0;
525     m_max_transform_feedback_separate_attribs = 0;
526
527     m_is_valid = false;
528 }
529
530 // I've seen some engines do this, they must have a reason.
531 // Some newer drivers don't report back extensions added to core GL. So make a separate list that contains those extensions.
532 // TODO: I'm not so sure about this whole idea.
533 // TODO: Make sure all this makes sense in core profiles.
534 void vogl_context_info::determine_core_extensions()
535 {
536     VOGL_FUNC_TRACER
537
538 #define ADD_EXT(x)                       \
539     do                                   \
540     {                                    \
541         m_core_extensions.push_back(#x); \
542     } while (0)
543     if (m_version >= VOGL_GL_VERSION_1_2)
544     {
545         ADD_EXT(GL_EXT_texture3D);
546         ADD_EXT(GL_EXT_bgra);
547         ADD_EXT(GL_EXT_packed_pixels);
548         ADD_EXT(GL_EXT_rescale_normal);
549         ADD_EXT(GL_EXT_separate_specular_color);
550         ADD_EXT(GL_SGIS_texture_edge_clamp);
551         ADD_EXT(GL_SGIS_texture_lod);
552         ADD_EXT(GL_EXT_draw_range_elements);
553     }
554
555     if (m_version >= VOGL_GL_VERSION_1_3)
556     {
557         ADD_EXT(GL_ARB_texture_compression);
558         ADD_EXT(GL_ARB_texture_cube_map);
559         ADD_EXT(GL_ARB_multisample);
560         ADD_EXT(GL_ARB_multitexture);
561         ADD_EXT(GL_ARB_transpose_matrix);
562         ADD_EXT(GL_ARB_texture_env_add);
563         ADD_EXT(GL_ARB_texture_env_combine);
564         ADD_EXT(GL_ARB_texture_env_dot3);
565         ADD_EXT(GL_ARB_texture_border_clamp);
566     }
567
568     if (m_version >= VOGL_GL_VERSION_1_4)
569     {
570         ADD_EXT(GL_EXT_blend_color);
571         ADD_EXT(GL_EXT_blend_minmax);
572         ADD_EXT(GL_EXT_blend_subtract);
573         ADD_EXT(GL_SGIS_generate_mipmap);
574         ADD_EXT(GL_NV_blend_square);
575         ADD_EXT(GL_ARB_depth_texture);
576         ADD_EXT(GL_ARB_shadow);
577         ADD_EXT(GL_EXT_fog_coord);
578         ADD_EXT(GL_EXT_multi_draw_arrays);
579         ADD_EXT(GL_ARB_point_parameters);
580         ADD_EXT(GL_EXT_secondary_color);
581         ADD_EXT(GL_EXT_blend_func_separate);
582         ADD_EXT(GL_EXT_stencil_wrap);
583         ADD_EXT(GL_ARB_texture_env_crossbar);
584         ADD_EXT(GL_EXT_texture_lod_bias);
585         ADD_EXT(GL_ARB_texture_mirrored_repeat);
586         ADD_EXT(GL_ARB_window_pos);
587     }
588
589     if (m_version >= VOGL_GL_VERSION_1_5)
590     {
591         ADD_EXT(GL_ARB_vertex_buffer_object);
592         ADD_EXT(GL_ARB_occlusion_query);
593         ADD_EXT(GL_EXT_shadow_funcs);
594     }
595
596     if (m_version >= VOGL_GL_VERSION_2_0)
597     {
598         ADD_EXT(GL_ARB_shader_objects);
599         ADD_EXT(GL_ARB_vertex_shader);
600         ADD_EXT(GL_ARB_fragment_shader);
601         ADD_EXT(GL_ARB_shading_language_100);
602         ADD_EXT(GL_ARB_draw_buffers);
603         ADD_EXT(GL_ARB_texture_non_power_of_two);
604         ADD_EXT(GL_ARB_point_sprite);
605         ADD_EXT(GL_EXT_blend_equation_separate);
606     }
607
608     if (m_version >= VOGL_GL_VERSION_2_1)
609     {
610         ADD_EXT(GL_EXT_texture_sRGB);
611         ADD_EXT(GL_ARB_pixel_buffer_object);
612     }
613
614     if (m_version >= VOGL_GL_VERSION_3_0)
615     {
616         ADD_EXT(GL_EXT_framebuffer_sRGB);
617         ADD_EXT(GL_EXT_gpu_shader4);
618         ADD_EXT(GL_NV_conditional_render);
619         ADD_EXT(GL_ARB_color_buffer_float);
620         ADD_EXT(GL_ARB_depth_buffer_float);
621         ADD_EXT(GL_ARB_texture_float);
622         ADD_EXT(GL_EXT_packed_float);
623         ADD_EXT(GL_EXT_texture_shared_exponent);
624         ADD_EXT(GL_EXT_framebuffer_object);
625         ADD_EXT(GL_NV_half_float);
626         ADD_EXT(GL_EXT_texture_integer);
627         ADD_EXT(GL_EXT_texture_array);
628         ADD_EXT(GL_EXT_packed_depth_stencil);
629         ADD_EXT(GL_EXT_draw_buffers2);
630         ADD_EXT(GL_EXT_texture_compression_rgtc);
631         ADD_EXT(GL_EXT_transform_feedback);
632         ADD_EXT(GL_APPLE_vertex_array_object);
633         ADD_EXT(GL_ARB_half_float_pixel);
634         ADD_EXT(GL_EXT_framebuffer_multisample);
635         ADD_EXT(GL_EXT_framebuffer_blit);
636     }
637
638     if (m_version >= VOGL_GL_VERSION_3_2)
639     {
640         ADD_EXT(GL_ARB_sync);
641     }
642 #undef ADD_EXT
643
644     m_core_extensions.unique();
645 }
646
647 bool vogl_context_info::serialize(vogl::json_node &node, const vogl_blob_manager &blob_manager) const
648 {
649     VOGL_FUNC_TRACER
650
651     if (!m_is_valid)
652     {
653         VOGL_ASSERT_ALWAYS;
654         return false;
655     }
656
657     if (!m_desc.serialize(node, blob_manager))
658         return false;
659
660     node.add_key_value("version_major", VOGL_GL_VERSION_GET_MAJOR(m_version));
661     node.add_key_value("version_minor", VOGL_GL_VERSION_GET_MINOR(m_version));
662     node.add_key_value("version_patch", VOGL_GL_VERSION_GET_PATCH(m_version));
663
664     node.add_key_value("glsl_version_major", VOGL_GL_VERSION_GET_MAJOR(m_glsl_version));
665     node.add_key_value("glsl_version_minor", VOGL_GL_VERSION_GET_MINOR(m_glsl_version));
666
667     node.add_key_value("forward_compatible", m_forward_compatible);
668     node.add_key_value("core_profile", m_core_profile);
669     node.add_key_value("debug_context", m_debug_context);
670
671     node.add_key_value("version_string", m_version_str);
672     node.add_key_value("glsl_version_string", m_glsl_version_str);
673     node.add_key_value("vendor_string", m_vendor_str);
674     node.add_key_value("renderer_string", m_renderer_str);
675
676     node.add_key_value("max_vertex_attribs", m_max_vertex_attribs);
677     node.add_key_value("max_texture_coords", m_max_texture_coords);
678     node.add_key_value("max_texture_units", m_max_texture_units);
679     node.add_key_value("max_texture_image_units", m_max_texture_image_units);
680     node.add_key_value("max_combined_texture_coords", m_max_combined_texture_coords);
681     node.add_key_value("max_draw_buffers", m_max_draw_buffers);
682     node.add_key_value("max_lights", m_max_lights);
683     node.add_key_value("max_uniform_buffer_bindings", m_max_uniform_buffer_bindings);
684     node.add_key_value("max_arb_program_matrices", m_max_arb_program_matrices);
685     node.add_key_value("max_arb_vertex_program_env_params", m_max_arb_vertex_program_env_params);
686     node.add_key_value("max_arb_fragment_program_env_params", m_max_arb_fragment_program_env_params);
687     node.add_key_value("max_transform_feedback_separate_attribs", m_max_transform_feedback_separate_attribs);
688
689     json_node &extensions_array = node.add_array("extensions");
690     for (uint i = 0; i < m_extensions.size(); i++)
691         extensions_array.add_value(m_extensions[i]);
692
693     return true;
694 }
695
696 bool vogl_context_info::deserialize(const vogl::json_node &node, const vogl_blob_manager &blob_manager)
697 {
698     VOGL_FUNC_TRACER
699
700     clear();
701
702     if (!node.is_object())
703         return false;
704
705     bool success = node.get_value_as_string("version_string", m_version_str);
706
707     if (!m_desc.deserialize(node, blob_manager))
708         return false;
709
710     int version_major = 0, version_minor = 0, version_patch = 0;
711     version_major = node.value_as_int("version_major");
712     version_minor = node.value_as_int("version_minor");
713     version_patch = node.value_as_int("version_patch");
714     m_version = VOGL_CREATE_GL_VERSION(version_major, version_minor, version_patch);
715
716     int glsl_version_major = 0, glsl_version_minor = 0;
717     glsl_version_major = node.value_as_int("glsl_version_major");
718     glsl_version_minor = node.value_as_int("glsl_version_minor");
719     m_glsl_version = VOGL_CREATE_GL_VERSION(glsl_version_major, glsl_version_minor, 0);
720
721     m_forward_compatible = node.value_as_bool("forward_compatible");
722     m_core_profile = node.value_as_bool("core_profile");
723     m_debug_context = node.value_as_bool("debug_context");
724     m_glsl_version_str = node.value_as_string("glsl_version_string");
725     m_vendor_str = node.value_as_string("vendor_string");
726     m_renderer_str = node.value_as_string("renderer_string");
727
728     m_max_vertex_attribs = node.value_as_uint32("max_vertex_attribs");
729     m_max_texture_coords = node.value_as_uint32("max_texture_coords");
730     m_max_texture_units = node.value_as_uint32("max_texture_units");
731     m_max_texture_image_units = node.value_as_uint32("max_texture_image_units");
732     m_max_combined_texture_coords = node.value_as_uint32("max_combined_texture_coords");
733     m_max_draw_buffers = node.value_as_uint32("max_draw_buffers");
734     m_max_lights = node.value_as_uint32("max_lights");
735     m_max_uniform_buffer_bindings = node.value_as_uint32("max_uniform_buffer_bindings");
736     m_max_arb_program_matrices = node.value_as_uint32("max_arb_program_matrices");
737     m_max_arb_vertex_program_env_params = node.value_as_uint32("max_arb_vertex_program_env_params");
738     m_max_arb_fragment_program_env_params = node.value_as_uint32("max_arb_fragment_program_env_params");
739     m_max_transform_feedback_separate_attribs = node.value_as_uint32("max_transform_feedback_separate_attribs");
740
741     const json_node *pExtensions_array = node.find_child_array("extensions");
742     if (pExtensions_array)
743     {
744         m_extensions.resize(pExtensions_array->size());
745
746         for (uint i = 0; i < pExtensions_array->size(); i++)
747             m_extensions[i] = pExtensions_array->get_value(i).as_string();
748
749         m_extensions.unique();
750     }
751
752     determine_core_extensions();
753
754     VOGL_ASSERT(success);
755
756     m_is_valid = success;
757
758     return success;
759 }
760
761 bool vogl_context_info::supports_extension(const char *pExt) const
762 {
763     VOGL_FUNC_TRACER
764
765     if (!m_is_valid)
766     {
767         VOGL_ASSERT_ALWAYS;
768         return false;
769     }
770
771     vogl::dynamic_string ext(pExt);
772
773     if (!ext.begins_with("GL_", true))
774     {
775         vogl_warning_printf("%s: Extension does not begin with \"GL_\" prefix, was this intended?\n", VOGL_METHOD_NAME);
776     }
777
778 #if 0
779         // Let's see if this is ever necessary. Also not sure how it interacts with core profiles, yet.
780         if (m_core_extensions.find_sorted(ext) >= 0)
781                 return true;
782 #endif
783
784     return m_extensions.find_sorted(ext) >= 0;
785 }