]> git.cworth.org Git - vogl/blob - src/vogltrace/vogl_intercept.cpp
- Initial support for KHR_debug API's in tracer/replayer
[vogl] / src / vogltrace / vogl_intercept.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_intercept.cpp
27 #include "vogl_trace.h"
28 #include "vogl_trace_stream_types.h"
29 #include "vogl_trace_packet.h"
30 #include "vogl_texture_format.h"
31 #include "vogl_gl_state_snapshot.h"
32 #include "vogl_trace_file_writer.h"
33 #include "vogl_framebuffer_capturer.h"
34 #include "vogl_trace_file_reader.h"
35
36 // voglcore
37 #include "vogl_hash_map.h"
38 #include "vogl_console.h"
39 #include "vogl_colorized_console.h"
40 #include "vogl_command_line_params.h"
41 #include "vogl_cfile_stream.h"
42 #include "vogl_value.h"
43 #include "vogl_file_utils.h"
44 #include "vogl_uuid.h"
45 #include "vogl_unique_ptr.h"
46
47 #include <unistd.h>
48 #include <sys/syscall.h>
49
50 #include <X11/Xatom.h>
51
52 #if VOGL_REMOTING
53 #include "vogl_remote.h"
54 #endif
55
56 #define MINIZ_NO_ZLIB_COMPATIBLE_NAMES
57 #include "vogl_miniz.h"
58
59 #include "btrace.h"
60
61 // loki
62 #include "TypeTraits.h"
63
64 #include <turbojpeg.h>
65
66 #define VOGL_INTERCEPT_TRACE_FILE_VERSION 0x0102
67
68 #define VOGL_STOP_CAPTURE_FILENAME "__stop_capture__"
69 #define VOGL_TRIGGER_CAPTURE_FILENAME "__trigger_capture__"
70
71 #define VOGL_CMD_LINE_OPTIONS_FILE "vogl_cmd_line.txt"
72
73 #define VOGL_BACKTRACE_HASHMAP_CAPACITY 50000
74
75 class vogl_context;
76 class vogl_entrypoint_serializer;
77
78 //----------------------------------------------------------------------------------------------------------------------
79 // Globals
80 //----------------------------------------------------------------------------------------------------------------------
81 static atomic32_t g_vogl_has_been_initialized;
82 static pthread_once_t g_vogl_init_once_control = PTHREAD_ONCE_INIT;
83 static pthread_key_t g_vogl_thread_local_data;
84 static cfile_stream *g_vogl_pLog_stream;
85 static vogl_exception_callback_t g_vogl_pPrev_exception_callback;
86 static GLuint g_dummy_program;
87
88 //----------------------------------------------------------------------------------------------------------------------
89 // Forward declaration
90 //----------------------------------------------------------------------------------------------------------------------
91 static void vogl_glInternalTraceCommandRAD(GLuint cmd, GLuint size, const GLubyte *data);
92 static void vogl_end_capture(bool inside_signal_handler = false);
93 static void vogl_atexit();
94
95 //----------------------------------------------------------------------------------------------------------------------
96 // Context sharelist shadow locking
97 //----------------------------------------------------------------------------------------------------------------------
98 static bool g_app_uses_sharelists;
99 static void vogl_context_shadow_lock();
100 static void vogl_context_shadow_unlock();
101
102 class vogl_scoped_context_shadow_lock
103 {
104     bool m_took_lock;
105
106 public:
107     inline vogl_scoped_context_shadow_lock()
108         : m_took_lock(g_app_uses_sharelists)
109     {
110         if (m_took_lock)
111             vogl_context_shadow_lock();
112     }
113
114     inline ~vogl_scoped_context_shadow_lock()
115     {
116         if (m_took_lock)
117             vogl_context_shadow_unlock();
118     }
119 };
120
121 //----------------------------------------------------------------------------------------------------------------------
122 // Command line params
123 //----------------------------------------------------------------------------------------------------------------------
124 static command_line_param_desc g_command_line_param_descs[] =
125     {
126         { "vogl_dump_gl_full", 0, false, NULL },
127         { "vogl_dump_gl_calls", 0, false, NULL },
128         { "vogl_dump_gl_buffers", 0, false, NULL },
129         { "vogl_dump_gl_shaders", 0, false, NULL },
130         { "vogl_sleep_at_startup", 1, false, NULL },
131         { "vogl_pause", 0, false, NULL },
132         { "vogl_long_pause", 0, false, NULL },
133         { "vogl_dump_stats", 0, false, NULL },
134         { "vogl_debug", 0, false, NULL },
135         { "vogl_flush_files_after_each_call", 0, false, NULL },
136         { "vogl_flush_files_after_each_swap", 0, false, NULL },
137         { "vogl_disable_signal_interception", 0, false, NULL },
138         { "vogl_logfile", 1, false, NULL },
139         { "vogl_logfile_append", 1, false, NULL },
140         { "vogl_tracefile", 1, false, NULL },
141         { "vogl_tracepath", 1, false, NULL },
142         { "vogl_dump_png_screenshots", 0, false, NULL },
143         { "vogl_dump_jpeg_screenshots", 0, false, NULL },
144         { "vogl_jpeg_quality", 0, false, NULL },
145         { "vogl_screenshot_prefix", 1, false, NULL },
146         { "vogl_hash_backbuffer", 0, false, NULL },
147         { "vogl_dump_backbuffer_hashes", 1, false, NULL },
148         { "vogl_sum_hashing", 0, false, NULL },
149         { "vogl_disable_atexit_context_flushing", 0, false, NULL },
150         { "vogl_null_mode", 0, false, NULL },
151         { "vogl_force_debug_context", 0, false, NULL },
152         { "vogl_disable_client_side_array_tracing", 0, false, NULL },
153         { "vogl_disable_gl_program_binary", 0, false, NULL },
154         { "vogl_func_tracing", 0, false, NULL },
155         { "vogl_backtrace_all_calls", 0, false, NULL },
156         { "vogl_exit_after_x_frames", 1, false, NULL },
157         { "vogl_traceport", 1, false, NULL },
158     };
159
160 //----------------------------------------------------------------------------------------------------------------------
161 // Globals
162 //----------------------------------------------------------------------------------------------------------------------
163 bool g_dump_gl_calls_flag;
164 bool g_dump_gl_buffers_flag;
165 bool g_dump_gl_shaders_flag;
166 bool g_disable_gl_program_binary_flag;
167 bool g_null_mode;
168 bool g_backtrace_all_calls;
169 static bool g_disable_client_side_array_tracing;
170
171 static bool g_flush_files_after_each_call;
172 static bool g_flush_files_after_each_swap;
173 static bool g_gather_statistics;
174
175 static vogl_trace_file_writer g_vogl_trace_writer(&g_vogl_process_gl_ctypes);
176 static mutex g_vogl_trace_mutex(0, true);
177
178 static uint g_vogl_total_frames_to_capture;
179 static uint g_vogl_frames_remaining_to_capture;
180 static bool g_vogl_stop_capturing;
181 static dynamic_string g_vogl_capture_path, g_vogl_capture_basename;
182 static vogl_capture_status_callback_func_ptr g_vogl_pCapture_status_callback;
183 static void *g_vogl_pCapture_status_opaque;
184
185 static vogl_backtrace_hashmap g_backtrace_hashmap;
186 static mutex g_backtrace_hashmap_mutex(0, false);
187
188 //----------------------------------------------------------------------------------------------------------------------
189 // vogl_get_current_kernel_thread_id
190 //----------------------------------------------------------------------------------------------------------------------
191 static inline uint64_t vogl_get_current_kernel_thread_id()
192 {
193     return static_cast<uint64_t>(syscall(SYS_gettid));
194 }
195
196 //----------------------------------------------------------------------------------------------------------------------
197 // class vogl_entrypoint_serializer
198 //----------------------------------------------------------------------------------------------------------------------
199 class vogl_entrypoint_serializer
200 {
201     VOGL_NO_COPY_OR_ASSIGNMENT_OP(vogl_entrypoint_serializer);
202
203 public:
204     inline vogl_entrypoint_serializer()
205         : m_packet(&g_vogl_process_gl_ctypes),
206           m_in_begin(false)
207     {
208     }
209
210     inline vogl_entrypoint_serializer(gl_entrypoint_id_t id, vogl_context *pContext)
211         : m_packet(&g_vogl_process_gl_ctypes),
212           m_in_begin(false)
213     {
214         begin(id, pContext);
215     }
216
217     const vogl_trace_packet &get_packet() const
218     {
219         return m_packet;
220     }
221     vogl_trace_packet &get_packet()
222     {
223         return m_packet;
224     }
225
226     // begin()/end() is NOT nestable
227     // Returns false if nesting detected
228     bool begin(gl_entrypoint_id_t id, vogl_context *pContext);
229
230     void set_begin_rdtsc(uint64_t val)
231     {
232         m_packet.set_begin_rdtsc(val);
233     }
234
235     bool is_in_begin() const
236     {
237         return m_in_begin;
238     }
239
240     inline gl_entrypoint_id_t get_cur_entrypoint() const
241     {
242         return m_packet.get_entrypoint_id();
243     }
244
245     inline void add_return_param(vogl_ctype_t ctype, const void *pParam, uint param_size)
246     {
247         VOGL_ASSERT(m_in_begin);
248         m_packet.set_return_param(ctype, pParam, param_size);
249     }
250
251     inline void add_param(uint8_t param_id, vogl_ctype_t ctype, const void *pParam, uint param_size)
252     {
253         VOGL_ASSERT(m_in_begin);
254         m_packet.set_param(param_id, ctype, pParam, param_size);
255     }
256
257     inline void add_ref_client_memory(uint8_t param_id, vogl_ctype_t pointee_ctype, const void *pData, uint64_t data_size)
258     {
259         VOGL_ASSERT(m_in_begin);
260         m_packet.set_ref_client_memory(param_id, pointee_ctype, pData, data_size);
261     }
262
263     inline void add_array_client_memory(uint8_t param_id, vogl_ctype_t pointee_ctype, uint64_t array_size, const void *pData, uint64_t data_size)
264     {
265         VOGL_ASSERT(m_in_begin);
266         m_packet.set_array_client_memory(param_id, pointee_ctype, array_size, pData, data_size);
267     }
268
269     inline bool add_key_value(const value &key, const value &value)
270     {
271         VOGL_ASSERT(m_in_begin);
272         return m_packet.set_key_value(key, value);
273     }
274
275     inline bool add_key_value_blob(const value &key, uint8_vec &blob)
276     {
277         VOGL_ASSERT(m_in_begin);
278         return m_packet.set_key_value(key, blob);
279     }
280
281     inline bool add_key_value_blob(const value &key, const void *pData, uint data_size)
282     {
283         VOGL_ASSERT(m_in_begin);
284         return m_packet.set_key_value_blob(key, pData, data_size);
285     }
286
287     inline bool add_key_value_json_document(const value &key, const json_document &doc)
288     {
289         VOGL_ASSERT(m_in_begin);
290         return m_packet.set_key_value_json_document(key, doc);
291     }
292
293     inline const key_value_map &get_key_value_map() const
294     {
295         VOGL_ASSERT(m_in_begin);
296         return m_packet.get_key_value_map();
297     }
298     inline key_value_map &get_key_value_map()
299     {
300         VOGL_ASSERT(m_in_begin);
301         return m_packet.get_key_value_map();
302     }
303
304     inline void set_gl_begin_rdtsc(uint64_t val)
305     {
306         m_packet.set_gl_begin_rdtsc(val);
307     }
308     inline void set_gl_end_rdtsc(uint64_t val)
309     {
310         m_packet.set_gl_end_rdtsc(val);
311     }
312     inline void set_gl_begin_end_rdtsc(uint64_t begin, uint64_t end)
313     {
314         m_packet.set_gl_begin_rdtsc(begin);
315         m_packet.set_gl_end_rdtsc(end);
316     }
317
318     inline void end()
319     {
320         VOGL_ASSERT(m_in_begin);
321
322         if (!m_in_begin)
323         {
324             vogl_error_printf("%s: end() called without a matching call to begin()! Something is seriously wrong!\n", VOGL_METHOD_NAME);
325             return;
326         }
327
328         m_packet.end_construction(utils::RDTSC());
329
330         VOGL_ASSERT(m_packet.check());
331
332         const gl_entrypoint_desc_t &entrypoint_desc = g_vogl_entrypoint_descs[get_cur_entrypoint()];
333
334         if (m_packet.total_params() != entrypoint_desc.m_num_params)
335         {
336             vogl_error_printf("%s: Unexpected number of params passed to serializer! (entrypoint id %u)\n", VOGL_METHOD_NAME, get_cur_entrypoint());
337             m_in_begin = false;
338             return;
339         }
340
341         if (m_packet.has_return_value() != (entrypoint_desc.m_return_ctype != VOGL_VOID))
342         {
343             vogl_error_printf("%s: Return parameter serialization error (entrypoint id %u)!\n", VOGL_METHOD_NAME, get_cur_entrypoint());
344             m_in_begin = false;
345             return;
346         }
347
348         m_in_begin = false;
349     }
350
351 private:
352     vogl_trace_packet m_packet;
353     bool m_in_begin;
354 };
355
356 //----------------------------------------------------------------------------------------------------------------------
357 // struct vogl_thread_local_data
358 //----------------------------------------------------------------------------------------------------------------------
359 class vogl_thread_local_data
360 {
361 public:
362     vogl_thread_local_data()
363         : m_pContext(NULL),
364           m_calling_driver_entrypoint_id(VOGL_ENTRYPOINT_INVALID)
365     {
366     }
367
368     ~vogl_thread_local_data()
369     {
370         m_pContext = NULL;
371     }
372
373     vogl_context *m_pContext;
374     vogl_entrypoint_serializer m_serializer;
375
376     // Set to a valid entrypoint ID if we're currently trying to call the driver on this thread. The "direct" GL function wrappers (in
377     // vogl_entrypoints.cpp) call our vogl_direct_gl_func_prolog/epilog func callbacks below, which manipulate this member.
378     gl_entrypoint_id_t m_calling_driver_entrypoint_id;
379 };
380
381 //----------------------------------------------------------------------------------------------------------------------
382 // vogl_get_or_create_thread_local_data
383 //----------------------------------------------------------------------------------------------------------------------
384 static VOGL_FORCE_INLINE vogl_thread_local_data *vogl_get_or_create_thread_local_data()
385 {
386     vogl_thread_local_data *pTLS_data = static_cast<vogl_thread_local_data *>(pthread_getspecific(g_vogl_thread_local_data));
387     if (!pTLS_data)
388     {
389         pTLS_data = vogl_new(vogl_thread_local_data);
390
391         pthread_setspecific(g_vogl_thread_local_data, pTLS_data);
392     }
393
394     return pTLS_data;
395 }
396
397 //----------------------------------------------------------------------------------------------------------------------
398 // vogl_get_thread_local_data
399 //----------------------------------------------------------------------------------------------------------------------
400 static VOGL_FORCE_INLINE vogl_thread_local_data *vogl_get_thread_local_data()
401 {
402     return static_cast<vogl_thread_local_data *>(pthread_getspecific(g_vogl_thread_local_data));
403 }
404
405 //----------------------------------------------------------------------------------------------------------------------
406 // tls_thread_local_data_destructor
407 //----------------------------------------------------------------------------------------------------------------------
408 static void vogl_thread_local_data_destructor(void *pValue)
409 {
410     vogl_delete(static_cast<vogl_thread_local_data *>(pValue));
411
412     pthread_setspecific(g_vogl_thread_local_data, NULL);
413 }
414
415 //----------------------------------------------------------------------------------------------------------------------
416 // vogl_init_thread_local_data
417 //----------------------------------------------------------------------------------------------------------------------
418 static void vogl_init_thread_local_data()
419 {
420     int rc = pthread_key_create(&g_vogl_thread_local_data, vogl_thread_local_data_destructor);
421     if (rc)
422     {
423         vogl_error_printf("%s: pthread_key_create failed!\n", VOGL_FUNCTION_NAME);
424         exit(EXIT_FAILURE);
425     }
426 }
427
428 //----------------------------------------------------------------------------------------------------------------------
429 // vogl_init_logfile
430 //----------------------------------------------------------------------------------------------------------------------
431 static void vogl_init_logfile()
432 {
433     VOGL_FUNC_TRACER
434
435     dynamic_string backbuffer_hash_file;
436     if (g_command_line_params.get_value_as_string(backbuffer_hash_file, "vogl_dump_backbuffer_hashes"))
437     {
438         remove(backbuffer_hash_file.get_ptr());
439         vogl_message_printf("Deleted backbuffer hash file \"%s\"\n", backbuffer_hash_file.get_ptr());
440     }
441
442     dynamic_string log_file(g_command_line_params.get_value_as_string_or_empty("vogl_logfile"));
443     dynamic_string log_file_append(g_command_line_params.get_value_as_string_or_empty("vogl_logfile_append"));
444     if (log_file.is_empty() && log_file_append.is_empty())
445         return;
446
447     dynamic_string filename(log_file_append.is_empty() ? log_file : log_file_append);
448
449     // This purposely leaks, don't care
450     g_vogl_pLog_stream = vogl_new(cfile_stream);
451
452     if (!g_vogl_pLog_stream->open(filename.get_ptr(), cDataStreamWritable, !log_file_append.is_empty()))
453     {
454         vogl_error_printf("%s: Failed opening log file \"%s\"\n", VOGL_FUNCTION_NAME, filename.get_ptr());
455
456         vogl_delete(g_vogl_pLog_stream);
457         g_vogl_pLog_stream = NULL;
458
459         exit(EXIT_FAILURE);
460     }
461     else
462     {
463         vogl_message_printf("Opened log file \"%s\"\n", filename.get_ptr());
464
465         console::set_log_stream(g_vogl_pLog_stream);
466     }
467 }
468
469 //----------------------------------------------------------------------------------------------------------------------
470 // vogl_capture_on_next_swap
471 //----------------------------------------------------------------------------------------------------------------------
472 bool vogl_capture_on_next_swap(uint total_frames, const char *pPath, const char *pBase_filename, vogl_capture_status_callback_func_ptr pStatus_callback, void *pStatus_callback_opaque)
473 {
474     if (!total_frames)
475     {
476         vogl_error_printf("%s: total_frames cannot be 0\n", VOGL_FUNCTION_NAME);
477         return false;
478     }
479
480     scoped_mutex lock(g_vogl_trace_mutex);
481
482     if ((!g_vogl_frames_remaining_to_capture) && (!g_vogl_trace_writer.is_opened()))
483     {
484         g_vogl_total_frames_to_capture = total_frames;
485         g_vogl_capture_path = pPath ? pPath : "";
486         g_vogl_capture_basename = pBase_filename ? pBase_filename : "";
487         g_vogl_pCapture_status_callback = pStatus_callback;
488         g_vogl_pCapture_status_opaque = pStatus_callback_opaque;
489         g_vogl_stop_capturing = false;
490
491         vogl_debug_printf("%s: Total frames: %u, path: \"%s\", base filename: \"%s\", status callback: %p, status callback opaque: %p\n",
492                          VOGL_FUNCTION_NAME, total_frames, pPath, pBase_filename, pStatus_callback, pStatus_callback_opaque);
493     }
494     else
495     {
496         vogl_error_printf("%s: Cannot trigger capturing while a trace is currently in progress\n", VOGL_FUNCTION_NAME);
497         return false;
498     }
499
500     return true;
501 }
502
503 //----------------------------------------------------------------------------------------------------------------------
504 // vogl_stop_capturing
505 //----------------------------------------------------------------------------------------------------------------------
506 bool vogl_stop_capturing()
507 {
508     scoped_mutex lock(g_vogl_trace_mutex);
509
510     if (!g_vogl_trace_writer.is_opened())
511     {
512         vogl_error_printf("%s: Tracing is not active!\n", VOGL_FUNCTION_NAME);
513         return false;
514     }
515
516     g_vogl_stop_capturing = true;
517
518     vogl_debug_printf("%s: Closing trace immediately after next swap\n", VOGL_FUNCTION_NAME);
519
520     return true;
521 }
522
523 //----------------------------------------------------------------------------------------------------------------------
524 // vogl_stop_capturing
525 //----------------------------------------------------------------------------------------------------------------------
526 bool vogl_stop_capturing(vogl_capture_status_callback_func_ptr pStatus_callback, void *pStatus_callback_opaque)
527 {
528     scoped_mutex lock(g_vogl_trace_mutex);
529
530     if (!g_vogl_trace_writer.is_opened())
531     {
532         vogl_error_printf("%s: Tracing is not active!\n", VOGL_FUNCTION_NAME);
533         return false;
534     }
535
536     g_vogl_stop_capturing = true;
537     g_vogl_pCapture_status_callback = pStatus_callback;
538     g_vogl_pCapture_status_opaque = pStatus_callback_opaque;
539
540     vogl_debug_printf("%s: Closing trace immediately after next swap, status callback: %p, status callback opaque: %p\n",
541                      VOGL_FUNCTION_NAME, pStatus_callback, pStatus_callback_opaque);
542
543     return true;
544 }
545
546 //----------------------------------------------------------------------------------------------------------------------
547 // vogl_is_capturing
548 //----------------------------------------------------------------------------------------------------------------------
549 bool vogl_is_capturing()
550 {
551     scoped_mutex lock(g_vogl_trace_mutex);
552
553     return g_vogl_trace_writer.is_opened();
554 }
555
556 //----------------------------------------------------------------------------------------------------------------------
557 // vogl_dump_statistics
558 //----------------------------------------------------------------------------------------------------------------------
559 static void vogl_dump_statistics()
560 {
561     for (uint i = 0; i < VOGL_NUM_ENTRYPOINTS; i++)
562     {
563         if ((!g_vogl_entrypoint_descs[i].m_is_whitelisted) && (g_vogl_entrypoint_descs[i].m_trace_call_counter))
564         {
565             vogl_error_printf("A non-whitelisted function was called during tracing: %s\n", g_vogl_entrypoint_descs[i].m_pName);
566         }
567     }
568 }
569
570 //----------------------------------------------------------------------------------------------------------------------
571 // Deinitialization
572 //----------------------------------------------------------------------------------------------------------------------
573 void vogl_deinit()
574 {
575     VOGL_FUNC_TRACER
576
577     static bool s_already_deinitialized;
578     if (s_already_deinitialized)
579         return;
580     s_already_deinitialized = true;
581
582     VOGL_FUNC_TRACER
583     vogl_end_capture();
584
585     vogl_dump_statistics();
586 }
587
588 //----------------------------------------------------------------------------------------------------------------------
589 // vogl_exception_callback
590 // Note this function can be called ASYNCHRONOUSLY at signal time. Don't call any API function which is not async safe!
591 // TODO: Fix this function!
592 //----------------------------------------------------------------------------------------------------------------------
593 static void vogl_exception_callback()
594 {
595     VOGL_FUNC_TRACER
596
597     fprintf(stderr, "(vogltrace) Flushing log and closing trace files. Note any outstanding async buffer readbacks (for screen capturing) cannot be safely flushed!\n");
598
599     vogl_end_capture(true);
600
601     //uint num_contexts = g_context_manager.get_context_map().size();
602     //if (num_contexts)
603     //   vogl_error_printf("%s: App is exiting with %u active GL context(s)! Any outstanding async buffer readbacks cannot be safely flushed!\n", VOGL_FUNCTION_NAME, num_contexts);
604
605     if (g_vogl_pLog_stream)
606         g_vogl_pLog_stream->flush();
607
608     if (g_vogl_pPrev_exception_callback)
609     {
610         fprintf(stderr, "Calling prev handler\n");
611         (*g_vogl_pPrev_exception_callback)();
612     }
613 }
614
615 //----------------------------------------------------------------------------------------------------------------------
616 // vogl_init_command_line_params
617 //----------------------------------------------------------------------------------------------------------------------
618 static void vogl_init_command_line_params()
619 {
620     VOGL_FUNC_TRACER
621
622     float sleep_time = g_command_line_params.get_value_as_float("vogl_sleep_at_startup");
623     if (sleep_time > 0.0f)
624     {
625         vogl_sleep(static_cast<uint>(ceil(1000.0f * sleep_time)));
626     }
627
628     dynamic_string_array cmd_line_params;
629     char *pEnv_cmd_line = getenv("VOGL_CMD_LINE");
630     if (pEnv_cmd_line)
631     {
632         console::message("Reading command line params from env var\n");
633
634         dynamic_string cmd_line(pEnv_cmd_line);
635         cmd_line.unquote();
636
637         console::message("VOGL_CMD_LINE: %s\n", cmd_line.get_ptr());
638
639         if (!split_command_line_params(cmd_line.get_ptr(), cmd_line_params))
640             console::error("%s: Failed splitting command line params from env var: %s\n", VOGL_FUNCTION_NAME, pEnv_cmd_line);
641     }
642     else if (file_utils::does_file_exist(VOGL_CMD_LINE_OPTIONS_FILE))
643     {
644         console::message("Reading command line params from file \"%s\"\n", VOGL_CMD_LINE_OPTIONS_FILE);
645
646         dynamic_string_array opts;
647         if (!file_utils::read_text_file(VOGL_CMD_LINE_OPTIONS_FILE, opts, file_utils::cRTFTrim | file_utils::cRTFIgnoreEmptyLines | file_utils::cRTFIgnoreCommentedLines | file_utils::cRTFPrintErrorMessages))
648         {
649             console::error("Failed reading command line params from options file \"%s\"\n", VOGL_CMD_LINE_OPTIONS_FILE);
650         }
651         else
652         {
653             dynamic_string all_opts;
654             for (uint i = 0; i < opts.size(); i++)
655                 all_opts.format_append("%s ", opts[i].get_ptr());
656
657             if (!split_command_line_params(all_opts.get_ptr(), cmd_line_params))
658                 console::error("%s: Failed splitting command line params from options file: %s\n", VOGL_FUNCTION_NAME, pEnv_cmd_line);
659         }
660     }
661     else
662     {
663         console::message("Trying to use app's command line options\n");
664
665         cmd_line_params = get_command_line_params();
666     }
667
668     command_line_params::parse_config parse_cfg;
669     parse_cfg.m_single_minus_params = true;
670     parse_cfg.m_double_minus_params = true;
671     parse_cfg.m_ignore_non_params = pEnv_cmd_line ? false : true;
672     parse_cfg.m_ignore_unrecognized_params = pEnv_cmd_line ? false : true;
673     parse_cfg.m_pParam_accept_prefix = "vogl_";
674
675     if (!g_command_line_params.parse(cmd_line_params, VOGL_ARRAY_SIZE(g_command_line_param_descs), g_command_line_param_descs, parse_cfg))
676     {
677         console::error("%s: Failed parsing command line parameters\n", VOGL_FUNCTION_NAME);
678         exit(EXIT_FAILURE);
679     }
680
681     g_dump_gl_calls_flag = g_command_line_params.get_value_as_bool("vogl_dump_gl_calls");
682     g_dump_gl_buffers_flag = g_command_line_params.get_value_as_bool("vogl_dump_gl_buffers");
683     g_dump_gl_shaders_flag = g_command_line_params.get_value_as_bool("vogl_dump_gl_shaders");
684     g_disable_gl_program_binary_flag = g_command_line_params.get_value_as_bool("vogl_disable_gl_program_binary");
685     g_flush_files_after_each_call = g_command_line_params.get_value_as_bool("vogl_flush_files_after_each_call");
686     g_flush_files_after_each_swap = g_command_line_params.get_value_as_bool("vogl_flush_files_after_each_swap");
687
688     g_gather_statistics = g_command_line_params.get_value_as_bool("vogl_dump_stats");
689     g_null_mode = g_command_line_params.get_value_as_bool("vogl_null_mode");
690     g_backtrace_all_calls = g_command_line_params.get_value_as_bool("vogl_backtrace_all_calls");
691     g_disable_client_side_array_tracing = g_command_line_params.get_value_as_bool("vogl_disable_client_side_array_tracing");
692
693     if (g_command_line_params.get_value_as_bool("vogl_dump_gl_full"))
694     {
695         g_dump_gl_calls_flag = true;
696         g_dump_gl_buffers_flag = true;
697         g_dump_gl_shaders_flag = true;
698     }
699 }
700
701 //----------------------------------------------------------------------------------------------------------------------
702 // vogl_check_for_threaded_driver_optimizations
703 //----------------------------------------------------------------------------------------------------------------------
704 static bool vogl_check_for_threaded_driver_optimizations()
705 {
706     VOGL_FUNC_TRACER
707
708     const char *pThreaded_optimizations = getenv("__GL_THREADED_OPTIMIZATIONS");
709     if (!pThreaded_optimizations)
710         return false;
711
712     if (string_to_int(pThreaded_optimizations) != 0)
713     {
714         vogl_error_printf("-----------------------------------------------------------------------------------------------------------------------------------------------------------------\n");
715         vogl_error_printf("%s: __GL_THREADED_OPTIMIZATIONS is defined and non-zero -- it is HIGHLY recommended you remove this environment variable or tracing will be very slow!\n", VOGL_FUNCTION_NAME);
716         vogl_error_printf("-----------------------------------------------------------------------------------------------------------------------------------------------------------------\n");
717         return true;
718     }
719
720     return false;
721 }
722
723 //----------------------------------------------------------------------------------------------------------------------
724 // vogl_global_init - called once on the first intercepted GL/GLX function call
725 //
726 // Guaranteed to be called once only on the first GLX func call.  You can do more or less whatever you
727 // want here (this is after the low-level init, way past global constructor time, and probably during
728 // app init).  This is where cmd lines are processed, remoting is initialized, the log/trace files are
729 // opened, etc.
730 //----------------------------------------------------------------------------------------------------------------------
731 static void vogl_global_init()
732 {
733 #if VOGL_FUNCTION_TRACING
734     fflush(stdout);
735     fflush(stderr);
736     setvbuf(stdout, NULL, _IONBF, 0);
737     setvbuf(stderr, NULL, _IONBF, 0);
738 #endif
739
740     VOGL_FUNC_TRACER
741
742     g_thread_safe_random.seed_from_urandom();
743
744     colorized_console::init();
745
746     console::set_tool_prefix("(vogltrace) ");
747
748     console::message("Command line params: \"%s\"\n", get_command_line().get_ptr());
749
750     bool reliable_rdtsc = vogl::utils::init_rdtsc();
751     if (reliable_rdtsc)
752         console::message("Reliable tsc clocksource found. Using rdtsc.\n");
753     else
754         console::message("Unreliable tsc clocksource found. Not using rdtsc.\n");
755
756     vogl_init_command_line_params();
757
758     vogl_init_logfile();
759
760     vogl_common_lib_global_init();
761
762     if (g_command_line_params.has_key("vogl_tracefile"))
763     {
764         if (!g_vogl_trace_writer.open(g_command_line_params.get_value_as_string_or_empty("vogl_tracefile").get_ptr()))
765         {
766             // FIXME: What do we do? The caller WANTS a full-stream trace, and continuing execution is probably not desired.
767
768             vogl_error_printf("%s: Failed opening trace file, exiting application!\n", VOGL_FUNCTION_NAME);
769
770             exit(EXIT_FAILURE);
771         }
772     }
773
774     if (!g_command_line_params.get_value_as_bool("vogl_disable_signal_interception"))
775     {
776         console::message("Installing exception/signal callbacks\n");
777
778         colorized_console::set_exception_callback();
779
780         g_vogl_pPrev_exception_callback = vogl_set_exception_callback(vogl_exception_callback);
781     }
782
783 #if VOGL_REMOTING
784     console::message("vogl_traceport = %d\n", g_command_line_params.get_value_as_int("vogl_traceport"));
785     vogl_init_listener(g_command_line_params.get_value_as_int("vogl_traceport"));
786 #endif
787
788     vogl_check_for_threaded_driver_optimizations();
789
790     g_backtrace_hashmap.reserve(VOGL_BACKTRACE_HASHMAP_CAPACITY);
791
792     // atexit routines are called in the reverse order in which they were registered. We would like
793         //  our vogl_atexit() routine to be called before anything else (Ie C++ destructors, etc.) So we
794         //  put atexit at the end of vogl_global_init() and another at the end of glXMakeCurrent.
795     atexit(vogl_atexit);
796
797     console::message("vogl_global_init finished\n");
798
799     atomic_increment32(&g_vogl_has_been_initialized);
800 }
801
802 //----------------------------------------------------------------------------------------------------------------------
803 // vogl_check_context
804 //----------------------------------------------------------------------------------------------------------------------
805 static inline void vogl_check_context(gl_entrypoint_id_t id, vogl_context *pContext)
806 {
807     if (!pContext)
808     {
809         const char *pName = g_vogl_entrypoint_descs[id].m_pName;
810
811         // FIXME: Check to see if the func is in a non-GL category, anything but this!
812         // These are rare enough that this is not the biggest fire right now.
813         if ((pName[0] != 'g') || (pName[1] != 'l') || (pName[2] != 'X'))
814         {
815             uint n = vogl_strlen(pName);
816             if ((n <= 3) || ((pName[n - 3] != 'R') || (pName[n - 2] != 'A') || (pName[n - 1] != 'D')))
817             {
818                 vogl_error_printf("%s: OpenGL function \"%s\" called without an active context!\n", VOGL_FUNCTION_NAME, pName);
819             }
820         }
821     }
822 }
823
824 //----------------------------------------------------------------------------------------------------------------------
825 // vogl_entrypoint_prolog
826 // This function gets called on every GL call - be careful what you do here!
827 //----------------------------------------------------------------------------------------------------------------------
828 static inline vogl_thread_local_data *vogl_entrypoint_prolog(gl_entrypoint_id_t entrypoint_id)
829 {
830     if (!g_vogl_has_been_initialized)
831     {
832         pthread_once(&g_vogl_init_once_control, vogl_global_init);
833     }
834
835     vogl_thread_local_data *pTLS_data = vogl_get_or_create_thread_local_data();
836
837     // Something very odd is going on - the driver somehow called itself while WE where calling it, so let's immediately bail for safety.
838     if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
839         return pTLS_data;
840
841     // Atomically inc the 64-bit counter
842     // TODO: Make a helper for this
843     int64_t cur_ctr;
844     do
845     {
846         cur_ctr = g_vogl_entrypoint_descs[entrypoint_id].m_trace_call_counter;
847     } while (atomic_compare_exchange64(&g_vogl_entrypoint_descs[entrypoint_id].m_trace_call_counter, cur_ctr + 1, cur_ctr) != cur_ctr);
848
849     if ((!cur_ctr) && (!g_vogl_entrypoint_descs[entrypoint_id].m_is_whitelisted))
850         vogl_error_printf("%s: Function \"%s\" not yet in function whitelist, this API will not be replayed and this trace will not be replayable!\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[entrypoint_id].m_pName);
851
852     vogl_check_context(entrypoint_id, pTLS_data->m_pContext);
853
854     return pTLS_data;
855 }
856
857 //----------------------------------------------------------------------------------------------------------------------
858 // struct gl_vertex_attribute
859 //----------------------------------------------------------------------------------------------------------------------
860 struct gl_vertex_attribute
861 {
862     GLint m_size;
863     GLenum m_type;
864     GLboolean m_normalized;
865     GLsizei m_stride;
866     const GLvoid *m_pointer;
867     GLuint m_buffer;
868     bool m_enabled;
869
870     void clear()
871     {
872         m_size = 4;
873         m_type = GL_FLOAT;
874         m_normalized = false;
875         m_stride = 0;
876         m_pointer = NULL;
877         m_buffer = 0;
878         m_enabled = 0;
879     }
880 };
881 const uint VOGL_MAX_SUPPORTED_GL_VERTEX_ATTRIBUTES = 32;
882
883 typedef vogl::hash_map<GLenum, GLuint> gl_buffer_binding_map;
884 //----------------------------------------------------------------------------------------------------------------------
885 // struct gl_buffer_desc
886 //----------------------------------------------------------------------------------------------------------------------
887 struct gl_buffer_desc
888 {
889     GLuint m_handle;
890     int64_t m_size;
891     GLenum m_usage;
892
893     void *m_pMap;
894     int64_t m_map_ofs;
895     int64_t m_map_size;
896
897     // FIXME: Don't alias this!
898     // NOTE: This is a GLbitfield of m_map_range is true, otherwise it's a GL_ENUM!!
899     GLbitfield m_map_access;
900
901     bool m_map_range;
902
903     struct flushed_range
904     {
905         inline flushed_range(int64_t ofs, int64_t size)
906             : m_ofs(ofs), m_size(size)
907         {
908         }
909         inline flushed_range()
910         {
911         }
912
913         int64_t m_ofs;
914         int64_t m_size;
915     };
916     vogl::vector<flushed_range> m_flushed_ranges;
917
918     inline gl_buffer_desc()
919     {
920         clear();
921     }
922     inline gl_buffer_desc(GLuint handle)
923     {
924         clear();
925         m_handle = handle;
926     }
927
928     inline void clear()
929     {
930         m_handle = 0;
931         m_size = 0;
932         m_usage = 0;
933         m_pMap = NULL;
934         m_map_ofs = 0;
935         m_map_size = 0;
936         m_map_access = 0;
937         m_map_range = false;
938         m_flushed_ranges.clear();
939     }
940 };
941
942 typedef vogl::hash_map<GLuint, gl_buffer_desc> gl_buffer_desc_map;
943
944 //----------------------------------------------------------------------------------------------------------------------
945 // vogl_scoped_gl_error_absorber
946 //----------------------------------------------------------------------------------------------------------------------
947 class vogl_scoped_gl_error_absorber
948 {
949     vogl_context *m_pContext;
950
951 public:
952     vogl_scoped_gl_error_absorber(vogl_context *pContext);
953     ~vogl_scoped_gl_error_absorber();
954 };
955
956 //----------------------------------------------------------------------------------------------------------------------
957 // class vogl_tracer_snapshot_handle_remapper
958 //----------------------------------------------------------------------------------------------------------------------
959 class vogl_context_handle_remapper : public vogl_handle_remapper
960 {
961     VOGL_NO_COPY_OR_ASSIGNMENT_OP(vogl_context_handle_remapper);
962
963     vogl_context *m_pContext;
964
965 public:
966     vogl_context_handle_remapper(vogl_context *pContext)
967         : m_pContext(pContext)
968     {
969     }
970
971     virtual bool is_default_remapper() const
972     {
973         return false;
974     }
975
976     virtual bool is_valid_handle(vogl_namespace_t handle_namespace, uint64_t from_handle);
977
978     virtual bool determine_from_object_target(vogl_namespace_t handle_namespace, uint64_t from_handle, GLenum &target);
979
980     virtual bool determine_to_object_target(vogl_namespace_t handle_namespace, uint64_t to_handle, GLenum &target)
981     {
982         return determine_from_object_target(handle_namespace, to_handle, target);
983     }
984 };
985
986 //----------------------------------------------------------------------------------------------------------------------
987 // class vogl_context
988 //----------------------------------------------------------------------------------------------------------------------
989 class vogl_context
990 {
991     VOGL_NO_COPY_OR_ASSIGNMENT_OP(vogl_context);
992
993 public:
994     vogl_context(GLXContext handle)
995         : m_ref_count(1),
996           m_deleted_flag(false),
997           m_pShared_state(this),
998           m_context_handle(handle),
999           m_sharelist_handle(NULL),
1000           m_pDpy(NULL),
1001           m_drawable(None),
1002           m_read_drawable(None),
1003           m_render_type(0),
1004           m_fb_config(NULL),
1005           m_direct(false),
1006           m_created_from_attribs(false),
1007           m_current_thread(0),
1008           m_max_vertex_attribs(0),
1009           m_has_been_made_current(false),
1010           m_window_width(-1),
1011           m_window_height(-1),
1012           m_frame_index(0),
1013           m_creation_func(VOGL_ENTRYPOINT_INVALID),
1014           m_latched_gl_error(GL_NO_ERROR),
1015           m_cur_program(0),
1016           m_in_gl_begin(false),
1017           m_uses_client_side_arrays(false),
1018           m_handle_remapper(this),
1019           m_current_display_list_handle(-1),
1020           m_current_display_list_mode(GL_NONE)
1021     {
1022         utils::zero_object(m_xvisual_info);
1023     }
1024
1025     ~vogl_context()
1026     {
1027     }
1028
1029     int get_ref_count() const
1030     {
1031         return m_ref_count;
1032     }
1033     int add_ref()
1034     {
1035         ++m_ref_count;
1036         return m_ref_count;
1037     }
1038     int del_ref()
1039     {
1040         --m_ref_count;
1041         return m_ref_count;
1042     }
1043
1044     bool get_deleted_flag() const
1045     {
1046         return m_deleted_flag;
1047     }
1048     void set_deleted_flag(bool val)
1049     {
1050         m_deleted_flag = val;
1051     }
1052
1053     vogl_context *get_shared_state() const
1054     {
1055         return m_pShared_state;
1056     }
1057     void set_shared_context(vogl_context *pContext)
1058     {
1059         m_pShared_state = pContext;
1060     }
1061
1062     vogl_context *get_context_state()
1063     {
1064         return this;
1065     }
1066
1067     bool is_root_context() const
1068     {
1069         return this == m_pShared_state;
1070     }
1071     bool is_share_context() const
1072     {
1073         return this != m_pShared_state;
1074     }
1075
1076     GLXContext get_context_handle() const
1077     {
1078         return m_context_handle;
1079     }
1080
1081     GLXContext get_sharelist_handle() const
1082     {
1083         return m_sharelist_handle;
1084     }
1085     void set_sharelist_handle(GLXContext context)
1086     {
1087         m_sharelist_handle = context;
1088     }
1089
1090     const Display *get_display() const
1091     {
1092         return m_pDpy;
1093     }
1094     void set_display(const Display *pDpy)
1095     {
1096         m_pDpy = pDpy;
1097     }
1098
1099     void set_drawable(GLXDrawable drawable)
1100     {
1101         m_drawable = drawable;
1102     }
1103     GLXDrawable get_drawable() const
1104     {
1105         return m_drawable;
1106     }
1107
1108     void set_read_drawable(GLXDrawable read)
1109     {
1110         m_read_drawable = read;
1111     }
1112     GLXDrawable get_read_drawable() const
1113     {
1114         return m_read_drawable;
1115     }
1116
1117     void set_render_type(int render_type)
1118     {
1119         m_render_type = render_type;
1120     }
1121     int get_render_type() const
1122     {
1123         return m_render_type;
1124     }
1125
1126     bool get_direct() const
1127     {
1128         return m_direct;
1129     }
1130     void set_direct(bool direct)
1131     {
1132         m_direct = direct;
1133     }
1134
1135     const XVisualInfo &get_xvisual_info() const
1136     {
1137         return m_xvisual_info;
1138     }
1139     void set_xvisual_info(const XVisualInfo *p)
1140     {
1141         m_xvisual_info = *p;
1142     }
1143
1144     bool get_created_from_attribs() const
1145     {
1146         return m_created_from_attribs;
1147     }
1148     void set_created_from_attribs(bool created_from_attribs)
1149     {
1150         m_created_from_attribs = created_from_attribs;
1151     }
1152
1153     uint64_t get_current_thread() const
1154     {
1155         return m_current_thread;
1156     }
1157     void set_current_thread(uint64_t tid)
1158     {
1159         m_current_thread = tid;
1160     }
1161
1162     void set_creation_func(gl_entrypoint_id_t func)
1163     {
1164         m_creation_func = func;
1165     }
1166     gl_entrypoint_id_t get_creation_func() const
1167     {
1168         return m_creation_func;
1169     }
1170
1171     void set_fb_config(GLXFBConfig config)
1172     {
1173         m_fb_config = config;
1174     }
1175     GLXFBConfig get_fb_config()
1176     {
1177         return m_fb_config;
1178     }
1179
1180     inline bool get_has_been_made_current() const
1181     {
1182         return m_has_been_made_current;
1183     }
1184
1185     void init()
1186     {
1187         VOGL_ASSERT(m_creation_func != VOGL_ENTRYPOINT_INVALID);
1188         if (m_creation_func == VOGL_ENTRYPOINT_INVALID)
1189             return;
1190
1191         vogl_context_attribs attribs(m_attrib_list.get_ptr(), m_attrib_list.size());
1192         m_context_desc.init(m_creation_func, m_direct, (vogl_trace_ptr_value)m_context_handle, (vogl_trace_ptr_value)m_sharelist_handle, attribs);
1193     }
1194
1195     void set_attrib_list(const int *attrib_list)
1196     {
1197         int n = vogl_determine_attrib_list_array_size(attrib_list);
1198         m_attrib_list.clear();
1199         m_attrib_list.append(attrib_list, n);
1200     }
1201
1202     const vogl::vector<int> &get_attrib_list() const
1203     {
1204         return m_attrib_list;
1205     }
1206
1207     // true if a core profile was explictly requested in the attrib list.
1208     inline bool requested_core_profile() const
1209     {
1210         return (m_context_desc.get_attribs().get_value_or_default(GLX_CONTEXT_PROFILE_MASK_ARB) & GLX_CONTEXT_CORE_PROFILE_BIT_ARB) != 0;
1211     }
1212
1213     // true if a compat profile was explictly requested in the attrib list.
1214     inline bool requested_compatibility_profile() const
1215     {
1216         return (m_context_desc.get_attribs().get_value_or_default(GLX_CONTEXT_PROFILE_MASK_ARB) & GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB) != 0;
1217     }
1218
1219     // true if a debug context was explictly requested in the attrib list.
1220     inline bool requested_debug_context() const
1221     {
1222         return (m_context_desc.get_attribs().get_value_or_default(GLX_CONTEXT_FLAGS_ARB) & GLX_CONTEXT_DEBUG_BIT_ARB) != 0;
1223     }
1224
1225     // true if a forward compatible context was explictly requested in the attrib list.
1226     inline bool requested_forward_compatible() const
1227     {
1228         return (m_context_desc.get_attribs().get_value_or_default(GLX_CONTEXT_FLAGS_ARB) & GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB) != 0;
1229     }
1230
1231     // true if this is a core profile context (the context must have been made current first)
1232     inline bool is_core_profile() const
1233     {
1234         return m_context_info.is_core_profile();
1235     }
1236
1237     // only valid after the first MakeCurrent
1238     inline GLuint get_max_vertex_attribs() const
1239     {
1240         return m_max_vertex_attribs;
1241     }
1242     inline GLuint get_max_texture_coords() const
1243     {
1244         return m_context_info.get_max_texture_coords();
1245     }
1246
1247     // compat only - will be 0 in core
1248     inline GLuint get_max_texture_units() const
1249     {
1250         return m_context_info.get_max_texture_units();
1251     }
1252
1253     const vogl_context_desc &get_context_desc() const
1254     {
1255         return m_context_desc;
1256     }
1257     const vogl_context_info &get_context_info() const
1258     {
1259         return m_context_info;
1260     }
1261
1262     const vogl_capture_context_params &get_capture_context_params() const
1263     {
1264         return m_capture_context_params;
1265     }
1266     vogl_capture_context_params &get_capture_context_params()
1267     {
1268         return m_capture_context_params;
1269     }
1270
1271     const vogl_framebuffer_capturer &get_framebuffer_capturer() const
1272     {
1273         return m_framebuffer_capturer;
1274     }
1275     vogl_framebuffer_capturer &get_framebuffer_capturer()
1276     {
1277         return m_framebuffer_capturer;
1278     }
1279
1280     inline void on_make_current()
1281     {
1282         set_current_thread(vogl_get_current_kernel_thread_id());
1283
1284         if (!m_has_been_made_current)
1285         {
1286             vogl_scoped_gl_error_absorber gl_error_absorber(this);
1287             VOGL_NOTE_UNUSED(gl_error_absorber);
1288
1289             m_max_vertex_attribs = vogl_get_gl_integer(GL_MAX_VERTEX_ATTRIBS);
1290             if (m_max_vertex_attribs > VOGL_MAX_SUPPORTED_GL_VERTEX_ATTRIBUTES)
1291             {
1292                 vogl_error_printf("%s: GL_MAX_VERTEX_ATTRIBS is larger than supported (%u, max supported is %u), trace may not contain all client side vertex attribs\n", VOGL_METHOD_NAME, m_max_vertex_attribs, VOGL_MAX_SUPPORTED_GL_VERTEX_ATTRIBUTES);
1293                 m_max_vertex_attribs = VOGL_MAX_SUPPORTED_GL_VERTEX_ATTRIBUTES;
1294             }
1295
1296             if (!m_context_info.init(m_context_desc))
1297             {
1298                 vogl_error_printf("%s: Failed initializing m_context_info!\n", VOGL_METHOD_NAME);
1299             }
1300
1301             if (!m_has_been_made_current)
1302             {
1303                 on_first_make_current();
1304             }
1305
1306             m_has_been_made_current = true;
1307         }
1308     }
1309
1310     bool is_context_current()
1311     {
1312         if (!GL_ENTRYPOINT(glXGetCurrentContext))
1313             return false;
1314
1315         // Double check that the context that we think is current is actually current.
1316         GLXContext cur_context = GL_ENTRYPOINT(glXGetCurrentContext)();
1317         if (!cur_context)
1318         {
1319             VOGL_ASSERT(!m_current_thread);
1320             return false;
1321         }
1322
1323         if (get_context_handle() != cur_context)
1324         {
1325             VOGL_ASSERT(!m_current_thread);
1326             return false;
1327         }
1328
1329         VOGL_ASSERT(vogl_get_current_kernel_thread_id() == m_current_thread);
1330
1331         return true;
1332     }
1333
1334     // This will be called with the context made current, however the TLS struct won't indicate that this context is current, and m_current_thread will not reflect this either!
1335     // Note this will be called before glXMakeCurrent() when contexts are switching, and it's possible the call could fail (and this context could remain current). So don't do anything drastic here.
1336     void on_release_current_prolog()
1337     {
1338         if (!is_context_current())
1339             return;
1340
1341         peek_and_record_gl_error();
1342
1343         m_framebuffer_capturer.flush();
1344
1345         peek_and_drop_gl_error();
1346     }
1347
1348     void on_release_current_epilog()
1349     {
1350         set_current_thread(0);
1351     }
1352
1353     void on_destroy_prolog()
1354     {
1355         if (!is_context_current())
1356         {
1357             m_framebuffer_capturer.deinit(false);
1358             return;
1359         }
1360
1361         peek_and_record_gl_error();
1362
1363         m_framebuffer_capturer.deinit(true);
1364
1365         peek_and_drop_gl_error();
1366     }
1367
1368     // buffer handle and target shadowing
1369     void gen_buffers(GLsizei n, GLuint *pIDs)
1370     {
1371         if (!pIDs)
1372             return;
1373
1374         vogl_scoped_context_shadow_lock lock;
1375
1376         for (GLsizei i = 0; i < n; i++)
1377         {
1378             GLuint id = pIDs[i];
1379             if (id)
1380             {
1381                 if (!get_shared_state()->m_capture_context_params.m_buffer_targets.insert(id, GL_NONE).second)
1382                 {
1383                     vogl_error_printf("%s: Can't insert buffer handle 0x%04X into buffer target map!\n", VOGL_METHOD_NAME, id);
1384                 }
1385             }
1386         }
1387     }
1388
1389     void bind_buffer(GLenum target, GLuint id)
1390     {
1391         if (!id)
1392             return;
1393
1394         vogl_scoped_context_shadow_lock lock;
1395
1396         GLenum *pTarget = get_shared_state()->m_capture_context_params.m_buffer_targets.find_value(id);
1397         if (!pTarget)
1398         {
1399             vogl_error_printf("%s: Unable to find buffer handle 0x%04X in buffer target map!\n", VOGL_METHOD_NAME, id);
1400             return;
1401         }
1402
1403         if (*pTarget == GL_NONE)
1404         {
1405             // This is the first bind, so record the target. Otherwise they are rebinding to a different target, which shouldn't matter to us for snapshotting purposes (right??).
1406             *pTarget = target;
1407         }
1408     }
1409
1410     void delete_buffers(GLsizei n, const GLuint *buffers)
1411     {
1412         if ((!n) || (!buffers))
1413             return;
1414
1415         vogl_scoped_context_shadow_lock lock;
1416
1417         for (GLsizei i = 0; i < n; i++)
1418         {
1419             GLuint buffer = buffers[i];
1420             if (!buffer)
1421                 continue;
1422
1423             get_shared_state()->m_buffer_descs.erase(buffer);
1424
1425             if (!get_shared_state()->m_capture_context_params.m_buffer_targets.erase(buffer))
1426             {
1427                 vogl_error_printf("%s: Can't erase buffer handle 0x%04X from buffer target map!\n", VOGL_METHOD_NAME, buffer);
1428             }
1429         }
1430     }
1431
1432     inline gl_buffer_desc &get_or_create_buffer_desc(GLuint handle)
1433     {
1434         vogl_scoped_context_shadow_lock lock;
1435
1436         gl_buffer_desc_map::iterator buf_it(get_shared_state()->m_buffer_descs.find(handle));
1437         if (buf_it != get_shared_state()->m_buffer_descs.end())
1438             return buf_it->second;
1439
1440         gl_buffer_desc desc(handle);
1441         return (get_shared_state()->m_buffer_descs.insert(handle, desc).first)->second;
1442     }
1443
1444     inline uint get_total_mapped_buffers() const
1445     {
1446         vogl_scoped_context_shadow_lock lock;
1447
1448         uint total = 0;
1449         for (gl_buffer_desc_map::const_iterator it = get_shared_state()->m_buffer_descs.begin(); it != get_shared_state()->m_buffer_descs.end(); ++it)
1450         {
1451             if (it->second.m_pMap)
1452                 total++;
1453         }
1454         return total;
1455     }
1456
1457     inline void set_window_dimensions(int width, int height)
1458     {
1459         m_window_width = width;
1460         m_window_height = height;
1461     }
1462
1463     inline int get_window_width() const
1464     {
1465         return m_window_width;
1466     }
1467     inline int get_window_height() const
1468     {
1469         return m_window_height;
1470     }
1471
1472     uint64_t get_frame_index() const
1473     {
1474         return m_frame_index;
1475     }
1476     void set_frame_index(uint f)
1477     {
1478         m_frame_index = f;
1479     }
1480     void inc_frame_index()
1481     {
1482         m_frame_index++;
1483     }
1484
1485     GLuint get_cur_program() const
1486     {
1487         return m_cur_program;
1488     }
1489     void set_cur_program(GLuint program)
1490     {
1491         m_cur_program = program;
1492     }
1493
1494     GLenum get_latched_gl_error() const
1495     {
1496         return m_latched_gl_error;
1497     }
1498     bool has_latched_gl_error() const
1499     {
1500         return m_latched_gl_error != GL_NO_ERROR;
1501     }
1502     void clear_latched_gl_error()
1503     {
1504         m_latched_gl_error = GL_NO_ERROR;
1505     }
1506     void set_latched_gl_error(GLenum err)
1507     {
1508         m_latched_gl_error = err;
1509     }
1510
1511     // Returns the context's most recent GL error, NOT the currently latched error.
1512     GLenum peek_and_record_gl_error()
1513     {
1514         if (m_in_gl_begin)
1515             return GL_NO_ERROR;
1516
1517         GLenum gl_err = GL_ENTRYPOINT(glGetError)();
1518
1519         if (gl_err != GL_NO_ERROR)
1520         {
1521             if (!has_latched_gl_error())
1522             {
1523                 set_latched_gl_error(gl_err);
1524
1525                 vogl_warning_printf("%s: GL error %s occurred sometime before this function was called. This error has been latched by the tracer onto the tracer's context shadow struct. This error will be reported to the caller the next time glGetError() is called, and will mask any GL error returned by that future call.\n",
1526                                    VOGL_METHOD_NAME, g_gl_enums.find_gl_error_name(gl_err));
1527             }
1528             else
1529             {
1530                 vogl_warning_printf("%s: GL error %s occurred sometime before this function was called. The tracer already had a latched GL error of %s. This error will be suppressed by the tracer (because it would have been by GL itself if the tracer was not present).\n",
1531                                    VOGL_METHOD_NAME, g_gl_enums.find_gl_error_name(gl_err), g_gl_enums.find_gl_error_name(get_latched_gl_error()));
1532             }
1533         }
1534
1535         return gl_err;
1536     }
1537
1538     // Gets and drops the current GL error (this is done to "hide" any errors we've introduced by tracing from the client app).
1539     // Be sure to retrieve and latch any client errors by calling peek_and_record_gl_error() first!
1540     GLenum peek_and_drop_gl_error()
1541     {
1542         if (m_in_gl_begin)
1543             return GL_NO_ERROR;
1544
1545         GLenum gl_err = GL_ENTRYPOINT(glGetError)();
1546
1547         if (gl_err != GL_NO_ERROR)
1548         {
1549             vogl_error_printf("%s: GL error %s occurred internally while libvogltrace was making GL calls. This GL error will not be seen by the client app (THIS SHOULD NOT HAPPEN)\n", VOGL_METHOD_NAME, g_gl_enums.find_gl_error_name(gl_err));
1550         }
1551
1552         return gl_err;
1553     }
1554
1555     // TODO: Modify each shadowing method to print detailed error messages
1556     // TODO: Move all these shadow methods right into vogl_capture_context_params
1557
1558     // Texture handle shadowing
1559     void gen_textures(GLsizei n, GLuint *pTextures)
1560     {
1561         if (!pTextures)
1562             return;
1563
1564         vogl_scoped_context_shadow_lock lock;
1565
1566         for (GLsizei i = 0; i < n; i++)
1567         {
1568             GLuint handle = pTextures[i];
1569             if (handle)
1570             {
1571                 if (!get_shared_state()->m_capture_context_params.m_textures.insert(handle, handle, GL_NONE))
1572                 {
1573                     vogl_warning_printf("%s: Unable to add texture handle %u to texture handle shadow map!\n", VOGL_METHOD_NAME, handle);
1574                 }
1575             }
1576         }
1577     }
1578
1579     void del_textures(GLsizei n, const GLuint *pTextures)
1580     {
1581         if (!pTextures)
1582             return;
1583
1584         vogl_scoped_context_shadow_lock lock;
1585
1586         for (GLsizei i = 0; i < n; i++)
1587         {
1588             GLuint handle = pTextures[i];
1589             if (handle)
1590             {
1591                 if (!get_shared_state()->m_capture_context_params.m_textures.erase(handle))
1592                 {
1593                     vogl_warning_printf("%s: Failed erasing handle %u from texture handle shadow map!\n", VOGL_METHOD_NAME, handle);
1594                 }
1595             }
1596         }
1597     }
1598
1599     void bind_texture(GLenum target, GLuint texture)
1600     {
1601         if (texture)
1602         {
1603             vogl_scoped_context_shadow_lock lock;
1604
1605             get_shared_state()->m_capture_context_params.m_textures.update(texture, target);
1606         }
1607     }
1608
1609     void bind_texture_conditionally(GLenum target, GLuint texture)
1610     {
1611         if (texture)
1612         {
1613             vogl_scoped_context_shadow_lock lock;
1614
1615             get_shared_state()->m_capture_context_params.m_textures.conditional_update(texture, GL_NONE, target);
1616         }
1617     }
1618
1619     // Framebuffer handle shadowing
1620     void gen_framebuffers(GLsizei n, GLuint *pFramebuffers)
1621     {
1622         if (!pFramebuffers)
1623             return;
1624         for (GLsizei i = 0; i < n; i++)
1625         {
1626             GLuint handle = pFramebuffers[i];
1627             if (handle)
1628                 get_context_state()->m_capture_context_params.m_framebuffers.insert(handle);
1629         }
1630     }
1631
1632     void del_framebuffers(GLsizei n, const GLuint *pFramebuffers)
1633     {
1634         if (!pFramebuffers)
1635             return;
1636         for (GLsizei i = 0; i < n; i++)
1637         {
1638             GLuint handle = pFramebuffers[i];
1639             if (handle)
1640                 get_context_state()->m_capture_context_params.m_framebuffers.erase(handle);
1641         }
1642     }
1643
1644     // VAO handle shadowing
1645     void gen_vertexarrays(GLsizei n, GLuint *pArrays)
1646     {
1647         if (!pArrays)
1648             return;
1649         for (GLsizei i = 0; i < n; i++)
1650         {
1651             GLuint handle = pArrays[i];
1652             if (handle)
1653                 get_context_state()->m_capture_context_params.m_vaos.insert(handle);
1654         }
1655     }
1656
1657     void del_vertexarrays(GLsizei n, const GLuint *pArrays)
1658     {
1659         if (!pArrays)
1660             return;
1661         for (GLsizei i = 0; i < n; i++)
1662         {
1663             GLuint handle = pArrays[i];
1664             if (handle)
1665                 get_context_state()->m_capture_context_params.m_vaos.erase(handle);
1666         }
1667     }
1668
1669     void bind_vertexarray(GLuint array)
1670     {
1671         if (array)
1672             get_context_state()->m_capture_context_params.m_vaos.insert(array);
1673     }
1674
1675     // sync handle shadowing
1676     void gen_sync(GLsync sync)
1677     {
1678         if (sync)
1679         {
1680             vogl_scoped_context_shadow_lock lock;
1681
1682             get_shared_state()->m_capture_context_params.m_syncs.insert((uint64_t)sync);
1683         }
1684     }
1685
1686     void del_sync(GLsync sync)
1687     {
1688         if (sync)
1689         {
1690             vogl_scoped_context_shadow_lock lock;
1691
1692             get_shared_state()->m_capture_context_params.m_syncs.erase((uint64_t)sync);
1693         }
1694     }
1695
1696     // sampler handle shadowing
1697     void gen_samplers(GLsizei n, const GLuint *pSamplers)
1698     {
1699         if (!pSamplers)
1700             return;
1701
1702         vogl_scoped_context_shadow_lock lock;
1703
1704         for (GLsizei i = 0; i < n; i++)
1705         {
1706             GLuint handle = pSamplers[i];
1707             if (handle)
1708                 get_shared_state()->m_capture_context_params.m_samplers.insert(handle);
1709         }
1710     }
1711
1712     void del_samplers(GLsizei n, const GLuint *pSamplers)
1713     {
1714         if (!pSamplers)
1715             return;
1716
1717         vogl_scoped_context_shadow_lock lock;
1718
1719         for (GLsizei i = 0; i < n; i++)
1720         {
1721             GLuint handle = pSamplers[i];
1722             if (handle)
1723                 get_shared_state()->m_capture_context_params.m_samplers.erase(handle);
1724         }
1725     }
1726
1727     // query handle and target shadowing
1728     void gen_queries(GLsizei n, GLuint *pIDs)
1729     {
1730         if (!pIDs)
1731             return;
1732
1733         vogl_scoped_context_shadow_lock lock;
1734
1735         for (GLsizei i = 0; i < n; i++)
1736         {
1737             GLuint id = pIDs[i];
1738             if (id)
1739                 get_shared_state()->m_capture_context_params.m_query_targets.insert(id, GL_NONE);
1740         }
1741     }
1742
1743     void del_queries(GLsizei n, const GLuint *pIDs)
1744     {
1745         if (!pIDs)
1746             return;
1747
1748         vogl_scoped_context_shadow_lock lock;
1749
1750         for (GLsizei i = 0; i < n; i++)
1751         {
1752             GLuint id = pIDs[i];
1753             if (id)
1754                 get_shared_state()->m_capture_context_params.m_query_targets.erase(id);
1755         }
1756     }
1757
1758     void begin_query(GLenum target, GLuint id)
1759     {
1760         if (id)
1761         {
1762             vogl_scoped_context_shadow_lock lock;
1763
1764             if (get_shared_state()->m_capture_context_params.m_query_targets.contains(id))
1765             {
1766                 get_shared_state()->m_capture_context_params.m_query_targets[id] = target;
1767             }
1768             else
1769             {
1770                 vogl_error_printf("%s: Unable to find query target handle %u in query target handle shadow\n", VOGL_METHOD_NAME, id);
1771             }
1772         }
1773     }
1774
1775     // arb programs
1776     void gen_arb_programs(GLsizei n, const GLuint *pHandles)
1777     {
1778         if (!pHandles)
1779             return;
1780
1781         vogl_scoped_context_shadow_lock lock;
1782
1783         for (GLsizei i = 0; i < n; i++)
1784         {
1785             GLuint handle = pHandles[i];
1786             if (handle)
1787                 get_shared_state()->m_capture_context_params.m_arb_program_targets.insert(handle, GL_NONE);
1788         }
1789     }
1790
1791     void bind_arb_program(GLenum target, GLuint handle)
1792     {
1793         if (handle)
1794         {
1795             vogl_scoped_context_shadow_lock lock;
1796
1797             get_shared_state()->m_capture_context_params.m_arb_program_targets[handle] = target;
1798         }
1799     }
1800
1801     void del_arb_programs(GLsizei n, const GLuint *pHandles)
1802     {
1803         if (!pHandles)
1804             return;
1805
1806         vogl_scoped_context_shadow_lock lock;
1807
1808         for (GLsizei i = 0; i < n; i++)
1809         {
1810             GLuint handle = pHandles[i];
1811             if (handle)
1812                 get_shared_state()->m_capture_context_params.m_arb_program_targets.erase(handle);
1813         }
1814     }
1815
1816     // renderbuffer handle shadowing
1817     void gen_render_buffers(GLsizei n, GLuint *pIDs)
1818     {
1819         if (!pIDs)
1820             return;
1821
1822         vogl_scoped_context_shadow_lock lock;
1823
1824         for (GLsizei i = 0; i < n; i++)
1825         {
1826             GLuint id = pIDs[i];
1827             if (id)
1828             {
1829                 if (!get_shared_state()->m_capture_context_params.m_rbos.insert(id, id, GL_NONE))
1830                 {
1831                     vogl_error_printf("%s: Can't insert render buffer handle 0x%04X into render buffer shadow!\n", VOGL_METHOD_NAME, id);
1832                 }
1833             }
1834         }
1835     }
1836
1837     void del_render_buffers(GLsizei n, const GLuint *buffers)
1838     {
1839         if ((!n) || (!buffers))
1840             return;
1841
1842         vogl_scoped_context_shadow_lock lock;
1843
1844         for (GLsizei i = 0; i < n; i++)
1845         {
1846             GLuint buffer = buffers[i];
1847             if (!buffer)
1848                 continue;
1849
1850             if (!get_shared_state()->m_capture_context_params.m_rbos.erase(buffer))
1851             {
1852                 vogl_error_printf("%s: Can't erase render buffer handle 0x%04X from render buffer shadow!\n", VOGL_METHOD_NAME, buffer);
1853             }
1854         }
1855     }
1856
1857     // program/shader shadowing
1858     GLuint handle_create_program(gl_entrypoint_id_t id)
1859     {
1860         GLuint handle;
1861
1862         if (id == VOGL_ENTRYPOINT_glCreateProgram)
1863             handle = GL_ENTRYPOINT(glCreateProgram)();
1864         else
1865         {
1866             VOGL_ASSERT(id == VOGL_ENTRYPOINT_glCreateProgramObjectARB);
1867             handle = GL_ENTRYPOINT(glCreateProgramObjectARB)();
1868         }
1869
1870         vogl_scoped_context_shadow_lock lock;
1871
1872         if (handle)
1873         {
1874             if (!get_shared_state()->m_capture_context_params.m_objs.update(handle, handle, VOGL_PROGRAM_OBJECT))
1875                 vogl_error_printf("%s: Failed inserting program handle %u into object shadow!\n", VOGL_METHOD_NAME, handle);
1876         }
1877         else
1878         {
1879             vogl_error_printf("%s: glCreateProgram/glCreateProgramObjectARB on handle %u failed!\n", VOGL_METHOD_NAME, handle);
1880         }
1881
1882         return handle;
1883     }
1884
1885     GLuint handle_create_shader(gl_entrypoint_id_t id, GLenum type)
1886     {
1887         GLuint handle;
1888
1889         if (id == VOGL_ENTRYPOINT_glCreateShader)
1890             handle = GL_ENTRYPOINT(glCreateShader)(type);
1891         else
1892         {
1893             VOGL_ASSERT(id == VOGL_ENTRYPOINT_glCreateShaderObjectARB);
1894             handle = GL_ENTRYPOINT(glCreateShaderObjectARB)(type);
1895         }
1896
1897         vogl_scoped_context_shadow_lock lock;
1898
1899         if (handle)
1900         {
1901             if (!get_shared_state()->m_capture_context_params.m_objs.update(handle, handle, VOGL_SHADER_OBJECT))
1902                 vogl_error_printf("%s: Failed inserting shader handle %u into object shadow! (type=%s)\n", VOGL_METHOD_NAME, handle, g_gl_enums.find_gl_name(type));
1903         }
1904         else
1905         {
1906             vogl_error_printf("%s: glCreateShader/glCreateShaderObjectARB on handle %u failed! (type=%s)\n", VOGL_METHOD_NAME, handle, g_gl_enums.find_gl_name(type));
1907         }
1908
1909         return handle;
1910     }
1911
1912     bool has_linked_program_snapshot(GLuint handle)
1913     {
1914         vogl_scoped_context_shadow_lock lock;
1915
1916         return get_shared_state()->m_capture_context_params.m_linked_programs.find_snapshot(handle) != NULL;
1917     }
1918
1919     bool add_linked_program_snapshot(GLuint handle, GLenum binary_format = GL_NONE, const void *pBinary = NULL, uint binary_size = 0)
1920     {
1921         vogl_scoped_context_shadow_lock lock;
1922
1923         return get_shared_state()->m_capture_context_params.m_linked_programs.add_snapshot(m_context_info, m_handle_remapper, handle, binary_format, pBinary, binary_size);
1924     }
1925
1926     void handle_use_program(gl_entrypoint_id_t id, GLuint program)
1927     {
1928         // Note: This mixes ARB and non-ARB funcs. to probe around, which is evil.
1929
1930         peek_and_record_gl_error();
1931
1932         check_program_binding_shadow();
1933
1934         vogl_scoped_context_shadow_lock lock;
1935
1936         VOGL_ASSERT(!program || (get_shared_state()->m_capture_context_params.m_objs.get_target(program) == VOGL_PROGRAM_OBJECT));
1937
1938         GLuint prev_program = m_cur_program;
1939
1940         bool prev_is_program = false;
1941         GLint prev_is_marked_for_deletion = false;
1942         vogl::growable_array<GLuint, 8> prev_attached_replay_shaders;
1943
1944         if ((prev_program) && (program != prev_program))
1945         {
1946             prev_is_program = GL_ENTRYPOINT(glIsProgram)(prev_program);
1947             peek_and_drop_gl_error();
1948
1949             if (prev_is_program)
1950             {
1951                 GL_ENTRYPOINT(glGetProgramiv)(prev_program, GL_DELETE_STATUS, &prev_is_marked_for_deletion);
1952                 peek_and_drop_gl_error();
1953
1954                 if (prev_is_marked_for_deletion)
1955                 {
1956                     // The currently bound program is marked for deletion, so record which shaders are attached to it in case the program is actually deleted by the driver on the UseProgram() call.
1957                     GLint num_attached_shaders = 0;
1958                     GL_ENTRYPOINT(glGetProgramiv)(prev_program, GL_ATTACHED_SHADERS, &num_attached_shaders);
1959                     peek_and_drop_gl_error();
1960
1961                     if (num_attached_shaders)
1962                     {
1963                         prev_attached_replay_shaders.resize(num_attached_shaders);
1964
1965                         GLsizei actual_count = 0;
1966                         GL_ENTRYPOINT(glGetAttachedShaders)(prev_program, num_attached_shaders, &actual_count, prev_attached_replay_shaders.get_ptr());
1967                         peek_and_drop_gl_error();
1968
1969                         VOGL_ASSERT(actual_count == num_attached_shaders);
1970                     }
1971                 }
1972             }
1973         }
1974
1975         if (id == VOGL_ENTRYPOINT_glUseProgram)
1976             GL_ENTRYPOINT(glUseProgram)(program);
1977         else
1978         {
1979             VOGL_ASSERT(id == VOGL_ENTRYPOINT_glUseProgramObjectARB);
1980             GL_ENTRYPOINT(glUseProgramObjectARB)(program);
1981         }
1982
1983         GLenum gl_err = peek_and_record_gl_error();
1984         if (gl_err != GL_NO_ERROR)
1985         {
1986             vogl_error_printf("%s: glUseProgram/glUseProgramObjectARB on handle %u returned GL error %s\n", VOGL_METHOD_NAME, program, g_gl_enums.find_gl_error_name(gl_err));
1987             return;
1988         }
1989
1990         if ((prev_program) && (prev_program != program))
1991         {
1992             bool is_prev_still_program = GL_ENTRYPOINT(glIsProgram)(prev_program);
1993             if (!is_prev_still_program)
1994             {
1995                 VOGL_ASSERT(prev_is_program);
1996                 VOGL_ASSERT(prev_is_marked_for_deletion);
1997
1998                 // The previously bound program is really dead now, kill it from our tables and also check up on any shaders it was attached to.
1999                 bool was_deleted = get_shared_state()->m_capture_context_params.m_objs.erase(prev_program);
2000                 VOGL_ASSERT(was_deleted);
2001                 VOGL_NOTE_UNUSED(was_deleted);
2002
2003                 get_shared_state()->m_capture_context_params.m_linked_programs.remove_snapshot(prev_program);
2004
2005                 for (uint i = 0; i < prev_attached_replay_shaders.size(); i++)
2006                 {
2007                     GLuint shader_handle = prev_attached_replay_shaders[i];
2008
2009                     bool is_still_shader = GL_ENTRYPOINT(glIsShader)(shader_handle);
2010                     peek_and_drop_gl_error();
2011
2012                     if (is_still_shader)
2013                         continue;
2014
2015                     if (!get_shared_state()->m_capture_context_params.m_objs.contains(shader_handle))
2016                     {
2017                         // We didn't create this shader handle, the AMD driver did on a program binary link, so ignore it.
2018                         continue;
2019                     }
2020
2021                     // The attached shader is now really dead.
2022                     VOGL_ASSERT(get_shared_state()->m_capture_context_params.m_objs.get_target(shader_handle) == VOGL_SHADER_OBJECT);
2023                     if (!get_shared_state()->m_capture_context_params.m_objs.erase(shader_handle))
2024                     {
2025                         vogl_error_printf("%s: Failed finding attached shader %u in objects hash table, while handling the actual deletion of program %u\n", VOGL_METHOD_NAME, shader_handle, prev_program);
2026                     }
2027                 }
2028             }
2029         }
2030
2031         m_cur_program = program;
2032
2033         check_program_binding_shadow();
2034     }
2035
2036     void handle_del_shader(gl_entrypoint_id_t id, GLuint obj)
2037     {
2038         // Note: This mixes ARB and non-ARB funcs. to probe around, which is evil.
2039
2040         peek_and_record_gl_error();
2041
2042         check_program_binding_shadow();
2043
2044         vogl_scoped_context_shadow_lock lock;
2045
2046         VOGL_ASSERT(!obj || (get_shared_state()->m_capture_context_params.m_objs.get_target(obj) == VOGL_SHADER_OBJECT));
2047
2048         if (id == VOGL_ENTRYPOINT_glDeleteObjectARB)
2049             GL_ENTRYPOINT(glDeleteObjectARB)(obj);
2050         else
2051             GL_ENTRYPOINT(glDeleteShader)(obj);
2052
2053         GLenum gl_err = peek_and_record_gl_error();
2054         if (gl_err != GL_NO_ERROR)
2055         {
2056             vogl_error_printf("%s: glDeleteShader/glDeleteObjectARB on handle %u returned GL error %s\n", VOGL_METHOD_NAME, obj, g_gl_enums.find_gl_error_name(gl_err));
2057             return;
2058         }
2059
2060         if (!obj)
2061             return;
2062
2063         bool is_still_shader = GL_ENTRYPOINT(glIsShader)(obj);
2064         peek_and_drop_gl_error();
2065
2066         if (!is_still_shader)
2067         {
2068             // The shader is really gone.
2069             bool was_deleted = get_shared_state()->m_capture_context_params.m_objs.erase(obj);
2070             VOGL_ASSERT(was_deleted);
2071             VOGL_NOTE_UNUSED(was_deleted);
2072         }
2073         else
2074         {
2075             GLint marked_for_deletion = 0;
2076             GL_ENTRYPOINT(glGetShaderiv)(obj, GL_DELETE_STATUS, &marked_for_deletion);
2077             peek_and_drop_gl_error();
2078
2079             VOGL_VERIFY(marked_for_deletion);
2080
2081             // The shader is attached to a live program object (which may or may not be actually in the marked_as_deleted state)
2082             // we'll get around to it when the program object is deleted, or when they remove the program object from the current state.
2083         }
2084     }
2085
2086     void handle_del_program(gl_entrypoint_id_t id, GLuint obj)
2087     {
2088         // Note: This mixes ARB and non-ARB funcs. to probe around, which is evil.
2089
2090         peek_and_record_gl_error();
2091
2092         check_program_binding_shadow();
2093
2094         vogl_scoped_context_shadow_lock lock;
2095
2096         VOGL_ASSERT(!obj || (get_shared_state()->m_capture_context_params.m_objs.get_target(obj) == VOGL_PROGRAM_OBJECT));
2097
2098         bool is_program = GL_ENTRYPOINT(glIsProgram)(obj) != 0;
2099         peek_and_drop_gl_error();
2100
2101         vogl::growable_array<GLuint, 8> attached_replay_shaders;
2102
2103         if ((is_program) && (obj))
2104         {
2105             GLint num_attached_shaders = 0;
2106             GL_ENTRYPOINT(glGetProgramiv)(obj, GL_ATTACHED_SHADERS, &num_attached_shaders);
2107             peek_and_drop_gl_error();
2108
2109             if (num_attached_shaders)
2110             {
2111                 attached_replay_shaders.resize(num_attached_shaders);
2112
2113                 GLsizei actual_count = 0;
2114                 GL_ENTRYPOINT(glGetAttachedShaders)(obj, num_attached_shaders, &actual_count, attached_replay_shaders.get_ptr());
2115                 peek_and_drop_gl_error();
2116
2117                 VOGL_ASSERT(actual_count == num_attached_shaders);
2118             }
2119         }
2120
2121         if (id == VOGL_ENTRYPOINT_glDeleteObjectARB)
2122             GL_ENTRYPOINT(glDeleteObjectARB)(obj);
2123         else
2124             GL_ENTRYPOINT(glDeleteProgram)(obj);
2125
2126         GLenum gl_err = peek_and_record_gl_error();
2127         if (gl_err != GL_NO_ERROR)
2128         {
2129             vogl_error_printf("%s: glDeleteProgram/glDeleteObjectARB on handle %u returned GL error %s\n", VOGL_METHOD_NAME, obj, g_gl_enums.find_gl_error_name(gl_err));
2130             return;
2131         }
2132
2133         if (!obj)
2134             return;
2135
2136         bool is_still_program = GL_ENTRYPOINT(glIsProgram)(obj) != 0;
2137         peek_and_drop_gl_error();
2138
2139         GLint marked_for_deletion = 0;
2140         if (is_still_program)
2141         {
2142             // It must still be bound to the context, or referred to in some other way that we don't know about.
2143             GL_ENTRYPOINT(glGetProgramiv)(obj, GL_DELETE_STATUS, &marked_for_deletion);
2144             bool delete_status_check_succeeded = (peek_and_drop_gl_error() == GL_NO_ERROR);
2145
2146             VOGL_VERIFY(delete_status_check_succeeded);
2147             VOGL_VERIFY(marked_for_deletion);
2148         }
2149         else if (!is_still_program)
2150         {
2151             VOGL_ASSERT(is_program);
2152
2153             // The program is really gone now.
2154             bool was_deleted = get_shared_state()->m_capture_context_params.m_objs.erase(obj);
2155             VOGL_ASSERT(was_deleted);
2156             VOGL_NOTE_UNUSED(was_deleted);
2157
2158             get_shared_state()->m_capture_context_params.m_linked_programs.remove_snapshot(obj);
2159
2160             if (m_cur_program == obj)
2161             {
2162                 // This shouldn't happen - if the program is still bound to the context then it should still be a program.
2163                 VOGL_ASSERT_ALWAYS;
2164                 m_cur_program = 0;
2165             }
2166
2167             for (uint i = 0; i < attached_replay_shaders.size(); i++)
2168             {
2169                 GLuint shader_handle = attached_replay_shaders[i];
2170
2171                 bool is_still_shader = GL_ENTRYPOINT(glIsShader)(shader_handle) != 0;
2172                 peek_and_drop_gl_error();
2173
2174                 if (is_still_shader)
2175                     continue;
2176
2177                 if (!get_shared_state()->m_capture_context_params.m_objs.contains(shader_handle))
2178                 {
2179                     // We didn't create this shader handle, the AMD driver did on a program binary link, so ignore it.
2180                     continue;
2181                 }
2182
2183                 // The attached shader is now really dead.
2184                 VOGL_ASSERT(get_shared_state()->m_capture_context_params.m_objs.get_target(shader_handle) == VOGL_SHADER_OBJECT);
2185                 if (!get_shared_state()->m_capture_context_params.m_objs.erase(shader_handle))
2186                 {
2187                     vogl_error_printf("%s: Failed finding attached shader %u in objects shadow, while handling the deletion of program %u\n", VOGL_METHOD_NAME, shader_handle, obj);
2188                 }
2189             }
2190         }
2191
2192         check_program_binding_shadow();
2193     }
2194
2195     void handle_del_object(gl_entrypoint_id_t id, GLuint obj)
2196     {
2197         vogl_scoped_context_shadow_lock lock;
2198
2199         if (!obj)
2200             return;
2201
2202         GLenum target = get_shared_state()->m_capture_context_params.m_objs.get_target(obj);
2203
2204         if (target == VOGL_PROGRAM_OBJECT)
2205             handle_del_program(id, obj);
2206         else if (target == VOGL_SHADER_OBJECT)
2207             handle_del_shader(id, obj);
2208         else
2209         {
2210             vogl_error_printf("%s: glDeleteObjectARB: Unable to find object handle %u in object shadow\n", VOGL_METHOD_NAME, obj);
2211
2212             GL_ENTRYPOINT(glDeleteObjectARB)(obj);
2213         }
2214     }
2215
2216     void handle_detach_shader(gl_entrypoint_id_t id, GLuint program, GLuint shader)
2217     {
2218         vogl_scoped_context_shadow_lock lock;
2219
2220         peek_and_record_gl_error();
2221
2222         // Note: This mixes ARB and non-ARB funcs. to probe around, which is evil.
2223
2224         GLboolean was_shader = GL_ENTRYPOINT(glIsShader)(shader);
2225         peek_and_drop_gl_error();
2226
2227         GLint marked_for_deletion = 0;
2228         GL_ENTRYPOINT(glGetShaderiv)(shader, GL_DELETE_STATUS, &marked_for_deletion);
2229         peek_and_drop_gl_error();
2230
2231         if (id == VOGL_ENTRYPOINT_glDetachObjectARB)
2232             GL_ENTRYPOINT(glDetachObjectARB)(program, shader);
2233         else
2234         {
2235             VOGL_ASSERT(id == VOGL_ENTRYPOINT_glDetachShader);
2236             GL_ENTRYPOINT(glDetachShader)(program, shader);
2237         }
2238
2239         GLenum gl_err = peek_and_record_gl_error();
2240         if (gl_err != GL_NO_ERROR)
2241         {
2242             vogl_error_printf("%s: glDetachShader/glDetachObjectARB on program handle %u shader handle %u returned GL error %s\n", VOGL_METHOD_NAME, program, shader, g_gl_enums.find_gl_error_name(gl_err));
2243             return;
2244         }
2245
2246         GLboolean is_shader = GL_ENTRYPOINT(glIsShader)(shader);
2247         peek_and_drop_gl_error();
2248
2249         if ((marked_for_deletion) && (was_shader) && (!is_shader))
2250         {
2251             // The shader is really gone now.
2252             bool was_deleted = get_shared_state()->m_capture_context_params.m_objs.erase(shader);
2253             VOGL_ASSERT(was_deleted);
2254             VOGL_NOTE_UNUSED(was_deleted);
2255         }
2256     }
2257
2258     // glBegin/glEnd shadowing
2259
2260     // Note: This flag gets set even when the client is composing a display list!
2261     void set_in_gl_begin(bool value)
2262     {
2263         m_in_gl_begin = value;
2264     }
2265     bool get_in_gl_begin() const
2266     {
2267         return m_in_gl_begin;
2268     }
2269
2270     void set_uses_client_side_arrays(bool value)
2271     {
2272         m_uses_client_side_arrays = value;
2273     }
2274     bool get_uses_client_side_arrays() const
2275     {
2276         return m_uses_client_side_arrays;
2277     }
2278
2279     typedef vogl::map<dynamic_string, dynamic_string, dynamic_string_less_than_case_sensitive, dynamic_string_equal_to_case_sensitive> extension_id_to_string_map_t;
2280     extension_id_to_string_map_t &get_extension_map()
2281     {
2282         return m_extension_map;
2283     }
2284
2285     const vogl_context_handle_remapper &get_handle_remapper() const
2286     {
2287         return m_handle_remapper;
2288     }
2289     vogl_context_handle_remapper &get_handle_remapper()
2290     {
2291         return m_handle_remapper;
2292     }
2293
2294     // Display list shadowing
2295
2296     GLenum get_current_display_list_mode() const
2297     {
2298         return m_current_display_list_mode;
2299     }
2300     bool is_composing_display_list() const
2301     {
2302         return m_current_display_list_handle >= 0;
2303     }
2304     GLint get_current_display_list_handle() const
2305     {
2306         return m_current_display_list_handle;
2307     }
2308
2309     bool new_list(GLuint handle, GLenum mode)
2310     {
2311         VOGL_FUNC_TRACER
2312
2313         VOGL_ASSERT((mode == GL_COMPILE) || (mode == GL_COMPILE_AND_EXECUTE));
2314
2315         if (m_current_display_list_handle >= 0)
2316         {
2317             vogl_error_printf("%s: Can't define new display list %u while display list %i is already being defined!\n", VOGL_METHOD_NAME, handle, m_current_display_list_handle);
2318             return false;
2319         }
2320
2321         m_current_display_list_handle = handle;
2322         m_current_display_list_mode = mode;
2323
2324         vogl_scoped_context_shadow_lock lock;
2325
2326         get_shared_state()->m_capture_context_params.m_display_lists.new_list(handle, handle);
2327
2328         return true;
2329     }
2330
2331     bool end_list()
2332     {
2333         VOGL_FUNC_TRACER
2334
2335         if (m_current_display_list_handle < 0)
2336         {
2337             vogl_error_printf("%s: No display list is active!\n", VOGL_METHOD_NAME);
2338             return false;
2339         }
2340
2341         {
2342             vogl_scoped_context_shadow_lock lock;
2343
2344             get_shared_state()->m_capture_context_params.m_display_lists.end_list(m_current_display_list_handle);
2345         }
2346
2347         m_current_display_list_handle = -1;
2348         m_current_display_list_mode = GL_NONE;
2349
2350         return true;
2351     }
2352
2353     void gen_lists(GLuint result, GLsizei range)
2354     {
2355         VOGL_FUNC_TRACER
2356
2357         if (!range)
2358             return;
2359
2360         vogl_scoped_context_shadow_lock lock;
2361
2362         get_shared_state()->m_capture_context_params.m_display_lists.gen_lists(result, range);
2363     }
2364
2365     void del_lists(GLuint list, GLsizei range)
2366     {
2367         VOGL_FUNC_TRACER
2368
2369         if (!range)
2370             return;
2371
2372         vogl_scoped_context_shadow_lock lock;
2373
2374         get_shared_state()->m_capture_context_params.m_display_lists.del_lists(list, range);
2375     }
2376
2377     void glx_font(const char *pFont, int first, int count, int list_base)
2378     {
2379         vogl_scoped_context_shadow_lock lock;
2380
2381         get_shared_state()->m_capture_context_params.m_display_lists.glx_font(pFont, first, count, list_base);
2382     }
2383
2384     bool parse_list_and_update_shadows(GLuint handle, vogl_display_list_state::pBind_callback_func_ptr pBind_callback, void *pBind_callback_opaque)
2385     {
2386         vogl_scoped_context_shadow_lock lock;
2387
2388         return get_shared_state()->m_capture_context_params.m_display_lists.parse_list_and_update_shadows(handle, pBind_callback, pBind_callback_opaque);
2389     }
2390
2391     bool parse_lists_and_update_shadows(GLsizei n, GLenum type, const GLvoid *lists, vogl_display_list_state::pBind_callback_func_ptr pBind_callback, void *pBind_callback_opaque)
2392     {
2393         vogl_scoped_context_shadow_lock lock;
2394
2395         return get_shared_state()->m_capture_context_params.m_display_lists.parse_lists_and_update_shadows(n, type, lists, pBind_callback, pBind_callback_opaque);
2396     }
2397
2398     bool add_packet_to_current_display_list(gl_entrypoint_id_t func, const vogl_trace_packet &packet)
2399     {
2400         VOGL_FUNC_TRACER
2401
2402         if (m_current_display_list_handle < 0)
2403             return true;
2404
2405         if (!vogl_display_list_state::is_call_listable(func, packet))
2406         {
2407             if (g_vogl_entrypoint_descs[func].m_is_listable)
2408             {
2409                 if (!g_vogl_entrypoint_descs[func].m_whitelisted_for_displaylists)
2410                     vogl_error_printf("%s: Failed serializing trace packet into display list shadow! Call is not listable.\n", VOGL_FUNCTION_NAME);
2411                 else
2412                     vogl_error_printf("%s: Failed serializing trace packet into display list shadow! Call with these parameters is not listable.\n", VOGL_FUNCTION_NAME);
2413             }
2414             return false;
2415         }
2416
2417         vogl_scoped_context_shadow_lock lock;
2418
2419         return get_shared_state()->m_capture_context_params.m_display_lists.add_packet_to_list(m_current_display_list_handle, func, packet);
2420     }
2421
2422 private:
2423     int m_ref_count;
2424     bool m_deleted_flag;
2425     vogl_context *m_pShared_state;
2426
2427     GLXContext m_context_handle;
2428     GLXContext m_sharelist_handle;
2429
2430     const Display *m_pDpy;
2431     GLXDrawable m_drawable;
2432     GLXDrawable m_read_drawable;
2433     int m_render_type;
2434     XVisualInfo m_xvisual_info;
2435     GLXFBConfig m_fb_config;
2436
2437     bool m_direct;
2438
2439     bool m_created_from_attribs;
2440     vogl::vector<int> m_attrib_list;
2441
2442     uint64_t m_current_thread; // as returned by vogl_get_current_kernel_thread_id()
2443
2444     GLuint m_max_vertex_attribs;
2445
2446     bool m_has_been_made_current;
2447
2448     int m_window_width, m_window_height;
2449     uint64_t m_frame_index;
2450
2451     gl_entrypoint_id_t m_creation_func;
2452     vogl_context_desc m_context_desc;
2453     vogl_context_info m_context_info; // only valid after first MakeCurrent
2454
2455     extension_id_to_string_map_t m_extension_map;
2456
2457     GLenum m_latched_gl_error;
2458
2459     gl_buffer_desc_map m_buffer_descs;
2460
2461     vogl_capture_context_params m_capture_context_params;
2462
2463     vogl_framebuffer_capturer m_framebuffer_capturer;
2464
2465     GLuint m_cur_program;
2466
2467     bool m_in_gl_begin;
2468     bool m_uses_client_side_arrays;
2469
2470     vogl_context_handle_remapper m_handle_remapper;
2471
2472     int m_current_display_list_handle;
2473     GLenum m_current_display_list_mode;
2474
2475     static void debug_callback_arb(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, GLvoid *pUser_param)
2476     {
2477         (void)length;
2478
2479         char final_message[4096];
2480
2481         vogl_context *pContext = (vogl_context *)(pUser_param);
2482
2483         vogl_format_debug_output_arb(final_message, sizeof(final_message), source, type, id, severity, reinterpret_cast<const char *>(message));
2484
2485         if (pContext)
2486         {
2487             vogl_warning_printf("%s: Trace context: 0x%" PRIX64 ", Thread id: 0x%" PRIX64 "\n%s\n", VOGL_FUNCTION_NAME,
2488                                cast_val_to_uint64(pContext->m_context_handle), vogl_get_current_kernel_thread_id(), final_message);
2489         }
2490         else
2491         {
2492             vogl_warning_printf("%s: %s\n", VOGL_FUNCTION_NAME, final_message);
2493         }
2494     }
2495
2496     void on_first_make_current()
2497     {
2498         if ((g_command_line_params.get_value_as_bool("vogl_force_debug_context")) && (m_context_info.is_debug_context()))
2499         {
2500             if (GL_ENTRYPOINT(glDebugMessageCallbackARB) && m_context_info.supports_extension("GL_ARB_debug_output"))
2501             {
2502                 VOGL_CHECK_GL_ERROR;
2503
2504                 GL_ENTRYPOINT(glDebugMessageCallbackARB)(debug_callback_arb, (GLvoid *)this);
2505                 GL_ENTRYPOINT(glEnable)(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
2506
2507                 VOGL_CHECK_GL_ERROR;
2508             }
2509             else
2510             {
2511                 vogl_error_printf("%s: Can't enable debug context, either glDebugMessageCallbackARB func or the GL_ARB_debug_output extension is not available!\n", VOGL_METHOD_NAME);
2512             }
2513         }
2514     }
2515
2516     // Note: Check for any GL errors before calling this method.
2517     bool check_program_binding_shadow()
2518     {
2519         GLint actual_cur_program = 0;
2520         GL_ENTRYPOINT(glGetIntegerv)(GL_CURRENT_PROGRAM, &actual_cur_program);
2521
2522         if (peek_and_drop_gl_error() != GL_NO_ERROR)
2523             vogl_error_printf("%s: GL error checking program binding shadow!\n", VOGL_METHOD_NAME);
2524
2525         if (m_cur_program == static_cast<GLuint>(actual_cur_program))
2526             return true;
2527
2528         // OK, on AMD it plays games with GL_CURRENT_PROGRAM when the currently bound program is deleted. Check for this scenario.
2529         bool is_still_program = GL_ENTRYPOINT(glIsProgram)(m_cur_program) != 0;
2530         if ((peek_and_drop_gl_error() == GL_NO_ERROR) && (is_still_program))
2531         {
2532             GLint marked_for_deletion = GL_FALSE;
2533             GL_ENTRYPOINT(glGetProgramiv)(m_cur_program, GL_DELETE_STATUS, &marked_for_deletion);
2534
2535             if ((peek_and_drop_gl_error() == GL_NO_ERROR) && (marked_for_deletion))
2536                 return true;
2537         }
2538
2539         VOGL_VERIFY(!"m_cur_program appears out of sync with GL's GL_CURRENT_PROGRAM");
2540         return false;
2541     }
2542 };
2543
2544 typedef vogl::hash_map<GLXContext, vogl_context *, bit_hasher<GLXContext> > glxcontext_map;
2545
2546 //----------------------------------------------------------------------------------------------------------------------
2547 // vogl_context_handle_remapper::is_valid_handle
2548 //----------------------------------------------------------------------------------------------------------------------
2549 bool vogl_context_handle_remapper::is_valid_handle(vogl_namespace_t handle_namespace, uint64_t from_handle)
2550 {
2551     if (!from_handle)
2552         return 0;
2553
2554     uint32 handle = static_cast<uint32>(from_handle);
2555
2556     const vogl_capture_context_params &capture_context_params = m_pContext->get_shared_state()->get_capture_context_params();
2557
2558     // TODO: Support all the object types
2559     if (handle_namespace == VOGL_NAMESPACE_SHADERS)
2560     {
2561         VOGL_ASSERT(handle == from_handle);
2562         return (capture_context_params.m_objs.get_target(handle) == VOGL_SHADER_OBJECT);
2563     }
2564     else if (handle_namespace == VOGL_NAMESPACE_PROGRAMS)
2565     {
2566         VOGL_ASSERT(handle == from_handle);
2567         return (capture_context_params.m_objs.get_target(handle) == VOGL_PROGRAM_OBJECT);
2568     }
2569     else if (handle_namespace == VOGL_NAMESPACE_TEXTURES)
2570     {
2571         VOGL_ASSERT(handle == from_handle);
2572         return capture_context_params.m_textures.contains(handle);
2573     }
2574
2575     VOGL_VERIFY(0);
2576     return false;
2577 }
2578
2579 //----------------------------------------------------------------------------------------------------------------------
2580 // vogl_context_handle_remapper::determine_from_object_target
2581 //----------------------------------------------------------------------------------------------------------------------
2582 bool vogl_context_handle_remapper::determine_from_object_target(vogl_namespace_t handle_namespace, uint64_t from_handle, GLenum &target)
2583 {
2584     target = GL_NONE;
2585
2586     if (!from_handle)
2587         return false;
2588
2589     uint32 handle = static_cast<uint32>(from_handle);
2590
2591     const vogl_capture_context_params &capture_context_params = m_pContext->get_shared_state()->get_capture_context_params();
2592
2593     // TODO: Support all the object types
2594     if (handle_namespace == VOGL_NAMESPACE_TEXTURES)
2595     {
2596         if (capture_context_params.m_textures.contains(handle))
2597         {
2598             target = capture_context_params.m_textures.get_target(handle);
2599             return true;
2600         }
2601     }
2602
2603     VOGL_VERIFY(0);
2604     return false;
2605 }
2606
2607 //----------------------------------------------------------------------------------------------------------------------
2608 // vogl_scoped_gl_error_absorber::vogl_scoped_gl_error_absorber
2609 //----------------------------------------------------------------------------------------------------------------------
2610 vogl_scoped_gl_error_absorber::vogl_scoped_gl_error_absorber(vogl_context *pContext)
2611     : m_pContext(pContext)
2612 {
2613     // Latch any errors that are present on the context, if any, so the client will see it later
2614     if (pContext)
2615         pContext->peek_and_record_gl_error();
2616 }
2617
2618 //----------------------------------------------------------------------------------------------------------------------
2619 // vogl_scoped_gl_error_absorber::~vogl_scoped_gl_error_absorber
2620 //----------------------------------------------------------------------------------------------------------------------
2621 vogl_scoped_gl_error_absorber::~vogl_scoped_gl_error_absorber()
2622 {
2623     // Now get the current GL error and drop it, so the client app doesn't see it
2624     if (m_pContext)
2625         m_pContext->peek_and_drop_gl_error();
2626 }
2627
2628 //----------------------------------------------------------------------------------------------------------------------
2629 // class vogl_context_manager
2630 //----------------------------------------------------------------------------------------------------------------------
2631 class vogl_context_manager
2632 {
2633     VOGL_NO_COPY_OR_ASSIGNMENT_OP(vogl_context_manager);
2634
2635 public:
2636     vogl_context_manager()
2637         : m_glx_context_map_lock(0, true)
2638     {
2639     }
2640
2641     vogl_context *create_context(GLXContext handle)
2642     {
2643         VOGL_ASSERT(handle);
2644
2645         vogl_context *pVOGL_context = vogl_new(vogl_context, handle);
2646
2647         {
2648             scoped_mutex lock(m_glx_context_map_lock);
2649             m_glx_context_map.insert(handle, pVOGL_context);
2650         }
2651
2652         return pVOGL_context;
2653     }
2654
2655     vogl_context *lookup_vogl_context(GLXContext handle)
2656     {
2657         VOGL_ASSERT(handle);
2658
2659         vogl_context *pVOGL_context;
2660         VOGL_NOTE_UNUSED(pVOGL_context);
2661         glxcontext_map::iterator it;
2662
2663         {
2664             scoped_mutex lock(m_glx_context_map_lock);
2665             it = m_glx_context_map.find(handle);
2666         }
2667
2668         return (it != m_glx_context_map.end()) ? it->second : NULL;
2669     }
2670
2671     bool destroy_context(GLXContext handle)
2672     {
2673         VOGL_ASSERT(handle);
2674
2675         vogl_context *pVOGL_context = lookup_vogl_context(handle);
2676         if (!pVOGL_context)
2677             return false;
2678
2679         {
2680             scoped_mutex lock(m_glx_context_map_lock);
2681             m_glx_context_map.erase(handle);
2682         }
2683
2684         vogl_thread_local_data *pTLS_data = vogl_get_or_create_thread_local_data();
2685         if ((pTLS_data) && (pTLS_data->m_pContext == pVOGL_context))
2686             pTLS_data->m_pContext = NULL;
2687
2688         vogl_delete(pVOGL_context);
2689
2690         return true;
2691     }
2692
2693     vogl_context *get_or_create_context(GLXContext handle)
2694     {
2695         VOGL_ASSERT(handle);
2696
2697         vogl_context *pVOGL_context = lookup_vogl_context(handle);
2698         if (!pVOGL_context)
2699             pVOGL_context = vogl_new(vogl_context, handle);
2700
2701         return pVOGL_context;
2702     }
2703
2704     vogl_context *make_current(GLXContext handle)
2705     {
2706         VOGL_ASSERT(handle);
2707
2708         vogl_context *pVOGL_context = get_or_create_context(handle);
2709
2710         if (pVOGL_context->get_current_thread())
2711         {
2712             if (pVOGL_context->get_current_thread() != vogl_get_current_kernel_thread_id())
2713             {
2714                 vogl_error_printf("%s: context is being made current, but is already current on another thread\n", VOGL_METHOD_NAME);
2715             }
2716             else
2717             {
2718                 vogl_warning_printf("%s: context is already current (redundant call)\n", VOGL_METHOD_NAME);
2719             }
2720         }
2721
2722         vogl_get_or_create_thread_local_data()->m_pContext = pVOGL_context;
2723
2724         pVOGL_context->on_make_current();
2725
2726         return pVOGL_context;
2727     }
2728
2729     vogl_context *get_current()
2730     {
2731         return static_cast<vogl_context *>(vogl_get_or_create_thread_local_data()->m_pContext);
2732     }
2733
2734     void release_current()
2735     {
2736         vogl_context *pVOGL_context = get_current();
2737         if (pVOGL_context)
2738         {
2739             if (!pVOGL_context->get_current_thread())
2740             {
2741                 vogl_error_printf("%s: Context manager's current context is not marked as current on any thread\n", VOGL_METHOD_NAME);
2742             }
2743             pVOGL_context->on_release_current_epilog();
2744
2745             vogl_get_or_create_thread_local_data()->m_pContext = NULL;
2746         }
2747     }
2748
2749     void lock()
2750     {
2751         m_glx_context_map_lock.lock();
2752     }
2753
2754     void unlock()
2755     {
2756         m_glx_context_map_lock.unlock();
2757     }
2758
2759     const glxcontext_map &get_context_map() const
2760     {
2761         return m_glx_context_map;
2762     }
2763
2764     vogl_context *find_context(const Display *dpy, GLXDrawable drawable)
2765     {
2766         lock();
2767
2768         const glxcontext_map &contexts = m_glx_context_map;
2769         for (glxcontext_map::const_iterator it = contexts.begin(); it != contexts.end(); ++it)
2770         {
2771             vogl_context *p = it->second;
2772             if ((p->get_display() == dpy) && (p->get_drawable() == drawable))
2773             {
2774                 unlock();
2775                 return p;
2776             }
2777         }
2778
2779         unlock();
2780         return NULL;
2781     }
2782
2783 private:
2784     mutex m_glx_context_map_lock;
2785     glxcontext_map m_glx_context_map;
2786 };
2787
2788 vogl_context_manager g_context_manager;
2789
2790 //----------------------------------------------------------------------------------------------------------------------
2791 // vogl_context_shadow_lock
2792 //----------------------------------------------------------------------------------------------------------------------
2793 static inline void vogl_context_shadow_lock()
2794 {
2795     g_context_manager.lock();
2796 }
2797
2798 //----------------------------------------------------------------------------------------------------------------------
2799 // vogl_context_shadow_unlock
2800 //----------------------------------------------------------------------------------------------------------------------
2801 static inline void vogl_context_shadow_unlock()
2802 {
2803     g_context_manager.unlock();
2804 }
2805
2806 //----------------------------------------------------------------------------------------------------------------------
2807 // vogl_atexit
2808 //----------------------------------------------------------------------------------------------------------------------
2809 static void vogl_atexit()
2810 {
2811     vogl_debug_printf("vogl_atexit()\n");
2812
2813     scoped_mutex lock(g_vogl_trace_mutex);
2814
2815     vogl_deinit();
2816 }
2817
2818 //----------------------------------------------------------------------------------------------------------------------
2819 // vogl_backtrace
2820 //----------------------------------------------------------------------------------------------------------------------
2821 static uint32 vogl_backtrace(uint addrs_to_skip)
2822 {
2823     vogl_backtrace_addrs addrs;
2824     addrs.m_num_addrs = btrace_get(addrs.m_addrs, addrs.cMaxAddrs, addrs_to_skip);
2825
2826     vogl_backtrace_hashmap::insert_result ins_res;
2827
2828     uint32 index = 0;
2829
2830     g_backtrace_hashmap_mutex.lock();
2831
2832     if (!g_backtrace_hashmap.insert_no_grow(ins_res, addrs))
2833         vogl_error_printf("%s: Backtrace hashmap exhausted! Please increase VOGL_BACKTRACE_HASHMAP_CAPACITY. Some backtraces in this trace will not have symbols.\n", VOGL_FUNCTION_NAME);
2834     else
2835     {
2836         index = ins_res.first.get_index();
2837         (ins_res.first)->second++;
2838     }
2839
2840     g_backtrace_hashmap_mutex.unlock();
2841
2842     return index;
2843 }
2844
2845 //----------------------------------------------------------------------------------------------------------------------
2846 // vogl_flush_backtrace_to_trace_file
2847 //----------------------------------------------------------------------------------------------------------------------
2848 static bool vogl_flush_backtrace_to_trace_file()
2849 {
2850     scoped_mutex lock(g_vogl_trace_mutex);
2851
2852     if (!g_vogl_trace_writer.is_opened() || (g_vogl_trace_writer.get_trace_archive() == NULL))
2853         return false;
2854
2855     json_document doc;
2856
2857     g_backtrace_hashmap_mutex.lock();
2858
2859     uint backtrace_hashmap_size = g_backtrace_hashmap.size();
2860     if (backtrace_hashmap_size)
2861     {
2862         vogl_message_printf("%s: Writing backtrace %u addrs\n", VOGL_FUNCTION_NAME, backtrace_hashmap_size);
2863
2864         json_node *pRoot = doc.get_root();
2865         pRoot->init_array();
2866
2867         for (vogl_backtrace_hashmap::const_iterator it = g_backtrace_hashmap.begin(); it != g_backtrace_hashmap.end(); ++it)
2868         {
2869             json_node &node = pRoot->add_array();
2870
2871             node.add_key_value("index", it.get_index());
2872             node.add_key_value("count", it->second);
2873
2874             json_node &addrs_arr = node.add_array("addrs");
2875             const vogl_backtrace_addrs &addrs = it->first;
2876
2877             for (uint i = 0; i < addrs.m_num_addrs; i++)
2878             {
2879                 addrs_arr.add_value(to_hex_string(static_cast<uint64_t>(addrs.m_addrs[i])));
2880             }
2881         }
2882     }
2883
2884     g_backtrace_hashmap.reset();
2885     g_backtrace_hashmap_mutex.unlock();
2886
2887     if (backtrace_hashmap_size)
2888     {
2889         char_vec data;
2890         doc.serialize(data, true, 0, false);
2891
2892         if (g_vogl_trace_writer.get_trace_archive()->add_buf_using_id(data.get_ptr(), data.size(), VOGL_TRACE_ARCHIVE_BACKTRACE_MAP_ADDRS_FILENAME).is_empty())
2893             vogl_error_printf("%s: Failed adding serialized backtrace addrs to trace archive\n", VOGL_FUNCTION_NAME);
2894         else
2895             vogl_message_printf("%s: Done writing backtrace addrs\n", VOGL_FUNCTION_NAME);
2896     }
2897
2898     return true;
2899 }
2900
2901 //----------------------------------------------------------------------------------------------------------------------
2902 // vogl_flush_compilerinfo_to_trace_file
2903 //----------------------------------------------------------------------------------------------------------------------
2904 static bool vogl_flush_compilerinfo_to_trace_file()
2905 {
2906     scoped_mutex lock(g_vogl_trace_mutex);
2907
2908     if (!g_vogl_trace_writer.is_opened() || (g_vogl_trace_writer.get_trace_archive() == NULL))
2909         return false;
2910
2911     json_document doc;
2912
2913     vogl_message_printf("%s: Begin resolving compilerinfo to symbols\n", VOGL_FUNCTION_NAME);
2914
2915     json_node *pRoot = doc.get_root();
2916
2917     vogl::json_node &compiler_info_node = pRoot->add_array("compiler_info");
2918     compiler_info_node.add_key_value("time", __TIME__);
2919     compiler_info_node.add_key_value("date", __DATE__);
2920 #ifdef __VERSION__
2921     compiler_info_node.add_key_value("version", __VERSION__);
2922 #endif
2923 #ifdef __i386__
2924     compiler_info_node.add_key_value("arch", "32bit");
2925 #else
2926     compiler_info_node.add_key_value("arch", "64bit");
2927 #endif
2928
2929     char_vec data;
2930     doc.serialize(data, true, 0, false);
2931
2932     if (g_vogl_trace_writer.get_trace_archive()->add_buf_using_id(data.get_ptr(), data.size(), VOGL_TRACE_ARCHIVE_COMPILER_INFO_FILENAME).is_empty())
2933         vogl_error_printf("%s: Failed adding serialized compilerinfo to trace archive\n", VOGL_FUNCTION_NAME);
2934     else
2935         vogl_message_printf("%s: Done resolving compilerinfo to symbols\n", VOGL_FUNCTION_NAME);
2936
2937     return true;
2938 }
2939
2940 //----------------------------------------------------------------------------------------------------------------------
2941 // vogl_flush_machineinfo_to_trace_file
2942 //----------------------------------------------------------------------------------------------------------------------
2943 static bool vogl_flush_machineinfo_to_trace_file()
2944 {
2945     scoped_mutex lock(g_vogl_trace_mutex);
2946
2947     if (!g_vogl_trace_writer.is_opened() || (g_vogl_trace_writer.get_trace_archive() == NULL))
2948         return false;
2949
2950     json_document doc;
2951
2952     vogl_message_printf("%s: Begin resolving machineinfo to symbols\n", VOGL_FUNCTION_NAME);
2953
2954     json_node *pRoot = doc.get_root();
2955
2956     btrace_get_machine_info(pRoot);
2957
2958     char_vec data;
2959     doc.serialize(data, true, 0, false);
2960
2961     if (g_vogl_trace_writer.get_trace_archive()->add_buf_using_id(data.get_ptr(), data.size(), VOGL_TRACE_ARCHIVE_MACHINE_INFO_FILENAME).is_empty())
2962         vogl_error_printf("%s: Failed adding serialized machineinfo to trace archive\n", VOGL_FUNCTION_NAME);
2963     else
2964         vogl_message_printf("%s: Done resolving machineinfo to symbols\n", VOGL_FUNCTION_NAME);
2965
2966     return true;
2967 }
2968
2969 //----------------------------------------------------------------------------------------------------------------------
2970 // vogl_entrypoint_serializer::begin
2971 //----------------------------------------------------------------------------------------------------------------------
2972 inline bool vogl_entrypoint_serializer::begin(gl_entrypoint_id_t id, vogl_context *pContext)
2973 {
2974     if (m_in_begin)
2975     {
2976         // Nothing good will come of this - the output will be fucked.
2977         vogl_error_printf("%s: begin() call not matched with end() - something is very wrong!)\n", VOGL_METHOD_NAME);
2978         VOGL_ASSERT_ALWAYS;
2979         return false;
2980     }
2981
2982     m_in_begin = true;
2983
2984     uint64_t thread_id = vogl_get_current_kernel_thread_id();
2985     uint64_t context_id = pContext ? reinterpret_cast<uint64_t>(pContext->get_context_handle()) : 0;
2986
2987     m_packet.begin_construction(id, context_id, g_vogl_trace_writer.get_next_gl_call_counter(), thread_id, utils::RDTSC());
2988
2989     if ((g_backtrace_all_calls) && (g_vogl_trace_writer.is_opened()))
2990     {
2991         // Take a backtrace and store its hashtable index into the packet.
2992         m_packet.set_backtrace_hash_index(vogl_backtrace(1));
2993     }
2994
2995     return true;
2996 }
2997
2998 //----------------------------------------------------------------------------------------------------------------------
2999 // vogl_is_in_null_mode
3000 //----------------------------------------------------------------------------------------------------------------------
3001 static inline bool vogl_is_in_null_mode()
3002 {
3003     return g_null_mode;
3004 }
3005
3006 //----------------------------------------------------------------------------------------------------------------------
3007 // vogl_is_in_null_mode
3008 //----------------------------------------------------------------------------------------------------------------------
3009 static inline bool vogl_func_is_nulled(gl_entrypoint_id_t id)
3010 {
3011     return vogl_is_in_null_mode() && g_vogl_entrypoint_descs[id].m_is_nullable;
3012 }
3013
3014 //----------------------------------------------------------------------------------------------------------------------
3015 // Custom array parameter size helper macros
3016 // IMPORTANT: These helpers need to not crash or return weird shit if there is no context current, in case the client
3017 // messes up and makes a GL call without an active context.
3018 //----------------------------------------------------------------------------------------------------------------------
3019 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_GL_ENUM(pname) g_gl_enums.get_pname_count(pname)
3020
3021 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXChooseFBConfig_attrib_list(e, c, rt, r, nu, ne, a, p) vogl_determine_attrib_list_array_size(attrib_list)
3022 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXChooseVisual_attribList(e, c, rt, r, nu, ne, a, p) vogl_determine_attrib_list_array_size(attribList)
3023 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXCreateWindow_attrib_list(e, c, rt, r, nu, ne, a, p) vogl_determine_attrib_list_array_size(attrib_list)
3024 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXCreatePixmap_attrib_list(e, c, rt, r, nu, ne, a, p) vogl_determine_attrib_list_array_size(attrib_list)
3025 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXCreatePbuffer_attrib_list(e, c, rt, r, nu, ne, a, p) vogl_determine_attrib_list_array_size(attrib_list)
3026 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXCreateContextAttribsARB_attrib_list(e, c, rt, r, nu, ne, a, p) vogl_determine_attrib_list_array_size(attrib_list)
3027
3028 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXBindVideoDeviceNV_attrib_list(e, c, rt, r, nu, ne, a, p) vogl_determine_attrib_list_array_size(attrib_list)
3029 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXBindTexImageEXT_attrib_list(e, c, rt, r, nu, ne, a, p) vogl_determine_attrib_list_array_size(attrib_list)
3030
3031 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetUniformLocation_name(e, c, rt, r, nu, ne, a, p) (name ? (strlen((const char *)name) + 1) : -1)
3032 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetUniformLocationARB_name(e, c, rt, r, nu, ne, a, p) (name ? (strlen(name) + 1) : -1)
3033
3034 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glBindAttribLocation_name(e, c, rt, r, nu, ne, a, p) (name ? (strlen((const char *)name) + 1) : -1)
3035 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glBindAttribLocationARB_name(e, c, rt, r, nu, ne, a, p) (name ? (strlen(name) + 1) : -1)
3036
3037 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetAttribLocationARB_name(e, c, rt, r, nu, ne, a, p) (name ? (strlen((const char *)name) + 1) : -1)
3038 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetAttribLocation_name(e, c, rt, r, nu, ne, a, p) (name ? (strlen((const char *)name) + 1) : -1)
3039
3040 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetShaderInfoLog_infoLog(e, c, rt, r, nu, ne, a, p) (length ? (*length + 1) : bufSize)
3041 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetInfoLogARB_infoLog(e, c, rt, r, nu, ne, a, p) (length ? (*length + 1) : maxLength)
3042
3043 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glClearBufferData_data(e, c, rt, r, nu, ne, a, p) vogl_get_image_format_size_in_bytes(format, type)
3044
3045 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glVertexPointer_pointer(e, c, rt, r, nu, ne, a, p) 0
3046 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glVertexPointerEXT_pointer(e, c, rt, r, nu, ne, a, p) 0
3047 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glColorPointer_pointer(e, c, rt, r, nu, ne, a, p) 0
3048 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glColorPointerEXT_pointer(e, c, rt, r, nu, ne, a, p) 0
3049 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glSecondaryColorPointer_pointer(e, c, rt, r, nu, ne, a, p) 0
3050 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexCoordPointer_pointer(e, c, rt, r, nu, ne, a, p) 0
3051 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexCoordPointerEXT_pointer(e, c, rt, r, nu, ne, a, p) 0
3052 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glFogCoordPointer_pointer(e, c, rt, r, nu, ne, a, p) 0
3053 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glFogCoordPointerEXT_pointer(e, c, rt, r, nu, ne, a, p) 0
3054 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glIndexPointer_pointer(e, c, rt, r, nu, ne, a, p) 0
3055 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glIndexPointerEXT_pointer(e, c, rt, r, nu, ne, a, p) 0
3056 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glNormalPointer_pointer(e, c, rt, r, nu, ne, a, p) 0
3057 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glNormalPointerEXT_pointer(e, c, rt, r, nu, ne, a, p) 0
3058 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glEdgeFlagPointer_pointer(e, c, rt, r, nu, ne, a, p) 0
3059 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glEdgeFlagPointerEXT_pointer(e, c, rt, r, nu, ne, a, p) 0
3060 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glInterleavedArrays_pointer(e, c, rt, r, nu, ne, a, p) 0
3061
3062 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glVertexAttribPointer_pointer(e, c, rt, r, nu, ne, a, p) 0
3063 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glVertexAttribIPointer_pointer(e, c, rt, r, nu, ne, a, p) 0
3064 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glVertexAttribPointerARB_pointer(e, c, rt, r, nu, ne, a, p) 0
3065
3066 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glDrawRangeElements_indices(e, c, rt, r, nu, ne, a, p) 0
3067 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glDrawRangeElementsBaseVertex_indices(e, c, rt, r, nu, ne, a, p) 0
3068 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glDrawRangeElementsEXT_indices(e, c, rt, r, nu, ne, a, p) 0
3069 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glDrawElements_indices(e, c, rt, r, nu, ne, a, p) 0
3070 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glDrawElementsInstanced_indices(e, c, rt, r, nu, ne, a, p) 0
3071 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glDrawElementsInstancedARB_indices(e, c, rt, r, nu, ne, a, p) 0
3072 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glDrawElementsInstancedEXT_indices(e, c, rt, r, nu, ne, a, p) 0
3073 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glDrawElementsBaseVertex_indices(e, c, rt, r, nu, ne, a, p) 0
3074
3075 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glNamedBufferDataEXT_data(e, c, rt, r, nu, ne, a, p) size
3076 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glNamedBufferSubDataEXT_data(e, c, rt, r, nu, ne, a, p) size
3077
3078 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glMap1f_points(e, c, rt, r, nu, ne, a, p) vogl_determine_glMap1_size(target, stride, order)
3079 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glMap1d_points(e, c, rt, r, nu, ne, a, p) vogl_determine_glMap1_size(target, stride, order)
3080 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glMap2f_points(e, c, rt, r, nu, ne, a, p) vogl_determine_glMap2_size(target, ustride, uorder, vstride, vorder)
3081 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glMap2d_points(e, c, rt, r, nu, ne, a, p) vogl_determine_glMap2_size(target, ustride, uorder, vstride, vorder)
3082
3083 // KHR_debug
3084 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glDebugMessageInsert_buf(e, c, rt, r, nu, ne, a, p) ((length < 0) ? (buf ? strlen((const char *)buf) : 0 ) : length)
3085 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glPushDebugGroup_message(e, c, rt, r, nu, ne, a, p) ((length < 0) ? (message ? strlen((const char *)message) : 0 ) : length)
3086 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glObjectLabel_label(e, c, rt, r, nu, ne, a, p) ((length < 0) ? (label ? strlen((const char *)label) : 0 ) : length)
3087 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glObjectPtrLabel_label(e, c, rt, r, nu, ne, a, p) ((length < 0) ? (label ? strlen((const char *)label) : 0 ) : length)
3088
3089 //----------------------------------------------------------------------------------------------------------------------
3090 // Texture/image API's array size helper macros
3091 // TODO: For glTexImage3DEXT, glTexSubImage1DEXT, etc. - should these check the currently bound GL_PIXEL_UNPACK_BUFFER?
3092 //----------------------------------------------------------------------------------------------------------------------
3093 size_t vogl_calc_set_tex_image_serialize_size(vogl_context *pContext, GLenum format, GLenum type, GLsizei width, GLsizei height, GLsizei depth)
3094 {
3095     if (pContext)
3096     {
3097         if (vogl_get_bound_gl_buffer(GL_PIXEL_UNPACK_BUFFER))
3098             return 0;
3099     }
3100
3101     return vogl_get_image_size(format, type, width, height, depth);
3102 }
3103
3104 size_t vogl_calc_get_tex_image_serialize_size(vogl_context *pContext, GLenum format, GLenum type, GLsizei width, GLsizei height, GLsizei depth)
3105 {
3106     if (pContext)
3107     {
3108         if (vogl_get_bound_gl_buffer(GL_PIXEL_PACK_BUFFER))
3109             return 0;
3110     }
3111
3112     return vogl_get_image_size(format, type, width, height, depth);
3113 }
3114
3115 size_t vogl_calc_get_tex_target_serialize_size(vogl_context *pContext, GLenum target, GLint level, GLenum format, GLenum type)
3116 {
3117     if (pContext)
3118     {
3119         if (vogl_get_bound_gl_buffer(GL_PIXEL_PACK_BUFFER))
3120             return 0;
3121     }
3122
3123     return vogl_get_tex_target_image_size(target, level, format, type);
3124 }
3125
3126 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexImage1D_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, 1, 1)
3127 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexImage2D_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, 1)
3128 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexImage3D_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, depth)
3129 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexImage3DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, depth)
3130
3131 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexSubImage1D_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, 1, 1)
3132 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexSubImage1DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, 1, 1)
3133
3134 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexSubImage2D_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, 1)
3135 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexSubImage2DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, 1)
3136
3137 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexSubImage3D_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, depth)
3138 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexSubImage3DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, depth)
3139
3140 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTextureImage3DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, depth)
3141 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTextureImage2DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, 1)
3142 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTextureImage1DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, 1, 1)
3143
3144 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTextureSubImage3DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, depth)
3145 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTextureSubImage2DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, 1)
3146 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTextureSubImage1DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, 1, 1)
3147
3148 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glMultiTexImage3DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, depth)
3149 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glMultiTexImage2DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, 1)
3150 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glMultiTexImage1DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, 1, 1)
3151
3152 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glMultiTexSubImage3DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, depth)
3153 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glMultiTexSubImage2DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, 1)
3154 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glMultiTexSubImage1DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, 1, 1)
3155
3156 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glDrawPixels_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, 1)
3157 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glConvolutionFilter1D_image(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, 1, 1)
3158 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glConvolutionFilter2D_image(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, 1)
3159
3160 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glColorTable_table(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, 1, 1)
3161 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glColorSubTable_data(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, count, 1, 1)
3162
3163 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glBitmap_size(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, GL_COLOR_INDEX, GL_BITMAP, width, height, 1)
3164 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glPolygonStipple_mask(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, GL_COLOR_INDEX, GL_BITMAP, 32, 32, 1)
3165
3166 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetTexImage_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_get_tex_target_serialize_size(pContext, target, level, format, type)
3167
3168 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glStringMarkerGREMEDY_string(e, c, rt, r, nu, ne, a, p) ((string) ? (!(len) ? (strlen(static_cast<const char *>(string)) + 1) : (len)) : 0)
3169
3170 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glViewportArrayv_v(e, c, rt, r, nu, ne, a, p) (4 * (count))
3171 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glScissorArrayv_v(e, c, rt, r, nu, ne, a, p) (4 * (count))
3172 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glDepthRangeArrayv_v(e, c, rt, r, nu, ne, a, p) (2 * (count))
3173
3174 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetActiveAttrib_name(e, c, rt, r, nu, ne, a, p) ((name) ? (strlen((const char *)(name)) + 1) : -1)
3175 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetActiveAttribARB_name(e, c, rt, r, nu, ne, a, p) ((name) ? (strlen((const char *)(name)) + 1) : -1)
3176
3177 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glReadPixels_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_get_tex_image_serialize_size(pContext, format, type, width, height, 1)
3178
3179 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glBindFragDataLocationIndexed_name(e, c, rt, r, nu, ne, a, p) (name ? (strlen((const char *)(name)) + 1) : -1)
3180 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glBindFragDataLocation_name(e, c, rt, r, nu, ne, a, p) (name ? (strlen((const char *)(name)) + 1) : -1)
3181 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glBindFragDataLocationEXT_name(e, c, rt, r, nu, ne, a, p) (name ? (strlen((const char *)(name)) + 1) : -1)
3182
3183 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glBitmap_bitmap(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, GL_COLOR_INDEX, GL_BITMAP, width, height, 1)
3184
3185 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetActiveUniform_name(e, c, rt, r, nu, ne, a, p) ((name) ? ((length) ? (*(length) + 1) : (bufSize)) : -1)
3186
3187 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetAttachedShaders_obj(e, c, rt, r, nu, ne, a, p) ((obj) ? ((count) ? *(count) : (maxCount)) : -1)
3188
3189 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetProgramInfoLog_infoLog(e, c, rt, r, nu, ne, a, p) ((infoLog) ? ((length) ? (*length + 1) : (bufSize)) : -1)
3190
3191 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetShaderSource_source(e, c, rt, r, nu, ne, a, p) ((source) ? ((length) ? (*(length) + 1) : (bufSize)) : -1)
3192
3193 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glCallLists_lists(e, c, rt, r, nu, ne, a, p) (vogl_get_gl_type_size(type) * (n))
3194
3195 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetDebugMessageLogARB_messageLog(e, c, rt, r, nu, ne, a, p) vogl_compute_message_log_size_in_bytes(count, lengths)
3196 static GLsizei vogl_compute_message_log_size_in_bytes(GLuint count, const GLsizei *lengths)
3197 {
3198     if (!lengths)
3199         return 0;
3200     GLsizei total_length = 0;
3201     for (uint i = 0; i < count; i++)
3202         total_length += lengths[i];
3203     return total_length;
3204 }
3205
3206 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glSeparableFilter2D_row(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, 1, 1)
3207 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glSeparableFilter2D_column(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, height, 1, 1)
3208
3209 // TODO - These are all gets, so they aren't completely necessary for proper replaying because they have no side effects (except for possibly glError's).
3210 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetUniformfv_params(e, c, rt, r, nu, ne, a, p) -1
3211 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetUniformiv_params(e, c, rt, r, nu, ne, a, p) -1
3212 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetPolygonStipple_mask(e, c, rt, r, nu, ne, a, p) -1
3213 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetMapdv_v(e, c, rt, r, nu, ne, a, p) -1
3214 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetMapfv_v(e, c, rt, r, nu, ne, a, p) -1
3215 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetMapiv_v(e, c, rt, r, nu, ne, a, p) -1
3216 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetColorTable_table(e, c, rt, r, nu, ne, a, p) -1
3217 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetConvolutionFilter_image(e, c, rt, r, nu, ne, a, p) -1
3218 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetSeparableFilter_row(e, c, rt, r, nu, ne, a, p) -1
3219 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetSeparableFilter_column(e, c, rt, r, nu, ne, a, p) -1
3220 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetSeparableFilter_span(e, c, rt, r, nu, ne, a, p) -1
3221 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetHistogram_values(e, c, rt, r, nu, ne, a, p) -1
3222 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetMinmax_values(e, c, rt, r, nu, ne, a, p) -1
3223 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetCompressedTexImage_img(e, c, rt, r, nu, ne, a, p) -1
3224
3225 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glClearBufferfv_value(e, c, rt, r, nu, ne, a, p) vogl_get_clearbuffer_array_size(buffer)
3226 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glClearBufferuiv_value(e, c, rt, r, nu, ne, a, p) vogl_get_clearbuffer_array_size(buffer)
3227 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glClearBufferiv_value(e, c, rt, r, nu, ne, a, p) vogl_get_clearbuffer_array_size(buffer)
3228 static int vogl_get_clearbuffer_array_size(GLenum buffer)
3229 {
3230     if ((buffer == GL_DEPTH) || (buffer == GL_STENCIL))
3231         return 1;
3232     else if (utils::is_in_set<GLenum, GLenum>(buffer, GL_COLOR, GL_FRONT, GL_BACK, GL_LEFT, GL_RIGHT, GL_FRONT_AND_BACK))
3233         return 4;
3234
3235     vogl_warning_printf("%s: Invalid value for buffer parameter passed to glClearBufferfv: 0x%04X\n", VOGL_FUNCTION_NAME, buffer);
3236     return -1;
3237 }
3238
3239 #if 0
3240 // TODO/investigate
3241 (vogltrace) Debug:
3242 glTexImage3DEXT
3243 (vogltrace) Debug:
3244 glColorTableSGI
3245 (vogltrace) Debug:
3246 glColorSubTableEXT
3247 (vogltrace) Debug:
3248 glColorTableEXT
3249 (vogltrace) Debug:
3250 glXChooseFBConfig
3251 #endif
3252
3253 //----------------------------------------------------------------------------------------------------------------------
3254 // Custom return parameter array size helper macros
3255 //----------------------------------------------------------------------------------------------------------------------
3256 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXGetFBConfigs(dpy, screen, nelements) (nelements ? *nelements : 1)
3257 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXChooseFBConfig(dpy, screen, attrib_list, nelements) (nelements ? *nelements : 1)
3258 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXChooseVisual(dpy, screen, nelements) 1
3259 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXGetVisualFromFBConfig(dpy, config) 1
3260 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXGetCurrentDisplay() 1
3261 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXGetCurrentDisplayEXT() 1
3262 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXEnumerateVideoCaptureDevicesNV(dpy, screen, nelements) (nelements ? *nelements : 1)
3263 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXEnumerateVideoDevicesNV(dpy, screen, nelements) (nelements ? *nelements : 1)
3264
3265 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetString(name) (result ? (strlen(reinterpret_cast<const char *>(result)) + 1) : 0)
3266 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetStringi(name, idx) (result ? (strlen(reinterpret_cast<const char *>(result)) + 1) : 0)
3267 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXGetClientString(dpy, name) (result ? (strlen(reinterpret_cast<const char *>(result)) + 1) : 0)
3268 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXQueryExtensionsString(dpy, name) (result ? (strlen(reinterpret_cast<const char *>(result)) + 1) : 0)
3269 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXQueryServerString(dpy, screen, name) (result ? (strlen(reinterpret_cast<const char *>(result)) + 1) : 0)
3270
3271 //----------------------------------------------------------------------------------------------------------------------
3272 static void vogl_print_hex(const void *p, uint64_t size, uint64_t type_size)
3273 {
3274     if (!p)
3275     {
3276         vogl_log_printf("<null>\n");
3277         return;
3278     }
3279
3280     const uint8_t *ptr = reinterpret_cast<const uint8_t *>(p);
3281     if ((type_size == 2) && (!(size & 1)))
3282     {
3283         int c = 0;
3284         vogl_log_printf("[ ");
3285         for (uint64_t i = 0; i < size; i += 2)
3286         {
3287             if (i)
3288                 vogl_log_printf(", ");
3289             vogl_log_printf("0x%04X", *reinterpret_cast<const uint16_t *>(ptr + i));
3290
3291             if ((++c & 7) == 7)
3292                 vogl_log_printf("\n");
3293         }
3294         vogl_log_printf(" ]");
3295     }
3296     else if ((type_size == 4) && (!(size & 3)))
3297     {
3298         int c = 0;
3299         vogl_log_printf("[ ");
3300         for (uint64_t i = 0; i < size; i += 4)
3301         {
3302             if (i)
3303                 vogl_log_printf(", ");
3304             vogl_log_printf("0x%08X", *reinterpret_cast<const uint32_t *>(ptr + i));
3305
3306             if ((++c & 7) == 7)
3307                 vogl_log_printf("\n");
3308         }
3309         vogl_log_printf(" ]");
3310     }
3311     else if ((type_size == 8) && (!(size & 7)))
3312     {
3313         int c = 0;
3314         vogl_log_printf("[ ");
3315         for (uint64_t i = 0; i < size; i += 8)
3316         {
3317             if (i)
3318                 vogl_log_printf(", ");
3319             vogl_log_printf("0x%" PRIX64, *reinterpret_cast<const uint64_t *>(ptr + i));
3320
3321             if ((++c & 7) == 7)
3322                 vogl_log_printf("\n");
3323         }
3324         vogl_log_printf(" ]");
3325     }
3326     else
3327     {
3328         int c = 0;
3329         if (size > 15)
3330             vogl_log_printf("\n");
3331
3332         vogl_log_printf("[ ");
3333         for (uint64_t i = 0; i < size; i++)
3334         {
3335             if (i)
3336                 vogl_log_printf(", ");
3337             vogl_log_printf("%02X", ptr[i]);
3338
3339             if ((++c & 63) == 63)
3340                 vogl_log_printf("\n");
3341         }
3342         vogl_log_printf(" ]");
3343     }
3344 }
3345
3346 //----------------------------------------------------------------------------------------------------------------------
3347 static void vogl_print_string(const char *pStr, uint64_t total_size)
3348 {
3349     for (uint64_t i = 0; i < total_size; i++)
3350     {
3351         uint8_t c = reinterpret_cast<const uint8_t *>(pStr)[i];
3352         if (c == '\n')
3353             vogl_log_printf("\n");
3354         else
3355         {
3356             if ((c < 32) || (c > 127))
3357                 c = '.';
3358             vogl_log_printf("%c", c);
3359         }
3360
3361         if ((i & 511) == 511)
3362             vogl_log_printf(" \\\n");
3363     }
3364 }
3365
3366 //----------------------------------------------------------------------------------------------------------------------
3367 template <typename T>
3368 static inline void vogl_dump_value_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pDesc, uint param_index, const char *pParam_name, const char *pType, vogl_ctype_t type, const T &val)
3369 {
3370     VOGL_NOTE_UNUSED(pContext);
3371
3372     int size = sizeof(T);
3373
3374     if (g_vogl_process_gl_ctypes[type].m_size != size)
3375         vogl_error_printf("%s: size mismatch on ctype %u\n", VOGL_FUNCTION_NAME, type);
3376
3377     if (serializer.is_in_begin())
3378     {
3379         serializer.add_param(param_index, type, &val, sizeof(val));
3380     }
3381
3382     if (g_dump_gl_calls_flag)
3383     {
3384         vogl_log_printf("%s: %s %s, ctype: %s, size: %i: ", pDesc, pType, pParam_name, g_vogl_process_gl_ctypes[type].m_pName, size);
3385
3386         if (Loki::TypeTraits<T>::isPointer)
3387         {
3388             vogl_log_printf("OPAQUE POINTER TYPE");
3389         }
3390         else if (size <= 0)
3391         {
3392             vogl_log_printf("OPAQUE TYPE");
3393         }
3394         else
3395         {
3396             vogl_print_hex(&val, size, size);
3397
3398             if (((type == VOGL_GLFLOAT) || (type == VOGL_GLCLAMPF)) && (size == sizeof(float)))
3399             {
3400                 float flt_val = *reinterpret_cast<const float *>(&val);
3401                 vogl_log_printf(" %f", flt_val);
3402             }
3403             else if (((type == VOGL_GLDOUBLE) || (type == VOGL_GLCLAMPD)) && (size == sizeof(double)))
3404             {
3405                 double dbl_val = *reinterpret_cast<const double *>(&val);
3406                 vogl_log_printf(" %f", dbl_val);
3407             }
3408             else if ((type == VOGL_GLENUM) && (size == sizeof(int)))
3409             {
3410                 GLenum enum_val = *reinterpret_cast<const GLenum *>(&val);
3411                 const char *pName = g_gl_enums.find_name(enum_val);
3412                 if (pName)
3413                     vogl_log_printf(" %s", pName);
3414             }
3415         }
3416
3417         vogl_log_printf("\n");
3418     }
3419 }
3420
3421 //----------------------------------------------------------------------------------------------------------------------
3422 template <typename T>
3423 static inline void vogl_dump_ptr_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pDesc, uint param_index, const char *pParam_name, const char *pType, vogl_ctype_t type, const T &val)
3424 {
3425     VOGL_NOTE_UNUSED(pContext);
3426
3427     VOGL_ASSUME(Loki::TypeTraits<T>::isPointer);
3428     int size = sizeof(T);
3429
3430     if (g_vogl_process_gl_ctypes[type].m_size != size)
3431         vogl_error_printf("%s: size mismatch on ctype %u\n", VOGL_FUNCTION_NAME, type);
3432
3433     if (serializer.is_in_begin())
3434     {
3435         serializer.add_param(param_index, type, &val, sizeof(val));
3436     }
3437
3438     if (g_dump_gl_calls_flag)
3439     {
3440         vogl_log_printf("%s: %s %s, ctype: %s, size: %i, ptr: 0x%" PRIX64 "\n", pDesc, pType, pParam_name, g_vogl_process_gl_ctypes[type].m_pName, size, cast_val_to_uint64(val));
3441     }
3442 }
3443
3444 //----------------------------------------------------------------------------------------------------------------------
3445 template <class T>
3446 static inline void vogl_dump_ref_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pDesc, uint param_index, const char *pParam_name, const char *pType, vogl_ctype_t type, const T *pObj)
3447 {
3448     VOGL_NOTE_UNUSED(pContext);
3449
3450     if (g_vogl_process_gl_ctypes[type].m_size != sizeof(const T *))
3451         vogl_error_printf("%s: size mismatch on ctype %u\n", VOGL_FUNCTION_NAME, type);
3452
3453     int obj_size = gl_ctype_sizeof<T>::size;
3454
3455     vogl_ctype_t pointee_type = g_vogl_process_gl_ctypes[type].m_pointee_ctype;
3456     if (pointee_type == VOGL_INVALID_CTYPE)
3457     {
3458         vogl_error_printf("%s: Type %u doesn't have a pointee ctype\n", VOGL_FUNCTION_NAME, type);
3459         return;
3460     }
3461
3462     if (g_vogl_process_gl_ctypes[pointee_type].m_size != obj_size)
3463         vogl_error_printf("%s: size mismatch on pointee ctype %u\n", VOGL_FUNCTION_NAME, type);
3464
3465     if (serializer.is_in_begin())
3466     {
3467         serializer.add_param(param_index, type, &pObj, sizeof(pObj));
3468
3469         if ((pObj) && (obj_size > 0))
3470         {
3471             serializer.add_ref_client_memory(param_index, pointee_type, pObj, obj_size);
3472         }
3473     }
3474
3475     if (g_dump_gl_calls_flag)
3476     {
3477         vogl_log_printf("%s: %s %s, ptr: 0x%" PRIX64 ", ctype: %s, pointee_ctype: %s, pointee_size: %i: ", pDesc, pType, pParam_name, cast_val_to_uint64(pObj), g_vogl_process_gl_ctypes[type].m_pName, g_vogl_process_gl_ctypes[pointee_type].m_pName, obj_size);
3478         if (!pObj)
3479         {
3480             vogl_log_printf("NULL");
3481         }
3482         else if (obj_size <= 0)
3483         {
3484             vogl_log_printf("OPAQUE TYPE");
3485         }
3486         else
3487         {
3488             vogl_print_hex(pObj, obj_size, obj_size);
3489         }
3490
3491         vogl_log_printf("\n");
3492     }
3493 }
3494
3495 //----------------------------------------------------------------------------------------------------------------------
3496 template <class T>
3497 static inline void vogl_dump_array_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pDesc, uint param_index, const char *pParam_name, const char *pType, vogl_ctype_t type, const T *pArray, int64_t size)
3498 {
3499     VOGL_NOTE_UNUSED(pContext);
3500
3501     int64_t obj_size = gl_ctype_sizeof<T>::size;
3502     int64_t total_size = obj_size * math::maximum<int64_t>(size, 0);
3503
3504     vogl_ctype_t pointee_type = g_vogl_process_gl_ctypes[type].m_pointee_ctype;
3505     if (((type == VOGL_CONST_VOID_PTR) || (type == VOGL_CONST_GLVOID_PTR) || (type == VOGL_GLVOID_PTR)) && (size > 0))
3506     {
3507         obj_size = 1;
3508         total_size = size;
3509     }
3510     else
3511     {
3512         if (pointee_type == VOGL_INVALID_CTYPE)
3513         {
3514             vogl_error_printf("%s: Type %u doesn't have a pointee ctype\n", VOGL_FUNCTION_NAME, type);
3515             return;
3516         }
3517
3518         if (g_vogl_process_gl_ctypes[pointee_type].m_size != obj_size)
3519             vogl_error_printf("%s: Size mismatch on ctype %u\n", VOGL_FUNCTION_NAME, type);
3520     }
3521
3522     bool pointee_is_ptr = g_vogl_process_gl_ctypes[pointee_type].m_is_pointer;
3523
3524     if (serializer.is_in_begin())
3525     {
3526         serializer.add_param(param_index, type, &pArray, sizeof(pArray));
3527
3528         if ((pArray) && (size > 0) && (obj_size > 0))
3529         {
3530             serializer.add_array_client_memory(param_index, pointee_type, size, pArray, total_size);
3531         }
3532     }
3533
3534     if (g_dump_gl_calls_flag)
3535     {
3536         vogl_log_printf("%s: %s %s, ptr: 0x%" PRIX64 ", ctype: %s, pointee_ctype: %s, size: %" PRIi64 ", pointee_size: %" PRIi64 ", total size: %" PRIi64 ": ", pDesc, pType, pParam_name, cast_val_to_uint64(pArray), g_vogl_process_gl_ctypes[type].m_pName, g_vogl_process_gl_ctypes[pointee_type].m_pName,
3537                        size, obj_size, total_size);
3538         if (!pArray)
3539         {
3540             vogl_log_printf("NULL");
3541         }
3542         else if (size <= 0)
3543         {
3544             vogl_log_printf("UNKNOWN SIZE");
3545         }
3546         else if (obj_size <= 0)
3547         {
3548             vogl_log_printf("OPAQUE TYPE");
3549         }
3550         else
3551         {
3552             if (pointee_is_ptr)
3553             {
3554                 vogl_log_printf("POINTEE IS POINTER: \n");
3555             }
3556
3557             vogl_print_hex(pArray, total_size, obj_size);
3558
3559             switch (pointee_type)
3560             {
3561                 case VOGL_GLUBYTE:
3562                 case VOGL_GLBYTE:
3563                 case VOGL_GLCHAR:
3564                 case VOGL_GLCHARARB:
3565                 {
3566                     vogl_log_printf("\nAs string: \"");
3567                     vogl_print_string(*(const char **)&pArray, total_size);
3568                     vogl_log_printf("\"");
3569                     break;
3570                 }
3571                 default:
3572                 {
3573                     break;
3574                 }
3575             }
3576         }
3577
3578         vogl_log_printf("\n");
3579     }
3580 }
3581
3582 //----------------------------------------------------------------------------------------------------------------------
3583 // Return parameters
3584 //----------------------------------------------------------------------------------------------------------------------
3585 template <class T>
3586 static inline void vogl_dump_return_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pType, vogl_ctype_t type, int64_t size, const T &val)
3587 {
3588     VOGL_NOTE_UNUSED(size);
3589
3590     VOGL_ASSUME(!Loki::TypeTraits<T>::isPointer);
3591
3592     vogl_dump_value_param(pContext, serializer, "RETURN_VALUE", VOGL_RETURN_PARAM_INDEX, "result", pType, type, val);
3593 }
3594
3595 static inline void vogl_dump_return_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pType, vogl_ctype_t type, int64_t size, unsigned char *pPtr)
3596 {
3597     VOGL_NOTE_UNUSED(size);
3598
3599     size_t array_size = pPtr ? (strlen(reinterpret_cast<const char *>(pPtr)) + 1) : 0;
3600     vogl_dump_array_param(pContext, serializer, "RETURN_UCHAR_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr, array_size);
3601 }
3602
3603 static inline void vogl_dump_return_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pType, vogl_ctype_t type, int64_t size, const GLubyte *pPtr)
3604 {
3605     VOGL_NOTE_UNUSED(size);
3606
3607     size_t array_size = pPtr ? (strlen(reinterpret_cast<const char *>(pPtr)) + 1) : 0;
3608     vogl_dump_array_param(pContext, serializer, "RETURN_GLUBYTE_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr, array_size);
3609 }
3610
3611 static inline void vogl_dump_return_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pType, vogl_ctype_t type, int64_t size, void *pPtr)
3612 {
3613     VOGL_NOTE_UNUSED(size);
3614
3615     // opaque data
3616     vogl_dump_ptr_param(pContext, serializer, "RETURN_VOID_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr);
3617 }
3618
3619 static inline void vogl_dump_return_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pType, vogl_ctype_t type, int64_t size, unsigned int *pPtr)
3620 {
3621     vogl_dump_array_param(pContext, serializer, "RETURN_UINT_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr, size);
3622 }
3623
3624 static inline void vogl_dump_return_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pType, vogl_ctype_t type, int64_t size, long unsigned int *pPtr)
3625 {
3626     vogl_dump_array_param(pContext, serializer, "RETUURN_LUINT_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr, size);
3627 }
3628
3629 static inline void vogl_dump_return_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pType, vogl_ctype_t type, int64_t size, XVisualInfo *pPtr)
3630 {
3631     VOGL_NOTE_UNUSED(size);
3632
3633     vogl_dump_ref_param(pContext, serializer, "RETURN_XVISUALINFO_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr);
3634 }
3635
3636 static inline void vogl_dump_return_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pType, vogl_ctype_t type, int64_t size, GLXFBConfig *pPtr)
3637 {
3638     VOGL_NOTE_UNUSED(size);
3639
3640     vogl_dump_ref_param(pContext, serializer, "RETURN_GLXFBCONFIG_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr);
3641 }
3642
3643 static inline void vogl_dump_return_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pType, vogl_ctype_t type, int64_t size, GLXContext pPtr)
3644 {
3645     VOGL_NOTE_UNUSED(size);
3646
3647     // opaque data
3648     vogl_dump_ptr_param(pContext, serializer, "RETURN_GLXCONTEXT", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr);
3649 }
3650
3651 static inline void vogl_dump_return_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pType, vogl_ctype_t type, int64_t size, _XDisplay *pPtr)
3652 {
3653     VOGL_NOTE_UNUSED(size);
3654
3655     // opaque data
3656     vogl_dump_ptr_param(pContext, serializer, "RETURN_XDISPLAY_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr);
3657 }
3658
3659 //----------------------------------------------------------------------------------------------------------------------
3660 // vogl_should_serialize_call
3661 //----------------------------------------------------------------------------------------------------------------------
3662 static inline bool vogl_should_serialize_call(gl_entrypoint_id_t func, vogl_context *pContext)
3663 {
3664     bool is_in_display_list = pContext && pContext->is_composing_display_list();
3665     bool is_listable = g_vogl_entrypoint_descs[func].m_is_listable;
3666     bool is_whitelisted = g_vogl_entrypoint_descs[func].m_whitelisted_for_displaylists;
3667
3668     if ((is_in_display_list) && (is_listable) && (!is_whitelisted))
3669     {
3670         vogl_error_printf("%s: Called GL func %s is not currently supported in display lists! The replay will diverge.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[func].m_pName);
3671     }
3672
3673     // When we're writing a trace we ALWAYS want to serialize, even if the func is not listable (so we can at least process the trace, etc.)
3674     if (g_vogl_trace_writer.is_opened())
3675         return true;
3676
3677     return is_in_display_list && is_whitelisted;
3678 }
3679
3680 //----------------------------------------------------------------------------------------------------------------------
3681 // vogl_write_packet_to_trace
3682 //----------------------------------------------------------------------------------------------------------------------
3683 static inline void vogl_write_packet_to_trace(vogl_trace_packet &packet)
3684 {
3685     if (!g_vogl_trace_writer.is_opened())
3686         return;
3687
3688     scoped_mutex lock(g_vogl_trace_mutex);
3689
3690     // The trace got closed on another thread while we where serializing - this is OK I guess.
3691     // This can happen when control+c is pressed.
3692     if (g_vogl_trace_writer.is_opened())
3693     {
3694         bool success = g_vogl_trace_writer.write_packet(packet);
3695
3696         if (success)
3697         {
3698             if ((g_flush_files_after_each_call) ||
3699                 ((g_flush_files_after_each_swap) && (packet.get_entrypoint_id() == VOGL_ENTRYPOINT_glXSwapBuffers)))
3700             {
3701                 g_vogl_trace_writer.flush();
3702
3703                 if (g_vogl_pLog_stream)
3704                     g_vogl_pLog_stream->flush();
3705             }
3706         }
3707         else
3708         {
3709             vogl_error_printf("%s: Failed writing to trace file! Exiting app.\n", VOGL_FUNCTION_NAME);
3710
3711             // TODO: Add common termination handler func, or just stop writing to the trace? or call abort()
3712             exit(EXIT_FAILURE);
3713         }
3714     }
3715 }
3716
3717 //----------------------------------------------------------------------------------------------------------------------
3718 // Declare gl/glx internal wrapper functions, all start with "vogl_" (so we can safely get the address of our internal
3719 // wrappers, avoiding global symbol naming conflicts that I started to see on test apps when I started building with -fPIC)
3720 //----------------------------------------------------------------------------------------------------------------------
3721 // func begin
3722 #define DEF_PROTO_EXPORTED(ret, name, args, params)    \
3723     static ret VOGL_GLUER(vogl_, name) args           \
3724     {                                                  \
3725         if (vogl_func_is_nulled(VOGL_ENTRYPOINT_##name)) \
3726         {                                              \
3727             return (ret)0;                             \
3728         }                                              \
3729         ret result;
3730 #define DEF_PROTO_EXPORTED_VOID(ret, name, args, params) \
3731     static ret VOGL_GLUER(vogl_, name) args             \
3732     {                                                    \
3733         if (vogl_func_is_nulled(VOGL_ENTRYPOINT_##name))   \
3734             return;
3735 #define DEF_PROTO_INTERNAL(ret, name, args, params)    \
3736     static ret VOGL_GLUER(vogl_, name) args           \
3737     {                                                  \
3738         if (vogl_func_is_nulled(VOGL_ENTRYPOINT_##name)) \
3739         {                                              \
3740             return (ret)0;                             \
3741         }                                              \
3742         ret result;
3743 #define DEF_PROTO_INTERNAL_VOID(ret, name, args, params) \
3744     static ret VOGL_GLUER(vogl_, name) args             \
3745     {                                                    \
3746         if (vogl_func_is_nulled(VOGL_ENTRYPOINT_##name))   \
3747             return;
3748
3749 #define DEF_FUNCTION_BEGIN(exported, category, ret, ret_type_enum, num_params, name, args, params) exported(ret, name, args, params)
3750 #define DEF_FUNCTION_BEGIN_VOID(exported, category, ret, ret_type_enum, num_params, name, args, params) exported(ret, name, args, params)
3751
3752 // TODO: When serialization is off, the array size determination code is still active (which could involve useless GL calls and in the worst case could trigger errors when/if this code is buggy).
3753 // A completely different code path through the wrapper should be used.
3754
3755 // func init (after the optional custom function prolog)
3756 #define VOGL_MASTER_FUNCTION_PROLOG(name, params)                                                                                                                                                                                                  \
3757     if (g_dump_gl_calls_flag)                                                                                                                                                                                                                     \
3758     {                                                                                                                                                                                                                                             \
3759         vogl_message_printf("** BEGIN %s 0x%" PRIX64 "" PRIX64 "\n", #name, vogl_get_current_kernel_thread_id());                                                                                                                                                           \
3760     }                                                                                                                                                                                                                                             \
3761     vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_##name);                                                                                                                                                              \
3762     if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)                                                                                                                                                                      \
3763     {                                                                                                                                                                                                                                             \
3764         vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName); \
3765         return g_vogl_actual_gl_entrypoints.m_##name params;                                                                                                                                                                                       \
3766     }                                                                                                                                                                                                                                             \
3767     vogl_context *pContext = pTLS_data->m_pContext;                                                                                                                                                                                                \
3768     vogl_entrypoint_serializer &trace_serializer = pTLS_data->m_serializer;                                                                                                                                                                        \
3769     if (vogl_should_serialize_call(VOGL_ENTRYPOINT_##name, pContext))                                                                                                                                                                               \
3770     {                                                                                                                                                                                                                                             \
3771         if (!trace_serializer.begin(VOGL_ENTRYPOINT_##name, pContext))                                                                                                                                                                             \
3772         {                                                                                                                                                                                                                                         \
3773             vogl_warning_printf("%s: Reentrant wrapper call detected!\n", VOGL_FUNCTION_NAME);                                                                                                                                                   \
3774             return g_vogl_actual_gl_entrypoints.m_##name params;                                                                                                                                                                                   \
3775         }                                                                                                                                                                                                                                         \
3776     }
3777
3778 #define VOGL_MASTER_FUNCTION_PROLOG_VOID(name, params)                                                                                                                                                                                             \
3779     if (g_dump_gl_calls_flag)                                                                                                                                                                                                                     \
3780     {                                                                                                                                                                                                                                             \
3781         vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", #name, vogl_get_current_kernel_thread_id());                                                                                                                                                           \
3782     }                                                                                                                                                                                                                                             \
3783     vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_##name);                                                                                                                                                              \
3784     if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)                                                                                                                                                                      \
3785     {                                                                                                                                                                                                                                             \
3786         vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName); \
3787         g_vogl_actual_gl_entrypoints.m_##name params;                                                                                                                                                                                              \
3788         return;                                                                                                                                                                                                                                   \
3789     }                                                                                                                                                                                                                                             \
3790     vogl_context *pContext = pTLS_data->m_pContext;                                                                                                                                                                                                \
3791     vogl_entrypoint_serializer &trace_serializer = pTLS_data->m_serializer;                                                                                                                                                                        \
3792     if (vogl_should_serialize_call(VOGL_ENTRYPOINT_##name, pContext))                                                                                                                                                                               \
3793     {                                                                                                                                                                                                                                             \
3794         if (!trace_serializer.begin(VOGL_ENTRYPOINT_##name, pContext))                                                                                                                                                                             \
3795         {                                                                                                                                                                                                                                         \
3796             vogl_warning_printf("%s: Reentrant wrapper call detected!\n", VOGL_FUNCTION_NAME);                                                                                                                                                   \
3797             g_vogl_actual_gl_entrypoints.m_##name params;                                                                                                                                                                                          \
3798             return;                                                                                                                                                                                                                               \
3799         }                                                                                                                                                                                                                                         \
3800     }
3801
3802 #define DEF_FUNCTION_INIT(exported, category, ret, ret_type_enum, num_params, name, args, params) VOGL_MASTER_FUNCTION_PROLOG(name, params)
3803 #define DEF_FUNCTION_INIT_VOID(exported, category, ret, ret_type_enum, num_params, name, args, params) VOGL_MASTER_FUNCTION_PROLOG_VOID(name, params)
3804
3805 // func params
3806 #define DEF_FUNCTION_INPUT_VALUE_PARAM(idx, spectype, type, type_enum, param) vogl_dump_value_param(pContext, trace_serializer, "INPUT_VALUE", idx, #param, #type, type_enum, param);
3807 #define DEF_FUNCTION_INPUT_REFERENCE_PARAM(idx, spectype, type, type_enum, param) vogl_dump_ref_param(pContext, trace_serializer, "INPUT_REF", idx, #param, #type, type_enum, param);
3808 #define DEF_FUNCTION_INPUT_ARRAY_PARAM(idx, spectype, type, type_enum, param, size) vogl_dump_array_param(pContext, trace_serializer, "INPUT_ARRAY", idx, #param, #type, type_enum, param, size);
3809
3810 #define DEF_FUNCTION_OUTPUT_REFERENCE_PARAM(idx, spectype, type, type_enum, param) vogl_dump_ref_param(pContext, trace_serializer, "OUTPUT_REF", idx, #param, #type, type_enum, param);
3811 #define DEF_FUNCTION_OUTPUT_ARRAY_PARAM(idx, spectype, type, type_enum, param, size) vogl_dump_array_param(pContext, trace_serializer, "OUTPUT_ARRAY", idx, #param, #type, type_enum, param, size);
3812
3813 #define DEF_FUNCTION_RETURN_PARAM(spectype, type, type_enum, size) vogl_dump_return_param(pContext, trace_serializer, #type, type_enum, size, result);
3814
3815 #define DEF_FUNCTION_CALL_GL(exported, category, ret, ret_type_enum, num_params, name, args, params) \
3816     if (trace_serializer.is_in_begin())                                                              \
3817         trace_serializer.set_gl_begin_rdtsc(utils::RDTSC());                                         \
3818     result = g_vogl_actual_gl_entrypoints.m_##name params;                                            \
3819     if (trace_serializer.is_in_begin())                                                              \
3820         trace_serializer.set_gl_end_rdtsc(utils::RDTSC());
3821
3822 #define DEF_FUNCTION_CALL_GL_VOID(exported, category, ret, ret_type_enum, num_params, name, args, params) \
3823     if (trace_serializer.is_in_begin())                                                                   \
3824         trace_serializer.set_gl_begin_rdtsc(utils::RDTSC());                                              \
3825     g_vogl_actual_gl_entrypoints.m_##name params;                                                          \
3826     if (trace_serializer.is_in_begin())                                                                   \
3827         trace_serializer.set_gl_end_rdtsc(utils::RDTSC());
3828
3829 // Be careful modifying these END macros. They must be compatible with the logic in the glXSwapBuffers GL end prolog!
3830 // func end (after the optional custom function epilog)
3831 #define DEF_FUNCTION_END(exported, category, ret, ret_type_enum, num_params, name, args, params)                \
3832     if (g_dump_gl_calls_flag)                                                                                   \
3833     {                                                                                                           \
3834         vogl_message_printf("** END %s res=%s 0x%" PRIX64 "\n", #name, #ret, cast_val_to_uint64(result));                  \
3835     }                                                                                                           \
3836     if (trace_serializer.is_in_begin())                                                                         \
3837     {                                                                                                           \
3838         trace_serializer.end();                                                                                 \
3839         vogl_write_packet_to_trace(trace_serializer.get_packet());                                               \
3840         if (pContext)                                                                                           \
3841             pContext->add_packet_to_current_display_list(VOGL_ENTRYPOINT_##name, trace_serializer.get_packet()); \
3842     }                                                                                                           \
3843     return result;                                                                                              \
3844     }
3845
3846 #define DEF_FUNCTION_END_VOID(exported, category, ret, ret_type_enum, num_params, name, args, params)           \
3847     if (g_dump_gl_calls_flag)                                                                                   \
3848     {                                                                                                           \
3849         vogl_message_printf("** END %s\n", #name);                                                               \
3850     }                                                                                                           \
3851     if (trace_serializer.is_in_begin())                                                                         \
3852     {                                                                                                           \
3853         trace_serializer.end();                                                                                 \
3854         vogl_write_packet_to_trace(trace_serializer.get_packet());                                               \
3855         if (pContext)                                                                                           \
3856             pContext->add_packet_to_current_display_list(VOGL_ENTRYPOINT_##name, trace_serializer.get_packet()); \
3857     }                                                                                                           \
3858     }
3859
3860 //----------------------------------------------------------------------------------------------------------------------
3861 // gl/glx override functions
3862 //----------------------------------------------------------------------------------------------------------------------
3863 static __GLXextFuncPtr vogl_get_proc_address_helper(const GLubyte *procName)
3864 {
3865     if (!procName)
3866         return NULL;
3867
3868     if (g_dump_gl_calls_flag)
3869     {
3870         vogl_printf("glXGetProcAddress: \"%s\"\n", procName);
3871     }
3872
3873     if (!GL_ENTRYPOINT(glXGetProcAddress))
3874         return NULL;
3875
3876     // FIXME: We need to make this per-context on OSX (under Linux it doesn't matter, because all GL funcs are statically exported anyway as symbols by the SO)
3877     __GLXextFuncPtr pActual_entrypoint = GL_ENTRYPOINT(glXGetProcAddress)(procName);
3878     if (!pActual_entrypoint)
3879         return NULL;
3880
3881     for (uint i = 0; i < VOGL_NUM_ENTRYPOINTS; ++i)
3882     {
3883         if (vogl_strcmp(reinterpret_cast<const char *>(procName), g_vogl_entrypoint_descs[i].m_pName) == 0)
3884         {
3885             if (g_vogl_entrypoint_descs[i].m_pWrapper_func)
3886             {
3887                 if (!g_vogl_entrypoint_descs[i].m_is_whitelisted)
3888                 {
3889                     // TODO: Only print this message once
3890                     vogl_warning_printf("%s: App has queried the address of non-whitelisted GL func %s (this will only be a problem if this func. is actually called, and will reported during tracing and at exit)\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[i].m_pName);
3891                 }
3892
3893                 return reinterpret_cast<__GLXextFuncPtr>(g_vogl_entrypoint_descs[i].m_pWrapper_func);
3894             }
3895             else
3896                 break;
3897         }
3898     }
3899
3900     return pActual_entrypoint;
3901 }
3902
3903 //----------------------------------------------------------------------------------------------------------------------
3904 // Custom function handler implementations
3905 //----------------------------------------------------------------------------------------------------------------------
3906 #define DEF_FUNCTION_CUSTOM_HANDLER_glInternalTraceCommandRAD(exported, category, ret, ret_type_enum, num_params, name, args, params)
3907 static void vogl_glInternalTraceCommandRAD(GLuint cmd, GLuint size, const GLubyte *data)
3908 {
3909     if (g_dump_gl_calls_flag)
3910     {
3911         vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
3912     }
3913
3914     if (g_vogl_trace_writer.is_opened())
3915     {
3916         vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glInternalTraceCommandRAD, NULL);
3917
3918         uint64_t cur_rdtsc = utils::RDTSC();
3919         serializer.set_gl_begin_end_rdtsc(cur_rdtsc, cur_rdtsc + 1);
3920
3921         serializer.add_param(0, VOGL_GLUINT, &cmd, sizeof(cmd));
3922         serializer.add_param(1, VOGL_GLUINT, &size, sizeof(size));
3923         serializer.add_param(2, VOGL_CONST_GLUBYTE_PTR, &data, sizeof(data));
3924
3925         switch (cmd)
3926         {
3927             case cITCRDemarcation:
3928             {
3929                 break;
3930             }
3931             case cITCRKeyValueMap:
3932             {
3933                 if ((size == sizeof(key_value_map)) && (data))
3934                 {
3935                     // Directly jam in the key value map, so it properly serializes as readable JSON.
3936                     serializer.get_key_value_map() = *reinterpret_cast<const key_value_map *>(data);
3937                 }
3938                 else
3939                 {
3940                     vogl_error_printf("%s: data pointer is NULL, or invalid key_value_map size %u\n", VOGL_FUNCTION_NAME, size);
3941                     VOGL_ASSERT_ALWAYS;
3942                 }
3943                 break;
3944             }
3945             default:
3946             {
3947                 vogl_error_printf("%s: Unknown trace command type %u\n", VOGL_FUNCTION_NAME, cmd);
3948                 VOGL_ASSERT_ALWAYS;
3949                 break;
3950             }
3951         }
3952
3953         serializer.end();
3954         vogl_write_packet_to_trace(serializer.get_packet());
3955     }
3956
3957     if (g_dump_gl_calls_flag)
3958     {
3959         vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
3960     }
3961 }
3962
3963 //----------------------------------------------------------------------------------------------------------------------
3964 // TODO: Merge this with vogl_glXGetProcAddressARB to avoid duplicated code
3965 #define DEF_FUNCTION_CUSTOM_HANDLER_glXGetProcAddress(exported, category, ret, ret_type_enum, num_params, name, args, params)
3966 static __GLXextFuncPtr vogl_glXGetProcAddress(const GLubyte *procName)
3967 {
3968     uint64_t begin_rdtsc = utils::RDTSC();
3969
3970     if (g_dump_gl_calls_flag)
3971     {
3972         vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
3973     }
3974
3975     vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXGetProcAddress);
3976     if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
3977     {
3978         vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName);
3979         return GL_ENTRYPOINT(glXGetProcAddress)(procName);
3980     }
3981
3982     uint64_t gl_begin_rdtsc = utils::RDTSC();
3983     __GLXextFuncPtr ptr = vogl_get_proc_address_helper(procName);
3984     uint64_t gl_end_rdtsc = utils::RDTSC();
3985
3986     if (g_vogl_trace_writer.is_opened())
3987     {
3988         vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glXGetProcAddress, g_context_manager.get_current());
3989         serializer.set_begin_rdtsc(begin_rdtsc);
3990         serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
3991         serializer.add_param(0, VOGL_CONST_GLUBYTE_PTR, &procName, sizeof(procName));
3992         if (procName)
3993         {
3994             size_t len = strlen(reinterpret_cast<const char *>(procName)) + 1;
3995             serializer.add_array_client_memory(0, VOGL_GLUBYTE, len, procName, len);
3996         }
3997         serializer.add_return_param(VOGL_GLXEXTFUNCPTR, &ptr, sizeof(ptr));
3998         serializer.end();
3999         vogl_write_packet_to_trace(serializer.get_packet());
4000     }
4001
4002     if (g_dump_gl_calls_flag)
4003     {
4004         vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
4005     }
4006
4007     return ptr;
4008 }
4009
4010 //----------------------------------------------------------------------------------------------------------------------
4011 #define DEF_FUNCTION_CUSTOM_HANDLER_glXGetProcAddressARB(exported, category, ret, ret_type_enum, num_params, name, args, params)
4012 static __GLXextFuncPtr vogl_glXGetProcAddressARB(const GLubyte *procName)
4013 {
4014     uint64_t begin_rdtsc = utils::RDTSC();
4015
4016     if (g_dump_gl_calls_flag)
4017     {
4018         vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
4019     }
4020
4021     vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXGetProcAddressARB);
4022     if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
4023     {
4024         vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName);
4025         return GL_ENTRYPOINT(glXGetProcAddressARB)(procName);
4026     }
4027
4028     uint64_t gl_begin_rdtsc = utils::RDTSC();
4029     __GLXextFuncPtr ptr = vogl_get_proc_address_helper(procName);
4030     uint64_t gl_end_rdtsc = utils::RDTSC();
4031
4032     if (g_vogl_trace_writer.is_opened())
4033     {
4034         vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glXGetProcAddressARB, g_context_manager.get_current());
4035         serializer.set_begin_rdtsc(begin_rdtsc);
4036         serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
4037         serializer.add_param(0, VOGL_CONST_GLUBYTE_PTR, &procName, sizeof(procName));
4038         if (procName)
4039         {
4040             size_t len = strlen(reinterpret_cast<const char *>(procName)) + 1;
4041             serializer.add_array_client_memory(0, VOGL_GLUBYTE, len, procName, len);
4042         }
4043         serializer.add_return_param(VOGL_GLXEXTFUNCPTR, &ptr, sizeof(ptr));
4044         serializer.end();
4045         vogl_write_packet_to_trace(serializer.get_packet());
4046     }
4047
4048     if (g_dump_gl_calls_flag)
4049     {
4050         vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
4051     }
4052
4053     return ptr;
4054 }
4055
4056 //----------------------------------------------------------------------------------------------------------------------
4057 static void vogl_add_make_current_key_value_fields(const Display *dpy, GLXDrawable drawable, Bool result, vogl_context *pVOGL_context, vogl_entrypoint_serializer &serializer)
4058 {
4059     if ((result) && (pVOGL_context))
4060     {
4061         vogl_scoped_gl_error_absorber gl_error_absorber(pVOGL_context);
4062         VOGL_NOTE_UNUSED(gl_error_absorber);
4063
4064         GLint cur_viewport[4];
4065         GL_ENTRYPOINT(glGetIntegerv)(GL_VIEWPORT, cur_viewport);
4066
4067         serializer.add_key_value(string_hash("viewport_x"), cur_viewport[0]);
4068         serializer.add_key_value(string_hash("viewport_y"), cur_viewport[1]);
4069         serializer.add_key_value(string_hash("viewport_width"), cur_viewport[2]);
4070         serializer.add_key_value(string_hash("viewport_height"), cur_viewport[3]);
4071     }
4072
4073     if ((pVOGL_context) && (pVOGL_context->get_window_width() < 0))
4074     {
4075         if ((dpy) && (drawable) && (result))
4076         {
4077             Window root;
4078             int x, y;
4079             unsigned int width, height, border_width, depth;
4080             if (XGetGeometry(const_cast<Display *>(dpy), drawable, &root, &x, &y, &width, &height, &border_width, &depth) != False)
4081             {
4082                 pVOGL_context->set_window_dimensions(width, height);
4083
4084                 serializer.add_key_value(string_hash("win_width"), width);
4085                 serializer.add_key_value(string_hash("win_height"), height);
4086
4087                 if (g_dump_gl_calls_flag)
4088                 {
4089                     vogl_log_printf("** Current window dimensions: %ix%i\n", width, height);
4090                 }
4091             }
4092         }
4093     }
4094 }
4095
4096 #if 0
4097 //----------------------------------------------------------------------------------------------------------------------
4098 // HACK HACK - for NS2 experiment in AMD
4099 #define DEF_FUNCTION_CUSTOM_HANDLER_glTexStorage2D(exported, category, ret, ret_type_enum, num_params, name, args, params)
4100 static void vogl_glTexStorage2D(        GLenum target,
4101                                 GLsizei levels,
4102                                 GLenum internalformat,
4103                                 GLsizei width,
4104                                 GLsizei height)
4105 {
4106         GL_ENTRYPOINT(glTexParameteri)(target, GL_TEXTURE_BASE_LEVEL, 0);
4107         GL_ENTRYPOINT(glTexParameteri)(target, GL_TEXTURE_MAX_LEVEL, levels - 1);
4108
4109         if (target == GL_TEXTURE_2D)
4110         {
4111                 for (uint i = 0; i < levels; i++)
4112                 {
4113                         uint w = math::maximum<uint>(width >> i, 1);
4114                         uint h = math::maximum<uint>(height >> i, 1);
4115                         vogl::vector<uint8> pixels(w * h * 4);
4116                         GL_ENTRYPOINT(glTexImage2D)(GL_TEXTURE_2D, i, internalformat, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, pixels.get_ptr());
4117                 }
4118         }
4119 }
4120 #endif
4121
4122 //----------------------------------------------------------------------------------------------------------------------
4123 #define DEF_FUNCTION_CUSTOM_HANDLER_glXMakeCurrent(exported, category, ret, ret_type_enum, num_params, name, args, params)
4124 static Bool vogl_glXMakeCurrent(const Display *dpy, GLXDrawable drawable, GLXContext context)
4125 {
4126     uint64_t begin_rdtsc = utils::RDTSC();
4127
4128     if (g_dump_gl_calls_flag)
4129     {
4130         vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
4131     }
4132
4133     vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXMakeCurrent);
4134     if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
4135     {
4136         vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName);
4137         return GL_ENTRYPOINT(glXMakeCurrent)(dpy, drawable, context);
4138     }
4139
4140     if (g_dump_gl_calls_flag)
4141     {
4142         vogl_log_printf("** glXMakeCurrent TID: 0x%" PRIX64 " dpy: 0x%" PRIX64 " drawable: 0x%" PRIX64 " context: 0x%" PRIX64 "\n", vogl_get_current_kernel_thread_id(), cast_val_to_uint64(dpy), cast_val_to_uint64(drawable), cast_val_to_uint64(context));
4143     }
4144
4145     vogl_context *pCur_context = g_context_manager.get_current();
4146
4147     vogl_context *pNew_context = context ? g_context_manager.lookup_vogl_context(context) : NULL;
4148     if ((context) && (!pNew_context))
4149     {
4150         vogl_error_printf("%s: Unknown context handle 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(context));
4151     }
4152
4153     if (pCur_context)
4154     {
4155         if (pCur_context != pNew_context)
4156             pCur_context->on_release_current_prolog();
4157         else
4158             vogl_warning_printf("%s: Context 0x%" PRIX64 " is already current (redundant call)\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(context));
4159     }
4160
4161     uint64_t gl_begin_rdtsc = utils::RDTSC();
4162     Bool result = GL_ENTRYPOINT(glXMakeCurrent)(dpy, drawable, context);
4163     uint64_t gl_end_rdtsc = utils::RDTSC();
4164
4165     if ((result) && (pCur_context != pNew_context))
4166     {
4167         if (pCur_context)
4168             g_context_manager.release_current();
4169
4170         if (context)
4171         {
4172             vogl_context *p = g_context_manager.make_current(context);
4173             VOGL_ASSERT(p == pNew_context);
4174             VOGL_NOTE_UNUSED(p);
4175
4176             pNew_context->set_display(dpy);
4177             pNew_context->set_drawable(drawable);
4178             pNew_context->set_read_drawable(drawable);
4179         }
4180     }
4181
4182     if (g_dump_gl_calls_flag)
4183     {
4184         vogl_log_printf("** glXMakeCurrent result: %i\n", result);
4185     }
4186
4187     if (g_vogl_trace_writer.is_opened())
4188     {
4189         vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glXMakeCurrent, pCur_context);
4190         serializer.set_begin_rdtsc(begin_rdtsc);
4191         serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
4192         serializer.add_param(0, VOGL_CONST_DISPLAY_PTR, &dpy, sizeof(dpy));
4193         serializer.add_param(1, VOGL_GLXDRAWABLE, &drawable, sizeof(drawable));
4194         serializer.add_param(2, VOGL_GLXCONTEXT, &context, sizeof(context));
4195         serializer.add_return_param(VOGL_BOOL, &result, sizeof(result));
4196
4197         vogl_add_make_current_key_value_fields(dpy, drawable, result, pNew_context, serializer);
4198
4199         serializer.end();
4200         vogl_write_packet_to_trace(serializer.get_packet());
4201     }
4202
4203     if (g_dump_gl_calls_flag)
4204     {
4205         vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
4206     }
4207
4208     static bool s_added_atexit = false;
4209     if (!s_added_atexit)
4210     {
4211             // atexit routines are called in the reverse order in which they were registered. We would like
4212                 //  our vogl_atexit() routine to be called before anything else (Ie C++ destructors, etc.) So we
4213                 //  put atexit at the end of vogl_global_init() and another at the end of glXMakeCurrent.
4214         atexit(vogl_atexit);
4215         s_added_atexit = true;
4216     }
4217     
4218     return result;
4219 }
4220
4221 //----------------------------------------------------------------------------------------------------------------------
4222 #define DEF_FUNCTION_CUSTOM_HANDLER_glXMakeContextCurrent(exported, category, ret, ret_type_enum, num_params, name, args, params)
4223 static Bool vogl_glXMakeContextCurrent(const Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext context)
4224 {
4225     uint64_t begin_rdtsc = utils::RDTSC();
4226
4227     if (g_dump_gl_calls_flag)
4228     {
4229         vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
4230     }
4231
4232     vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXMakeContextCurrent);
4233     if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
4234     {
4235         vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName);
4236         return GL_ENTRYPOINT(glXMakeContextCurrent)(dpy, draw, read, context);
4237     }
4238
4239     if (g_dump_gl_calls_flag)
4240     {
4241         vogl_log_printf("** glXMakeContextCurrent TID: 0x%" PRIX64 " dpy: 0x%" PRIX64 " draw: 0x%" PRIX64 " read: 0x%" PRIX64 " context: 0x%" PRIX64 "\n", vogl_get_current_kernel_thread_id(), cast_val_to_uint64(dpy), cast_val_to_uint64(draw), cast_val_to_uint64(read), cast_val_to_uint64(context));
4242     }
4243
4244     vogl_context *pCur_context = g_context_manager.get_current();
4245
4246     vogl_context *pNew_context = context ? g_context_manager.lookup_vogl_context(context) : NULL;
4247     if ((context) && (!pNew_context))
4248     {
4249         vogl_error_printf("%s: Unknown coontext handle 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(context));
4250     }
4251
4252     if (pCur_context)
4253     {
4254         if (pCur_context != pNew_context)
4255             pCur_context->on_release_current_prolog();
4256         else
4257             vogl_warning_printf("%s: Context 0x%" PRIX64 " is already current (redundant call)\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(context));
4258     }
4259
4260     uint64_t gl_begin_rdtsc = utils::RDTSC();
4261     Bool result = GL_ENTRYPOINT(glXMakeContextCurrent)(dpy, draw, read, context);
4262     uint64_t gl_end_rdtsc = utils::RDTSC();
4263
4264     if ((result) && (pCur_context != pNew_context))
4265     {
4266         if (pCur_context)
4267             g_context_manager.release_current();
4268
4269         if (context)
4270         {
4271             vogl_context *p = g_context_manager.make_current(context);
4272             VOGL_ASSERT(p == pNew_context);
4273             VOGL_NOTE_UNUSED(p);
4274
4275             pNew_context->set_display(dpy);
4276             pNew_context->set_drawable(draw);
4277             pNew_context->set_read_drawable(read);
4278         }
4279     }
4280
4281     if (g_dump_gl_calls_flag)
4282     {
4283         vogl_log_printf("** glXMakeCurrent result: %i\n", result);
4284     }
4285
4286     if (g_vogl_trace_writer.is_opened())
4287     {
4288         vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glXMakeContextCurrent, pCur_context);
4289         serializer.set_begin_rdtsc(begin_rdtsc);
4290         serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
4291         serializer.add_param(0, VOGL_CONST_DISPLAY_PTR, &dpy, sizeof(dpy));
4292         serializer.add_param(1, VOGL_GLXDRAWABLE, &draw, sizeof(draw));
4293         serializer.add_param(2, VOGL_GLXDRAWABLE, &read, sizeof(read));
4294         serializer.add_param(3, VOGL_GLXCONTEXT, &context, sizeof(context));
4295         serializer.add_return_param(VOGL_BOOL, &result, sizeof(result));
4296
4297         vogl_add_make_current_key_value_fields(dpy, draw, result, pNew_context, serializer);
4298
4299         serializer.end();
4300         vogl_write_packet_to_trace(serializer.get_packet());
4301     }
4302
4303     if (g_dump_gl_calls_flag)
4304     {
4305         vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
4306     }
4307
4308     return result;
4309 }
4310
4311 //----------------------------------------------------------------------------------------------------------------------
4312 static bool vogl_screen_capture_callback(uint width, uint height, uint pitch, size_t size, GLenum pixel_format, GLenum pixel_type, const void *pImage, void *pOpaque, uint64_t frame_index)
4313 {
4314     vogl_context *pContext = static_cast<vogl_context *>(pOpaque);
4315
4316     if ((!pContext) || (!width) || (!height))
4317     {
4318         VOGL_ASSERT_ALWAYS;
4319         return false;
4320     }
4321
4322     if ((pixel_format != GL_RGB) || (pixel_type != GL_UNSIGNED_BYTE) || (pitch != width * 3))
4323     {
4324         VOGL_ASSERT_ALWAYS;
4325         return false;
4326     }
4327
4328     if (g_command_line_params.get_value_as_bool("vogl_dump_png_screenshots"))
4329     {
4330         size_t png_size = 0;
4331         void *pPNG_data = tdefl_write_image_to_png_file_in_memory_ex(pImage, width, height, 3, &png_size, 1, true);
4332
4333         dynamic_string screenshot_filename(cVarArg, "%s__%08" PRIx64 "_%08" PRIu64 ".png", g_command_line_params.get_value_as_string("vogl_screenshot_prefix", 0, "screenshot").get_ptr(), cast_val_to_uint64(pContext->get_context_handle()), cast_val_to_uint64(frame_index));
4334         if (!file_utils::write_buf_to_file(screenshot_filename.get_ptr(), pPNG_data, png_size))
4335         {
4336             console::error("Failed writing PNG screenshot to file %s\n", screenshot_filename.get_ptr());
4337         }
4338
4339         mz_free(pPNG_data);
4340     }
4341     else if (g_command_line_params.get_value_as_bool("vogl_dump_jpeg_screenshots"))
4342     {
4343         int jpeg_quality = g_command_line_params.get_value_as_int("vogl_jpeg_quality", 0, 80, 1, 100);
4344
4345         long unsigned int jpeg_size = 0;
4346         unsigned char *pJPEG_data = NULL;
4347
4348         tjhandle _jpegCompressor = tjInitCompress();
4349
4350         int status = tjCompress2(_jpegCompressor, (unsigned char *)pImage, width, pitch, height, TJPF_RGB,
4351                                  &pJPEG_data, &jpeg_size, TJSAMP_422, jpeg_quality,
4352                                  TJFLAG_FASTDCT | TJFLAG_BOTTOMUP);
4353
4354         tjDestroy(_jpegCompressor);
4355
4356         if (status == 0)
4357         {
4358             dynamic_string screenshot_filename(cVarArg, "%s_%08" PRIx64 "_%08" PRIu64 ".jpg",
4359                 g_command_line_params.get_value_as_string("vogl_screenshot_prefix", 0, "screenshot").get_ptr(),
4360                 cast_val_to_uint64(pContext->get_context_handle()),
4361                 cast_val_to_uint64(frame_index));
4362             if (!file_utils::write_buf_to_file(screenshot_filename.get_ptr(), pJPEG_data, jpeg_size))
4363             {
4364                 console::error("Failed writing JPEG screenshot to file %s\n", screenshot_filename.get_ptr());
4365             }
4366         }
4367
4368         tjFree(pJPEG_data);
4369     }
4370
4371     if (g_command_line_params.get_value_as_bool("vogl_dump_backbuffer_hashes") || g_command_line_params.get_value_as_bool("vogl_hash_backbuffer"))
4372     {
4373         uint64_t backbuffer_crc64;
4374
4375         if (g_command_line_params.get_value_as_bool("vogl_sum_hashing"))
4376         {
4377             backbuffer_crc64 = calc_sum64(static_cast<const uint8 *>(pImage), size);
4378         }
4379         else
4380         {
4381             backbuffer_crc64 = calc_crc64(CRC64_INIT, static_cast<const uint8 *>(pImage), size);
4382         }
4383
4384         console::printf("Frame %" PRIu64 " hash: 0x%016" PRIX64 "\n", cast_val_to_uint64(frame_index), backbuffer_crc64);
4385
4386         dynamic_string backbuffer_hash_file;
4387         if (g_command_line_params.get_value_as_string(backbuffer_hash_file, "vogl_dump_backbuffer_hashes"))
4388         {
4389             FILE *pFile = vogl_fopen(backbuffer_hash_file.get_ptr(), "a");
4390             if (!pFile)
4391                 console::error("Failed writing to backbuffer hash file %s\n", backbuffer_hash_file.get_ptr());
4392             else
4393             {
4394                 vogl_fprintf(pFile, "0x%016" PRIX64 "\n", backbuffer_crc64);
4395                 vogl_fclose(pFile);
4396             }
4397         }
4398     }
4399     return true;
4400 }
4401
4402 //----------------------------------------------------------------------------------------------------------------------
4403 static void vogl_tick_screen_capture(vogl_context *pVOGL_context)
4404 {
4405     if (!pVOGL_context)
4406         return;
4407
4408     uint width = pVOGL_context->get_window_width();
4409     uint height = pVOGL_context->get_window_height();
4410     if ((!width) || (!height))
4411         return;
4412
4413     bool grab_backbuffer = g_command_line_params.get_value_as_bool("vogl_dump_backbuffer_hashes") || g_command_line_params.get_value_as_bool("vogl_hash_backbuffer") ||
4414                            g_command_line_params.get_value_as_bool("vogl_dump_jpeg_screenshots") || g_command_line_params.get_value_as_bool("vogl_dump_png_screenshots");
4415     if (!grab_backbuffer)
4416         return;
4417
4418     vogl_scoped_gl_error_absorber gl_error_absorber(pVOGL_context);
4419     VOGL_NOTE_UNUSED(gl_error_absorber);
4420
4421     if (!pVOGL_context->get_framebuffer_capturer().is_initialized())
4422     {
4423         if (!pVOGL_context->get_framebuffer_capturer().init(2, vogl_screen_capture_callback, pVOGL_context, GL_RGB, GL_UNSIGNED_BYTE))
4424         {
4425             vogl_error_printf("%s: Failed initializing context's vogl_framebuffer_capturer!\n", VOGL_FUNCTION_NAME);
4426             return;
4427         }
4428     }
4429
4430     if (!pVOGL_context->get_framebuffer_capturer().capture(width, height, 0, GL_BACK, pVOGL_context->get_frame_index()))
4431     {
4432         vogl_error_printf("%s: vogl_framebuffer_capturer::capture() failed!\n", VOGL_FUNCTION_NAME);
4433         return;
4434     }
4435 }
4436
4437 //----------------------------------------------------------------------------------------------------------------------
4438 static vogl_gl_state_snapshot *vogl_snapshot_state(const Display *dpy, GLXDrawable drawable, vogl_context *pCur_context)
4439 {
4440     VOGL_NOTE_UNUSED(dpy);
4441     VOGL_NOTE_UNUSED(drawable);
4442
4443     // pCur_context may be NULL!
4444
4445     if (!GL_ENTRYPOINT(glXGetCurrentContext) || !GL_ENTRYPOINT(glXGetCurrentDisplay) ||
4446         !GL_ENTRYPOINT(glXGetCurrentDrawable) || !GL_ENTRYPOINT(glXGetCurrentReadDrawable))
4447         return NULL;
4448
4449     timed_scope ts(VOGL_FUNCTION_NAME);
4450
4451     g_context_manager.lock();
4452
4453     if (vogl_check_gl_error())
4454         vogl_error_printf("%s: A GL error occured sometime before this function was called\n", VOGL_FUNCTION_NAME);
4455
4456     const Display *orig_dpy = GL_ENTRYPOINT(glXGetCurrentDisplay)();
4457     GLXDrawable orig_drawable = GL_ENTRYPOINT(glXGetCurrentDrawable)();
4458     GLXDrawable orig_read_drawable = GL_ENTRYPOINT(glXGetCurrentReadDrawable)();
4459     GLXContext orig_context = GL_ENTRYPOINT(glXGetCurrentContext)();
4460
4461     if (!orig_dpy)
4462         orig_dpy = dpy;
4463
4464     vogl_check_gl_error();
4465
4466     vogl_gl_state_snapshot *pSnapshot = vogl_new(vogl_gl_state_snapshot);
4467
4468     const glxcontext_map &contexts = g_context_manager.get_context_map();
4469
4470     // TODO: Find a better way of determining which window dimensions to use.
4471     // No context is current, let's just find the biggest window.
4472     uint win_width = 0;
4473     uint win_height = 0;
4474     if (pCur_context)
4475     {
4476         win_width = pCur_context->get_window_width();
4477         win_height = pCur_context->get_window_height();
4478     }
4479     else
4480     {
4481         glxcontext_map::const_iterator it;
4482         for (it = contexts.begin(); it != contexts.end(); ++it)
4483         {
4484             vogl_context *pVOGL_context = it->second;
4485             if ((pVOGL_context->get_window_width() > (int)win_width) || (pVOGL_context->get_window_height() > (int)win_height))
4486             {
4487                 win_width = pVOGL_context->get_window_width();
4488                 win_height = pVOGL_context->get_window_height();
4489             }
4490         }
4491     }
4492
4493     vogl_message_printf("%s: Beginning capture: width %u, height %u\n", VOGL_FUNCTION_NAME, win_width, win_height);
4494
4495     if (!pSnapshot->begin_capture(win_width, win_height, pCur_context ? (uint64_t)pCur_context->get_context_handle() : 0, 0, g_vogl_trace_writer.get_cur_gl_call_counter(), true))
4496     {
4497         vogl_error_printf("%s: Failed beginning capture\n", VOGL_FUNCTION_NAME);
4498
4499         vogl_delete(pSnapshot);
4500         pSnapshot = NULL;
4501
4502         g_context_manager.unlock();
4503
4504         return NULL;
4505     }
4506
4507     vogl_printf("%s: Capturing %u context(s)\n", VOGL_FUNCTION_NAME, contexts.size());
4508
4509     glxcontext_map::const_iterator it;
4510     for (it = contexts.begin(); it != contexts.end(); ++it)
4511     {
4512         GLXContext glx_context = it->first;
4513         vogl_context *pVOGL_context = it->second;
4514
4515         if (pVOGL_context->get_deleted_flag())
4516         {
4517             vogl_error_printf("%s: Context 0x%" PRIX64 " has been deleted but is the root of a sharelist group - this scenario is not yet supported for state snapshotting.\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(glx_context));
4518             break;
4519         }
4520
4521         if (pVOGL_context->get_has_been_made_current())
4522         {
4523             if (!GL_ENTRYPOINT(glXMakeCurrent)(pVOGL_context->get_display(), pVOGL_context->get_drawable(), glx_context))
4524             {
4525                 vogl_error_printf("%s: Failed switching to trace context 0x%" PRIX64 ". (This context may be current on another thread.) Capture failed!\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(glx_context));
4526                 break;
4527             }
4528
4529             if (pVOGL_context->get_total_mapped_buffers())
4530             {
4531                 vogl_error_printf("%s: Trace context 0x%" PRIX64 " has %u buffer(s) mapped across a call to glXSwapBuffers(), which is not currently supported!\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(glx_context), pVOGL_context->get_total_mapped_buffers());
4532                 break;
4533             }
4534
4535             if (pVOGL_context->is_composing_display_list())
4536             {
4537                 vogl_error_printf("%s: Trace context 0x%" PRIX64 " is currently composing a display list across a call to glXSwapBuffers()!\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(glx_context));
4538                 break;
4539             }
4540
4541             if (pVOGL_context->get_in_gl_begin())
4542             {
4543                 vogl_error_printf("%s: Trace context 0x%" PRIX64 " is currently in a glBegin() across a call to glXSwapBuffers(), which is not supported!\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(glx_context));
4544                 break;
4545             }
4546         }
4547
4548         vogl_capture_context_params &capture_context_params = pVOGL_context->get_capture_context_params();
4549
4550         if (!pSnapshot->capture_context(pVOGL_context->get_context_desc(), pVOGL_context->get_context_info(), pVOGL_context->get_handle_remapper(), capture_context_params))
4551         {
4552             vogl_error_printf("%s: Failed capturing trace context 0x%" PRIX64 ", capture failed\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(glx_context));
4553             break;
4554         }
4555     }
4556
4557     if ((it == contexts.end()) && (pSnapshot->end_capture()))
4558     {
4559         vogl_printf("%s: Capture succeeded\n", VOGL_FUNCTION_NAME);
4560     }
4561     else
4562     {
4563         vogl_printf("%s: Capture failed\n", VOGL_FUNCTION_NAME);
4564
4565         vogl_delete(pSnapshot);
4566         pSnapshot = NULL;
4567     }
4568
4569     if (orig_dpy)
4570     {
4571         GL_ENTRYPOINT(glXMakeContextCurrent)(orig_dpy, orig_drawable, orig_read_drawable, orig_context);
4572     }
4573
4574     vogl_check_gl_error();
4575
4576     g_context_manager.unlock();
4577
4578     return pSnapshot;
4579 }
4580
4581 //----------------------------------------------------------------------------------------------------------------------
4582 // vogl_end_capture
4583 // Important: This could be called at signal time!
4584 //----------------------------------------------------------------------------------------------------------------------
4585 static void vogl_end_capture(bool inside_signal_handler)
4586 {
4587     VOGL_FUNC_TRACER
4588
4589     VOGL_NOTE_UNUSED(inside_signal_handler);
4590
4591     vogl_debug_printf("%s\n", VOGL_FUNCTION_NAME);
4592
4593     g_context_manager.lock();
4594
4595     vogl_context *pVOGL_context = g_context_manager.get_current();
4596
4597     if (pVOGL_context)
4598     {
4599         pVOGL_context->get_framebuffer_capturer().flush();
4600
4601         if (inside_signal_handler)
4602         {
4603             vogl_thread_local_data *pTLS_data = vogl_get_thread_local_data();
4604             if ((pTLS_data) && (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID))
4605             {
4606                 vogl_error_printf("%s: Signal handler called while the tracer was calling OpenGL in func %s!\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName);
4607
4608                 if (g_vogl_trace_writer.is_opened())
4609                 {
4610                     vogl_entrypoint_serializer &trace_serializer = pTLS_data->m_serializer;
4611                     if (trace_serializer.is_in_begin())
4612                     {
4613                         vogl_error_printf("%s: Attempting to flush final trace packet\n", VOGL_FUNCTION_NAME);
4614
4615                         trace_serializer.end();
4616
4617                         vogl_write_packet_to_trace(trace_serializer.get_packet());
4618                     }
4619                 }
4620             }
4621         }
4622     }
4623
4624     g_context_manager.unlock();
4625
4626     scoped_mutex lock(g_vogl_trace_mutex);
4627
4628     if (g_vogl_trace_writer.is_opened())
4629     {
4630         dynamic_string filename(g_vogl_trace_writer.get_filename());
4631         
4632         vogl_flush_compilerinfo_to_trace_file();
4633         vogl_flush_machineinfo_to_trace_file();
4634         vogl_flush_backtrace_to_trace_file();
4635
4636         if (!g_vogl_trace_writer.close())
4637         {
4638             vogl_error_printf("%s: Failed closing trace file!\n", VOGL_FUNCTION_NAME);
4639
4640             if (g_vogl_pCapture_status_callback)
4641                 (*g_vogl_pCapture_status_callback)(NULL, g_vogl_pCapture_status_opaque);
4642         }
4643         else
4644         {
4645             if (g_vogl_pCapture_status_callback)
4646                 (*g_vogl_pCapture_status_callback)(filename.get_ptr(), g_vogl_pCapture_status_opaque);
4647         }
4648
4649         if (g_pJSON_node_pool)
4650         {
4651             uint64_t total_bytes_freed = static_cast<uint64_t>(g_pJSON_node_pool->free_unused_blocks());
4652             vogl_debug_printf("%s: Freed %" PRIu64 " bytes from the JSON object pool (%" PRIu64 " bytes remaining)\n", VOGL_FUNCTION_NAME, total_bytes_freed, static_cast<uint64_t>(g_pJSON_node_pool->get_total_heap_bytes()));
4653         }
4654     }
4655
4656     g_vogl_frames_remaining_to_capture = 0;
4657
4658     g_vogl_pCapture_status_callback = NULL;
4659     g_vogl_pCapture_status_opaque = NULL;
4660 }
4661
4662 //----------------------------------------------------------------------------------------------------------------------
4663 static bool vogl_write_snapshot_to_trace(const char *pTrace_filename, const Display *dpy, GLXDrawable drawable, vogl_context *pVOGL_context)
4664 {
4665     VOGL_FUNC_TRACER
4666     vogl_message_printf("%s: Snapshot begin\n", VOGL_FUNCTION_NAME);
4667
4668     // pVOGL_context may be NULL here!
4669
4670     vogl_unique_ptr<vogl_gl_state_snapshot> pSnapshot(vogl_snapshot_state(dpy, drawable, pVOGL_context));
4671     if (!pSnapshot.get())
4672     {
4673         vogl_error_printf("%s: Failed snapshotting GL/GLX state!\n", VOGL_FUNCTION_NAME);
4674
4675         VOGL_FUNC_TRACER
4676         vogl_end_capture();
4677         return false;
4678     }
4679
4680     pSnapshot->set_frame_index(0);
4681
4682     if (!g_vogl_trace_writer.open(pTrace_filename, NULL, true, false))
4683     {
4684         vogl_error_printf("%s: Failed creating trace file \"%s\"!\n", VOGL_FUNCTION_NAME, pTrace_filename);
4685
4686         VOGL_FUNC_TRACER
4687         vogl_end_capture();
4688         return false;
4689     }
4690
4691     vogl_archive_blob_manager &trace_archive = *g_vogl_trace_writer.get_trace_archive();
4692
4693     vogl_message_printf("%s: Serializing snapshot data to JSON document\n", VOGL_FUNCTION_NAME);
4694
4695     // TODO: This can take a lot of memory, probably better off to split the snapshot into separate smaller binary json or whatever files stored directly in the archive.
4696     json_document doc;
4697     if (!pSnapshot->serialize(*doc.get_root(), trace_archive, &g_vogl_process_gl_ctypes))
4698     {
4699         vogl_error_printf("%s: Failed serializing GL state snapshot!\n", VOGL_FUNCTION_NAME);
4700
4701         VOGL_FUNC_TRACER
4702         vogl_end_capture();
4703         return false;
4704     }
4705
4706     pSnapshot.reset();
4707
4708     vogl_message_printf("%s: Serializing JSON document to UBJ\n", VOGL_FUNCTION_NAME);
4709
4710     uint8_vec binary_snapshot_data;
4711     vogl::vector<char> snapshot_data;
4712
4713     // TODO: This can take a lot of memory
4714     doc.binary_serialize(binary_snapshot_data);
4715
4716     vogl_message_printf("%s: Compressing UBJ data and adding to trace archive\n", VOGL_FUNCTION_NAME);
4717
4718     dynamic_string binary_snapshot_id(trace_archive.add_buf_compute_unique_id(binary_snapshot_data.get_ptr(), binary_snapshot_data.size(), "binary_state_snapshot", VOGL_BINARY_JSON_EXTENSION));
4719     if (binary_snapshot_id.is_empty())
4720     {
4721         vogl_error_printf("%s: Failed adding binary GL snapshot file to output blob manager!\n", VOGL_FUNCTION_NAME);
4722
4723         VOGL_FUNC_TRACER
4724         vogl_end_capture();
4725         return false;
4726     }
4727
4728     binary_snapshot_data.clear();
4729
4730     snapshot_data.clear();
4731
4732 #if 0
4733         // TODO: This requires too much temp memory!
4734         doc.serialize(snapshot_data, true, 0, false);
4735
4736         dynamic_string snapshot_id(trace_archive.add_buf_compute_unique_id(snapshot_data.get_ptr(), snapshot_data.size(), "state_snapshot", VOGL_TEXT_JSON_EXTENSION));
4737         if (snapshot_id.is_empty())
4738         {
4739                 vogl_error_printf("%s: Failed adding binary GL snapshot file to output blob manager!\n", VOGL_FUNCTION_NAME);
4740                 g_vogl_trace_writer.deinit();
4741                 return false;
4742         }
4743 #endif
4744
4745     key_value_map snapshot_key_value_map;
4746     snapshot_key_value_map.insert("command_type", "state_snapshot");
4747     snapshot_key_value_map.insert("binary_id", binary_snapshot_id);
4748
4749 #if 0
4750         // TODO: This requires too much temp memory!
4751         snapshot_key_value_map.insert("id", snapshot_id);
4752 #endif
4753
4754     vogl_ctypes &trace_gl_ctypes = g_vogl_process_gl_ctypes;
4755     if (!vogl_write_glInternalTraceCommandRAD(g_vogl_trace_writer.get_stream(), &trace_gl_ctypes, cITCRKeyValueMap, sizeof(snapshot_key_value_map), reinterpret_cast<const GLubyte *>(&snapshot_key_value_map)))
4756     {
4757         VOGL_FUNC_TRACER
4758         vogl_end_capture();
4759         vogl_error_printf("%s: Failed writing to trace file!\n", VOGL_FUNCTION_NAME);
4760         return false;
4761     }
4762
4763     if (!vogl_write_glInternalTraceCommandRAD(g_vogl_trace_writer.get_stream(), &trace_gl_ctypes, cITCRDemarcation, 0, NULL))
4764     {
4765         VOGL_FUNC_TRACER
4766         vogl_end_capture();
4767         vogl_error_printf("%s: Failed writing to trace file!\n", VOGL_FUNCTION_NAME);
4768         return false;
4769     }
4770
4771     doc.clear(false);
4772
4773     if (g_pJSON_node_pool)
4774     {
4775         uint64_t total_bytes_freed = static_cast<uint64_t>(g_pJSON_node_pool->free_unused_blocks());
4776         vogl_debug_printf("%s: Freed %" PRIu64 " bytes from the JSON object pool (%" PRIu64 " bytes remaining)\n", VOGL_FUNCTION_NAME, total_bytes_freed, static_cast<uint64_t>(g_pJSON_node_pool->get_total_heap_bytes()));
4777     }
4778
4779     vogl_message_printf("%s: Snapshot complete\n", VOGL_FUNCTION_NAME);
4780
4781     return true;
4782 }
4783
4784 //----------------------------------------------------------------------------------------------------------------------
4785 static void vogl_capture_status_callback_func(const char *pFilename, void *pOpaque)
4786 {
4787     // only for testing
4788     VOGL_ASSERT(pOpaque == (void *)1);
4789     vogl_message_printf("%s: Filename \"%s\", opaque: %p\n", VOGL_FUNCTION_NAME, pFilename ? pFilename : "<null>", pOpaque);
4790 }
4791
4792 //----------------------------------------------------------------------------------------------------------------------
4793 static bool vogl_check_for_trigger_file(const char *pBase_name, dynamic_string &filename)
4794 {
4795     filename = pBase_name;
4796     if (!file_utils::does_file_exist(filename.get_ptr()))
4797     {
4798         dynamic_string path_to_check(g_command_line_params.get_value_as_string_or_empty("vogl_tracepath"));
4799         if (path_to_check.is_empty())
4800             path_to_check = file_utils::get_pathname(g_command_line_params.get_value_as_string_or_empty("vogl_tracefile").get_ptr());
4801
4802         if (path_to_check.is_empty())
4803             return false;
4804
4805         file_utils::combine_path(filename, path_to_check.get_ptr(), pBase_name);
4806         if (!file_utils::does_file_exist(filename.get_ptr()))
4807             return false;
4808     }
4809
4810     return true;
4811 }
4812
4813 //----------------------------------------------------------------------------------------------------------------------
4814 static void vogl_check_for_capture_stop_file()
4815 {
4816     if (!vogl_is_capturing())
4817         return;
4818
4819     dynamic_string stop_filename;
4820     if (!vogl_check_for_trigger_file(VOGL_STOP_CAPTURE_FILENAME, stop_filename))
4821         return;
4822
4823     file_utils::delete_file(stop_filename.get_ptr());
4824
4825     vogl_stop_capturing();
4826 }
4827
4828 //----------------------------------------------------------------------------------------------------------------------
4829 static void vogl_check_for_capture_trigger_file()
4830 {
4831     {
4832         scoped_mutex lock(g_vogl_trace_mutex);
4833         if ((g_vogl_frames_remaining_to_capture) || (g_vogl_trace_writer.is_opened()))
4834             return;
4835     }
4836
4837     dynamic_string trigger_filename;
4838     if (!vogl_check_for_trigger_file(VOGL_TRIGGER_CAPTURE_FILENAME, trigger_filename))
4839         return;
4840
4841     vogl_sleep(100);
4842
4843     // Lamely try to protected against racing - a better method is probably inotify: http://www.thegeekstuff.com/2010/04/inotify-c-program-example/
4844     for (;;)
4845     {
4846         uint64_t size;
4847         file_utils::get_file_size(trigger_filename.get_ptr(), size);
4848
4849         vogl_sleep(100);
4850
4851         uint64_t size1;
4852         file_utils::get_file_size(trigger_filename.get_ptr(), size1);
4853
4854         if (size == size1)
4855             break;
4856
4857         vogl_sleep(250);
4858     }
4859
4860     uint total_frames = 1;
4861     dynamic_string path;
4862     dynamic_string base_name;
4863
4864     dynamic_string_array lines;
4865     if (!file_utils::read_text_file(trigger_filename.get_ptr(), lines, file_utils::cRTFTrim | file_utils::cRTFIgnoreEmptyLines))
4866     {
4867         vogl_error_printf("%s: Failed reading from trigger file \"%s\", using default parameters to trigger a capture.\n", VOGL_FUNCTION_NAME, trigger_filename.get_ptr());
4868         lines.clear();
4869     }
4870
4871     if (lines.size() >= 1)
4872     {
4873         if (lines[0] == "all")
4874             total_frames = cUINT32_MAX;
4875         else
4876             total_frames = string_to_uint(lines[0].get_ptr(), 1);
4877
4878         if (lines.size() >= 2)
4879         {
4880             path = lines[1];
4881
4882             if (lines.size() >= 3)
4883                 base_name = lines[2];
4884         }
4885     }
4886
4887     file_utils::delete_file(trigger_filename.get_ptr());
4888
4889     bool success = vogl_capture_on_next_swap(total_frames, path.get_ptr(), base_name.get_ptr(), vogl_capture_status_callback_func, (void *)1);
4890
4891     if (!success)
4892         vogl_error_printf("%s: Failed enabling capture mode\n", VOGL_FUNCTION_NAME);
4893     else
4894         vogl_message_printf("%s: Successfully enabled capture mode, will capture up to %u frame(s), override path \"%s\", override base_name \"%s\"\n", VOGL_FUNCTION_NAME, total_frames, path.get_ptr(), base_name.get_ptr());
4895 }
4896
4897 //----------------------------------------------------------------------------------------------------------------------
4898 //  vogl_tick_capture
4899 //----------------------------------------------------------------------------------------------------------------------
4900 static void vogl_tick_capture(const Display *dpy, GLXDrawable drawable, vogl_context *pVOGL_context)
4901 {
4902     VOGL_FUNC_TRACER
4903
4904     // pVOGL_context may be NULL here!
4905
4906     vogl_check_for_capture_stop_file();
4907     vogl_check_for_capture_trigger_file();
4908
4909     scoped_mutex lock(g_vogl_trace_mutex);
4910
4911     if ((g_vogl_total_frames_to_capture) && (!g_vogl_frames_remaining_to_capture))
4912     {
4913         g_vogl_frames_remaining_to_capture = g_vogl_total_frames_to_capture;
4914         g_vogl_total_frames_to_capture = 0;
4915     }
4916
4917     if (g_vogl_stop_capturing)
4918     {
4919         g_vogl_stop_capturing = false;
4920
4921         if (g_vogl_trace_writer.is_opened())
4922         {
4923             VOGL_FUNC_TRACER
4924             vogl_end_capture();
4925             return;
4926         }
4927     }
4928
4929     if (!g_vogl_frames_remaining_to_capture)
4930         return;
4931
4932     if (!g_vogl_trace_writer.is_opened())
4933     {
4934         dynamic_string trace_path(g_command_line_params.get_value_as_string_or_empty("vogl_tracepath"));
4935         if (trace_path.is_empty())
4936             trace_path = "/tmp";
4937         if (!g_vogl_capture_path.is_empty())
4938             trace_path = g_vogl_capture_path;
4939
4940         time_t t = time(NULL);
4941         struct tm ltm = *localtime(&t);
4942
4943         dynamic_string trace_basename("capture");
4944         if (!g_vogl_capture_basename.is_empty())
4945             trace_basename = g_vogl_capture_basename;
4946
4947         dynamic_string filename(cVarArg, "%s_%04d_%02d_%02d_%02d_%02d_%02d.bin", trace_basename.get_ptr(), ltm.tm_year + 1900, ltm.tm_mon + 1, ltm.tm_mday, ltm.tm_hour, ltm.tm_min, ltm.tm_sec);
4948
4949         dynamic_string full_trace_filename;
4950         file_utils::combine_path(full_trace_filename, trace_path.get_ptr(), filename.get_ptr());
4951
4952         if (g_vogl_frames_remaining_to_capture == cUINT32_MAX)
4953             vogl_message_printf("%s: Initiating capture of all remaining frames to file \"%s\"\n", VOGL_FUNCTION_NAME, full_trace_filename.get_ptr());
4954         else
4955             vogl_message_printf("%s: Initiating capture of up to %u frame(s) to file \"%s\"\n", VOGL_FUNCTION_NAME, g_vogl_frames_remaining_to_capture, full_trace_filename.get_ptr());
4956
4957         if (!vogl_write_snapshot_to_trace(full_trace_filename.get_ptr(), dpy, drawable, pVOGL_context))
4958         {
4959             file_utils::delete_file(full_trace_filename.get_ptr());
4960             vogl_error_printf("%s: Failed creating GL state snapshot, closing and deleting trace file\n", VOGL_FUNCTION_NAME);
4961         }
4962     }
4963     else
4964     {
4965         if (g_vogl_frames_remaining_to_capture != cUINT32_MAX)
4966             g_vogl_frames_remaining_to_capture--;
4967
4968         // See if we should stop capturing.
4969         if (!g_vogl_frames_remaining_to_capture)
4970         {
4971             VOGL_FUNC_TRACER
4972             vogl_end_capture();
4973         }
4974     }
4975 }
4976
4977 //----------------------------------------------------------------------------------------------------------------------
4978 //  vogl_glXSwapBuffersGLFuncProlog
4979 //----------------------------------------------------------------------------------------------------------------------
4980 static inline void vogl_glXSwapBuffersGLFuncProlog(const Display *dpy, GLXDrawable drawable, vogl_context *pVOGL_context, vogl_entrypoint_serializer &trace_serializer)
4981 {
4982     // pVOGL_context may be NULL here!
4983
4984     if (!GL_ENTRYPOINT(glXGetCurrentContext) || !GL_ENTRYPOINT(glXGetCurrentDisplay) ||
4985         !GL_ENTRYPOINT(glXGetCurrentDrawable) || !GL_ENTRYPOINT(glXGetCurrentReadDrawable))
4986     {
4987         return;
4988     }
4989
4990     bool override_current_context = false;
4991
4992     if ((!pVOGL_context) || ((pVOGL_context->get_display() != dpy) || (pVOGL_context->get_drawable() != drawable)))
4993     {
4994         // NVidia/AMD closed source don't seem to care if a context is current when glXSwapBuffer()'s is called. But Mesa doesn't like it.
4995         vogl_warning_printf_once("%s: No context is current, or the current context's display/drawable don't match the provided display/drawable. Will try to find the first context which matches the provided params, but this may not work reliably.\n", VOGL_FUNCTION_NAME);
4996
4997         pVOGL_context = g_context_manager.find_context(dpy, drawable);
4998
4999         if (!pVOGL_context)
5000         {
5001             vogl_error_printf("%s: Unable to determine which GL context is associated with the indicated drawable/display! Will not be able to take a screen capture, or record context related information to the trace!\n", VOGL_FUNCTION_NAME);
5002             return;
5003         }
5004         else if (pVOGL_context->get_current_thread() != 0)
5005         {
5006             vogl_error_printf("%s: The GL context which matches the provided display/drawable is already current on another thread!\n", VOGL_FUNCTION_NAME);
5007             return;
5008         }
5009
5010         override_current_context = true;
5011     }
5012
5013     GLXContext orig_context = 0;
5014     const Display *orig_dpy = NULL;
5015     GLXDrawable orig_drawable = 0;
5016     GLXDrawable orig_read_drawable = 0;
5017     if (override_current_context)
5018     {
5019         orig_context = GL_ENTRYPOINT(glXGetCurrentContext)();
5020         orig_dpy = GL_ENTRYPOINT(glXGetCurrentDisplay)();
5021         orig_drawable = GL_ENTRYPOINT(glXGetCurrentDrawable)();
5022         orig_read_drawable = GL_ENTRYPOINT(glXGetCurrentReadDrawable)();
5023
5024         if (!orig_dpy)
5025             orig_dpy = dpy;
5026
5027         GL_ENTRYPOINT(glXMakeCurrent)(pVOGL_context->get_display(), pVOGL_context->get_drawable(), pVOGL_context->get_context_handle());
5028     }
5029
5030     Window root = 0;
5031     int x = 0, y = 0;
5032     unsigned int width = 0, height = 0, border_width = 0, depth = 0;
5033     if ((dpy) && (XGetGeometry(const_cast<Display *>(dpy), drawable, &root, &x, &y, &width, &height, &border_width, &depth) != False))
5034     {
5035         pVOGL_context->set_window_dimensions(width, height);
5036
5037         vogl_tick_screen_capture(pVOGL_context);
5038     }
5039     else
5040     {
5041         console::warning("%s: XGetGeometry() call failed!\n", VOGL_FUNCTION_NAME);
5042     }
5043
5044     if (trace_serializer.is_in_begin())
5045     {
5046         trace_serializer.add_key_value(string_hash("win_width"), pVOGL_context->get_window_width());
5047         trace_serializer.add_key_value(string_hash("win_height"), pVOGL_context->get_window_height());
5048     }
5049
5050     if (g_dump_gl_calls_flag)
5051     {
5052         vogl_log_printf("** Current window dimensions: %ix%i\n", pVOGL_context->get_window_width(), pVOGL_context->get_window_height());
5053     }
5054
5055     pVOGL_context->inc_frame_index();
5056
5057     if ((override_current_context) && (orig_dpy))
5058     {
5059         GL_ENTRYPOINT(glXMakeContextCurrent)(orig_dpy, orig_drawable, orig_read_drawable, orig_context);
5060     }
5061 }
5062
5063 //----------------------------------------------------------------------------------------------------------------------
5064 #define DEF_FUNCTION_CUSTOM_HANDLER_glXSwapBuffers(exported, category, ret, ret_type_enum, num_params, name, args, params)
5065 static void vogl_glXSwapBuffers(const Display *dpy, GLXDrawable drawable)
5066 {
5067     uint64_t begin_rdtsc = utils::RDTSC();
5068
5069     if (g_dump_gl_calls_flag)
5070     {
5071         vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5072     }
5073
5074     vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXSwapBuffers);
5075     if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
5076     {
5077         vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName);
5078         return GL_ENTRYPOINT(glXSwapBuffers)(dpy, drawable);
5079     }
5080
5081     // Use a local serializer because the call to glXSwapBuffer()'s will make GL calls if something like the Steam Overlay is active.
5082     vogl_entrypoint_serializer serializer;
5083
5084     if (g_vogl_trace_writer.is_opened())
5085     {
5086         serializer.begin(VOGL_ENTRYPOINT_glXSwapBuffers, g_context_manager.get_current());
5087         serializer.add_param(0, VOGL_CONST_DISPLAY_PTR, &dpy, sizeof(dpy));
5088         serializer.add_param(1, VOGL_GLXDRAWABLE, &drawable, sizeof(drawable));
5089     }
5090
5091     vogl_glXSwapBuffersGLFuncProlog(dpy, drawable, pTLS_data->m_pContext, serializer);
5092
5093     uint64_t gl_begin_rdtsc = utils::RDTSC();
5094
5095     // Call the driver directly, bypassing our GL/GLX wrappers which set m_calling_driver_entrypoint_id. The Steam Overlay may call us back!
5096     DIRECT_GL_ENTRYPOINT(glXSwapBuffers)(dpy, drawable);
5097
5098     uint64_t gl_end_rdtsc = utils::RDTSC();
5099
5100     if (g_vogl_trace_writer.is_opened())
5101     {
5102         serializer.set_begin_rdtsc(begin_rdtsc);
5103         serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
5104         serializer.end();
5105         vogl_write_packet_to_trace(serializer.get_packet());
5106     }
5107
5108     vogl_tick_capture(dpy, drawable, pTLS_data->m_pContext);
5109
5110     if (g_dump_gl_calls_flag)
5111     {
5112         vogl_log_printf("** glXSwapBuffers TID: 0x%" PRIX64 " Display: 0x%" PRIX64 " drawable: 0x%" PRIX64 "\n", vogl_get_current_kernel_thread_id(), cast_val_to_uint64(dpy), cast_val_to_uint64(drawable));
5113     }
5114
5115     if (g_dump_gl_calls_flag)
5116     {
5117         vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5118     }
5119
5120     if (g_command_line_params.has_key("vogl_exit_after_x_frames") && (pTLS_data->m_pContext))
5121     {
5122         uint64_t max_num_frames = g_command_line_params.get_value_as_uint64("vogl_exit_after_x_frames");
5123         uint64_t cur_num_frames = pTLS_data->m_pContext->get_frame_index();
5124
5125         if (cur_num_frames >= max_num_frames)
5126         {
5127             vogl_message_printf("Number of frames specified by --vogl_exit_after_x_frames param reached, forcing trace to close and calling exit()\n");
5128
5129             vogl_end_capture();
5130
5131             // Exit the app
5132             exit(0);
5133         }
5134     }
5135 }
5136
5137 //----------------------------------------------------------------------------------------------------------------------
5138 #define DEF_FUNCTION_CUSTOM_HANDLER_glXCreateContextAttribsARB(exported, category, ret, ret_type_enum, num_params, name, args, params)
5139 static GLXContext vogl_glXCreateContextAttribsARB(const Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list)
5140 {
5141     uint64_t begin_rdtsc = utils::RDTSC();
5142
5143     if (g_dump_gl_calls_flag)
5144     {
5145         vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5146     }
5147
5148     vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXCreateContextAttribsARB);
5149     if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
5150     {
5151         vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName);
5152         return GL_ENTRYPOINT(glXCreateContextAttribsARB)(dpy, config, share_context, direct, attrib_list);
5153     }
5154
5155     vogl_context_attribs context_attribs;
5156
5157     if (g_command_line_params.get_value_as_bool("vogl_force_debug_context"))
5158     {
5159         vogl_warning_printf("%s: Forcing debug context\n", VOGL_FUNCTION_NAME);
5160
5161         context_attribs.init(attrib_list);
5162         if (!context_attribs.has_key(GLX_CONTEXT_FLAGS_ARB))
5163             context_attribs.add_key(GLX_CONTEXT_FLAGS_ARB, 0);
5164
5165         int context_flags_value_ofs = context_attribs.find_value_ofs(GLX_CONTEXT_FLAGS_ARB);
5166         VOGL_ASSERT(context_flags_value_ofs >= 0);
5167         if (context_flags_value_ofs >= 0)
5168             context_attribs[context_flags_value_ofs] |= GLX_CONTEXT_DEBUG_BIT_ARB;
5169
5170         int context_major_version_ofs = context_attribs.find_value_ofs(GLX_CONTEXT_MAJOR_VERSION_ARB);
5171         int context_minor_version_ofs = context_attribs.find_value_ofs(GLX_CONTEXT_MINOR_VERSION_ARB);
5172
5173         if (context_major_version_ofs < 0)
5174         {
5175             // Don't slam up if they haven't requested a specific GL version, the driver will give us the most recent version that is backwards compatible with 1.0 (i.e. 4.3 for NVidia's current dirver).
5176         }
5177         else if (context_attribs[context_major_version_ofs] < 3)
5178         {
5179             context_attribs[context_major_version_ofs] = 3;
5180
5181             if (context_minor_version_ofs < 0)
5182                 context_attribs.add_key(GLX_CONTEXT_MINOR_VERSION_ARB, 0);
5183             else
5184                 context_attribs[context_minor_version_ofs] = 0;
5185
5186             vogl_warning_printf("%s: Forcing GL context version up to v3.0 due to debug context usage\n", VOGL_FUNCTION_NAME);
5187         }
5188
5189         attrib_list = context_attribs.get_vec().get_ptr();
5190     }
5191
5192     uint64_t gl_begin_rdtsc = utils::RDTSC();
5193     GLXContext result = GL_ENTRYPOINT(glXCreateContextAttribsARB)(dpy, config, share_context, direct, attrib_list);
5194     uint64_t gl_end_rdtsc = utils::RDTSC();
5195
5196     if (g_dump_gl_calls_flag)
5197     {
5198         vogl_log_printf("** glXCreateContextAttribsARB TID: 0x%" PRIX64 " Display: 0x%" PRIX64 " config: 0x%" PRIX64 " share_context: 0x%" PRIX64 " direct %i attrib_list: 0x%" PRIX64 ", result: 0x%" PRIX64 "\n", vogl_get_current_kernel_thread_id(), cast_val_to_uint64(dpy), cast_val_to_uint64(config), cast_val_to_uint64(share_context), (int)direct, cast_val_to_uint64(attrib_list), cast_val_to_uint64(result));
5199     }
5200
5201     if (g_vogl_trace_writer.is_opened())
5202     {
5203         vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glXCreateContextAttribsARB, g_context_manager.get_current());
5204         serializer.set_begin_rdtsc(begin_rdtsc);
5205         serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
5206         serializer.add_param(0, VOGL_CONST_DISPLAY_PTR, &dpy, sizeof(dpy));
5207         serializer.add_param(1, VOGL_GLXFBCONFIG, &config, sizeof(config));
5208         serializer.add_param(2, VOGL_GLXCONTEXT, &share_context, sizeof(share_context));
5209         serializer.add_param(3, VOGL_BOOL, &direct, sizeof(direct));
5210         serializer.add_param(4, VOGL_CONST_INT_PTR, &attrib_list, sizeof(attrib_list));
5211         if (attrib_list)
5212         {
5213             uint n = vogl_determine_attrib_list_array_size(attrib_list);
5214             serializer.add_array_client_memory(4, VOGL_INT, n, attrib_list, sizeof(int) * n);
5215         }
5216         serializer.add_return_param(VOGL_GLXCONTEXT, &result, sizeof(result));
5217         serializer.end();
5218         vogl_write_packet_to_trace(serializer.get_packet());
5219     }
5220
5221     if (result)
5222     {
5223         if (share_context)
5224         {
5225             if (!g_app_uses_sharelists)
5226                 vogl_message_printf("%s: sharelist usage detected\n", VOGL_FUNCTION_NAME);
5227
5228             g_app_uses_sharelists = true;
5229         }
5230
5231         g_context_manager.lock();
5232
5233         vogl_context *pVOGL_context = g_context_manager.create_context(result);
5234         pVOGL_context->set_display(dpy);
5235         pVOGL_context->set_fb_config(config);
5236         pVOGL_context->set_sharelist_handle(share_context);
5237         pVOGL_context->set_direct(direct);
5238         pVOGL_context->set_attrib_list(attrib_list);
5239         pVOGL_context->set_created_from_attribs(true);
5240         pVOGL_context->set_creation_func(VOGL_ENTRYPOINT_glXCreateContextAttribsARB);
5241
5242         if (share_context)
5243         {
5244             vogl_context *pShare_context = g_context_manager.lookup_vogl_context(share_context);
5245
5246             if (!pShare_context)
5247                 vogl_error_printf("%s: Failed finding share context 0x%" PRIx64 " in context manager's hashmap! This handle is probably invalid.\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(share_context));
5248             else
5249             {
5250                 while (!pShare_context->is_root_context())
5251                     pShare_context = pShare_context->get_shared_state();
5252
5253                 pVOGL_context->set_shared_context(pShare_context);
5254
5255                 pShare_context->add_ref();
5256             }
5257         }
5258
5259         pVOGL_context->init();
5260
5261         g_context_manager.unlock();
5262     }
5263
5264     if (g_dump_gl_calls_flag)
5265     {
5266         vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5267     }
5268
5269     return result;
5270 }
5271
5272 //----------------------------------------------------------------------------------------------------------------------
5273 // vogl_get_fb_config_from_xvisual_info
5274 // Attempts to find the GLXFBConfig corresponding to a particular visual.
5275 // TODO: Test this more!
5276 //----------------------------------------------------------------------------------------------------------------------
5277 static GLXFBConfig *vogl_get_fb_config_from_xvisual_info(const Display *dpy, const XVisualInfo *vis)
5278 {
5279     vogl_context_attribs attribs;
5280
5281 #define GET_CONFIG(attrib)                                   \
5282     do                                                       \
5283     {                                                        \
5284         int val = 0;                                         \
5285         GL_ENTRYPOINT(glXGetConfig)(dpy, vis, attrib, &val); \
5286         if (val)                                             \
5287             attribs.add_key(attrib, val);                    \
5288     } while (0)
5289
5290     int is_rgba = 0;
5291     GL_ENTRYPOINT(glXGetConfig)(dpy, vis, GLX_RGBA, &is_rgba);
5292
5293     attribs.add_key(GLX_RENDER_TYPE, is_rgba ? GLX_RGBA_BIT : GLX_COLOR_INDEX_BIT);
5294     attribs.add_key(GLX_X_RENDERABLE, True);
5295     attribs.add_key(GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT);
5296
5297     if (!is_rgba)
5298         GET_CONFIG(GLX_BUFFER_SIZE);
5299
5300     GET_CONFIG(GLX_LEVEL);
5301
5302     GET_CONFIG(GLX_DOUBLEBUFFER);
5303     GET_CONFIG(GLX_STEREO);
5304     GET_CONFIG(GLX_AUX_BUFFERS);
5305     if (is_rgba)
5306     {
5307         GET_CONFIG(GLX_RED_SIZE);
5308         GET_CONFIG(GLX_GREEN_SIZE);
5309         GET_CONFIG(GLX_BLUE_SIZE);
5310         GET_CONFIG(GLX_ALPHA_SIZE);
5311     }
5312     GET_CONFIG(GLX_DEPTH_SIZE);
5313     GET_CONFIG(GLX_STENCIL_SIZE);
5314
5315     GET_CONFIG(GLX_TRANSPARENT_INDEX_VALUE);
5316     GET_CONFIG(GLX_TRANSPARENT_RED_VALUE);
5317     GET_CONFIG(GLX_TRANSPARENT_GREEN_VALUE);
5318     GET_CONFIG(GLX_TRANSPARENT_BLUE_VALUE);
5319     GET_CONFIG(GLX_TRANSPARENT_ALPHA_VALUE);
5320
5321     if (attribs.get_value_or_default(GLX_TRANSPARENT_INDEX_VALUE) || attribs.get_value_or_default(GLX_TRANSPARENT_RED_VALUE) ||
5322         attribs.get_value_or_default(GLX_TRANSPARENT_GREEN_VALUE) || attribs.get_value_or_default(GLX_TRANSPARENT_BLUE_VALUE) ||
5323         attribs.get_value_or_default(GLX_TRANSPARENT_ALPHA_VALUE))
5324     {
5325         GET_CONFIG(GLX_TRANSPARENT_TYPE);
5326     }
5327 #undef GET_CONFIG
5328
5329 #if 0
5330         for (uint i = 0; i < attribs.size(); i += 2)
5331         {
5332                 if (!attribs[i])
5333                         break;
5334                 printf("%s 0x%x\n", g_gl_enums.find_glx_name(attribs[i]), attribs[i + 1]);
5335         }
5336 #endif
5337
5338     int num_configs = 0;
5339     GLXFBConfig *pConfigs = GL_ENTRYPOINT(glXChooseFBConfig)(dpy, vis->screen, attribs.get_ptr(), &num_configs);
5340     return num_configs ? pConfigs : NULL;
5341 }
5342
5343 //----------------------------------------------------------------------------------------------------------------------
5344 #define DEF_FUNCTION_CUSTOM_HANDLER_glXCreateContext(exported, category, ret, ret_type_enum, num_params, name, args, params)
5345 static GLXContext vogl_glXCreateContext(const Display *dpy, const XVisualInfo *vis, GLXContext shareList, Bool direct)
5346 {
5347     uint64_t begin_rdtsc = utils::RDTSC();
5348
5349     if (g_dump_gl_calls_flag)
5350     {
5351         vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5352     }
5353
5354     vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXCreateContext);
5355     if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
5356     {
5357         vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName);
5358         return GL_ENTRYPOINT(glXCreateContext)(dpy, vis, shareList, direct);
5359     }
5360
5361     if (g_command_line_params.get_value_as_bool("vogl_force_debug_context"))
5362     {
5363         vogl_warning_printf("%s: Can't enable debug contexts via glXCreateContext(), forcing call to use glXCreateContextsAttribsARB() instead\n", VOGL_FUNCTION_NAME);
5364
5365         GLXFBConfig *pConfig = vogl_get_fb_config_from_xvisual_info(dpy, vis);
5366         if (!pConfig)
5367         {
5368             vogl_error_printf("%s: Can't enable debug contexts: Unable to find the FB config that matches the passed in XVisualInfo!\n", VOGL_FUNCTION_NAME);
5369         }
5370         else
5371         {
5372             int empty_attrib_list[1] = { 0 };
5373             return vogl_glXCreateContextAttribsARB(dpy, pConfig[0], shareList, direct, empty_attrib_list);
5374         }
5375     }
5376
5377     uint64_t gl_begin_rdtsc = utils::RDTSC();
5378     GLXContext result = GL_ENTRYPOINT(glXCreateContext)(dpy, vis, shareList, direct);
5379     uint64_t gl_end_rdtsc = utils::RDTSC();
5380
5381     if (g_dump_gl_calls_flag)
5382     {
5383         vogl_log_printf("** glXCreateContext TID: 0x%" PRIX64 " dpy: 0x%" PRIX64 " vis: 0x%" PRIX64 " shareList: 0x%" PRIX64 " direct %i, result: 0x%" PRIX64 "\n", vogl_get_current_kernel_thread_id(), cast_val_to_uint64(dpy), cast_val_to_uint64(vis), cast_val_to_uint64(shareList), (int)direct, cast_val_to_uint64(result));
5384     }
5385
5386     if (g_vogl_trace_writer.is_opened())
5387     {
5388         vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glXCreateContext, g_context_manager.get_current());
5389         serializer.set_begin_rdtsc(begin_rdtsc);
5390         serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
5391         serializer.add_param(0, VOGL_CONST_DISPLAY_PTR, &dpy, sizeof(dpy));
5392         serializer.add_param(1, VOGL_CONST_XVISUALINFO_PTR, &vis, sizeof(vis));
5393         serializer.add_param(2, VOGL_GLXCONTEXT, &shareList, sizeof(shareList));
5394         serializer.add_param(3, VOGL_BOOL, &direct, sizeof(direct));
5395         serializer.add_return_param(VOGL_GLXCONTEXT, &result, sizeof(result));
5396         if (vis)
5397             serializer.add_ref_client_memory(1, VOGL_XVISUALINFO, vis, sizeof(XVisualInfo));
5398         serializer.end();
5399         vogl_write_packet_to_trace(serializer.get_packet());
5400     }
5401
5402     if (result)
5403     {
5404         if (shareList)
5405         {
5406             if (!g_app_uses_sharelists)
5407                 vogl_message_printf("%s: sharelist usage detected\n", VOGL_FUNCTION_NAME);
5408
5409             g_app_uses_sharelists = true;
5410         }
5411
5412         g_context_manager.lock();
5413
5414         vogl_context *pVOGL_context = g_context_manager.create_context(result);
5415         pVOGL_context->set_display(dpy);
5416         pVOGL_context->set_xvisual_info(vis);
5417         pVOGL_context->set_sharelist_handle(shareList);
5418         pVOGL_context->set_direct(direct);
5419         pVOGL_context->set_creation_func(VOGL_ENTRYPOINT_glXCreateContext);
5420
5421         if (shareList)
5422         {
5423             vogl_context *pShare_context = g_context_manager.lookup_vogl_context(shareList);
5424
5425             if (!pShare_context)
5426                 vogl_error_printf("%s: Failed finding share context 0x%" PRIx64 " in context manager's hashmap! This handle is probably invalid.\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(shareList));
5427             else
5428             {
5429                 while (!pShare_context->is_root_context())
5430                     pShare_context = pShare_context->get_shared_state();
5431
5432                 pVOGL_context->set_shared_context(pShare_context);
5433
5434                 pShare_context->add_ref();
5435             }
5436         }
5437
5438         pVOGL_context->init();
5439
5440         g_context_manager.unlock();
5441     }
5442
5443     if (g_dump_gl_calls_flag)
5444     {
5445         vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5446     }
5447
5448     return result;
5449 }
5450
5451 //----------------------------------------------------------------------------------------------------------------------
5452 #define DEF_FUNCTION_CUSTOM_HANDLER_glXCreateNewContext(exported, category, ret, ret_type_enum, num_params, name, args, params)
5453 static GLXContext vogl_glXCreateNewContext(const Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct)
5454 {
5455     if (render_type != GLX_RGBA_TYPE)
5456     {
5457         vogl_error_printf("%s: Unsupported render type (%s)!\n", VOGL_FUNCTION_NAME, g_gl_enums.find_glx_name(render_type));
5458     }
5459
5460     if (g_command_line_params.get_value_as_bool("vogl_force_debug_context"))
5461     {
5462         vogl_warning_printf("%s: Redirecting call from glxCreateNewContext() to glxCreateContextAttribsARB because --vogl_force_debug_context was specified. Note this may fail if glXCreateWindow() was called.\n", VOGL_FUNCTION_NAME);
5463
5464         return vogl_glXCreateContextAttribsARB(dpy, config, share_list, direct, NULL);
5465     }
5466
5467     uint64_t begin_rdtsc = utils::RDTSC();
5468
5469     if (g_dump_gl_calls_flag)
5470     {
5471         vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5472     }
5473
5474     vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXCreateNewContext);
5475     if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
5476     {
5477         vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName);
5478         return GL_ENTRYPOINT(glXCreateNewContext)(dpy, config, render_type, share_list, direct);
5479     }
5480
5481     uint64_t gl_begin_rdtsc = utils::RDTSC();
5482     GLXContext result = GL_ENTRYPOINT(glXCreateNewContext)(dpy, config, render_type, share_list, direct);
5483     uint64_t gl_end_rdtsc = utils::RDTSC();
5484
5485     if (g_dump_gl_calls_flag)
5486     {
5487         vogl_log_printf("** glXCreateNewContext TID: 0x%" PRIX64 " dpy: 0x%" PRIX64 " config: 0x%" PRIX64 " render_type: %i shareList: 0x%" PRIX64 " direct %i, result: 0x%" PRIX64 "\n",
5488                        vogl_get_current_kernel_thread_id(), cast_val_to_uint64(dpy), cast_val_to_uint64(config), render_type, cast_val_to_uint64(share_list), static_cast<int>(direct), cast_val_to_uint64(result));
5489     }
5490
5491     if (g_vogl_trace_writer.is_opened())
5492     {
5493         vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glXCreateNewContext, g_context_manager.get_current());
5494         serializer.set_begin_rdtsc(begin_rdtsc);
5495         serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
5496         serializer.add_param(0, VOGL_CONST_DISPLAY_PTR, &dpy, sizeof(dpy));
5497         serializer.add_param(1, VOGL_GLXFBCONFIG, &config, sizeof(config));
5498         serializer.add_param(2, VOGL_INT, &render_type, sizeof(render_type));
5499         serializer.add_param(3, VOGL_GLXCONTEXT, &share_list, sizeof(share_list));
5500         serializer.add_param(4, VOGL_BOOL, &direct, sizeof(direct));
5501         serializer.add_return_param(VOGL_GLXCONTEXT, &result, sizeof(result));
5502         serializer.end();
5503         vogl_write_packet_to_trace(serializer.get_packet());
5504     }
5505
5506     if (result)
5507     {
5508         if (share_list)
5509         {
5510             if (!g_app_uses_sharelists)
5511                 vogl_message_printf("%s: sharelist usage detected\n", VOGL_FUNCTION_NAME);
5512
5513             g_app_uses_sharelists = true;
5514         }
5515
5516         g_context_manager.lock();
5517
5518         vogl_context *pVOGL_context = g_context_manager.create_context(result);
5519         pVOGL_context->set_display(dpy);
5520         pVOGL_context->set_fb_config(config);
5521         pVOGL_context->set_sharelist_handle(share_list);
5522         pVOGL_context->set_direct(direct);
5523         pVOGL_context->set_creation_func(VOGL_ENTRYPOINT_glXCreateNewContext);
5524
5525         if (share_list)
5526         {
5527             vogl_context *pShare_context = g_context_manager.lookup_vogl_context(share_list);
5528
5529             if (!pShare_context)
5530                 vogl_error_printf("%s: Failed finding share context 0x%" PRIx64 " in context manager's hashmap! This handle is probably invalid.\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(share_list));
5531             else
5532             {
5533                 while (!pShare_context->is_root_context())
5534                     pShare_context = pShare_context->get_shared_state();
5535
5536                 pVOGL_context->set_shared_context(pShare_context);
5537
5538                 pShare_context->add_ref();
5539             }
5540         }
5541
5542         pVOGL_context->init();
5543
5544         g_context_manager.unlock();
5545     }
5546
5547     if (g_dump_gl_calls_flag)
5548     {
5549         vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5550     }
5551
5552     return result;
5553 }
5554
5555 //----------------------------------------------------------------------------------------------------------------------
5556 #define DEF_FUNCTION_CUSTOM_HANDLER_glXDestroyContext(exported, category, ret, ret_type_enum, num_params, name, args, params)
5557 static void vogl_glXDestroyContext(const Display *dpy, GLXContext context)
5558 {
5559     uint64_t begin_rdtsc = utils::RDTSC();
5560
5561     if (g_dump_gl_calls_flag)
5562     {
5563         vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5564     }
5565
5566     vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXDestroyContext);
5567     if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
5568     {
5569         vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName);
5570         return GL_ENTRYPOINT(glXDestroyContext)(dpy, context);
5571     }
5572
5573     if (g_dump_gl_calls_flag)
5574     {
5575         vogl_log_printf("** glXDestroyContext TID: 0x%" PRIX64 " Display: 0x%" PRIX64 " context: 0x%" PRIX64 "\n", vogl_get_current_kernel_thread_id(), cast_val_to_uint64(dpy), cast_val_to_uint64(context));
5576     }
5577
5578     vogl_context *pContext = context ? g_context_manager.lookup_vogl_context(context) : NULL;
5579     if (!pContext)
5580         vogl_error_printf("%s: glXDestroyContext() called on an unknown context handle 0x%" PRIX64 "!\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(context));
5581     else if (pContext->get_current_thread())
5582         vogl_error_printf("%s: glXDestroyContext() called on a handle 0x%" PRIX64 " that is still current on thread 0x%" PRIX64 "! This may cause the asynchronous framebuffer capturing system to miss frames!\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(context), pContext->get_current_thread());
5583
5584     if (pContext)
5585     {
5586         pContext->on_destroy_prolog();
5587     }
5588
5589     uint64_t gl_begin_rdtsc = utils::RDTSC();
5590     GL_ENTRYPOINT(glXDestroyContext)(dpy, context);
5591     uint64_t gl_end_rdtsc = utils::RDTSC();
5592
5593     if (g_vogl_trace_writer.is_opened())
5594     {
5595         vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glXDestroyContext, g_context_manager.get_current());
5596         serializer.set_begin_rdtsc(begin_rdtsc);
5597         serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
5598         serializer.add_param(0, VOGL_CONST_DISPLAY_PTR, &dpy, sizeof(dpy));
5599         serializer.add_param(1, VOGL_GLXCONTEXT, &context, sizeof(context));
5600         serializer.end();
5601         vogl_write_packet_to_trace(serializer.get_packet());
5602         g_vogl_trace_writer.flush();
5603     }
5604
5605     if (pContext)
5606     {
5607         g_context_manager.lock();
5608
5609         VOGL_ASSERT(!pContext->get_deleted_flag());
5610         if (!pContext->get_deleted_flag())
5611         {
5612             pContext->set_deleted_flag(true);
5613
5614             if (pContext->is_share_context())
5615             {
5616                 VOGL_ASSERT(pContext->get_ref_count() == 1);
5617             }
5618
5619             int new_ref_count = pContext->del_ref();
5620             if (new_ref_count <= 0)
5621             {
5622                 if (pContext->is_share_context())
5623                 {
5624                     vogl_context *pRoot_context = pContext->get_shared_state();
5625
5626                     pContext->set_shared_context(NULL);
5627
5628                     if (pRoot_context->del_ref() == 0)
5629                     {
5630                         VOGL_ASSERT(pRoot_context->get_deleted_flag());
5631
5632                         bool status = g_context_manager.destroy_context(pRoot_context->get_context_handle());
5633                         VOGL_ASSERT(status);
5634                         VOGL_NOTE_UNUSED(status);
5635                     }
5636                 }
5637
5638                 bool status = g_context_manager.destroy_context(context);
5639                 VOGL_ASSERT(status);
5640                 VOGL_NOTE_UNUSED(status);
5641             }
5642         }
5643
5644         g_context_manager.unlock();
5645     }
5646
5647     if (g_vogl_pLog_stream)
5648     {
5649         // TODO: Ensure this is actually thread safe (does the gcc C runtime mutex this?)
5650         g_vogl_pLog_stream->flush();
5651     }
5652
5653     if (g_dump_gl_calls_flag)
5654     {
5655         vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5656     }
5657 }
5658
5659 //----------------------------------------------------------------------------------------------------------------------
5660 #define DEF_FUNCTION_CUSTOM_HANDLER_glGetError(exported, category, ret, ret_type_enum, num_params, name, args, params)
5661 static GLenum vogl_glGetError()
5662 {
5663     uint64_t begin_rdtsc = utils::RDTSC();
5664
5665     if (g_dump_gl_calls_flag)
5666     {
5667         vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5668     }
5669
5670     vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glGetError);
5671     if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
5672     {
5673         vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName);
5674         return GL_ENTRYPOINT(glGetError)();
5675     }
5676
5677     if (g_dump_gl_calls_flag)
5678     {
5679         vogl_log_printf("** glGetError TID: 0x%" PRIX64 "\n", vogl_get_current_kernel_thread_id());
5680     }
5681
5682     vogl_context *pContext = pTLS_data->m_pContext;
5683     // pContext may be NULL here if the user has called glGetError() incorrectly, we've already printed the error message, but we're still going to call the driver (which will probably just immediately return).
5684     // Also, even if we have a latched error for this context, we MUST call glGetError() to guarantee there are no current errors on the context (to preserve the original behavior if the tracer wasn't present).
5685
5686     uint64_t gl_begin_rdtsc = utils::RDTSC();
5687     GLenum gl_err = GL_ENTRYPOINT(glGetError)();
5688     uint64_t gl_end_rdtsc = utils::RDTSC();
5689
5690     if (g_vogl_trace_writer.is_opened())
5691     {
5692         vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glGetError, g_context_manager.get_current());
5693         serializer.set_begin_rdtsc(begin_rdtsc);
5694         serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
5695         serializer.add_return_param(VOGL_GLENUM, &gl_err, sizeof(gl_err));
5696
5697         if ((pContext) && (pContext->has_latched_gl_error()))
5698         {
5699             // Record the latched error too, so the replayer knows what's going on.
5700             serializer.add_key_value("latched_gl_error", pContext->get_latched_gl_error());
5701         }
5702
5703         serializer.end();
5704         vogl_write_packet_to_trace(serializer.get_packet());
5705         g_vogl_trace_writer.flush();
5706     }
5707
5708     // See if our context's shadow has a latched GL error recorded by the tracer in an earlier call. If so, it must override this GL error.
5709     if (pContext && pContext->has_latched_gl_error())
5710     {
5711         if (gl_err != GL_NO_ERROR)
5712         {
5713             vogl_warning_printf("%s: glGetError() called with a GL error latched on the context by the tracer. Current error is 0x%04X, latched error is 0x%04X. Note the queued error will suppress the current error.\n", VOGL_FUNCTION_NAME, gl_err, pContext->get_latched_gl_error());
5714         }
5715
5716         // We're going to replace the current GL error with our previously latched error, which *would have* masked this error if the tracer wasn't present.
5717         gl_err = pContext->get_latched_gl_error();
5718
5719         pContext->clear_latched_gl_error();
5720     }
5721
5722     if (g_dump_gl_calls_flag)
5723     {
5724         vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5725     }
5726
5727     return gl_err;
5728 }
5729
5730 //----------------------------------------------------------------------------------------------------------------------
5731 // shader source code
5732 //----------------------------------------------------------------------------------------------------------------------
5733 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glShaderSourceARB(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_serialize_shader_source(trace_serializer, count, string, length);
5734 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glShaderSource(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_serialize_shader_source(trace_serializer, count, (const GLcharARB *const *)string, length);
5735 static void vogl_serialize_shader_source(vogl_entrypoint_serializer &trace_serializer, GLsizei count, const GLcharARB *const *string, const GLint *length)
5736 {
5737     if (g_dump_gl_shaders_flag)
5738     {
5739         vogl_log_printf("Source source code, %i string(s):\n", count);
5740         for (GLsizei i = 0; i < count; i++)
5741         {
5742             const char *pStr = (const char *)string[i];
5743             int str_len = 0;
5744             if (length)
5745                 str_len = length[i];
5746             else
5747                 str_len = pStr ? (vogl_strlen(pStr) + 1) : 0;
5748
5749             vogl_log_printf("\"");
5750             vogl_print_string(pStr, str_len);
5751             vogl_log_printf("\"\n");
5752         }
5753     }
5754
5755     if (trace_serializer.is_in_begin())
5756     {
5757         for (GLsizei i = 0; i < count; i++)
5758         {
5759             const char *pStr = (const char *)string[i];
5760             int str_len = 0;
5761             if (length)
5762                 str_len = length[i];
5763             else
5764                 str_len = pStr ? (vogl_strlen(pStr) + 1) : 0;
5765
5766             if ((str_len) && (pStr))
5767                 trace_serializer.add_key_value_blob(i, pStr, str_len);
5768         }
5769     }
5770 }
5771
5772 //----------------------------------------------------------------------------------------------------------------------
5773 // vogl_uses_client_side_arrays
5774 //----------------------------------------------------------------------------------------------------------------------
5775 static bool vogl_uses_client_side_arrays(vogl_context *pContext, bool indexed)
5776 {
5777     if ((!pContext) || (!pContext->get_uses_client_side_arrays()) || (pContext->is_core_profile()))
5778         return false;
5779
5780     vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
5781     VOGL_NOTE_UNUSED(gl_error_absorber);
5782
5783     if (indexed)
5784     {
5785         GLuint element_array_buffer = vogl_get_bound_gl_buffer(GL_ELEMENT_ARRAY_BUFFER);
5786         if (!element_array_buffer)
5787             return true;
5788     }
5789
5790     bool used_old_style_gl_client_side_arrays = false;
5791
5792     GLint prev_client_active_texture = 0;
5793     GL_ENTRYPOINT(glGetIntegerv)(GL_CLIENT_ACTIVE_TEXTURE, &prev_client_active_texture);
5794
5795     const uint tex_coords = pContext->get_max_texture_coords();
5796
5797     for (uint i = 0; i < VOGL_NUM_CLIENT_SIDE_ARRAY_DESCS; i++)
5798     {
5799         const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[i];
5800         if (i == vogl_texcoord_pointer_array_id)
5801         {
5802             for (uint tex_index = 0; tex_index < tex_coords; tex_index++)
5803             {
5804                 GL_ENTRYPOINT(glClientActiveTexture)(GL_TEXTURE0 + tex_index);
5805
5806                 GLboolean is_enabled = GL_ENTRYPOINT(glIsEnabled)(desc.m_is_enabled);
5807                 if (!is_enabled)
5808                     continue;
5809
5810                 GLint binding = 0;
5811                 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_binding, &binding);
5812                 if (binding)
5813                     continue;
5814
5815                 used_old_style_gl_client_side_arrays = true;
5816                 break;
5817             }
5818
5819             if (used_old_style_gl_client_side_arrays)
5820                 break;
5821         }
5822         else
5823         {
5824             GLboolean is_enabled = GL_ENTRYPOINT(glIsEnabled)(desc.m_is_enabled);
5825             if (!is_enabled)
5826                 continue;
5827
5828             GLint binding = 0;
5829             GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_binding, &binding);
5830             if (binding)
5831                 continue;
5832
5833             used_old_style_gl_client_side_arrays = true;
5834             break;
5835         }
5836     }
5837
5838     GL_ENTRYPOINT(glClientActiveTexture)(prev_client_active_texture);
5839
5840     if (used_old_style_gl_client_side_arrays)
5841         return true;
5842
5843     uint64_t vertex_attrib_client_side_arrays = 0;
5844     VOGL_ASSUME(VOGL_MAX_SUPPORTED_GL_VERTEX_ATTRIBUTES <= sizeof(vertex_attrib_client_side_arrays) * 8);
5845
5846     for (uint i = 0; i < pContext->get_max_vertex_attribs(); i++)
5847     {
5848         GLint is_enabled = 0;
5849         GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &is_enabled);
5850         if (!is_enabled)
5851             continue;
5852
5853         GLint cur_buf = 0;
5854         GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &cur_buf);
5855         if (cur_buf)
5856             continue;
5857
5858         return true;
5859     }
5860
5861     return false;
5862 }
5863
5864 //----------------------------------------------------------------------------------------------------------------------
5865 // vogl_serialize_client_side_arrays_helper
5866 //----------------------------------------------------------------------------------------------------------------------
5867 static void vogl_serialize_client_side_arrays_helper(
5868     vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, const char *pFunc,
5869     GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex, bool start_end_valid, bool indexed)
5870 {
5871     VOGL_NOTE_UNUSED(mode);
5872
5873     VOGL_NOTE_UNUSED(pFunc);
5874
5875     if ((!pContext) || (pContext->is_core_profile()))
5876         return;
5877
5878     if (end < start)
5879     {
5880         vogl_error_printf("%s: end (%i) must be >= start (%i)\n", VOGL_FUNCTION_NAME, end, start);
5881         return;
5882     }
5883
5884     uint index_size = vogl_get_gl_type_size(type);
5885     if (!index_size)
5886     {
5887         vogl_error_printf("%s: Invalid type parameter 0x%08X\n", VOGL_FUNCTION_NAME, type);
5888         return;
5889     }
5890
5891     vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
5892     VOGL_NOTE_UNUSED(gl_error_absorber);
5893
5894     GLuint element_array_buffer = 0;
5895     if (indexed)
5896     {
5897         element_array_buffer = vogl_get_bound_gl_buffer(GL_ELEMENT_ARRAY_BUFFER);
5898         if (!element_array_buffer)
5899         {
5900             if (!indices)
5901             {
5902                 vogl_error_printf("%s: No bound element array buffer, and indices parameter is NULL\n", VOGL_FUNCTION_NAME);
5903                 return;
5904             }
5905             else
5906             {
5907                 if (g_dump_gl_buffers_flag)
5908                 {
5909                     vogl_log_printf("Client side index data: ");
5910                     vogl_print_hex(indices, count * index_size, index_size);
5911                     vogl_log_printf("\n");
5912                 }
5913
5914                 if (trace_serializer.is_in_begin())
5915                 {
5916                     trace_serializer.add_key_value_blob(string_hash("indices"), indices, count * index_size);
5917                 }
5918             }
5919         }
5920     }
5921
5922     const gl_entrypoint_id_t cur_entrypoint = trace_serializer.get_cur_entrypoint();
5923     VOGL_NOTE_UNUSED(cur_entrypoint);
5924
5925     // TODO: Have the glSet*Pointer()'s funcs set a flag when the client uses this old shit, so we can avoid checking for it on apps that don't.
5926
5927     bool used_old_style_gl_client_side_arrays = false;
5928
5929     GLint prev_client_active_texture = 0;
5930     GL_ENTRYPOINT(glGetIntegerv)(GL_CLIENT_ACTIVE_TEXTURE, &prev_client_active_texture);
5931
5932     const uint tex_coords = pContext->get_max_texture_coords();
5933
5934     for (uint i = 0; i < VOGL_NUM_CLIENT_SIDE_ARRAY_DESCS; i++)
5935     {
5936         const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[i];
5937         if (i == vogl_texcoord_pointer_array_id)
5938         {
5939             for (uint tex_index = 0; tex_index < tex_coords; tex_index++)
5940             {
5941                 GL_ENTRYPOINT(glClientActiveTexture)(GL_TEXTURE0 + tex_index);
5942
5943                 GLboolean is_enabled = GL_ENTRYPOINT(glIsEnabled)(desc.m_is_enabled);
5944                 if (!is_enabled)
5945                     continue;
5946
5947                 GLint binding = 0;
5948                 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_binding, &binding);
5949                 if (binding)
5950                     continue;
5951
5952                 used_old_style_gl_client_side_arrays = true;
5953                 break;
5954             }
5955
5956             if (used_old_style_gl_client_side_arrays)
5957                 break;
5958         }
5959         else
5960         {
5961             GLboolean is_enabled = GL_ENTRYPOINT(glIsEnabled)(desc.m_is_enabled);
5962             if (!is_enabled)
5963                 continue;
5964
5965             GLint binding = 0;
5966             GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_binding, &binding);
5967             if (binding)
5968                 continue;
5969
5970             used_old_style_gl_client_side_arrays = true;
5971             break;
5972         }
5973     }
5974
5975     GL_ENTRYPOINT(glClientActiveTexture)(prev_client_active_texture);
5976
5977     uint64_t vertex_attrib_client_side_arrays = 0;
5978     VOGL_ASSUME(VOGL_MAX_SUPPORTED_GL_VERTEX_ATTRIBUTES <= sizeof(vertex_attrib_client_side_arrays) * 8);
5979
5980     for (uint i = 0; i < pContext->get_max_vertex_attribs(); i++)
5981     {
5982         GLint is_enabled = 0;
5983         GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &is_enabled);
5984         if (!is_enabled)
5985             continue;
5986
5987         GLint cur_buf = 0;
5988         GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &cur_buf);
5989         if (cur_buf)
5990             continue;
5991
5992         vertex_attrib_client_side_arrays |= (1ULL << i);
5993     }
5994
5995     if ((!used_old_style_gl_client_side_arrays) && (!vertex_attrib_client_side_arrays))
5996         return;
5997
5998     if (indexed)
5999     {
6000         if (!start_end_valid)
6001         {
6002             uint total_index_data_size = count * index_size;
6003
6004             // FIXME: Move index_data array to context state
6005             vogl::vector<uint8> index_data;
6006             const uint8 *pIndices_to_scan = static_cast<const uint8 *>(indices);
6007
6008             if (element_array_buffer)
6009             {
6010                 index_data.resize(total_index_data_size);
6011                 pIndices_to_scan = index_data.get_ptr();
6012
6013                 GL_ENTRYPOINT(glGetBufferSubData)(GL_ELEMENT_ARRAY_BUFFER, (GLintptr)indices, total_index_data_size, index_data.get_ptr());
6014             }
6015
6016             start = cUINT32_MAX;
6017             end = 0;
6018
6019             for (int i = 0; i < count; i++)
6020             {
6021                 uint v = 0;
6022
6023                 if (type == GL_UNSIGNED_BYTE)
6024                     v = pIndices_to_scan[i];
6025                 else if (type == GL_UNSIGNED_SHORT)
6026                     v = reinterpret_cast<const uint16 *>(pIndices_to_scan)[i];
6027                 else if (type == GL_UNSIGNED_INT)
6028                     v = reinterpret_cast<const uint32 *>(pIndices_to_scan)[i];
6029                 else
6030                 {
6031                     VOGL_ASSERT_ALWAYS;
6032                 }
6033
6034                 start = math::minimum(start, v);
6035                 end = math::maximum(end, v);
6036             }
6037         }
6038
6039         if (trace_serializer.is_in_begin())
6040         {
6041             trace_serializer.add_key_value(string_hash("start"), start);
6042             trace_serializer.add_key_value(string_hash("end"), end);
6043         }
6044     }
6045
6046     if (used_old_style_gl_client_side_arrays)
6047     {
6048         for (uint client_array_iter = 0; client_array_iter < VOGL_NUM_CLIENT_SIDE_ARRAY_DESCS; client_array_iter++)
6049         {
6050             const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[client_array_iter];
6051
6052             uint n = 1;
6053             uint base_key_index = 0x1000 + client_array_iter;
6054
6055             // Special case texcoord pointers, which are accessed via the client active texture.
6056             if (client_array_iter == vogl_texcoord_pointer_array_id)
6057             {
6058                 n = tex_coords;
6059                 base_key_index = 0x2000;
6060             }
6061
6062             for (uint inner_iter = 0; inner_iter < n; inner_iter++)
6063             {
6064                 if (client_array_iter == vogl_texcoord_pointer_array_id)
6065                 {
6066                     GL_ENTRYPOINT(glClientActiveTexture)(GL_TEXTURE0 + inner_iter);
6067                 }
6068
6069                 GLboolean is_enabled = GL_ENTRYPOINT(glIsEnabled)(desc.m_is_enabled);
6070                 if (!is_enabled)
6071                     continue;
6072
6073                 GLint binding = 0;
6074                 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_binding, &binding);
6075                 if (binding)
6076                     continue;
6077
6078                 GLvoid *ptr = NULL;
6079                 GL_ENTRYPOINT(glGetPointerv)(desc.m_get_pointer, &ptr);
6080                 if (!ptr)
6081                     continue;
6082
6083                 GLint type = GL_BOOL;
6084                 if (desc.m_get_type)
6085                 {
6086                     GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_type, &type);
6087                 }
6088
6089                 GLint stride = 0;
6090                 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_stride, &stride);
6091
6092                 GLint size = 1;
6093                 if (desc.m_get_size)
6094                 {
6095                     GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_size, &size);
6096                 }
6097
6098                 uint type_size = vogl_get_gl_type_size(type);
6099                 if (!type_size)
6100                 {
6101                     vogl_error_printf("%s: Can't determine type size of enabled client side array set by func %s\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[desc.m_entrypoint].m_pName);
6102                     continue;
6103                 }
6104
6105                 if ((desc.m_entrypoint == VOGL_ENTRYPOINT_glIndexPointer) || (desc.m_entrypoint == VOGL_ENTRYPOINT_glIndexPointerEXT) ||
6106                     (desc.m_entrypoint == VOGL_ENTRYPOINT_glFogCoordPointer) || (desc.m_entrypoint == VOGL_ENTRYPOINT_glFogCoordPointerEXT) ||
6107                     (desc.m_entrypoint == VOGL_ENTRYPOINT_glEdgeFlagPointer) || (desc.m_entrypoint == VOGL_ENTRYPOINT_glEdgeFlagPointerEXT))
6108                 {
6109                     size = 1;
6110                 }
6111                 else if ((desc.m_entrypoint == VOGL_ENTRYPOINT_glNormalPointer) || (desc.m_entrypoint == VOGL_ENTRYPOINT_glNormalPointerEXT))
6112                 {
6113                     size = 3;
6114                 }
6115                 else if ((size < 1) || (size > 4))
6116                 {
6117                     vogl_error_printf("%s: Size of client side array set by func %s must be between 1 and 4\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[desc.m_entrypoint].m_pName);
6118                     continue;
6119                 }
6120
6121                 if (!stride)
6122                     stride = type_size * size;
6123
6124                 uint first_vertex_ofs = (start + basevertex) * stride;
6125                 uint last_vertex_ofs = (end + basevertex) * stride;
6126                 uint vertex_data_size = (last_vertex_ofs + stride) - first_vertex_ofs;
6127
6128                 if (g_dump_gl_buffers_flag)
6129                 {
6130                     vogl_log_printf("Client side vertex data from %s index %u (comps: %i type_size: %i stride: %i):\n", g_vogl_entrypoint_descs[desc.m_entrypoint].m_pName, inner_iter, size, type_size, stride);
6131                     vogl_print_hex(static_cast<const uint8_t *>(ptr) + first_vertex_ofs, vertex_data_size, type_size);
6132                     vogl_log_printf("\n");
6133                 }
6134
6135                 if (trace_serializer.is_in_begin())
6136                 {
6137                     uint key_index = base_key_index + inner_iter;
6138                     trace_serializer.add_key_value_blob(static_cast<uint16>(key_index), static_cast<const uint8_t *>(ptr) + first_vertex_ofs, vertex_data_size);
6139                 }
6140             } // inner_iter
6141
6142         } // client_array_iter
6143
6144         GL_ENTRYPOINT(glClientActiveTexture)(prev_client_active_texture);
6145     } // used_old_style_gl_client_side_arrays
6146
6147     if (vertex_attrib_client_side_arrays)
6148     {
6149         for (uint i = 0; i < pContext->get_max_vertex_attribs(); i++)
6150         {
6151             if ((vertex_attrib_client_side_arrays & (1ULL << i)) == 0)
6152                 continue;
6153
6154             GLvoid *attrib_ptr = NULL;
6155             GL_ENTRYPOINT(glGetVertexAttribPointerv)(i, GL_VERTEX_ATTRIB_ARRAY_POINTER, &attrib_ptr);
6156
6157             if (!attrib_ptr)
6158             {
6159                 vogl_error_printf("%s: Enabled vertex attribute index %i has no vertex array buffer, and attribute pointer is NULL\n", VOGL_FUNCTION_NAME, i);
6160                 continue;
6161             }
6162
6163             GLint attrib_size = 0;
6164             GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_SIZE, &attrib_size);
6165
6166             GLint attrib_type = 0;
6167             GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_TYPE, &attrib_type);
6168
6169             GLint attrib_stride = 0;
6170             GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &attrib_stride);
6171
6172             uint num_comps = 4;
6173             if ((attrib_size != GL_BGRA) && (attrib_size < 1) && (attrib_size > 4))
6174             {
6175                 vogl_error_printf("%s: Enabled vertex attribute index %i has invalid size 0x%0X\n", VOGL_FUNCTION_NAME, i, attrib_size);
6176                 continue;
6177             }
6178             if ((attrib_size >= 1) && (attrib_size <= 4))
6179                 num_comps = attrib_size;
6180
6181             uint type_size = vogl_get_gl_type_size(attrib_type);
6182             if (!type_size)
6183             {
6184                 vogl_error_printf("%s: Vertex attribute index %i has unsupported type 0x%0X\n", VOGL_FUNCTION_NAME, i, attrib_type);
6185                 continue;
6186             }
6187
6188             uint stride = attrib_stride ? attrib_stride : (type_size * num_comps);
6189
6190             uint first_vertex_ofs = (start + basevertex) * stride;
6191             uint last_vertex_ofs = (end + basevertex) * stride;
6192             uint vertex_data_size = (last_vertex_ofs + stride) - first_vertex_ofs;
6193
6194             if (g_dump_gl_buffers_flag)
6195             {
6196                 vogl_log_printf("Client side vertex data for attrib %i (comps: %i type_size: %i stride: %i):\n", i, num_comps, type_size, stride);
6197
6198                 vogl_print_hex(static_cast<const uint8_t *>(attrib_ptr) + first_vertex_ofs, vertex_data_size, type_size);
6199
6200                 vogl_log_printf("\n");
6201             }
6202
6203             if (trace_serializer.is_in_begin())
6204             {
6205                 // TODO: Also send down start/end/first_vertex_ofs for debugging/verification purposes
6206                 trace_serializer.add_key_value_blob(static_cast<uint16>(i), static_cast<const uint8_t *>(attrib_ptr) + first_vertex_ofs, vertex_data_size);
6207             }
6208         }
6209     }
6210 }
6211
6212 //----------------------------------------------------------------------------------------------------------------------
6213 // glDrawRangeElements, glDrawRangeElementsBaseVertex, glDrawRangeElementsEXT
6214 //----------------------------------------------------------------------------------------------------------------------
6215 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDrawRangeElementsBaseVertex(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_draw_range_elements_base_vertex_helper(pContext, trace_serializer, #name, mode, start, end, count, type, indices, 0, true);
6216 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDrawRangeElements(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_draw_range_elements_base_vertex_helper(pContext, trace_serializer, #name, mode, start, end, count, type, indices, 0, true);
6217 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDrawRangeElementsEXT(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_draw_range_elements_base_vertex_helper(pContext, trace_serializer, #name, mode, start, end, count, type, indices, 0, true);
6218 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDrawElements(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_draw_range_elements_base_vertex_helper(pContext, trace_serializer, #name, mode, 0, 0, count, type, indices, 0, false);
6219 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDrawElementsInstanced(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_draw_range_elements_base_vertex_helper(pContext, trace_serializer, #name, mode, 0, 0, count, type, indices, 0, false);
6220
6221 static inline void vogl_draw_range_elements_base_vertex_helper(
6222     vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, const char *pFunc,
6223     GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex, bool start_end_valid)
6224 {
6225     if (trace_serializer.is_in_begin())
6226     {
6227         vogl_serialize_client_side_arrays_helper(pContext, trace_serializer, pFunc,
6228                                                 mode, start, end, count, type, indices, basevertex, start_end_valid, true);
6229     }
6230 }
6231
6232 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDrawArrays(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_draw_arrays_helper(pContext, trace_serializer, #name, mode, first, count);
6233 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDrawArraysEXT(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_draw_arrays_helper(pContext, trace_serializer, #name, mode, first, count);
6234 static void vogl_draw_arrays_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, const char *pFunc,
6235                                    GLenum mode, GLint first, GLsizei count)
6236 {
6237     if (trace_serializer.is_in_begin())
6238     {
6239         vogl_serialize_client_side_arrays_helper(pContext, trace_serializer, pFunc,
6240                                                 mode, first, first + count - 1, count, GL_UNSIGNED_BYTE, NULL, 0, true, false);
6241     }
6242 }
6243
6244 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDrawArraysInstanced(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_draw_arrays_instanced_helper(pContext, trace_serializer, #name, mode, first, count, instancecount);
6245 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDrawArraysInstancedEXT(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_draw_arrays_instanced_helper(pContext, trace_serializer, #name, mode, start, count, primcount);
6246 static void vogl_draw_arrays_instanced_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, const char *pFunc,
6247                                              GLenum mode, GLint first, GLsizei count, GLsizei primcount)
6248 {
6249     VOGL_NOTE_UNUSED(primcount);
6250     if (trace_serializer.is_in_begin())
6251     {
6252         vogl_serialize_client_side_arrays_helper(pContext, trace_serializer, pFunc,
6253                                                 mode, first, first + count - 1, count, GL_UNSIGNED_BYTE, NULL, 0, true, false);
6254     }
6255 }
6256
6257 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glMultiDrawArrays(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_multi_draw_arrays_helper(pContext, trace_serializer, #name);
6258 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glMultiDrawArraysEXT(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_multi_draw_arrays_helper(pContext, trace_serializer, #name);
6259 static inline void vogl_multi_draw_arrays_helper(
6260     vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, const char *pFunc)
6261 {
6262     if (trace_serializer.is_in_begin())
6263     {
6264         if (vogl_uses_client_side_arrays(pContext, false))
6265         {
6266             vogl_warning_printf("%s: Function \"%s\" uses client side arrays, which is not currently supported. This call will not replay properly.\n", VOGL_FUNCTION_NAME, pFunc);
6267         }
6268     }
6269 }
6270
6271 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glMultiDrawElements(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_multi_draw_elements_helper(pContext, trace_serializer, #name);
6272 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glMultiDrawElementsEXT(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_multi_draw_elements_helper(pContext, trace_serializer, #name);
6273 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glMultiDrawElementsBaseVertex(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_multi_draw_elements_helper(pContext, trace_serializer, #name);
6274 static void vogl_multi_draw_elements_helper(
6275     vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, const char *pFunc)
6276 {
6277     if (trace_serializer.is_in_begin())
6278     {
6279         if (vogl_uses_client_side_arrays(pContext, true))
6280         {
6281             vogl_warning_printf("%s: Function \"%s\" uses client side arrays, which is not currently supported. This call will not replay properly.\n", VOGL_FUNCTION_NAME, pFunc);
6282         }
6283     }
6284 }
6285
6286 //----------------------------------------------------------------------------------------------------------------------
6287 // String (extension manipulation)
6288 //----------------------------------------------------------------------------------------------------------------------
6289 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGetString(exported, category, ret, ret_type_enum, num_params, func_name, args, params) vogl_get_string_helper(#func_name, pContext, result, name, 0);
6290 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGetStringi(exported, category, ret, ret_type_enum, num_params, func_name, args, params) vogl_get_string_helper(#func_name, pContext, result, name, index);
6291 static inline void vogl_get_string_helper(const char *pFunc_name, vogl_context *pVOGL_context, const GLubyte *&pResult, GLenum name, GLuint index)
6292 {
6293     if (!g_disable_gl_program_binary_flag)
6294         return;
6295
6296     if ((pVOGL_context) && (pResult) && (name == GL_EXTENSIONS))
6297     {
6298         // Can't modify the driver's string directly, results in random crashes on my system. So we need to make a copy.
6299         char *pLoc = strstr((char *)pResult, "GL_ARB_get_program_binary");
6300         if (pLoc)
6301         {
6302             dynamic_string id(cVarArg, "%s_%x_%x", pFunc_name, name, index);
6303
6304             dynamic_string &ext_str = pVOGL_context->get_extension_map()[id];
6305             ext_str.set((char *)pResult);
6306
6307             int ofs = ext_str.find_left("GL_ARB_get_program_binary", true);
6308             if (ofs >= 0)
6309             {
6310                 ext_str.set_char(ofs + 3, 'X');
6311                 ext_str.set_char(ofs + 4, 'X');
6312                 ext_str.set_char(ofs + 5, 'X');
6313                 vogl_warning_printf("%s: Disabled GL_ARB_get_program_binary by changing its name to GL_XXX_get_program_binary.\n", VOGL_FUNCTION_NAME);
6314
6315                 pResult = (const GLubyte *)ext_str.get_ptr();
6316             }
6317         }
6318     }
6319 }
6320
6321 //----------------------------------------------------------------------------------------------------------------------
6322 // Buffer mapping, updating
6323 //----------------------------------------------------------------------------------------------------------------------
6324
6325 // TODO:
6326 // glMapNamedBufferEXT
6327 // glMapNamedBufferRangeEXT
6328 // glFlushMappedNamedBufferRangeEXT
6329 // glUnmapNamedBufferEXT
6330 // glGetNamedBufferSubDataEXT
6331
6332 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glNamedBufferDataEXT(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_named_buffer_data_ext_helper(pContext, trace_serializer, buffer, size, data, usage);
6333 static inline void vogl_named_buffer_data_ext_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLuint buffer, GLsizeiptr size, const GLvoid *data, GLenum usage)
6334 {
6335     VOGL_NOTE_UNUSED(trace_serializer);
6336
6337     if (!pContext)
6338         return;
6339
6340     if (g_dump_gl_buffers_flag)
6341     {
6342         vogl_log_printf("Buffer data (size: %" PRIu64 "):\n", static_cast<uint64_t>(size));
6343         vogl_print_hex(data, size, 1);
6344         vogl_log_printf("\n");
6345     }
6346
6347     gl_buffer_desc &buf_desc = pContext->get_or_create_buffer_desc(buffer);
6348     buf_desc.m_size = size;
6349     buf_desc.m_usage = usage;
6350
6351     if (buf_desc.m_pMap)
6352     {
6353         vogl_warning_printf("%s: Setting buffer's data on an already mapped buffer, buffer will get unmapped by GL\n", VOGL_FUNCTION_NAME);
6354     }
6355
6356     buf_desc.m_pMap = NULL;
6357     buf_desc.m_map_ofs = 0;
6358     buf_desc.m_map_size = 0;
6359     buf_desc.m_map_access = 0;
6360     buf_desc.m_map_range = 0;
6361     buf_desc.m_flushed_ranges.resize(0);
6362 }
6363
6364 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glBufferData(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_buffer_data_helper(pContext, trace_serializer, target, size, data, usage);
6365 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glBufferDataARB(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_buffer_data_helper(pContext, trace_serializer, target, size, data, usage);
6366 static inline void vogl_buffer_data_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage)
6367 {
6368     if (!pContext)
6369         return;
6370
6371     vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6372     VOGL_NOTE_UNUSED(gl_error_absorber);
6373
6374     GLuint buffer = vogl_get_bound_gl_buffer(target);
6375     if (!buffer)
6376     {
6377         vogl_error_printf("%s: No mapped buffer at target 0x%08X\n", VOGL_FUNCTION_NAME, target);
6378         return;
6379     }
6380
6381     vogl_named_buffer_data_ext_helper(pContext, trace_serializer, buffer, size, data, usage);
6382 }
6383
6384 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glNamedBufferSubDataEXT(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_named_buffer_subdata_ext_helper(pContext, trace_serializer, buffer, offset, size, data);
6385 static inline void vogl_named_buffer_subdata_ext_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLuint buffer, GLintptr offset, GLsizeiptr size, const GLvoid *data)
6386 {
6387     VOGL_NOTE_UNUSED(buffer);
6388     VOGL_NOTE_UNUSED(trace_serializer);
6389     VOGL_NOTE_UNUSED(pContext);
6390
6391     if (g_dump_gl_buffers_flag)
6392     {
6393         vogl_log_printf("Buffer sub data (offset: %" PRIu64 " size: %" PRIu64 "):\n", static_cast<uint64_t>(offset), static_cast<uint64_t>(size));
6394         vogl_print_hex(data, size, 1);
6395         vogl_log_printf("\n");
6396     }
6397 }
6398
6399 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glBufferSubData(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_buffer_subdata_helper(pContext, trace_serializer, target, offset, size, data);
6400 static inline void vogl_buffer_subdata_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data)
6401 {
6402     if (!pContext)
6403         return;
6404
6405     vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6406     VOGL_NOTE_UNUSED(gl_error_absorber);
6407
6408     GLuint buffer = vogl_get_bound_gl_buffer(target);
6409     if (!buffer)
6410     {
6411         vogl_error_printf("%s: No mapped buffer at target 0x%08X\n", VOGL_FUNCTION_NAME, target);
6412         return;
6413     }
6414
6415     vogl_named_buffer_subdata_ext_helper(pContext, trace_serializer, buffer, offset, size, data);
6416 }
6417
6418 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glMapBuffer(exported, category, ret, ret_type_enum, num_params, name, args, params) \
6419     GLenum orig_access = access;                                                                                          \
6420     vogl_map_buffer_gl_prolog_helper(pContext, trace_serializer, target, access);
6421 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glMapBufferARB(exported, category, ret, ret_type_enum, num_params, name, args, params) \
6422     GLenum orig_access = access;                                                                                             \
6423     vogl_map_buffer_gl_prolog_helper(pContext, trace_serializer, target, access);
6424 static inline void vogl_map_buffer_gl_prolog_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLenum target, GLenum &access)
6425 {
6426     VOGL_NOTE_UNUSED(target);
6427     VOGL_NOTE_UNUSED(pContext);
6428
6429     if (trace_serializer.is_in_begin() || g_dump_gl_buffers_flag)
6430     {
6431         if (access == GL_WRITE_ONLY)
6432         {
6433             access = GL_READ_WRITE;
6434         }
6435     }
6436 }
6437
6438 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glMapBuffer(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_map_buffer_gl_epilog_helper(pContext, target, orig_access, result);
6439 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glMapBufferARB(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_map_buffer_gl_epilog_helper(pContext, target, orig_access, result);
6440 static inline void vogl_map_buffer_gl_epilog_helper(vogl_context *pContext, GLenum target, GLenum access, GLvoid *pPtr)
6441 {
6442     if (!pContext)
6443         return;
6444
6445     if (!pPtr)
6446     {
6447         vogl_warning_printf("%s: Map failed!\n", VOGL_FUNCTION_NAME);
6448         return;
6449     }
6450
6451     vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6452     VOGL_NOTE_UNUSED(gl_error_absorber);
6453
6454     GLuint buffer = vogl_get_bound_gl_buffer(target);
6455     if (!buffer)
6456     {
6457         vogl_error_printf("%s: No mapped buffer at target 0x%08X\n", VOGL_FUNCTION_NAME, target);
6458         return;
6459     }
6460
6461     gl_buffer_desc &buf_desc = pContext->get_or_create_buffer_desc(buffer);
6462     if (buf_desc.m_pMap)
6463     {
6464         vogl_warning_printf("%s: Buffer 0x%08X is already mapped!\n", VOGL_FUNCTION_NAME, buffer);
6465         return;
6466     }
6467
6468     // We need to sync with the underlying GL here to retreive the actual, true size of the mapped buffer in case an error occurred earlier and we didn't actually record the true size of the buffer.
6469     GLint64 actual_buf_size = buf_desc.m_size;
6470     GL_ENTRYPOINT(glGetBufferParameteri64v)(target, GL_BUFFER_SIZE, &actual_buf_size);
6471
6472     buf_desc.m_size = actual_buf_size;
6473     buf_desc.m_pMap = pPtr;
6474     buf_desc.m_map_ofs = 0;
6475     buf_desc.m_map_size = actual_buf_size;
6476     buf_desc.m_map_access = access;
6477     buf_desc.m_map_range = false;
6478 }
6479
6480 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glMapBufferRange(exported, category, ret, ret_type_enum, num_params, name, args, params) \
6481     GLbitfield orig_access = access;                                                                                           \
6482     vogl_map_buffer_range_gl_prolog_helper(pContext, trace_serializer, target, offset, length, access);
6483 static inline void vogl_map_buffer_range_gl_prolog_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield &access)
6484 {
6485     VOGL_NOTE_UNUSED(length);
6486     VOGL_NOTE_UNUSED(offset);
6487     VOGL_NOTE_UNUSED(target);
6488     VOGL_NOTE_UNUSED(pContext);
6489
6490     if (trace_serializer.is_in_begin() || g_dump_gl_buffers_flag)
6491     {
6492         if (access & GL_MAP_WRITE_BIT)
6493         {
6494             // They are going to write, so we need to be able to read the data.
6495             // TODO: Warn user that we're going to not invalidate, which is definitely going to slow the GL driver down with CPU/GPU syncs.
6496             access &= ~GL_MAP_INVALIDATE_RANGE_BIT;
6497             access &= ~GL_MAP_INVALIDATE_BUFFER_BIT;
6498             access &= ~GL_MAP_UNSYNCHRONIZED_BIT;
6499             access |= GL_MAP_READ_BIT;
6500         }
6501     }
6502 }
6503
6504 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glMapBufferRange(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_map_buffer_range_gl_epilog_helper(pContext, target, offset, length, orig_access, result);
6505 static inline void vogl_map_buffer_range_gl_epilog_helper(vogl_context *pContext, GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield &access, GLvoid *pPtr)
6506 {
6507     if (!pContext)
6508         return;
6509
6510     if (!pPtr)
6511     {
6512         vogl_warning_printf("%s: Map failed!\n", VOGL_FUNCTION_NAME);
6513         return;
6514     }
6515
6516     vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6517     VOGL_NOTE_UNUSED(gl_error_absorber);
6518
6519     GLuint buffer = vogl_get_bound_gl_buffer(target);
6520     if (!buffer)
6521     {
6522         vogl_error_printf("%s: No mapped buffer at target 0x%08X\n", VOGL_FUNCTION_NAME, target);
6523         return;
6524     }
6525
6526     gl_buffer_desc &buf_desc = pContext->get_or_create_buffer_desc(buffer);
6527     if (buf_desc.m_pMap)
6528     {
6529         vogl_error_printf("%s: Buffer 0x%08X is already mapped!\n", VOGL_FUNCTION_NAME, buffer);
6530         return;
6531     }
6532
6533     if (length > buf_desc.m_size)
6534     {
6535         vogl_warning_printf("%s: passed in length parameter (%" PRIi64 ") is larger the buffer 0x%08X's recorded size (%" PRIi64 ")!\n",
6536                            VOGL_FUNCTION_NAME, static_cast<int64_t>(length), buffer, buf_desc.m_size);
6537
6538         GLint64 actual_buf_size = buf_desc.m_size;
6539         GL_ENTRYPOINT(glGetBufferParameteri64v)(target, GL_BUFFER_SIZE, &actual_buf_size);
6540         buf_desc.m_size = actual_buf_size;
6541     }
6542
6543     buf_desc.m_pMap = pPtr;
6544     buf_desc.m_map_ofs = offset;
6545     buf_desc.m_map_size = length;
6546     buf_desc.m_map_access = access;
6547     buf_desc.m_map_range = true;
6548 }
6549
6550 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glFlushMappedBufferRange(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_flush_mapped_buffer_range(pContext, target, offset, length);
6551 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glFlushMappedBufferRangeAPPLE(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_flush_mapped_buffer_range(pContext, target, offset, size);
6552 static inline void vogl_flush_mapped_buffer_range(vogl_context *pContext, GLenum target, GLintptr offset, GLsizeiptr length)
6553 {
6554     if (!pContext)
6555         return;
6556
6557     vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6558     VOGL_NOTE_UNUSED(gl_error_absorber);
6559
6560     GLuint buffer = vogl_get_bound_gl_buffer(target);
6561     if (!buffer)
6562     {
6563         vogl_error_printf("%s: No mapped buffer at target 0x%08X\n", VOGL_FUNCTION_NAME, target);
6564         return;
6565     }
6566
6567     gl_buffer_desc &buf_desc = pContext->get_or_create_buffer_desc(buffer);
6568     if (!buf_desc.m_pMap)
6569     {
6570         vogl_error_printf("%s: Buffer 0x%08X is not currently mapped!\n", VOGL_FUNCTION_NAME, buffer);
6571         return;
6572     }
6573
6574     if ((offset + length) > buf_desc.m_map_size)
6575     {
6576         vogl_warning_printf("%s: passed in offset (%" PRIi64 ") and/or length (%" PRIi64 ") parameters are out of range vs. buffer 0x%08X's recorded map size (%" PRIi64 ")!\n",
6577                            VOGL_FUNCTION_NAME, static_cast<int64_t>(offset), static_cast<int64_t>(length), buffer, buf_desc.m_map_size);
6578     }
6579
6580     buf_desc.m_flushed_ranges.push_back(gl_buffer_desc::flushed_range(offset, length));
6581 }
6582
6583 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glUnmapBuffer(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_unmap_buffer_helper(pContext, trace_serializer, target);
6584 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glUnmapBufferARB(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_unmap_buffer_helper(pContext, trace_serializer, target);
6585 static inline void vogl_unmap_buffer_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLenum target)
6586 {
6587     if (!pContext)
6588         return;
6589
6590     vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6591     VOGL_NOTE_UNUSED(gl_error_absorber);
6592
6593     GLuint buffer = vogl_get_bound_gl_buffer(target);
6594     if (!buffer)
6595     {
6596         vogl_error_printf("%s: No mapped buffer at target 0x%08X\n", VOGL_FUNCTION_NAME, target);
6597         return;
6598     }
6599
6600     gl_buffer_desc &buf_desc = pContext->get_or_create_buffer_desc(buffer);
6601     if (!buf_desc.m_pMap)
6602     {
6603         vogl_error_printf("%s: Buffer 0x%08X is not currently mapped!\n", VOGL_FUNCTION_NAME, buffer);
6604         return;
6605     }
6606
6607     bool writable_map = false;
6608     bool explicit_flush = false;
6609     if (buf_desc.m_map_range)
6610     {
6611         writable_map = (buf_desc.m_map_access & GL_MAP_WRITE_BIT) != 0;
6612         explicit_flush = (buf_desc.m_map_access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0;
6613     }
6614     else
6615     {
6616         writable_map = (buf_desc.m_map_access != GL_READ_ONLY);
6617     }
6618
6619     if (trace_serializer.is_in_begin())
6620     {
6621         trace_serializer.add_key_value(string_hash("map_access"), buf_desc.m_map_access);
6622         trace_serializer.add_key_value(string_hash("map_range"), buf_desc.m_map_range);
6623         trace_serializer.add_key_value(string_hash("explicit_flush"), explicit_flush);
6624         trace_serializer.add_key_value(string_hash("writable_map"), writable_map);
6625     }
6626
6627     if (writable_map)
6628     {
6629         if (explicit_flush)
6630         {
6631             if (!buf_desc.m_flushed_ranges.size())
6632             {
6633                 vogl_warning_printf("%s: Mapped buffer at target 0x%08X was mapped with GL_MAP_FLUSH_EXPLICIT_BIT, but no ranges where actually flushed\n", VOGL_FUNCTION_NAME, target);
6634             }
6635
6636             if (g_dump_gl_buffers_flag)
6637             {
6638                 for (uint i = 0; i < buf_desc.m_flushed_ranges.size(); i++)
6639                 {
6640                     vogl_log_printf("Flushed buffer data (ofs: %" PRIu64 " size: %" PRIu64 "):\n", buf_desc.m_flushed_ranges[i].m_ofs, buf_desc.m_flushed_ranges[i].m_size);
6641                     vogl_print_hex(static_cast<const uint8_t *>(buf_desc.m_pMap) + buf_desc.m_flushed_ranges[i].m_ofs, buf_desc.m_flushed_ranges[i].m_size, 1);
6642                     vogl_log_printf("\n");
6643                 }
6644             }
6645
6646             if (trace_serializer.is_in_begin())
6647             {
6648                 trace_serializer.add_key_value(string_hash("flushed_ranges"), buf_desc.m_flushed_ranges.size());
6649                 for (uint i = 0; i < buf_desc.m_flushed_ranges.size(); i++)
6650                 {
6651                     int key_index = i * 4;
6652                     trace_serializer.add_key_value(key_index, buf_desc.m_flushed_ranges[i].m_ofs);
6653                     trace_serializer.add_key_value(key_index + 1, buf_desc.m_flushed_ranges[i].m_size);
6654                     // TODO
6655                     VOGL_ASSERT(buf_desc.m_flushed_ranges[i].m_size <= cUINT32_MAX);
6656                     trace_serializer.add_key_value_blob(key_index + 2, static_cast<const uint8_t *>(buf_desc.m_pMap) + buf_desc.m_flushed_ranges[i].m_ofs, static_cast<uint>(buf_desc.m_flushed_ranges[i].m_size));
6657                 }
6658             }
6659         }
6660         else
6661         {
6662             if (g_dump_gl_buffers_flag)
6663             {
6664                 vogl_log_printf("Flushed buffer data (ofs: %" PRIu64 " size: %" PRIu64 "):\n", cast_val_to_uint64(buf_desc.m_map_ofs), cast_val_to_uint64(buf_desc.m_map_size));
6665                 vogl_print_hex(static_cast<const uint8_t *>(buf_desc.m_pMap), buf_desc.m_map_size, 1);
6666                 vogl_log_printf("\n");
6667             }
6668
6669             if (trace_serializer.is_in_begin())
6670             {
6671                 trace_serializer.add_key_value(0, buf_desc.m_map_ofs);
6672                 trace_serializer.add_key_value(1, buf_desc.m_map_size);
6673                 // TODO
6674                 VOGL_ASSERT(buf_desc.m_map_size <= cUINT32_MAX);
6675                 trace_serializer.add_key_value_blob(2, static_cast<const uint8_t *>(buf_desc.m_pMap), static_cast<uint>(buf_desc.m_map_size));
6676             }
6677         }
6678     }
6679
6680     buf_desc.m_pMap = NULL;
6681     buf_desc.m_map_ofs = 0;
6682     buf_desc.m_map_size = 0;
6683     buf_desc.m_map_access = 0;
6684     buf_desc.m_flushed_ranges.resize(0);
6685 }
6686
6687 //----------------------------------------------------------------------------------------------------------------------
6688 // glCreateProgram/glCreateProgramARB function epilog
6689 //----------------------------------------------------------------------------------------------------------------------
6690 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glCreateProgram(e, c, rt, r, nu, ne, a, p) \
6691     if (pContext)                                                                  \
6692         vogl_create_program_helper(pContext, result);
6693 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glCreateProgramObjectARB(e, c, rt, r, nu, ne, a, p) \
6694     if (pContext)                                                                           \
6695         vogl_create_program_helper(pContext, result);
6696 static inline void vogl_create_program_helper(vogl_context *pContext, GLuint handle)
6697 {
6698     VOGL_NOTE_UNUSED(pContext);
6699     VOGL_NOTE_UNUSED(handle);
6700
6701 #if 0
6702         if (handle)
6703         {
6704                 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6705                 VOGL_NOTE_UNUSED(gl_error_absorber);
6706
6707                 // Ensure program bins are always retrievable
6708                 GL_ENTRYPOINT(glProgramParameteri)(handle, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);
6709         }
6710 #endif
6711 }
6712
6713 //----------------------------------------------------------------------------------------------------------------------
6714 // glProgramParameteri GL prolog
6715 //----------------------------------------------------------------------------------------------------------------------
6716 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glProgramParameteri(e, c, rt, r, nu, ne, a, p) \
6717     if (pContext)                                                                    \
6718         vogl_program_parameteri_prolog(pContext, program, pname, value);
6719 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glProgramParameteriARB(e, c, rt, r, nu, ne, a, p) \
6720     if (pContext)                                                                       \
6721         vogl_program_parameteri_prolog(pContext, program, pname, value);
6722 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glProgramParameteriEXT(e, c, rt, r, nu, ne, a, p) \
6723     if (pContext)                                                                       \
6724         vogl_program_parameteri_prolog(pContext, program, pname, value);
6725 static void vogl_program_parameteri_prolog(vogl_context *pContext, GLuint program, GLenum pname, GLint &value)
6726 {
6727     VOGL_NOTE_UNUSED(pContext);
6728     VOGL_NOTE_UNUSED(program);
6729     VOGL_NOTE_UNUSED(pname);
6730     VOGL_NOTE_UNUSED(value);
6731
6732 #if 0
6733         if ((pname == GL_PROGRAM_BINARY_RETRIEVABLE_HINT) && (value == GL_FALSE))
6734         {
6735                 vogl_warning_printf("%s: Client is trying to set program %u's GL_PROGRAM_BINARY_RETRIEVABLE_HINT to GL_FALSE, the tracer is overriding this to GL_TRUE\n", VOGL_FUNCTION_NAME, program);
6736
6737                 value = GL_TRUE;
6738         }
6739 #endif
6740 }
6741
6742 //----------------------------------------------------------------------------------------------------------------------
6743 // glBindAttribLocationARB/glBindAttribLocation function epilog
6744 //----------------------------------------------------------------------------------------------------------------------
6745 //#define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glBindAttribLocationARB(e, c, rt, r, nu, ne, a, p) if (pContext) pContext->bind_attrib_location(programObj, index, name);
6746 //#define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glBindAttribLocation(e, c, rt, r, nu, ne, a, p) if (pContext) pContext->bind_attrib_location(program, index, reinterpret_cast<const char *>(name));
6747
6748 //----------------------------------------------------------------------------------------------------------------------
6749 // glDeleteProgramsARB/glDeleteProgram function epilog
6750 //----------------------------------------------------------------------------------------------------------------------
6751 //#define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDeleteProgramsARB(e, c, rt, r, nu, ne, a, p) if (pContext) pContext->delete_program_attrib_locations(n, programs);
6752 //#define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDeleteProgram(e, c, rt, r, nu, ne, a, p) if (pContext) pContext->delete_program_attrib_locations(1, &program);
6753
6754 //----------------------------------------------------------------------------------------------------------------------
6755 // vogl_dump_program_outputs
6756 //----------------------------------------------------------------------------------------------------------------------
6757 static void vogl_dump_program_outputs(json_node &doc_root, vogl_context *pContext, GLuint program)
6758 {
6759     if (pContext->get_context_info().supports_extension("GL_ARB_program_interface_query") &&
6760         GL_ENTRYPOINT(glGetProgramInterfaceiv) && GL_ENTRYPOINT(glGetProgramResourceName) && GL_ENTRYPOINT(glGetProgramResourceiv))
6761     {
6762         GLint num_active_outputs = 0;
6763         GL_ENTRYPOINT(glGetProgramInterfaceiv)(program, GL_PROGRAM_OUTPUT, GL_ACTIVE_RESOURCES, &num_active_outputs);
6764         pContext->peek_and_drop_gl_error();
6765
6766         doc_root.add_key_value("total_active_outputs", num_active_outputs);
6767
6768         json_node &outputs_object = doc_root.add_array("active_outputs");
6769         for (int i = 0; i < num_active_outputs; i++)
6770         {
6771             GLchar name[256];
6772             GLsizei name_len = 0;
6773             GL_ENTRYPOINT(glGetProgramResourceName)(program, GL_PROGRAM_OUTPUT, i, sizeof(name), &name_len, name);
6774             pContext->peek_and_drop_gl_error();
6775
6776             const GLenum props_to_query[5] = { GL_LOCATION, GL_LOCATION_INDEX, GL_TYPE, GL_ARRAY_SIZE, GL_IS_PER_PATCH }; // TODO: GL_LOCATION_COMPONENT
6777             GLint props[5] = { 0, 0, 0, 0, 0 };
6778             GL_ENTRYPOINT(glGetProgramResourceiv)(program, GL_PROGRAM_OUTPUT, i, VOGL_ARRAY_SIZE(props_to_query), props_to_query, VOGL_ARRAY_SIZE(props), NULL, props);
6779             pContext->peek_and_drop_gl_error();
6780
6781             json_node &output_node = outputs_object.add_object();
6782             output_node.add_key_value("index", i);
6783             output_node.add_key_value("name", reinterpret_cast<const char *>(name));
6784             output_node.add_key_value("location", props[0]);
6785             output_node.add_key_value("location_index", props[1]);
6786             output_node.add_key_value("type", props[2]);
6787             output_node.add_key_value("array_size", props[3]);
6788             output_node.add_key_value("is_per_patch", props[4]);
6789             //output_node.add_key_value("location_component", props[5]);
6790         }
6791     }
6792 }
6793
6794 //----------------------------------------------------------------------------------------------------------------------
6795 // glLinkProgramARB function epilog
6796 //----------------------------------------------------------------------------------------------------------------------
6797 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glLinkProgramARB(e, c, rt, r, nu, ne, a, p) vogl_link_program_arb(pContext, trace_serializer, programObj);
6798 static inline void vogl_link_program_arb(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLhandleARB programObj)
6799 {
6800     if (!pContext)
6801         return;
6802
6803     vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6804     VOGL_NOTE_UNUSED(gl_error_absorber);
6805
6806     GLint link_status = 0;
6807     GL_ENTRYPOINT(glGetObjectParameterivARB)(programObj, GL_OBJECT_LINK_STATUS_ARB, &link_status);
6808     pContext->peek_and_drop_gl_error();
6809
6810     if (trace_serializer.is_in_begin())
6811     {
6812         json_document doc;
6813         json_node &doc_root = *doc.get_root();
6814         doc_root.add_key_value("program", programObj);
6815         doc_root.add_key_value("link_status", link_status);
6816         doc_root.add_key_value("func_id", VOGL_ENTRYPOINT_glLinkProgramARB);
6817
6818         GLint active_attributes = 0;
6819         GL_ENTRYPOINT(glGetObjectParameterivARB)(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);
6820         pContext->peek_and_drop_gl_error();
6821
6822         doc_root.add_key_value("total_active_attributes", active_attributes);
6823
6824         if (active_attributes)
6825         {
6826             json_node &attribs_object = doc_root.add_array("active_attribs");
6827
6828             for (int i = 0; i < active_attributes; i++)
6829             {
6830                 GLint size = 0;
6831                 GLenum type = 0;
6832                 GLcharARB name[256];
6833
6834                 GL_ENTRYPOINT(glGetActiveAttribARB)(programObj, i, sizeof(name), NULL, &size, &type, name);
6835                 pContext->peek_and_drop_gl_error();
6836
6837                 if ((!name[0]) || ((name[0] == 'g') && (name[1] == 'l') && (name[2] == '_')))
6838                     continue;
6839
6840                 GLint location = GL_ENTRYPOINT(glGetAttribLocationARB)(programObj, name);
6841                 pContext->peek_and_drop_gl_error();
6842
6843                 if (location < 0)
6844                     continue;
6845
6846                 json_node &attrib_node = attribs_object.add_object();
6847                 attrib_node.add_key_value("index", i);
6848                 attrib_node.add_key_value("name", reinterpret_cast<const char *>(name));
6849                 attrib_node.add_key_value("location", location);
6850             }
6851         }
6852
6853         GLint active_uniforms = 0;
6854         GL_ENTRYPOINT(glGetObjectParameterivARB)(programObj, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &active_uniforms);
6855         pContext->peek_and_drop_gl_error();
6856
6857         doc_root.add_key_value("total_active_uniforms", active_uniforms);
6858
6859         if (active_uniforms)
6860         {
6861             json_node &uniforms_object = doc_root.add_array("active_uniforms");
6862
6863             for (int i = 0; i < active_uniforms; i++)
6864             {
6865                 GLsizei length = 0;
6866                 GLint size = 0;
6867                 GLenum type = 0;
6868                 GLcharARB name[256];
6869
6870                 GL_ENTRYPOINT(glGetActiveUniformARB)(programObj, i, sizeof(name), &length, &size, &type, name);
6871                 pContext->peek_and_drop_gl_error();
6872
6873                 if ((!name[0]) || (!length) || ((name[0] == 'g') && (name[1] == 'l') && (name[2] == '_')))
6874                     continue;
6875
6876                 GLint location = GL_ENTRYPOINT(glGetUniformLocationARB)(programObj, name);
6877                 pContext->peek_and_drop_gl_error();
6878
6879                 if (location < 0)
6880                     continue;
6881
6882                 json_node &uniform_node = uniforms_object.add_object();
6883                 uniform_node.add_key_value("index", i);
6884                 uniform_node.add_key_value("name", reinterpret_cast<const char *>(name));
6885                 uniform_node.add_key_value("location", location);
6886                 uniform_node.add_key_value("size", size);
6887                 uniform_node.add_key_value("type", type);
6888             }
6889         }
6890
6891         vogl_dump_program_outputs(doc_root, pContext, programObj);
6892
6893         trace_serializer.add_key_value_json_document("metadata", doc);
6894     }
6895
6896     if (programObj)
6897     {
6898         if ((link_status) || (!pContext->has_linked_program_snapshot(programObj)))
6899         {
6900             if (!pContext->add_linked_program_snapshot(programObj))
6901                 vogl_error_printf("%s: Failed snapshotting program into link-time program shadow table, program 0x%X\n", VOGL_FUNCTION_NAME, programObj);
6902         }
6903     }
6904 }
6905
6906 //----------------------------------------------------------------------------------------------------------------------
6907 // glLinkProgram/glProgramBinary function epilog
6908 //----------------------------------------------------------------------------------------------------------------------
6909 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glLinkProgram(e, c, rt, r, nu, ne, a, p) vogl_link_program_epilog_helper(pContext, trace_serializer, program, VOGL_ENTRYPOINT_##ne, GL_NONE, NULL, 0);
6910 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glProgramBinary(e, c, rt, r, nu, ne, a, p) vogl_link_program_epilog_helper(pContext, trace_serializer, program, VOGL_ENTRYPOINT_##ne, binaryFormat, binary, length);
6911 static inline void vogl_link_program_epilog_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLuint program, gl_entrypoint_id_t id, GLenum binary_format, const GLvoid *pBinary, GLsizei binary_length)
6912 {
6913     if (!pContext)
6914         return;
6915
6916     vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6917     VOGL_NOTE_UNUSED(gl_error_absorber);
6918
6919     GLint link_status = 0;
6920     GL_ENTRYPOINT(glGetProgramiv)(program, GL_LINK_STATUS, &link_status);
6921     pContext->peek_and_drop_gl_error();
6922
6923     if (trace_serializer.is_in_begin())
6924     {
6925         json_document doc;
6926         json_node &doc_root = *doc.get_root();
6927         doc_root.add_key_value("program", program);
6928         doc_root.add_key_value("link_status", link_status);
6929         doc_root.add_key_value("func_id", static_cast<uint32>(id));
6930
6931         // Active uniform blocks
6932         GLint active_uniform_blocks = 0;
6933         GL_ENTRYPOINT(glGetProgramiv)(program, GL_ACTIVE_UNIFORM_BLOCKS, &active_uniform_blocks);
6934         pContext->peek_and_drop_gl_error();
6935
6936         doc_root.add_key_value("active_uniform_blocks", active_uniform_blocks);
6937
6938         // Active attributes
6939         GLint active_attributes = 0;
6940         GL_ENTRYPOINT(glGetProgramiv)(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);
6941         pContext->peek_and_drop_gl_error();
6942
6943         doc_root.add_key_value("total_active_attributes", active_attributes);
6944
6945         if (active_attributes)
6946         {
6947             json_node &attribs_object = doc_root.add_array("active_attribs");
6948
6949             for (int i = 0; i < active_attributes; i++)
6950             {
6951                 GLint size = 0;
6952                 GLenum type = 0;
6953                 GLchar name[256];
6954
6955                 GL_ENTRYPOINT(glGetActiveAttrib)(program, i, sizeof(name), NULL, &size, &type, name);
6956                 pContext->peek_and_drop_gl_error();
6957
6958                 if ((!name[0]) || ((name[0] == 'g') && (name[1] == 'l') && (name[2] == '_')))
6959                     continue;
6960
6961                 GLint location = GL_ENTRYPOINT(glGetAttribLocation)(program, name);
6962                 pContext->peek_and_drop_gl_error();
6963
6964                 if (location < 0)
6965                     continue;
6966
6967                 json_node &attrib_node = attribs_object.add_object();
6968                 attrib_node.add_key_value("index", i);
6969                 attrib_node.add_key_value("name", reinterpret_cast<const char *>(name));
6970                 attrib_node.add_key_value("location", location);
6971             }
6972         }
6973
6974         // Active uniforms
6975         GLint active_uniforms = 0;
6976         GL_ENTRYPOINT(glGetProgramiv)(program, GL_ACTIVE_UNIFORMS, &active_uniforms);
6977         doc_root.add_key_value("total_active_uniforms", active_uniforms);
6978
6979         if (active_uniforms)
6980         {
6981             json_node &uniforms_object = doc_root.add_array("active_uniforms");
6982
6983             for (int i = 0; i < active_uniforms; i++)
6984             {
6985                 GLsizei length = 0;
6986                 GLint size = 0;
6987                 GLenum type = 0;
6988                 GLchar name[256];
6989
6990                 GL_ENTRYPOINT(glGetActiveUniform)(program, i, sizeof(name), &length, &size, &type, name);
6991                 pContext->peek_and_drop_gl_error();
6992
6993                 if ((!name[0]) || (!length) || ((name[0] == 'g') && (name[1] == 'l') && (name[2] == '_')))
6994                     continue;
6995
6996                 GLint location = GL_ENTRYPOINT(glGetUniformLocation)(program, name);
6997                 pContext->peek_and_drop_gl_error();
6998
6999                 if (location < 0)
7000                     continue;
7001
7002                 json_node &uniform_node = uniforms_object.add_object();
7003                 uniform_node.add_key_value("index", i);
7004                 uniform_node.add_key_value("name", reinterpret_cast<const char *>(name));
7005                 uniform_node.add_key_value("location", location);
7006                 uniform_node.add_key_value("size", size);
7007                 uniform_node.add_key_value("type", type);
7008             }
7009         }
7010
7011         // Program outputs
7012         vogl_dump_program_outputs(doc_root, pContext, program);
7013
7014         // Transform feedback
7015         GLint mode = GL_NONE;
7016         GL_ENTRYPOINT(glGetProgramiv)(program, GL_TRANSFORM_FEEDBACK_BUFFER_MODE, &mode);
7017         pContext->peek_and_drop_gl_error();
7018
7019         doc_root.add_key_value("transform_feedback_mode", g_gl_enums.find_gl_name(mode));
7020
7021         GLint num_varyings = 0;
7022         GL_ENTRYPOINT(glGetProgramiv)(program, GL_TRANSFORM_FEEDBACK_VARYINGS, &num_varyings);
7023         pContext->peek_and_drop_gl_error();
7024
7025         doc_root.add_key_value("transform_feedback_num_varyings", num_varyings);
7026
7027         if (num_varyings)
7028         {
7029             json_node &transform_feedback_varyings = doc_root.add_array("transform_feedback_varyings");
7030
7031             for (GLint i = 0; i < num_varyings; i++)
7032             {
7033                 GLchar name[512];
7034                 GLsizei length = 0, size = 0;
7035                 GLenum type = GL_NONE;
7036
7037                 GL_ENTRYPOINT(glGetTransformFeedbackVarying)(program, i, sizeof(name), &length, &size, &type, name);
7038                 pContext->peek_and_drop_gl_error();
7039
7040                 json_node &uniform_node = transform_feedback_varyings.add_object();
7041                 uniform_node.add_key_value("index", i);
7042                 uniform_node.add_key_value("name", reinterpret_cast<const char *>(name));
7043                 uniform_node.add_key_value("size", size);
7044                 uniform_node.add_key_value("type", type);
7045             }
7046         }
7047
7048         // Add JSON document to packet
7049         trace_serializer.add_key_value_json_document("metadata", doc);
7050     }
7051
7052     if (program)
7053     {
7054         if ((link_status) || (!pContext->has_linked_program_snapshot(program)))
7055         {
7056             if (id == VOGL_ENTRYPOINT_glProgramBinary)
7057             {
7058                 if (!pContext->add_linked_program_snapshot(program, binary_format, pBinary, binary_length))
7059                 {
7060                     vogl_error_printf("%s: Failed snapshotting binary program into link-time program shadow table, program 0x%X\n", VOGL_FUNCTION_NAME, program);
7061                 }
7062             }
7063             else
7064             {
7065                 if (!pContext->add_linked_program_snapshot(program))
7066                 {
7067                     vogl_error_printf("%s: Failed snapshotting program into link-time program shadow table, program 0x%X\n", VOGL_FUNCTION_NAME, program);
7068                 }
7069             }
7070         }
7071     }
7072 }
7073
7074 #define DEF_FUNCTION_CUSTOM_FUNC_PROLOG_glProgramBinary(e, c, rt, r, nu, ne, a, p) vogl_glProgramBinary_prolog(program, binaryFormat, binary, length);
7075 static inline void vogl_glProgramBinary_prolog(GLuint program, GLenum binaryFormat, const void *&pBinary, GLsizei &length)
7076 {
7077     VOGL_NOTE_UNUSED(binaryFormat);
7078
7079     if (g_disable_gl_program_binary_flag)
7080     {
7081         vogl_debug_printf("%s: Tracer is forcing a bogus program binary for program %d\n", VOGL_FUNCTION_NAME, program);
7082
7083         // These will intentionally cause the program binary to not link, forcing the application to use shader strings instead of binaries.
7084         pBinary = &g_dummy_program;
7085         length = 1;
7086     }
7087 }
7088
7089 //----------------------------------------------------------------------------------------------------------------------
7090 // glTransformFeedbackVaryings func epilog
7091 //----------------------------------------------------------------------------------------------------------------------
7092 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glTransformFeedbackVaryings(e, c, rt, r, nu, ne, a, p) \
7093     if (pContext)                                                                              \
7094         vogl_transform_feedback_varyings(pContext, trace_serializer, count, varyings);
7095 static inline void vogl_transform_feedback_varyings(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLsizei count, GLchar *const *pVaryings)
7096 {
7097     VOGL_NOTE_UNUSED(pContext);
7098
7099     if ((!count) || (!pVaryings) || (!trace_serializer.is_in_begin()))
7100         return;
7101
7102     dynamic_string varying;
7103     for (int i = 0; i < count; i++)
7104     {
7105         varying.empty();
7106         if (pVaryings[i])
7107             varying = reinterpret_cast<const char *>(pVaryings[i]);
7108
7109         trace_serializer.add_key_value(i, varying);
7110     }
7111 }
7112
7113 //----------------------------------------------------------------------------------------------------------------------
7114 // ARB program shadowing
7115 //----------------------------------------------------------------------------------------------------------------------
7116 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenProgramsARB(e, c, rt, r, nu, ne, a, p) \
7117     if (pContext)                                                                 \
7118         pContext->peek_and_record_gl_error();
7119 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenProgramsARB(e, c, rt, r, nu, ne, a, p) \
7120     if (pContext && !pContext->peek_and_record_gl_error())                        \
7121         pContext->gen_arb_programs(n, programs);
7122
7123 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteProgramsARB(e, c, rt, r, nu, ne, a, p) \
7124     if (pContext)                                                                    \
7125         pContext->peek_and_record_gl_error();
7126 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteProgramsARB(e, c, rt, r, nu, ne, a, p) \
7127     if (pContext && !pContext->peek_and_record_gl_error())                           \
7128         pContext->del_arb_programs(n, programs);
7129
7130 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindProgramARB(e, c, rt, r, nu, ne, a, p) \
7131     if (pContext)                                                                 \
7132         pContext->peek_and_record_gl_error();
7133 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindProgramARB(e, c, rt, r, nu, ne, a, p) \
7134     if (pContext && !pContext->peek_and_record_gl_error())                        \
7135         pContext->bind_arb_program(target, program);
7136
7137 //----------------------------------------------------------------------------------------------------------------------
7138 // renderbuffer shadowing
7139 //----------------------------------------------------------------------------------------------------------------------
7140 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenRenderbuffers(e, c, rt, r, nu, ne, a, p) \
7141     if (pContext)                                                                   \
7142         pContext->peek_and_record_gl_error();
7143 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenRenderbuffers(e, c, rt, r, nu, ne, a, p) \
7144     if (pContext && !pContext->peek_and_record_gl_error())                          \
7145         pContext->gen_render_buffers(n, renderbuffers);
7146
7147 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenRenderbuffersEXT(e, c, rt, r, nu, ne, a, p) \
7148     if (pContext)                                                                      \
7149         pContext->peek_and_record_gl_error();
7150 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenRenderbuffersEXT(e, c, rt, r, nu, ne, a, p) \
7151     if (pContext && !pContext->peek_and_record_gl_error())                             \
7152         pContext->gen_render_buffers(n, renderbuffers);
7153
7154 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteRenderbuffers(e, c, rt, r, nu, ne, a, p) \
7155     if (pContext)                                                                      \
7156         pContext->peek_and_record_gl_error();
7157 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteRenderbuffers(e, c, rt, r, nu, ne, a, p) \
7158     if (pContext && !pContext->peek_and_record_gl_error())                             \
7159         pContext->del_render_buffers(n, renderbuffers);
7160
7161 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteRenderbuffersEXT(e, c, rt, r, nu, ne, a, p) \
7162     if (pContext)                                                                         \
7163         pContext->peek_and_record_gl_error();
7164 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteRenderbuffersEXT(e, c, rt, r, nu, ne, a, p) \
7165     if (pContext && !pContext->peek_and_record_gl_error())                                \
7166         pContext->del_render_buffers(n, renderbuffers);
7167 //----------------------------------------------------------------------------------------------------------------------
7168 // Buffer shadowing
7169 //----------------------------------------------------------------------------------------------------------------------
7170 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenBuffers(e, c, rt, r, nu, ne, a, p) \
7171     if (pContext)                                                             \
7172         pContext->peek_and_record_gl_error();
7173 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenBuffers(e, c, rt, r, nu, ne, a, p) \
7174     if (pContext && !pContext->peek_and_record_gl_error())                    \
7175         pContext->gen_buffers(n, buffers);
7176
7177 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenBuffersARB(e, c, rt, r, nu, ne, a, p) \
7178     if (pContext)                                                                \
7179         pContext->peek_and_record_gl_error();
7180 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenBuffersARB(e, c, rt, r, nu, ne, a, p) \
7181     if (pContext && !pContext->peek_and_record_gl_error())                       \
7182         pContext->gen_buffers(n, buffers);
7183
7184 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBuffer(e, c, rt, r, nu, ne, a, p) \
7185     if (pContext)                                                             \
7186         pContext->peek_and_record_gl_error();
7187 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindBuffer(e, c, rt, r, nu, ne, a, p)                                           \
7188     if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7189         pContext->bind_buffer(target, buffer);
7190
7191 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferBase(e, c, rt, r, nu, ne, a, p) \
7192     if (pContext)                                                                 \
7193         pContext->peek_and_record_gl_error();
7194 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindBufferBase(e, c, rt, r, nu, ne, a, p)                                       \
7195     if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7196         pContext->bind_buffer(target, buffer);
7197
7198 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferBaseEXT(e, c, rt, r, nu, ne, a, p) \
7199     if (pContext)                                                                    \
7200         pContext->peek_and_record_gl_error();
7201 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindBufferBaseEXT(e, c, rt, r, nu, ne, a, p)                                    \
7202     if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7203         pContext->bind_buffer(target, buffer);
7204
7205 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferBaseNV(e, c, rt, r, nu, ne, a, p) \
7206     if (pContext)                                                                   \
7207         pContext->peek_and_record_gl_error();
7208 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindBufferBaseNV(e, c, rt, r, nu, ne, a, p)                                     \
7209     if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7210         pContext->bind_buffer(target, buffer);
7211
7212 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferRange(e, c, rt, r, nu, ne, a, p) \
7213     if (pContext)                                                                  \
7214         pContext->peek_and_record_gl_error();
7215 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindBufferRange(e, c, rt, r, nu, ne, a, p)                                      \
7216     if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7217         pContext->bind_buffer(target, buffer);
7218
7219 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferRangeEXT(e, c, rt, r, nu, ne, a, p) \
7220     if (pContext)                                                                     \
7221         pContext->peek_and_record_gl_error();
7222 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindBufferRangeEXT(e, c, rt, r, nu, ne, a, p)                                   \
7223     if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7224         pContext->bind_buffer(target, buffer);
7225
7226 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferRangeNV(e, c, rt, r, nu, ne, a, p) \
7227     if (pContext)                                                                    \
7228         pContext->peek_and_record_gl_error();
7229 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindBufferRangeNV(e, c, rt, r, nu, ne, a, p)                                    \
7230     if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7231         pContext->bind_buffer(target, buffer);
7232
7233 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferARB(e, c, rt, r, nu, ne, a, p) \
7234     if (pContext)                                                                \
7235         pContext->peek_and_record_gl_error();
7236 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindBufferARB(e, c, rt, r, nu, ne, a, p)                                        \
7237     if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7238         pContext->bind_buffer(target, buffer);
7239
7240 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteBuffers(e, c, rt, r, nu, ne, a, p) \
7241     if (pContext)                                                                \
7242         pContext->peek_and_record_gl_error();
7243 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteBuffers(e, c, rt, r, nu, ne, a, p)                                        \
7244     if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7245         pContext->delete_buffers(n, buffers);
7246
7247 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteBuffersARB(e, c, rt, r, nu, ne, a, p) \
7248     if (pContext)                                                                   \
7249         pContext->peek_and_record_gl_error();
7250 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteBuffersARB(e, c, rt, r, nu, ne, a, p)                                     \
7251     if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7252         pContext->delete_buffers(n, buffers);
7253
7254 //----------------------------------------------------------------------------------------------------------------------
7255 // Texture handle shadowing
7256 //----------------------------------------------------------------------------------------------------------------------
7257 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenTextures(e, c, rt, r, nu, ne, a, p) \
7258     if (pContext)                                                              \
7259         pContext->peek_and_record_gl_error();
7260 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenTextures(e, c, rt, r, nu, ne, a, p) \
7261     if (pContext && !pContext->peek_and_record_gl_error())                     \
7262         pContext->gen_textures(n, textures);
7263
7264 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenTexturesEXT(e, c, rt, r, nu, ne, a, p) \
7265     if (pContext)                                                                 \
7266         pContext->peek_and_record_gl_error();
7267 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenTexturesEXT(e, c, rt, r, nu, ne, a, p) \
7268     if (pContext && !pContext->peek_and_record_gl_error())                        \
7269         pContext->gen_textures(n, textures);
7270
7271 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteTextures(e, c, rt, r, nu, ne, a, p) \
7272     if (pContext)                                                                 \
7273         pContext->peek_and_record_gl_error();
7274 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteTextures(e, c, rt, r, nu, ne, a, p) \
7275     if (pContext && !pContext->peek_and_record_gl_error())                        \
7276         pContext->del_textures(n, textures);
7277
7278 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteTexturesEXT(e, c, rt, r, nu, ne, a, p) \
7279     if (pContext)                                                                    \
7280         pContext->peek_and_record_gl_error();
7281 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteTexturesEXT(e, c, rt, r, nu, ne, a, p) \
7282     if (pContext && !pContext->peek_and_record_gl_error())                           \
7283         pContext->del_textures(n, textures);
7284
7285 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindTexture(e, c, rt, r, nu, ne, a, p) \
7286     if (pContext)                                                              \
7287         pContext->peek_and_record_gl_error();
7288 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindTexture(e, c, rt, r, nu, ne, a, p)                                          \
7289     if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7290         pContext->bind_texture(target, texture);
7291
7292 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindTextureEXT(e, c, rt, r, nu, ne, a, p) \
7293     if (pContext)                                                                 \
7294         pContext->peek_and_record_gl_error();
7295 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindTextureEXT(e, c, rt, r, nu, ne, a, p)                                       \
7296     if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7297         pContext->bind_texture(target, texture);
7298
7299 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindMultiTextureEXT(e, c, rt, r, nu, ne, a, p) \
7300     if (pContext)                                                                      \
7301         pContext->peek_and_record_gl_error();
7302 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindMultiTextureEXT(e, c, rt, r, nu, ne, a, p)                                  \
7303     if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7304         pContext->bind_texture(target, texture);
7305
7306 //----------------------------------------------------------------------------------------------------------------------
7307 // Framebuffer handle shadowing
7308 //----------------------------------------------------------------------------------------------------------------------
7309 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenFramebuffers(e, c, rt, r, nu, ne, a, p) \
7310     if (pContext)                                                                  \
7311         pContext->peek_and_record_gl_error();
7312 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenFramebuffers(e, c, rt, r, nu, ne, a, p) \
7313     if (pContext && !pContext->peek_and_record_gl_error())                         \
7314         pContext->gen_framebuffers(n, framebuffers);
7315
7316 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenFramebuffersEXT(e, c, rt, r, nu, ne, a, p) \
7317     if (pContext)                                                                     \
7318         pContext->peek_and_record_gl_error();
7319 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenFramebuffersEXT(e, c, rt, r, nu, ne, a, p) \
7320     if (pContext && !pContext->peek_and_record_gl_error())                            \
7321         pContext->gen_framebuffers(n, framebuffers);
7322
7323 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteFramebuffers(e, c, rt, r, nu, ne, a, p) \
7324     if (pContext)                                                                     \
7325         pContext->peek_and_record_gl_error();
7326 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteFramebuffers(e, c, rt, r, nu, ne, a, p) \
7327     if (pContext && !pContext->peek_and_record_gl_error())                            \
7328         pContext->del_framebuffers(n, framebuffers);
7329
7330 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteFramebuffersEXT(e, c, rt, r, nu, ne, a, p) \
7331     if (pContext)                                                                        \
7332         pContext->peek_and_record_gl_error();
7333 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteFramebuffersEXT(e, c, rt, r, nu, ne, a, p) \
7334     if (pContext && !pContext->peek_and_record_gl_error())                               \
7335         pContext->del_framebuffers(n, framebuffers);
7336
7337 //----------------------------------------------------------------------------------------------------------------------
7338 // VAO handle shadowing
7339 //----------------------------------------------------------------------------------------------------------------------
7340 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenVertexArrays(e, c, rt, r, nu, ne, a, p) \
7341     if (pContext)                                                                  \
7342         pContext->peek_and_record_gl_error();
7343 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenVertexArrays(e, c, rt, r, nu, ne, a, p) \
7344     if (pContext && !pContext->peek_and_record_gl_error())                         \
7345         pContext->gen_vertexarrays(n, arrays);
7346
7347 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteVertexArrays(e, c, rt, r, nu, ne, a, p) \
7348     if (pContext)                                                                     \
7349         pContext->peek_and_record_gl_error();
7350 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteVertexArrays(e, c, rt, r, nu, ne, a, p) \
7351     if (pContext && !pContext->peek_and_record_gl_error())                            \
7352         pContext->del_vertexarrays(n, arrays);
7353
7354 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindVertexArray(e, c, rt, r, nu, ne, a, p) \
7355     if (pContext)                                                                  \
7356         pContext->peek_and_record_gl_error();
7357 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindVertexArray(e, c, rt, r, nu, ne, a, p)                                      \
7358     if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7359         pContext->bind_vertexarray(array);
7360
7361 //----------------------------------------------------------------------------------------------------------------------
7362 // Sync handle shadowing
7363 //----------------------------------------------------------------------------------------------------------------------
7364 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glFenceSync(e, c, rt, r, nu, ne, a, p) \
7365     if (pContext)                                                            \
7366         pContext->peek_and_record_gl_error();
7367 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glFenceSync(e, c, rt, r, nu, ne, a, p) \
7368     if (pContext && !pContext->peek_and_record_gl_error())                   \
7369         pContext->gen_sync(result);
7370
7371 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteSync(e, c, rt, r, nu, ne, a, p) \
7372     if (pContext)                                                             \
7373         pContext->peek_and_record_gl_error();
7374 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteSync(e, c, rt, r, nu, ne, a, p) \
7375     if (pContext && !pContext->peek_and_record_gl_error())                    \
7376         pContext->del_sync(sync);
7377
7378 //----------------------------------------------------------------------------------------------------------------------
7379 // Sampler object handle shadowing
7380 //----------------------------------------------------------------------------------------------------------------------
7381 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenSamplers(e, c, rt, r, nu, ne, a, p) \
7382     if (pContext)                                                              \
7383         pContext->peek_and_record_gl_error();
7384 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenSamplers(e, c, rt, r, nu, ne, a, p) \
7385     if (pContext && !pContext->peek_and_record_gl_error())                     \
7386         pContext->gen_samplers(count, samplers);
7387
7388 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteSamplers(e, c, rt, r, nu, ne, a, p) \
7389     if (pContext)                                                                 \
7390         pContext->peek_and_record_gl_error();
7391 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteSamplers(e, c, rt, r, nu, ne, a, p) \
7392     if (pContext && !pContext->peek_and_record_gl_error())                        \
7393         pContext->del_samplers(count, samplers);
7394
7395 //----------------------------------------------------------------------------------------------------------------------
7396 // Query handle shadowing
7397 //----------------------------------------------------------------------------------------------------------------------
7398 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenQueries(e, c, rt, r, nu, ne, a, p) \
7399     if (pContext)                                                             \
7400         pContext->peek_and_record_gl_error();
7401 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenQueries(e, c, rt, r, nu, ne, a, p) \
7402     if (pContext && !pContext->peek_and_record_gl_error())                    \
7403         pContext->gen_queries(n, ids);
7404
7405 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenQueriesARB(e, c, rt, r, nu, ne, a, p) \
7406     if (pContext)                                                                \
7407         pContext->peek_and_record_gl_error();
7408 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenQueriesARB(e, c, rt, r, nu, ne, a, p) \
7409     if (pContext && !pContext->peek_and_record_gl_error())                       \
7410         pContext->gen_queries(n, ids);
7411
7412 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteQueries(e, c, rt, r, nu, ne, a, p) \
7413     if (pContext)                                                                \
7414         pContext->peek_and_record_gl_error();
7415 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteQueries(e, c, rt, r, nu, ne, a, p) \
7416     if (pContext && !pContext->peek_and_record_gl_error())                       \
7417         pContext->del_queries(n, ids);
7418
7419 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteQueriesARB(e, c, rt, r, nu, ne, a, p) \
7420     if (pContext)                                                                   \
7421         pContext->peek_and_record_gl_error();
7422 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteQueriesARB(e, c, rt, r, nu, ne, a, p) \
7423     if (pContext && !pContext->peek_and_record_gl_error())                          \
7424         pContext->del_queries(n, ids);
7425
7426 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBeginQuery(e, c, rt, r, nu, ne, a, p) \
7427     if (pContext)                                                             \
7428         pContext->peek_and_record_gl_error();
7429 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBeginQuery(e, c, rt, r, nu, ne, a, p)                                           \
7430     if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7431         pContext->begin_query(target, id);
7432
7433 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBeginQueryARB(e, c, rt, r, nu, ne, a, p) \
7434     if (pContext)                                                                \
7435         pContext->peek_and_record_gl_error();
7436 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBeginQueryARB(e, c, rt, r, nu, ne, a, p)                                        \
7437     if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7438         pContext->begin_query(target, id);
7439
7440 //----------------------------------------------------------------------------------------------------------------------
7441 // Display list shadowing
7442 //----------------------------------------------------------------------------------------------------------------------
7443 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenLists(e, c, rt, r, nu, ne, a, p) \
7444     if (pContext)                                                           \
7445         pContext->peek_and_record_gl_error();
7446 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenLists(e, c, rt, r, nu, ne, a, p) \
7447     if (pContext && !pContext->peek_and_record_gl_error())                  \
7448         pContext->gen_lists(result, range);
7449
7450 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteLists(e, c, rt, r, nu, ne, a, p) \
7451     if (pContext)                                                              \
7452         pContext->peek_and_record_gl_error();
7453 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteLists(e, c, rt, r, nu, ne, a, p) \
7454     if (pContext && !pContext->peek_and_record_gl_error())                     \
7455         pContext->del_lists(list, range);
7456
7457 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glNewList(e, c, rt, r, nu, ne, a, p) \
7458     if (pContext)                                                          \
7459         pContext->peek_and_record_gl_error();
7460 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glNewList(e, c, rt, r, nu, ne, a, p) \
7461     if (pContext && !pContext->peek_and_record_gl_error())                 \
7462         pContext->new_list(list, mode);
7463
7464 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glEndList(e, c, rt, r, nu, ne, a, p) \
7465     if (pContext)                                                          \
7466         pContext->peek_and_record_gl_error();
7467 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glEndList(e, c, rt, r, nu, ne, a, p) \
7468     if (pContext && !pContext->peek_and_record_gl_error())                 \
7469         pContext->end_list();
7470
7471 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glXUseXFont(e, c, rt, r, nu, ne, a, p) \
7472     if (pContext)                                                            \
7473         pContext->peek_and_record_gl_error();
7474
7475 //----------------------------------------------------------------------------------------------------------------------
7476 // glBegin/glEnd shadowing
7477 //----------------------------------------------------------------------------------------------------------------------
7478 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBegin(e, c, rt, r, nu, ne, a, p) \
7479     if (pContext)                                                        \
7480         pContext->peek_and_record_gl_error();
7481 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBegin(e, c, rt, r, nu, ne, a, p) \
7482     if (pContext)                                                        \
7483         pContext->set_in_gl_begin(true);
7484
7485 //#define DEF_FUNCTION_CUSTOM_GL_PROLOG_glEnd(e, c, rt, r, nu, ne, a, p)
7486 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glEnd(e, c, rt, r, nu, ne, a, p) \
7487     if (pContext)                                                      \
7488         pContext->set_in_gl_begin(false);
7489
7490 //----------------------------------------------------------------------------------------------------------------------
7491 // Program/shader shadowing
7492 //----------------------------------------------------------------------------------------------------------------------
7493 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glCreateProgram(e, c, rt, r, nu, ne, a, p) \
7494     if (pContext)                                                                \
7495         result = pContext->handle_create_program(VOGL_ENTRYPOINT_##ne);           \
7496     else                                                                         \
7497         result = 0;
7498 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glCreateProgramObjectARB(e, c, rt, r, nu, ne, a, p) \
7499     if (pContext)                                                                         \
7500         result = pContext->handle_create_program(VOGL_ENTRYPOINT_##ne);                    \
7501     else                                                                                  \
7502         result = 0;
7503
7504 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glCreateShader(e, c, rt, r, nu, ne, a, p) \
7505     if (pContext)                                                               \
7506         result = pContext->handle_create_shader(VOGL_ENTRYPOINT_##ne, type);     \
7507     else                                                                        \
7508         result = 0;
7509 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glCreateShaderObjectARB(e, c, rt, r, nu, ne, a, p) \
7510     if (pContext)                                                                        \
7511         result = pContext->handle_create_shader(VOGL_ENTRYPOINT_##ne, shaderType);        \
7512     else                                                                                 \
7513         result = 0;
7514
7515 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glUseProgram(e, c, rt, r, nu, ne, a, p) \
7516     if (pContext)                                                             \
7517         pContext->handle_use_program(VOGL_ENTRYPOINT_##ne, program);
7518 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glUseProgramObjectARB(e, c, rt, r, nu, ne, a, p) \
7519     if (pContext)                                                                      \
7520         pContext->handle_use_program(VOGL_ENTRYPOINT_##ne, programObj);
7521
7522 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glDeleteShader(e, c, rt, r, nu, ne, a, p) \
7523     if (pContext)                                                               \
7524         pContext->handle_del_shader(VOGL_ENTRYPOINT_##ne, shader);
7525 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glDeleteProgram(e, c, rt, r, nu, ne, a, p) \
7526     if (pContext)                                                                \
7527         pContext->handle_del_program(VOGL_ENTRYPOINT_##ne, program);
7528 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glDeleteObjectARB(e, c, rt, r, nu, ne, a, p) \
7529     if (pContext)                                                                  \
7530         pContext->handle_del_object(VOGL_ENTRYPOINT_##ne, obj);
7531
7532 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glDetachShader(e, c, rt, r, nu, ne, a, p) \
7533     if (pContext)                                                               \
7534         pContext->handle_detach_shader(VOGL_ENTRYPOINT_##ne, program, shader);
7535 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glDetachObjectARB(e, c, rt, r, nu, ne, a, p) \
7536     if (pContext)                                                                  \
7537         pContext->handle_detach_shader(VOGL_ENTRYPOINT_##ne, containerObj, attachedObj);
7538
7539 //----------------------------------------------------------------------------------------------------------------------
7540 // Client side array usage detection
7541 //----------------------------------------------------------------------------------------------------------------------
7542 #define VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE                              \
7543     if ((!g_disable_client_side_array_tracing) && (pContext) && (pointer)) \
7544         vogl_check_for_client_side_array_usage(pContext, pointer);
7545 static inline void vogl_check_for_client_side_array_usage(vogl_context *pContext, const void *pPointer)
7546 {
7547     VOGL_NOTE_UNUSED(pPointer);
7548
7549     if (pContext->get_uses_client_side_arrays() || pContext->is_core_profile())
7550         return;
7551
7552     pContext->peek_and_record_gl_error();
7553
7554     GLint cur_array_buf_binding = 0;
7555     GL_ENTRYPOINT(glGetIntegerv)(GL_ARRAY_BUFFER_BINDING, &cur_array_buf_binding);
7556
7557     if (pContext->peek_and_drop_gl_error() == GL_NO_ERROR)
7558     {
7559         if (!cur_array_buf_binding)
7560         {
7561             pContext->set_uses_client_side_arrays(true);
7562             vogl_warning_printf("%s: Client side array usage has been detected, this will negatively impact tracing performance, use --vogl_disable_client_side_array_tracing to disable\n", VOGL_FUNCTION_NAME);
7563         }
7564     }
7565 }
7566
7567 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7568 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glNormalPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7569 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glColorPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7570 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glIndexPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7571 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glTexCoordPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7572 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glEdgeFlagPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7573 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glFogCoordPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7574 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glSecondaryColorPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7575 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glInterleavedArrays(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7576 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7577 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glNormalPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7578 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glColorPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7579 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glIndexPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7580 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glTexCoordPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7581 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glEdgeFlagPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7582 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glFogCoordPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7583 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glSecondaryColorPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7584 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexAttribPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7585 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexAttribPointerARB(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7586 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexAttribPointerNV(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7587 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexAttribIPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7588 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexAttribIPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7589 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexAttribLPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7590 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexAttribLPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7591
7592 //----------------------------------------------------------------------------------------------------------------------
7593 // glXUseXFont shadowing
7594 //----------------------------------------------------------------------------------------------------------------------
7595 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glXUseXFont(e, c, rt, r, nu, ne, a, p) vogl_glx_use_xfont_epilog_helper(pContext, trace_serializer, font, first, count, list_base);
7596 static void vogl_glx_use_xfont_epilog_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, Font font, int first, int count, int list_base)
7597 {
7598     if (!pContext)
7599         return;
7600
7601     if (pContext->peek_and_record_gl_error())
7602         return;
7603
7604     char *pFont = NULL;
7605
7606     if (pContext->get_display())
7607     {
7608         XFontStruct *pFont_struct = XQueryFont((Display *)pContext->get_display(), font);
7609
7610         if (pFont_struct)
7611         {
7612             unsigned long value = 0;
7613             Bool result = XGetFontProperty(pFont_struct, XA_FONT, &value);
7614             if (result)
7615             {
7616                 pFont = (char *)XGetAtomName((Display *)pContext->get_display(), (Atom)value);
7617                 if ((pFont) && (trace_serializer.is_in_begin()))
7618                 {
7619                     trace_serializer.add_key_value("font_name", pFont);
7620                 }
7621             }
7622         }
7623
7624         XFreeFontInfo(NULL, pFont_struct, 1);
7625     }
7626
7627     pContext->glx_font(pFont, first, count, list_base);
7628 }
7629
7630 //----------------------------------------------------------------------------------------------------------------------
7631 // vogl_display_list_bind_callback
7632 //----------------------------------------------------------------------------------------------------------------------
7633 static void vogl_display_list_bind_callback(vogl_namespace_t handle_namespace, GLenum target, GLuint handle, void *pOpaque)
7634 {
7635     vogl_context *pContext = static_cast<vogl_context *>(pOpaque);
7636
7637     // TODO: We don't whitelist anything but texture binds in display lists currently.
7638     switch (handle_namespace)
7639     {
7640         case VOGL_NAMESPACE_TEXTURES:
7641         {
7642             if ((handle) && (target != GL_NONE))
7643                 pContext->bind_texture_conditionally(target, handle);
7644             break;
7645         }
7646         default:
7647         {
7648             vogl_warning_printf("%s: TODO: Unsupported bind in display list, namespace %s target %s handle %u\n", VOGL_FUNCTION_NAME, vogl_get_namespace_name(handle_namespace), g_gl_enums.find_gl_name(target), handle);
7649             break;
7650         }
7651     }
7652 }
7653
7654 //----------------------------------------------------------------------------------------------------------------------
7655 // glCallList shadowing
7656 //----------------------------------------------------------------------------------------------------------------------
7657 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glCallList(e, c, rt, r, nu, ne, a, p) \
7658     if (pContext)                                                           \
7659         pContext->peek_and_record_gl_error();
7660 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glCallList(e, c, rt, r, nu, ne, a, p) \
7661     if (pContext && !pContext->peek_and_record_gl_error())                  \
7662         vogl_gl_call_list_helper(pContext, list);
7663 static void vogl_gl_call_list_helper(vogl_context *pContext, GLuint list)
7664 {
7665     if (!pContext)
7666         return;
7667
7668     pContext->parse_list_and_update_shadows(list, vogl_display_list_bind_callback, pContext);
7669 }
7670
7671 //----------------------------------------------------------------------------------------------------------------------
7672 // glCallLists shadowing
7673 //----------------------------------------------------------------------------------------------------------------------
7674 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glCallLists(e, c, rt, r, nu, ne, a, p) \
7675     if (pContext)                                                            \
7676         pContext->peek_and_record_gl_error();
7677 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glCallLists(e, c, rt, r, nu, ne, a, p) \
7678     if (pContext && !pContext->peek_and_record_gl_error())                   \
7679         vogl_gl_call_lists_helper(pContext, n, type, lists);
7680 static void vogl_gl_call_lists_helper(vogl_context *pContext, GLsizei n, GLenum type, const GLvoid *lists)
7681 {
7682     if (!pContext)
7683         return;
7684
7685     vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
7686     VOGL_NOTE_UNUSED(gl_error_absorber);
7687
7688     pContext->parse_lists_and_update_shadows(n, type, lists, vogl_display_list_bind_callback, pContext);
7689 }
7690
7691 //----------------------------------------------------------------------------------------------------------------------
7692 // Ensure all entrypoints are fully serializable
7693 // This function MUST appear before #include "gl_glx_array_size_macros.inc", below
7694 //----------------------------------------------------------------------------------------------------------------------
7695 static void vogl_check_entrypoints()
7696 {
7697     vogl_debug_printf("vogl_check_entrypoints: begin (specify --vogl_debug for more validation)\n");
7698
7699     typedef vogl::hash_map<uint, dynamic_string> array_size_macro_hashmap;
7700     array_size_macro_hashmap defined_array_size_macros;
7701     array_size_macro_hashmap undefined_array_size_macros;
7702
7703 #define CUSTOM_FUNC_HANDLER_DEFINED(id) g_vogl_entrypoint_descs[id].m_has_custom_func_handler = true; //printf("%u %s\n", id, g_vogl_entrypoint_descs[id].m_pName);
7704 #define CUSTOM_FUNC_HANDLER_NOT_DEFINED(id)
7705 #include "gl_glx_custom_func_handler_validator.inc"
7706 #undef CUSTOM_FUNC_HANDLER_DEFINED
7707 #undef CUSTOM_FUNC_HANDLER_NOT_DEFINED
7708
7709 #define VALIDATE_ARRAY_SIZE_MACRO_DEFINED(name, index) defined_array_size_macros.insert(index, #name);
7710 #define VALIDATE_ARRAY_SIZE_MACRO_NOT_DEFINED(name, index) undefined_array_size_macros.insert(index, #name);
7711 #include "gl_glx_array_size_macros_validator.inc"
7712 #undef VALIDATE_ARRAY_SIZE_MACRO_DEFINED
7713 #undef VALIDATE_ARRAY_SIZE_MACRO_NOT_DEFINED
7714
7715     vogl::vector<uint> undefined_func_return_array_size_macros;
7716
7717 #define CUSTOM_FUNC_RETURN_PARAM_ARRAY_SIZE_HANDLER_DEFINED(macro_name, func_name)
7718 #define CUSTOM_FUNC_RETURN_PARAM_ARRAY_SIZE_HANDLER_NOT_DEFINED(macro_name, func_name) g_vogl_entrypoint_descs[VOGL_ENTRYPOINT_##func_name].m_custom_return_param_array_size_macro_is_missing = true;
7719 #include "gl_glx_custom_return_param_array_size_macro_validator.inc"
7720 #undef CUSTOM_FUNC_RETURN_PARAM_ARRAY_SIZE_HANDLER_DEFINED
7721 #undef CUSTOM_FUNC_RETURN_PARAM_ARRAY_SIZE_HANDLER_NOT_DEFINED
7722
7723     if (vogl::check_for_command_line_param("--vogl_debug"))
7724     {
7725         for (array_size_macro_hashmap::const_iterator it = undefined_array_size_macros.begin(); it != undefined_array_size_macros.end(); ++it)
7726         {
7727             uint idx = it->first;
7728             const dynamic_string &name = it->second;
7729             VOGL_NOTE_UNUSED(name);
7730
7731             gl_entrypoint_id_t func = static_cast<gl_entrypoint_id_t>(idx >> 16);
7732             uint param = idx & 0xFFFF;
7733
7734             vogl_warning_printf("%s: Custom array size macro for func %u \"%s\" param %u has not been defined, this function cannot be traced\n",
7735                                VOGL_FUNCTION_NAME, func, g_vogl_entrypoint_descs[func].m_pName, param);
7736
7737             g_vogl_entrypoint_param_descs[func][param].m_custom_array_size_macro_is_missing = true;
7738             g_vogl_entrypoint_descs[func].m_custom_array_size_macro_is_missing = true;
7739         }
7740
7741         vogl_debug_printf("Undefined array size macros:\n");
7742         vogl_debug_printf("---\n");
7743         for (array_size_macro_hashmap::const_iterator it = undefined_array_size_macros.begin(); it != undefined_array_size_macros.end(); ++it)
7744         {
7745             const dynamic_string &name = it->second;
7746             vogl_debug_printf("%s\n", name.get_ptr());
7747         }
7748         vogl_debug_printf("---\n");
7749
7750         vogl_debug_printf("Undefined return param array size macros:\n");
7751         vogl_debug_printf("---\n");
7752         for (uint i = 0; i < VOGL_NUM_ENTRYPOINTS; i++)
7753         {
7754             vogl_ctype_t return_ctype = g_vogl_entrypoint_descs[i].m_return_ctype;
7755
7756             if (return_ctype == VOGL_VOID)
7757                 continue;
7758             if (!g_vogl_process_gl_ctypes[return_ctype].m_is_pointer)
7759                 continue;
7760             //if (g_vogl_process_gl_ctypes[return_ctype].m_is_opaque_pointer)
7761             //  continue;
7762
7763             if (g_vogl_entrypoint_descs[i].m_custom_return_param_array_size_macro_is_missing)
7764             {
7765                 vogl_debug_printf("%s, opaque_ptr: %u\n", g_vogl_entrypoint_descs[i].m_pName, g_vogl_process_gl_ctypes[return_ctype].m_is_opaque_pointer);
7766             }
7767
7768             if (g_vogl_entrypoint_descs[i].m_whitelisted_for_displaylists)
7769             {
7770                 if (!g_vogl_entrypoint_descs[i].m_is_listable)
7771                 {
7772                     vogl_debug_printf("Function %s is marked as whitelistable in display lists, but is not a listable function!\n", g_vogl_entrypoint_descs[i].m_pName);
7773                 }
7774             }
7775         }
7776         vogl_debug_printf("---\n");
7777
7778         vogl_debug_printf("Whitelisted funcs with undefined array size macros:\n");
7779         vogl_debug_printf("---\n");
7780         for (uint i = 0; i < VOGL_NUM_ENTRYPOINTS; i++)
7781         {
7782             const gl_entrypoint_desc_t &desc = g_vogl_entrypoint_descs[i];
7783             if ((!desc.m_is_whitelisted) || (desc.m_has_custom_func_handler))
7784                 continue;
7785
7786             if (desc.m_custom_array_size_macro_is_missing)
7787                 vogl_debug_printf("%s\n", desc.m_pName);
7788         }
7789         vogl_debug_printf("---\n");
7790
7791         vogl_debug_printf("Whitelisted funcs with undefined return param array size macros:\n");
7792         vogl_debug_printf("---\n");
7793         for (uint i = 0; i < VOGL_NUM_ENTRYPOINTS; i++)
7794         {
7795             const gl_entrypoint_desc_t &desc = g_vogl_entrypoint_descs[i];
7796             if (desc.m_is_whitelisted)
7797                 continue;
7798
7799             vogl_ctype_t return_ctype = g_vogl_entrypoint_descs[i].m_return_ctype;
7800
7801             if (return_ctype == VOGL_VOID)
7802                 continue;
7803             if (!g_vogl_process_gl_ctypes[return_ctype].m_is_pointer)
7804                 continue;
7805             if (g_vogl_process_gl_ctypes[return_ctype].m_is_opaque_pointer)
7806                 continue;
7807
7808             if (g_vogl_entrypoint_descs[i].m_custom_return_param_array_size_macro_is_missing)
7809             {
7810                 vogl_debug_printf("%s\n", g_vogl_entrypoint_descs[i].m_pName);
7811             }
7812         }
7813
7814         vogl_debug_printf("---\n");
7815     }
7816
7817     vogl_debug_printf("vogl_check_entrypoints: done\n");
7818 }
7819
7820 //----------------------------------------------------------------------------------------------------------------------
7821 // Include generated macros to define the internal entrypoint funcs
7822 //----------------------------------------------------------------------------------------------------------------------
7823 #include "gl_glx_array_size_macros.inc"
7824 #include "gl_glx_func_return_param_array_size_macros.inc"
7825 #include "gl_glx_func_defs.inc"
7826
7827 #ifndef NO_PUBLIC_EXPORTS
7828 //----------------------------------------------------------------------------------------------------------------------
7829 // Declare exported gl/glx functions (each exported func immediately calls one of the internal vogl_* functions)
7830 //----------------------------------------------------------------------------------------------------------------------
7831 #define DEF_PROTO_EXPORTED(ret, name, args, params) \
7832     VOGL_API_EXPORT ret name args                    \
7833     {                                               \
7834         return VOGL_GLUER(vogl_, name) params;     \
7835     }
7836 #define DEF_PROTO_EXPORTED_VOID(ret, name, args, params) \
7837     VOGL_API_EXPORT ret name args                         \
7838     {                                                    \
7839         VOGL_GLUER(vogl_, name) params;                 \
7840     }
7841 #define DEF_PROTO_INTERNAL(ret, name, args, params)
7842 #define DEF_PROTO_INTERNAL_VOID(ret, name, args, params)
7843 #define DEF_FUNCTION_BEGIN(exported, category, ret, ret_type_enum, num_params, name, args, params) exported(ret, name, args, params)
7844 #define DEF_FUNCTION_BEGIN_VOID(exported, category, ret, ret_type_enum, num_params, name, args, params) exported(ret, name, args, params)
7845 #define DEF_FUNCTION_INIT(exported, category, ret, ret_type_enum, num_params, name, args, params)
7846 #define DEF_FUNCTION_INIT_VOID(exported, category, ret, ret_type_enum, num_params, name, args, params)
7847 #define DEF_FUNCTION_INPUT_VALUE_PARAM(idx, spectype, type, type_enum, param)
7848 #define DEF_FUNCTION_INPUT_REFERENCE_PARAM(idx, spectype, type, type_enum, param)
7849 #define DEF_FUNCTION_INPUT_ARRAY_PARAM(idx, spectype, type, type_enum, param, size)
7850 #define DEF_FUNCTION_OUTPUT_REFERENCE_PARAM(idx, spectype, type, type_enum, param)
7851 #define DEF_FUNCTION_OUTPUT_ARRAY_PARAM(idx, spectype, type, type_enum, param, size)
7852 #define DEF_FUNCTION_RETURN_PARAM(spectype, type, type_enum, size)
7853 #define DEF_FUNCTION_CALL_GL(exported, category, ret, ret_type_enum, num_params, name, args, params)
7854 #define DEF_FUNCTION_CALL_GL_VOID(exported, category, ret, ret_type_enum, num_params, name, args, params)
7855 #define DEF_FUNCTION_END(exported, category, ret, ret_type_enum, num_params, name, args, params)
7856 #define DEF_FUNCTION_END_VOID(exported, category, ret, ret_type_enum, num_params, name, args, params)
7857 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_GL_ENUM(pname) -1
7858
7859 #include "gl_glx_array_size_macros.inc"
7860 #include "gl_glx_func_defs.inc"
7861 #endif
7862
7863 //----------------------------------------------------------------------------------------------------------------------
7864 // Define our exported gliGetProcAddressRAD function
7865 //----------------------------------------------------------------------------------------------------------------------
7866 VOGL_API_EXPORT __GLXextFuncPtr gliGetProcAddressRAD(const GLubyte *procName)
7867 {
7868     if ((procName) && (!vogl_strcmp(reinterpret_cast<const char *>(procName), "gliGetProcAddressRAD")))
7869         return (__GLXextFuncPtr)gliGetProcAddressRAD;
7870
7871     return vogl_glXGetProcAddressARB(procName);
7872 }
7873
7874 //----------------------------------------------------------------------------------------------------------------------
7875 // Determine addresses of our gl/glx wrapper functions
7876 //----------------------------------------------------------------------------------------------------------------------
7877 static void vogl_init_wrapper_func_ptrs()
7878 {
7879     gl_entrypoint_desc_t *pDst = g_vogl_entrypoint_descs;
7880
7881 #define DEF_PROTO(exported, category, ret, ret_type, num_params, name, args, params) \
7882     pDst->m_pWrapper_func = reinterpret_cast<vogl_void_func_ptr_t>(vogl_##name);       \
7883     ++pDst;
7884 #define DEF_PROTO_VOID(exported, category, ret, ret_type, num_params, name, args, params) \
7885     pDst->m_pWrapper_func = reinterpret_cast<vogl_void_func_ptr_t>(vogl_##name);            \
7886     ++pDst;
7887 #include "gl_glx_protos.inc"
7888 #undef DEF_PROTO
7889 #undef DEF_PROTO_VOID
7890 }
7891
7892 //----------------------------------------------------------------------------------------------------------------------
7893 // vogl_direct_gl_func_prolog - This function is called before EVERY single GL/GLX function call we make.
7894 //----------------------------------------------------------------------------------------------------------------------
7895 static void vogl_direct_gl_func_prolog(gl_entrypoint_id_t entrypoint_id, void *pUser_data, void **ppStack_data)
7896 {
7897     VOGL_NOTE_UNUSED(entrypoint_id);
7898     VOGL_NOTE_UNUSED(pUser_data);
7899
7900     if (g_dump_gl_calls_flag)
7901         printf("** GLPROLOG %s\n", g_vogl_entrypoint_descs[entrypoint_id].m_pName);
7902
7903     gl_entrypoint_id_t *pPrev_state = reinterpret_cast<gl_entrypoint_id_t *>(ppStack_data);
7904     *pPrev_state = VOGL_ENTRYPOINT_INVALID;
7905
7906     vogl_thread_local_data *pTLS_data = vogl_get_or_create_thread_local_data();
7907     if (pTLS_data)
7908     {
7909         *pPrev_state = pTLS_data->m_calling_driver_entrypoint_id;
7910         pTLS_data->m_calling_driver_entrypoint_id = entrypoint_id;
7911     }
7912 }
7913
7914 //----------------------------------------------------------------------------------------------------------------------
7915 // vogl_direct_gl_func_epilog - This function is called immediately after EVERY single GL/GLX function call we make.
7916 //----------------------------------------------------------------------------------------------------------------------
7917 static void vogl_direct_gl_func_epilog(gl_entrypoint_id_t entrypoint_id, void *pUser_data, void **ppStack_data)
7918 {
7919     VOGL_NOTE_UNUSED(entrypoint_id);
7920     VOGL_NOTE_UNUSED(pUser_data);
7921
7922 #if 0
7923     if (entrypoint_id == VOGL_ENTRYPOINT_glXMakeCurrent)
7924         {
7925                 // HACK HACK - crude test of the "calling driver entrypoint code"
7926                 glXGetCurrentContext();
7927         }
7928 #endif
7929
7930     if (g_dump_gl_calls_flag)
7931         printf("** GLEPILOG %s\n", g_vogl_entrypoint_descs[entrypoint_id].m_pName);
7932
7933     gl_entrypoint_id_t *pPrev_state = reinterpret_cast<gl_entrypoint_id_t *>(ppStack_data);
7934
7935     vogl_thread_local_data *pTLS_data = vogl_get_or_create_thread_local_data();
7936     if (pTLS_data)
7937     {
7938         pTLS_data->m_calling_driver_entrypoint_id = *pPrev_state;
7939     }
7940 }
7941
7942 //----------------------------------------------------------------------------------------------------------------------
7943 // Initialization
7944 // Note: Be VERY careful what you do in here! It's called very early during init (long before main, during c++ init)
7945 //----------------------------------------------------------------------------------------------------------------------
7946 void vogl_early_init()
7947 {
7948     vogl_init_thread_local_data();
7949
7950     vogl_set_direct_gl_func_prolog(vogl_direct_gl_func_prolog, NULL);
7951     vogl_set_direct_gl_func_epilog(vogl_direct_gl_func_epilog, NULL);
7952
7953     vogl_init_wrapper_func_ptrs();
7954
7955     vogl_check_entrypoints();
7956 }