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