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