1 /**************************************************************************
3 * Copyright 2013-2014 RAD Game Tools and Valve Software
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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
24 **************************************************************************/
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"
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"
48 #include <sys/syscall.h>
50 #include <X11/Xatom.h>
53 #include "vogl_remote.h"
56 #define MINIZ_NO_ZLIB_COMPATIBLE_NAMES
57 #include "vogl_miniz.h"
62 #include "TypeTraits.h"
64 #include <turbojpeg.h>
66 #define VOGL_INTERCEPT_TRACE_FILE_VERSION 0x0102
68 #define VOGL_STOP_CAPTURE_FILENAME "__stop_capture__"
69 #define VOGL_TRIGGER_CAPTURE_FILENAME "__trigger_capture__"
71 #define VOGL_CMD_LINE_OPTIONS_FILE "vogl_cmd_line.txt"
73 #define VOGL_BACKTRACE_HASHMAP_CAPACITY 50000
76 class vogl_entrypoint_serializer;
78 //----------------------------------------------------------------------------------------------------------------------
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;
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();
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();
102 class vogl_scoped_context_shadow_lock
107 inline vogl_scoped_context_shadow_lock()
108 : m_took_lock(g_app_uses_sharelists)
111 vogl_context_shadow_lock();
114 inline ~vogl_scoped_context_shadow_lock()
117 vogl_context_shadow_unlock();
121 //----------------------------------------------------------------------------------------------------------------------
122 // Command line params
123 //----------------------------------------------------------------------------------------------------------------------
124 static command_line_param_desc g_command_line_param_descs[] =
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 },
160 //----------------------------------------------------------------------------------------------------------------------
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;
168 bool g_backtrace_all_calls;
169 static bool g_disable_client_side_array_tracing;
171 static bool g_flush_files_after_each_call;
172 static bool g_flush_files_after_each_swap;
173 static bool g_gather_statistics;
175 static vogl_trace_file_writer g_vogl_trace_writer(&g_vogl_process_gl_ctypes);
176 static mutex g_vogl_trace_mutex(0, true);
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;
185 static vogl_backtrace_hashmap g_backtrace_hashmap;
186 static mutex g_backtrace_hashmap_mutex(0, false);
188 //----------------------------------------------------------------------------------------------------------------------
189 // vogl_get_current_kernel_thread_id
190 //----------------------------------------------------------------------------------------------------------------------
191 static inline uint64_t vogl_get_current_kernel_thread_id()
193 return static_cast<uint64_t>(syscall(SYS_gettid));
196 //----------------------------------------------------------------------------------------------------------------------
197 // class vogl_entrypoint_serializer
198 //----------------------------------------------------------------------------------------------------------------------
199 class vogl_entrypoint_serializer
201 VOGL_NO_COPY_OR_ASSIGNMENT_OP(vogl_entrypoint_serializer);
204 inline vogl_entrypoint_serializer()
205 : m_packet(&g_vogl_process_gl_ctypes),
210 inline vogl_entrypoint_serializer(gl_entrypoint_id_t id, vogl_context *pContext)
211 : m_packet(&g_vogl_process_gl_ctypes),
217 const vogl_trace_packet &get_packet() const
221 vogl_trace_packet &get_packet()
226 // begin()/end() is NOT nestable
227 // Returns false if nesting detected
228 bool begin(gl_entrypoint_id_t id, vogl_context *pContext);
230 void set_begin_rdtsc(uint64_t val)
232 m_packet.set_begin_rdtsc(val);
235 bool is_in_begin() const
240 inline gl_entrypoint_id_t get_cur_entrypoint() const
242 return m_packet.get_entrypoint_id();
245 inline void add_return_param(vogl_ctype_t ctype, const void *pParam, uint param_size)
247 VOGL_ASSERT(m_in_begin);
248 m_packet.set_return_param(ctype, pParam, param_size);
251 inline void add_param(uint8_t param_id, vogl_ctype_t ctype, const void *pParam, uint param_size)
253 VOGL_ASSERT(m_in_begin);
254 m_packet.set_param(param_id, ctype, pParam, param_size);
257 inline void add_ref_client_memory(uint8_t param_id, vogl_ctype_t pointee_ctype, const void *pData, uint64_t data_size)
259 VOGL_ASSERT(m_in_begin);
260 m_packet.set_ref_client_memory(param_id, pointee_ctype, pData, data_size);
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)
265 VOGL_ASSERT(m_in_begin);
266 m_packet.set_array_client_memory(param_id, pointee_ctype, array_size, pData, data_size);
269 inline bool add_key_value(const value &key, const value &value)
271 VOGL_ASSERT(m_in_begin);
272 return m_packet.set_key_value(key, value);
275 inline bool add_key_value_blob(const value &key, uint8_vec &blob)
277 VOGL_ASSERT(m_in_begin);
278 return m_packet.set_key_value(key, blob);
281 inline bool add_key_value_blob(const value &key, const void *pData, uint data_size)
283 VOGL_ASSERT(m_in_begin);
284 return m_packet.set_key_value_blob(key, pData, data_size);
287 inline bool add_key_value_json_document(const value &key, const json_document &doc)
289 VOGL_ASSERT(m_in_begin);
290 return m_packet.set_key_value_json_document(key, doc);
293 inline const key_value_map &get_key_value_map() const
295 VOGL_ASSERT(m_in_begin);
296 return m_packet.get_key_value_map();
298 inline key_value_map &get_key_value_map()
300 VOGL_ASSERT(m_in_begin);
301 return m_packet.get_key_value_map();
304 inline void set_gl_begin_rdtsc(uint64_t val)
306 m_packet.set_gl_begin_rdtsc(val);
308 inline void set_gl_end_rdtsc(uint64_t val)
310 m_packet.set_gl_end_rdtsc(val);
312 inline void set_gl_begin_end_rdtsc(uint64_t begin, uint64_t end)
314 m_packet.set_gl_begin_rdtsc(begin);
315 m_packet.set_gl_end_rdtsc(end);
320 VOGL_ASSERT(m_in_begin);
324 vogl_error_printf("%s: end() called without a matching call to begin()! Something is seriously wrong!\n", VOGL_METHOD_NAME);
328 m_packet.end_construction(utils::RDTSC());
330 VOGL_ASSERT(m_packet.check());
332 const gl_entrypoint_desc_t &entrypoint_desc = g_vogl_entrypoint_descs[get_cur_entrypoint()];
334 if (m_packet.total_params() != entrypoint_desc.m_num_params)
336 vogl_error_printf("%s: Unexpected number of params passed to serializer! (entrypoint id %u)\n", VOGL_METHOD_NAME, get_cur_entrypoint());
341 if (m_packet.has_return_value() != (entrypoint_desc.m_return_ctype != VOGL_VOID))
343 vogl_error_printf("%s: Return parameter serialization error (entrypoint id %u)!\n", VOGL_METHOD_NAME, get_cur_entrypoint());
352 vogl_trace_packet m_packet;
356 //----------------------------------------------------------------------------------------------------------------------
357 // struct vogl_thread_local_data
358 //----------------------------------------------------------------------------------------------------------------------
359 class vogl_thread_local_data
362 vogl_thread_local_data()
364 m_calling_driver_entrypoint_id(VOGL_ENTRYPOINT_INVALID)
368 ~vogl_thread_local_data()
373 vogl_context *m_pContext;
374 vogl_entrypoint_serializer m_serializer;
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;
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()
386 vogl_thread_local_data *pTLS_data = static_cast<vogl_thread_local_data *>(pthread_getspecific(g_vogl_thread_local_data));
389 pTLS_data = vogl_new(vogl_thread_local_data);
391 pthread_setspecific(g_vogl_thread_local_data, pTLS_data);
397 //----------------------------------------------------------------------------------------------------------------------
398 // vogl_get_thread_local_data
399 //----------------------------------------------------------------------------------------------------------------------
400 static VOGL_FORCE_INLINE vogl_thread_local_data *vogl_get_thread_local_data()
402 return static_cast<vogl_thread_local_data *>(pthread_getspecific(g_vogl_thread_local_data));
405 //----------------------------------------------------------------------------------------------------------------------
406 // tls_thread_local_data_destructor
407 //----------------------------------------------------------------------------------------------------------------------
408 static void vogl_thread_local_data_destructor(void *pValue)
410 vogl_delete(static_cast<vogl_thread_local_data *>(pValue));
412 pthread_setspecific(g_vogl_thread_local_data, NULL);
415 //----------------------------------------------------------------------------------------------------------------------
416 // vogl_init_thread_local_data
417 //----------------------------------------------------------------------------------------------------------------------
418 static void vogl_init_thread_local_data()
420 int rc = pthread_key_create(&g_vogl_thread_local_data, vogl_thread_local_data_destructor);
423 vogl_error_printf("%s: pthread_key_create failed!\n", VOGL_FUNCTION_NAME);
428 //----------------------------------------------------------------------------------------------------------------------
430 //----------------------------------------------------------------------------------------------------------------------
431 static void vogl_init_logfile()
435 dynamic_string backbuffer_hash_file;
436 if (g_command_line_params.get_value_as_string(backbuffer_hash_file, "vogl_dump_backbuffer_hashes"))
438 remove(backbuffer_hash_file.get_ptr());
439 vogl_message_printf("Deleted backbuffer hash file \"%s\"\n", backbuffer_hash_file.get_ptr());
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())
447 dynamic_string filename(log_file_append.is_empty() ? log_file : log_file_append);
449 // This purposely leaks, don't care
450 g_vogl_pLog_stream = vogl_new(cfile_stream);
452 if (!g_vogl_pLog_stream->open(filename.get_ptr(), cDataStreamWritable, !log_file_append.is_empty()))
454 vogl_error_printf("%s: Failed opening log file \"%s\"\n", VOGL_FUNCTION_NAME, filename.get_ptr());
456 vogl_delete(g_vogl_pLog_stream);
457 g_vogl_pLog_stream = NULL;
463 vogl_message_printf("Opened log file \"%s\"\n", filename.get_ptr());
465 console::set_log_stream(g_vogl_pLog_stream);
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)
476 vogl_error_printf("%s: total_frames cannot be 0\n", VOGL_FUNCTION_NAME);
480 scoped_mutex lock(g_vogl_trace_mutex);
482 if ((!g_vogl_frames_remaining_to_capture) && (!g_vogl_trace_writer.is_opened()))
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;
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);
496 vogl_error_printf("%s: Cannot trigger capturing while a trace is currently in progress\n", VOGL_FUNCTION_NAME);
503 //----------------------------------------------------------------------------------------------------------------------
504 // vogl_stop_capturing
505 //----------------------------------------------------------------------------------------------------------------------
506 bool vogl_stop_capturing()
508 scoped_mutex lock(g_vogl_trace_mutex);
510 if (!g_vogl_trace_writer.is_opened())
512 vogl_error_printf("%s: Tracing is not active!\n", VOGL_FUNCTION_NAME);
516 g_vogl_stop_capturing = true;
518 vogl_debug_printf("%s: Closing trace immediately after next swap\n", VOGL_FUNCTION_NAME);
523 //----------------------------------------------------------------------------------------------------------------------
524 // vogl_stop_capturing
525 //----------------------------------------------------------------------------------------------------------------------
526 bool vogl_stop_capturing(vogl_capture_status_callback_func_ptr pStatus_callback, void *pStatus_callback_opaque)
528 scoped_mutex lock(g_vogl_trace_mutex);
530 if (!g_vogl_trace_writer.is_opened())
532 vogl_error_printf("%s: Tracing is not active!\n", VOGL_FUNCTION_NAME);
536 g_vogl_stop_capturing = true;
537 g_vogl_pCapture_status_callback = pStatus_callback;
538 g_vogl_pCapture_status_opaque = pStatus_callback_opaque;
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);
546 //----------------------------------------------------------------------------------------------------------------------
548 //----------------------------------------------------------------------------------------------------------------------
549 bool vogl_is_capturing()
551 scoped_mutex lock(g_vogl_trace_mutex);
553 return g_vogl_trace_writer.is_opened();
556 //----------------------------------------------------------------------------------------------------------------------
557 // vogl_dump_statistics
558 //----------------------------------------------------------------------------------------------------------------------
559 static void vogl_dump_statistics()
561 for (uint i = 0; i < VOGL_NUM_ENTRYPOINTS; i++)
563 if ((!g_vogl_entrypoint_descs[i].m_is_whitelisted) && (g_vogl_entrypoint_descs[i].m_trace_call_counter))
565 vogl_error_printf("A non-whitelisted function was called during tracing: %s\n", g_vogl_entrypoint_descs[i].m_pName);
570 //----------------------------------------------------------------------------------------------------------------------
572 //----------------------------------------------------------------------------------------------------------------------
577 static bool s_already_deinitialized;
578 if (s_already_deinitialized)
580 s_already_deinitialized = true;
585 vogl_dump_statistics();
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()
597 fprintf(stderr, "(vogltrace) Flushing log and closing trace files. Note any outstanding async buffer readbacks (for screen capturing) cannot be safely flushed!\n");
599 vogl_end_capture(true);
601 //uint num_contexts = g_context_manager.get_context_map().size();
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);
605 if (g_vogl_pLog_stream)
606 g_vogl_pLog_stream->flush();
608 if (g_vogl_pPrev_exception_callback)
610 fprintf(stderr, "Calling prev handler\n");
611 (*g_vogl_pPrev_exception_callback)();
615 //----------------------------------------------------------------------------------------------------------------------
616 // vogl_init_command_line_params
617 //----------------------------------------------------------------------------------------------------------------------
618 static void vogl_init_command_line_params()
622 float sleep_time = g_command_line_params.get_value_as_float("vogl_sleep_at_startup");
623 if (sleep_time > 0.0f)
625 vogl_sleep(static_cast<uint>(ceil(1000.0f * sleep_time)));
628 dynamic_string_array cmd_line_params;
629 char *pEnv_cmd_line = getenv("VOGL_CMD_LINE");
632 console::message("Reading command line params from env var\n");
634 dynamic_string cmd_line(pEnv_cmd_line);
637 console::message("VOGL_CMD_LINE: %s\n", cmd_line.get_ptr());
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);
642 else if (file_utils::does_file_exist(VOGL_CMD_LINE_OPTIONS_FILE))
644 console::message("Reading command line params from file \"%s\"\n", VOGL_CMD_LINE_OPTIONS_FILE);
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))
649 console::error("Failed reading command line params from options file \"%s\"\n", VOGL_CMD_LINE_OPTIONS_FILE);
653 dynamic_string all_opts;
654 for (uint i = 0; i < opts.size(); i++)
655 all_opts.format_append("%s ", opts[i].get_ptr());
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);
663 console::message("Trying to use app's command line options\n");
665 cmd_line_params = get_command_line_params();
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_";
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))
677 console::error("%s: Failed parsing command line parameters\n", VOGL_FUNCTION_NAME);
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");
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");
693 if (g_command_line_params.get_value_as_bool("vogl_dump_gl_full"))
695 g_dump_gl_calls_flag = true;
696 g_dump_gl_buffers_flag = true;
697 g_dump_gl_shaders_flag = true;
701 //----------------------------------------------------------------------------------------------------------------------
702 // vogl_check_for_threaded_driver_optimizations
703 //----------------------------------------------------------------------------------------------------------------------
704 static bool vogl_check_for_threaded_driver_optimizations()
708 const char *pThreaded_optimizations = getenv("__GL_THREADED_OPTIMIZATIONS");
709 if (!pThreaded_optimizations)
712 if (string_to_int(pThreaded_optimizations) != 0)
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");
723 //----------------------------------------------------------------------------------------------------------------------
724 // vogl_global_init - called once on the first intercepted GL/GLX function call
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
730 //----------------------------------------------------------------------------------------------------------------------
731 static void vogl_global_init()
733 #if VOGL_FUNCTION_TRACING
736 setvbuf(stdout, NULL, _IONBF, 0);
737 setvbuf(stderr, NULL, _IONBF, 0);
742 g_thread_safe_random.seed_from_urandom();
744 colorized_console::init();
746 console::set_tool_prefix("(vogltrace) ");
748 console::message("Command line params: \"%s\"\n", get_command_line().get_ptr());
750 bool reliable_rdtsc = vogl::utils::init_rdtsc();
752 console::message("Reliable tsc clocksource found. Using rdtsc.\n");
754 console::message("Unreliable tsc clocksource found. Not using rdtsc.\n");
756 vogl_init_command_line_params();
760 vogl_common_lib_global_init();
762 if (g_command_line_params.has_key("vogl_tracefile"))
764 if (!g_vogl_trace_writer.open(g_command_line_params.get_value_as_string_or_empty("vogl_tracefile").get_ptr()))
766 // FIXME: What do we do? The caller WANTS a full-stream trace, and continuing execution is probably not desired.
768 vogl_error_printf("%s: Failed opening trace file, exiting application!\n", VOGL_FUNCTION_NAME);
774 if (!g_command_line_params.get_value_as_bool("vogl_disable_signal_interception"))
776 console::message("Installing exception/signal callbacks\n");
778 colorized_console::set_exception_callback();
780 g_vogl_pPrev_exception_callback = vogl_set_exception_callback(vogl_exception_callback);
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"));
788 vogl_check_for_threaded_driver_optimizations();
790 g_backtrace_hashmap.reserve(VOGL_BACKTRACE_HASHMAP_CAPACITY);
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.
797 console::message("vogl_global_init finished\n");
799 atomic_increment32(&g_vogl_has_been_initialized);
802 //----------------------------------------------------------------------------------------------------------------------
803 // vogl_check_context
804 //----------------------------------------------------------------------------------------------------------------------
805 static inline void vogl_check_context(gl_entrypoint_id_t id, vogl_context *pContext)
809 const char *pName = g_vogl_entrypoint_descs[id].m_pName;
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'))
815 uint n = vogl_strlen(pName);
816 if ((n <= 3) || ((pName[n - 3] != 'R') || (pName[n - 2] != 'A') || (pName[n - 1] != 'D')))
818 vogl_error_printf("%s: OpenGL function \"%s\" called without an active context!\n", VOGL_FUNCTION_NAME, pName);
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)
830 if (!g_vogl_has_been_initialized)
832 pthread_once(&g_vogl_init_once_control, vogl_global_init);
835 vogl_thread_local_data *pTLS_data = vogl_get_or_create_thread_local_data();
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)
841 // Atomically inc the 64-bit counter
842 // TODO: Make a helper for this
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);
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);
852 vogl_check_context(entrypoint_id, pTLS_data->m_pContext);
857 //----------------------------------------------------------------------------------------------------------------------
858 // struct gl_vertex_attribute
859 //----------------------------------------------------------------------------------------------------------------------
860 struct gl_vertex_attribute
864 GLboolean m_normalized;
866 const GLvoid *m_pointer;
874 m_normalized = false;
881 const uint VOGL_MAX_SUPPORTED_GL_VERTEX_ATTRIBUTES = 32;
883 typedef vogl::hash_map<GLenum, GLuint> gl_buffer_binding_map;
884 //----------------------------------------------------------------------------------------------------------------------
885 // struct gl_buffer_desc
886 //----------------------------------------------------------------------------------------------------------------------
887 struct gl_buffer_desc
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;
905 inline flushed_range(int64_t ofs, int64_t size)
906 : m_ofs(ofs), m_size(size)
909 inline flushed_range()
916 vogl::vector<flushed_range> m_flushed_ranges;
918 inline gl_buffer_desc()
922 inline gl_buffer_desc(GLuint handle)
938 m_flushed_ranges.clear();
942 typedef vogl::hash_map<GLuint, gl_buffer_desc> gl_buffer_desc_map;
944 //----------------------------------------------------------------------------------------------------------------------
945 // vogl_scoped_gl_error_absorber
946 //----------------------------------------------------------------------------------------------------------------------
947 class vogl_scoped_gl_error_absorber
949 vogl_context *m_pContext;
952 vogl_scoped_gl_error_absorber(vogl_context *pContext);
953 ~vogl_scoped_gl_error_absorber();
956 //----------------------------------------------------------------------------------------------------------------------
957 // class vogl_tracer_snapshot_handle_remapper
958 //----------------------------------------------------------------------------------------------------------------------
959 class vogl_context_handle_remapper : public vogl_handle_remapper
961 VOGL_NO_COPY_OR_ASSIGNMENT_OP(vogl_context_handle_remapper);
963 vogl_context *m_pContext;
966 vogl_context_handle_remapper(vogl_context *pContext)
967 : m_pContext(pContext)
971 virtual bool is_default_remapper() const
976 virtual bool is_valid_handle(vogl_namespace_t handle_namespace, uint64_t from_handle);
978 virtual bool determine_from_object_target(vogl_namespace_t handle_namespace, uint64_t from_handle, GLenum &target);
980 virtual bool determine_to_object_target(vogl_namespace_t handle_namespace, uint64_t to_handle, GLenum &target)
982 return determine_from_object_target(handle_namespace, to_handle, target);
986 //----------------------------------------------------------------------------------------------------------------------
987 // class vogl_context
988 //----------------------------------------------------------------------------------------------------------------------
991 VOGL_NO_COPY_OR_ASSIGNMENT_OP(vogl_context);
994 vogl_context(GLXContext handle)
996 m_deleted_flag(false),
997 m_pShared_state(this),
998 m_context_handle(handle),
999 m_sharelist_handle(NULL),
1002 m_read_drawable(None),
1006 m_created_from_attribs(false),
1007 m_current_thread(0),
1008 m_max_vertex_attribs(0),
1009 m_has_been_made_current(false),
1011 m_window_height(-1),
1013 m_creation_func(VOGL_ENTRYPOINT_INVALID),
1014 m_latched_gl_error(GL_NO_ERROR),
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)
1022 utils::zero_object(m_xvisual_info);
1029 int get_ref_count() const
1044 bool get_deleted_flag() const
1046 return m_deleted_flag;
1048 void set_deleted_flag(bool val)
1050 m_deleted_flag = val;
1053 vogl_context *get_shared_state() const
1055 return m_pShared_state;
1057 void set_shared_context(vogl_context *pContext)
1059 m_pShared_state = pContext;
1062 vogl_context *get_context_state()
1067 bool is_root_context() const
1069 return this == m_pShared_state;
1071 bool is_share_context() const
1073 return this != m_pShared_state;
1076 GLXContext get_context_handle() const
1078 return m_context_handle;
1081 GLXContext get_sharelist_handle() const
1083 return m_sharelist_handle;
1085 void set_sharelist_handle(GLXContext context)
1087 m_sharelist_handle = context;
1090 const Display *get_display() const
1094 void set_display(const Display *pDpy)
1099 void set_drawable(GLXDrawable drawable)
1101 m_drawable = drawable;
1103 GLXDrawable get_drawable() const
1108 void set_read_drawable(GLXDrawable read)
1110 m_read_drawable = read;
1112 GLXDrawable get_read_drawable() const
1114 return m_read_drawable;
1117 void set_render_type(int render_type)
1119 m_render_type = render_type;
1121 int get_render_type() const
1123 return m_render_type;
1126 bool get_direct() const
1130 void set_direct(bool direct)
1135 const XVisualInfo &get_xvisual_info() const
1137 return m_xvisual_info;
1139 void set_xvisual_info(const XVisualInfo *p)
1141 m_xvisual_info = *p;
1144 bool get_created_from_attribs() const
1146 return m_created_from_attribs;
1148 void set_created_from_attribs(bool created_from_attribs)
1150 m_created_from_attribs = created_from_attribs;
1153 uint64_t get_current_thread() const
1155 return m_current_thread;
1157 void set_current_thread(uint64_t tid)
1159 m_current_thread = tid;
1162 void set_creation_func(gl_entrypoint_id_t func)
1164 m_creation_func = func;
1166 gl_entrypoint_id_t get_creation_func() const
1168 return m_creation_func;
1171 void set_fb_config(GLXFBConfig config)
1173 m_fb_config = config;
1175 GLXFBConfig get_fb_config()
1180 inline bool get_has_been_made_current() const
1182 return m_has_been_made_current;
1187 VOGL_ASSERT(m_creation_func != VOGL_ENTRYPOINT_INVALID);
1188 if (m_creation_func == VOGL_ENTRYPOINT_INVALID)
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);
1195 void set_attrib_list(const int *attrib_list)
1197 int n = vogl_determine_attrib_list_array_size(attrib_list);
1198 m_attrib_list.clear();
1199 m_attrib_list.append(attrib_list, n);
1202 const vogl::vector<int> &get_attrib_list() const
1204 return m_attrib_list;
1207 // true if a core profile was explictly requested in the attrib list.
1208 inline bool requested_core_profile() const
1210 return (m_context_desc.get_attribs().get_value_or_default(GLX_CONTEXT_PROFILE_MASK_ARB) & GLX_CONTEXT_CORE_PROFILE_BIT_ARB) != 0;
1213 // true if a compat profile was explictly requested in the attrib list.
1214 inline bool requested_compatibility_profile() const
1216 return (m_context_desc.get_attribs().get_value_or_default(GLX_CONTEXT_PROFILE_MASK_ARB) & GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB) != 0;
1219 // true if a debug context was explictly requested in the attrib list.
1220 inline bool requested_debug_context() const
1222 return (m_context_desc.get_attribs().get_value_or_default(GLX_CONTEXT_FLAGS_ARB) & GLX_CONTEXT_DEBUG_BIT_ARB) != 0;
1225 // true if a forward compatible context was explictly requested in the attrib list.
1226 inline bool requested_forward_compatible() const
1228 return (m_context_desc.get_attribs().get_value_or_default(GLX_CONTEXT_FLAGS_ARB) & GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB) != 0;
1231 // true if this is a core profile context (the context must have been made current first)
1232 inline bool is_core_profile() const
1234 return m_context_info.is_core_profile();
1237 // only valid after the first MakeCurrent
1238 inline GLuint get_max_vertex_attribs() const
1240 return m_max_vertex_attribs;
1242 inline GLuint get_max_texture_coords() const
1244 return m_context_info.get_max_texture_coords();
1247 // compat only - will be 0 in core
1248 inline GLuint get_max_texture_units() const
1250 return m_context_info.get_max_texture_units();
1253 const vogl_context_desc &get_context_desc() const
1255 return m_context_desc;
1257 const vogl_context_info &get_context_info() const
1259 return m_context_info;
1262 const vogl_capture_context_params &get_capture_context_params() const
1264 return m_capture_context_params;
1266 vogl_capture_context_params &get_capture_context_params()
1268 return m_capture_context_params;
1271 const vogl_framebuffer_capturer &get_framebuffer_capturer() const
1273 return m_framebuffer_capturer;
1275 vogl_framebuffer_capturer &get_framebuffer_capturer()
1277 return m_framebuffer_capturer;
1280 inline void on_make_current()
1282 set_current_thread(vogl_get_current_kernel_thread_id());
1284 if (!m_has_been_made_current)
1286 vogl_scoped_gl_error_absorber gl_error_absorber(this);
1287 VOGL_NOTE_UNUSED(gl_error_absorber);
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)
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;
1296 if (!m_context_info.init(m_context_desc))
1298 vogl_error_printf("%s: Failed initializing m_context_info!\n", VOGL_METHOD_NAME);
1301 if (!m_has_been_made_current)
1303 on_first_make_current();
1306 m_has_been_made_current = true;
1310 bool is_context_current()
1312 if (!GL_ENTRYPOINT(glXGetCurrentContext))
1315 // Double check that the context that we think is current is actually current.
1316 GLXContext cur_context = GL_ENTRYPOINT(glXGetCurrentContext)();
1319 VOGL_ASSERT(!m_current_thread);
1323 if (get_context_handle() != cur_context)
1325 VOGL_ASSERT(!m_current_thread);
1329 VOGL_ASSERT(vogl_get_current_kernel_thread_id() == m_current_thread);
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()
1338 if (!is_context_current())
1341 peek_and_record_gl_error();
1343 m_framebuffer_capturer.flush();
1345 peek_and_drop_gl_error();
1348 void on_release_current_epilog()
1350 set_current_thread(0);
1353 void on_destroy_prolog()
1355 if (!is_context_current())
1357 m_framebuffer_capturer.deinit(false);
1361 peek_and_record_gl_error();
1363 m_framebuffer_capturer.deinit(true);
1365 peek_and_drop_gl_error();
1368 // buffer handle and target shadowing
1369 void gen_buffers(GLsizei n, GLuint *pIDs)
1374 vogl_scoped_context_shadow_lock lock;
1376 for (GLsizei i = 0; i < n; i++)
1378 GLuint id = pIDs[i];
1381 if (!get_shared_state()->m_capture_context_params.m_buffer_targets.insert(id, GL_NONE).second)
1383 vogl_error_printf("%s: Can't insert buffer handle 0x%04X into buffer target map!\n", VOGL_METHOD_NAME, id);
1389 void bind_buffer(GLenum target, GLuint id)
1394 vogl_scoped_context_shadow_lock lock;
1396 GLenum *pTarget = get_shared_state()->m_capture_context_params.m_buffer_targets.find_value(id);
1399 vogl_error_printf("%s: Unable to find buffer handle 0x%04X in buffer target map!\n", VOGL_METHOD_NAME, id);
1403 if (*pTarget == GL_NONE)
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??).
1410 void delete_buffers(GLsizei n, const GLuint *buffers)
1412 if ((!n) || (!buffers))
1415 vogl_scoped_context_shadow_lock lock;
1417 for (GLsizei i = 0; i < n; i++)
1419 GLuint buffer = buffers[i];
1423 get_shared_state()->m_buffer_descs.erase(buffer);
1425 if (!get_shared_state()->m_capture_context_params.m_buffer_targets.erase(buffer))
1427 vogl_error_printf("%s: Can't erase buffer handle 0x%04X from buffer target map!\n", VOGL_METHOD_NAME, buffer);
1432 inline gl_buffer_desc &get_or_create_buffer_desc(GLuint handle)
1434 vogl_scoped_context_shadow_lock lock;
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;
1440 gl_buffer_desc desc(handle);
1441 return (get_shared_state()->m_buffer_descs.insert(handle, desc).first)->second;
1444 inline uint get_total_mapped_buffers() const
1446 vogl_scoped_context_shadow_lock lock;
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)
1451 if (it->second.m_pMap)
1457 inline void set_window_dimensions(int width, int height)
1459 m_window_width = width;
1460 m_window_height = height;
1463 inline int get_window_width() const
1465 return m_window_width;
1467 inline int get_window_height() const
1469 return m_window_height;
1472 uint64_t get_frame_index() const
1474 return m_frame_index;
1476 void set_frame_index(uint f)
1480 void inc_frame_index()
1485 GLuint get_cur_program() const
1487 return m_cur_program;
1489 void set_cur_program(GLuint program)
1491 m_cur_program = program;
1494 GLenum get_latched_gl_error() const
1496 return m_latched_gl_error;
1498 bool has_latched_gl_error() const
1500 return m_latched_gl_error != GL_NO_ERROR;
1502 void clear_latched_gl_error()
1504 m_latched_gl_error = GL_NO_ERROR;
1506 void set_latched_gl_error(GLenum err)
1508 m_latched_gl_error = err;
1511 // Returns the context's most recent GL error, NOT the currently latched error.
1512 GLenum peek_and_record_gl_error()
1517 GLenum gl_err = GL_ENTRYPOINT(glGetError)();
1519 if (gl_err != GL_NO_ERROR)
1521 if (!has_latched_gl_error())
1523 set_latched_gl_error(gl_err);
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));
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()));
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()
1545 GLenum gl_err = GL_ENTRYPOINT(glGetError)();
1547 if (gl_err != GL_NO_ERROR)
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));
1555 // TODO: Modify each shadowing method to print detailed error messages
1556 // TODO: Move all these shadow methods right into vogl_capture_context_params
1558 // Texture handle shadowing
1559 void gen_textures(GLsizei n, GLuint *pTextures)
1564 vogl_scoped_context_shadow_lock lock;
1566 for (GLsizei i = 0; i < n; i++)
1568 GLuint handle = pTextures[i];
1571 if (!get_shared_state()->m_capture_context_params.m_textures.insert(handle, handle, GL_NONE))
1573 vogl_warning_printf("%s: Unable to add texture handle %u to texture handle shadow map!\n", VOGL_METHOD_NAME, handle);
1579 void del_textures(GLsizei n, const GLuint *pTextures)
1584 vogl_scoped_context_shadow_lock lock;
1586 for (GLsizei i = 0; i < n; i++)
1588 GLuint handle = pTextures[i];
1591 if (!get_shared_state()->m_capture_context_params.m_textures.erase(handle))
1593 vogl_warning_printf("%s: Failed erasing handle %u from texture handle shadow map!\n", VOGL_METHOD_NAME, handle);
1599 void bind_texture(GLenum target, GLuint texture)
1603 vogl_scoped_context_shadow_lock lock;
1605 get_shared_state()->m_capture_context_params.m_textures.update(texture, target);
1609 void bind_texture_conditionally(GLenum target, GLuint texture)
1613 vogl_scoped_context_shadow_lock lock;
1615 get_shared_state()->m_capture_context_params.m_textures.conditional_update(texture, GL_NONE, target);
1619 // Framebuffer handle shadowing
1620 void gen_framebuffers(GLsizei n, GLuint *pFramebuffers)
1624 for (GLsizei i = 0; i < n; i++)
1626 GLuint handle = pFramebuffers[i];
1628 get_context_state()->m_capture_context_params.m_framebuffers.insert(handle);
1632 void del_framebuffers(GLsizei n, const GLuint *pFramebuffers)
1636 for (GLsizei i = 0; i < n; i++)
1638 GLuint handle = pFramebuffers[i];
1640 get_context_state()->m_capture_context_params.m_framebuffers.erase(handle);
1644 // VAO handle shadowing
1645 void gen_vertexarrays(GLsizei n, GLuint *pArrays)
1649 for (GLsizei i = 0; i < n; i++)
1651 GLuint handle = pArrays[i];
1653 get_context_state()->m_capture_context_params.m_vaos.insert(handle);
1657 void del_vertexarrays(GLsizei n, const GLuint *pArrays)
1661 for (GLsizei i = 0; i < n; i++)
1663 GLuint handle = pArrays[i];
1665 get_context_state()->m_capture_context_params.m_vaos.erase(handle);
1669 void bind_vertexarray(GLuint array)
1672 get_context_state()->m_capture_context_params.m_vaos.insert(array);
1675 // sync handle shadowing
1676 void gen_sync(GLsync sync)
1680 vogl_scoped_context_shadow_lock lock;
1682 get_shared_state()->m_capture_context_params.m_syncs.insert((uint64_t)sync);
1686 void del_sync(GLsync sync)
1690 vogl_scoped_context_shadow_lock lock;
1692 get_shared_state()->m_capture_context_params.m_syncs.erase((uint64_t)sync);
1696 // sampler handle shadowing
1697 void gen_samplers(GLsizei n, const GLuint *pSamplers)
1702 vogl_scoped_context_shadow_lock lock;
1704 for (GLsizei i = 0; i < n; i++)
1706 GLuint handle = pSamplers[i];
1708 get_shared_state()->m_capture_context_params.m_samplers.insert(handle);
1712 void del_samplers(GLsizei n, const GLuint *pSamplers)
1717 vogl_scoped_context_shadow_lock lock;
1719 for (GLsizei i = 0; i < n; i++)
1721 GLuint handle = pSamplers[i];
1723 get_shared_state()->m_capture_context_params.m_samplers.erase(handle);
1727 // query handle and target shadowing
1728 void gen_queries(GLsizei n, GLuint *pIDs)
1733 vogl_scoped_context_shadow_lock lock;
1735 for (GLsizei i = 0; i < n; i++)
1737 GLuint id = pIDs[i];
1739 get_shared_state()->m_capture_context_params.m_query_targets.insert(id, GL_NONE);
1743 void del_queries(GLsizei n, const GLuint *pIDs)
1748 vogl_scoped_context_shadow_lock lock;
1750 for (GLsizei i = 0; i < n; i++)
1752 GLuint id = pIDs[i];
1754 get_shared_state()->m_capture_context_params.m_query_targets.erase(id);
1758 void begin_query(GLenum target, GLuint id)
1762 vogl_scoped_context_shadow_lock lock;
1764 if (get_shared_state()->m_capture_context_params.m_query_targets.contains(id))
1766 get_shared_state()->m_capture_context_params.m_query_targets[id] = target;
1770 vogl_error_printf("%s: Unable to find query target handle %u in query target handle shadow\n", VOGL_METHOD_NAME, id);
1776 void gen_arb_programs(GLsizei n, const GLuint *pHandles)
1781 vogl_scoped_context_shadow_lock lock;
1783 for (GLsizei i = 0; i < n; i++)
1785 GLuint handle = pHandles[i];
1787 get_shared_state()->m_capture_context_params.m_arb_program_targets.insert(handle, GL_NONE);
1791 void bind_arb_program(GLenum target, GLuint handle)
1795 vogl_scoped_context_shadow_lock lock;
1797 get_shared_state()->m_capture_context_params.m_arb_program_targets[handle] = target;
1801 void del_arb_programs(GLsizei n, const GLuint *pHandles)
1806 vogl_scoped_context_shadow_lock lock;
1808 for (GLsizei i = 0; i < n; i++)
1810 GLuint handle = pHandles[i];
1812 get_shared_state()->m_capture_context_params.m_arb_program_targets.erase(handle);
1816 // renderbuffer handle shadowing
1817 void gen_render_buffers(GLsizei n, GLuint *pIDs)
1822 vogl_scoped_context_shadow_lock lock;
1824 for (GLsizei i = 0; i < n; i++)
1826 GLuint id = pIDs[i];
1829 if (!get_shared_state()->m_capture_context_params.m_rbos.insert(id, id, GL_NONE))
1831 vogl_error_printf("%s: Can't insert render buffer handle 0x%04X into render buffer shadow!\n", VOGL_METHOD_NAME, id);
1837 void del_render_buffers(GLsizei n, const GLuint *buffers)
1839 if ((!n) || (!buffers))
1842 vogl_scoped_context_shadow_lock lock;
1844 for (GLsizei i = 0; i < n; i++)
1846 GLuint buffer = buffers[i];
1850 if (!get_shared_state()->m_capture_context_params.m_rbos.erase(buffer))
1852 vogl_error_printf("%s: Can't erase render buffer handle 0x%04X from render buffer shadow!\n", VOGL_METHOD_NAME, buffer);
1857 // program/shader shadowing
1858 GLuint handle_create_program(gl_entrypoint_id_t id)
1862 if (id == VOGL_ENTRYPOINT_glCreateProgram)
1863 handle = GL_ENTRYPOINT(glCreateProgram)();
1866 VOGL_ASSERT(id == VOGL_ENTRYPOINT_glCreateProgramObjectARB);
1867 handle = GL_ENTRYPOINT(glCreateProgramObjectARB)();
1870 vogl_scoped_context_shadow_lock lock;
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);
1879 vogl_error_printf("%s: glCreateProgram/glCreateProgramObjectARB on handle %u failed!\n", VOGL_METHOD_NAME, handle);
1885 GLuint handle_create_shader(gl_entrypoint_id_t id, GLenum type)
1889 if (id == VOGL_ENTRYPOINT_glCreateShader)
1890 handle = GL_ENTRYPOINT(glCreateShader)(type);
1893 VOGL_ASSERT(id == VOGL_ENTRYPOINT_glCreateShaderObjectARB);
1894 handle = GL_ENTRYPOINT(glCreateShaderObjectARB)(type);
1897 vogl_scoped_context_shadow_lock lock;
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));
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));
1912 bool has_linked_program_snapshot(GLuint handle)
1914 vogl_scoped_context_shadow_lock lock;
1916 return get_shared_state()->m_capture_context_params.m_linked_programs.find_snapshot(handle) != NULL;
1919 bool add_linked_program_snapshot(GLuint handle, GLenum binary_format = GL_NONE, const void *pBinary = NULL, uint binary_size = 0)
1921 vogl_scoped_context_shadow_lock lock;
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);
1926 void handle_use_program(gl_entrypoint_id_t id, GLuint program)
1928 // Note: This mixes ARB and non-ARB funcs. to probe around, which is evil.
1930 peek_and_record_gl_error();
1932 check_program_binding_shadow();
1934 vogl_scoped_context_shadow_lock lock;
1936 VOGL_ASSERT(!program || (get_shared_state()->m_capture_context_params.m_objs.get_target(program) == VOGL_PROGRAM_OBJECT));
1938 GLuint prev_program = m_cur_program;
1940 bool prev_is_program = false;
1941 GLint prev_is_marked_for_deletion = false;
1942 vogl::growable_array<GLuint, 8> prev_attached_replay_shaders;
1944 if ((prev_program) && (program != prev_program))
1946 prev_is_program = GL_ENTRYPOINT(glIsProgram)(prev_program);
1947 peek_and_drop_gl_error();
1949 if (prev_is_program)
1951 GL_ENTRYPOINT(glGetProgramiv)(prev_program, GL_DELETE_STATUS, &prev_is_marked_for_deletion);
1952 peek_and_drop_gl_error();
1954 if (prev_is_marked_for_deletion)
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();
1961 if (num_attached_shaders)
1963 prev_attached_replay_shaders.resize(num_attached_shaders);
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();
1969 VOGL_ASSERT(actual_count == num_attached_shaders);
1975 if (id == VOGL_ENTRYPOINT_glUseProgram)
1976 GL_ENTRYPOINT(glUseProgram)(program);
1979 VOGL_ASSERT(id == VOGL_ENTRYPOINT_glUseProgramObjectARB);
1980 GL_ENTRYPOINT(glUseProgramObjectARB)(program);
1983 GLenum gl_err = peek_and_record_gl_error();
1984 if (gl_err != GL_NO_ERROR)
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));
1990 if ((prev_program) && (prev_program != program))
1992 bool is_prev_still_program = GL_ENTRYPOINT(glIsProgram)(prev_program);
1993 if (!is_prev_still_program)
1995 VOGL_ASSERT(prev_is_program);
1996 VOGL_ASSERT(prev_is_marked_for_deletion);
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);
2003 get_shared_state()->m_capture_context_params.m_linked_programs.remove_snapshot(prev_program);
2005 for (uint i = 0; i < prev_attached_replay_shaders.size(); i++)
2007 GLuint shader_handle = prev_attached_replay_shaders[i];
2009 bool is_still_shader = GL_ENTRYPOINT(glIsShader)(shader_handle);
2010 peek_and_drop_gl_error();
2012 if (is_still_shader)
2015 if (!get_shared_state()->m_capture_context_params.m_objs.contains(shader_handle))
2017 // We didn't create this shader handle, the AMD driver did on a program binary link, so ignore it.
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))
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);
2031 m_cur_program = program;
2033 check_program_binding_shadow();
2036 void handle_del_shader(gl_entrypoint_id_t id, GLuint obj)
2038 // Note: This mixes ARB and non-ARB funcs. to probe around, which is evil.
2040 peek_and_record_gl_error();
2042 check_program_binding_shadow();
2044 vogl_scoped_context_shadow_lock lock;
2046 VOGL_ASSERT(!obj || (get_shared_state()->m_capture_context_params.m_objs.get_target(obj) == VOGL_SHADER_OBJECT));
2048 if (id == VOGL_ENTRYPOINT_glDeleteObjectARB)
2049 GL_ENTRYPOINT(glDeleteObjectARB)(obj);
2051 GL_ENTRYPOINT(glDeleteShader)(obj);
2053 GLenum gl_err = peek_and_record_gl_error();
2054 if (gl_err != GL_NO_ERROR)
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));
2063 bool is_still_shader = GL_ENTRYPOINT(glIsShader)(obj);
2064 peek_and_drop_gl_error();
2066 if (!is_still_shader)
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);
2075 GLint marked_for_deletion = 0;
2076 GL_ENTRYPOINT(glGetShaderiv)(obj, GL_DELETE_STATUS, &marked_for_deletion);
2077 peek_and_drop_gl_error();
2079 VOGL_VERIFY(marked_for_deletion);
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.
2086 void handle_del_program(gl_entrypoint_id_t id, GLuint obj)
2088 // Note: This mixes ARB and non-ARB funcs. to probe around, which is evil.
2090 peek_and_record_gl_error();
2092 check_program_binding_shadow();
2094 vogl_scoped_context_shadow_lock lock;
2096 VOGL_ASSERT(!obj || (get_shared_state()->m_capture_context_params.m_objs.get_target(obj) == VOGL_PROGRAM_OBJECT));
2098 bool is_program = GL_ENTRYPOINT(glIsProgram)(obj) != 0;
2099 peek_and_drop_gl_error();
2101 vogl::growable_array<GLuint, 8> attached_replay_shaders;
2103 if ((is_program) && (obj))
2105 GLint num_attached_shaders = 0;
2106 GL_ENTRYPOINT(glGetProgramiv)(obj, GL_ATTACHED_SHADERS, &num_attached_shaders);
2107 peek_and_drop_gl_error();
2109 if (num_attached_shaders)
2111 attached_replay_shaders.resize(num_attached_shaders);
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();
2117 VOGL_ASSERT(actual_count == num_attached_shaders);
2121 if (id == VOGL_ENTRYPOINT_glDeleteObjectARB)
2122 GL_ENTRYPOINT(glDeleteObjectARB)(obj);
2124 GL_ENTRYPOINT(glDeleteProgram)(obj);
2126 GLenum gl_err = peek_and_record_gl_error();
2127 if (gl_err != GL_NO_ERROR)
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));
2136 bool is_still_program = GL_ENTRYPOINT(glIsProgram)(obj) != 0;
2137 peek_and_drop_gl_error();
2139 GLint marked_for_deletion = 0;
2140 if (is_still_program)
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);
2146 VOGL_VERIFY(delete_status_check_succeeded);
2147 VOGL_VERIFY(marked_for_deletion);
2149 else if (!is_still_program)
2151 VOGL_ASSERT(is_program);
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);
2158 get_shared_state()->m_capture_context_params.m_linked_programs.remove_snapshot(obj);
2160 if (m_cur_program == obj)
2162 // This shouldn't happen - if the program is still bound to the context then it should still be a program.
2167 for (uint i = 0; i < attached_replay_shaders.size(); i++)
2169 GLuint shader_handle = attached_replay_shaders[i];
2171 bool is_still_shader = GL_ENTRYPOINT(glIsShader)(shader_handle) != 0;
2172 peek_and_drop_gl_error();
2174 if (is_still_shader)
2177 if (!get_shared_state()->m_capture_context_params.m_objs.contains(shader_handle))
2179 // We didn't create this shader handle, the AMD driver did on a program binary link, so ignore it.
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))
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);
2192 check_program_binding_shadow();
2195 void handle_del_object(gl_entrypoint_id_t id, GLuint obj)
2197 vogl_scoped_context_shadow_lock lock;
2202 GLenum target = get_shared_state()->m_capture_context_params.m_objs.get_target(obj);
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);
2210 vogl_error_printf("%s: glDeleteObjectARB: Unable to find object handle %u in object shadow\n", VOGL_METHOD_NAME, obj);
2212 GL_ENTRYPOINT(glDeleteObjectARB)(obj);
2216 void handle_detach_shader(gl_entrypoint_id_t id, GLuint program, GLuint shader)
2218 vogl_scoped_context_shadow_lock lock;
2220 peek_and_record_gl_error();
2222 // Note: This mixes ARB and non-ARB funcs. to probe around, which is evil.
2224 GLboolean was_shader = GL_ENTRYPOINT(glIsShader)(shader);
2225 peek_and_drop_gl_error();
2227 GLint marked_for_deletion = 0;
2228 GL_ENTRYPOINT(glGetShaderiv)(shader, GL_DELETE_STATUS, &marked_for_deletion);
2229 peek_and_drop_gl_error();
2231 if (id == VOGL_ENTRYPOINT_glDetachObjectARB)
2232 GL_ENTRYPOINT(glDetachObjectARB)(program, shader);
2235 VOGL_ASSERT(id == VOGL_ENTRYPOINT_glDetachShader);
2236 GL_ENTRYPOINT(glDetachShader)(program, shader);
2239 GLenum gl_err = peek_and_record_gl_error();
2240 if (gl_err != GL_NO_ERROR)
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));
2246 GLboolean is_shader = GL_ENTRYPOINT(glIsShader)(shader);
2247 peek_and_drop_gl_error();
2249 if ((marked_for_deletion) && (was_shader) && (!is_shader))
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);
2258 // glBegin/glEnd shadowing
2260 // Note: This flag gets set even when the client is composing a display list!
2261 void set_in_gl_begin(bool value)
2263 m_in_gl_begin = value;
2265 bool get_in_gl_begin() const
2267 return m_in_gl_begin;
2270 void set_uses_client_side_arrays(bool value)
2272 m_uses_client_side_arrays = value;
2274 bool get_uses_client_side_arrays() const
2276 return m_uses_client_side_arrays;
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()
2282 return m_extension_map;
2285 const vogl_context_handle_remapper &get_handle_remapper() const
2287 return m_handle_remapper;
2289 vogl_context_handle_remapper &get_handle_remapper()
2291 return m_handle_remapper;
2294 // Display list shadowing
2296 GLenum get_current_display_list_mode() const
2298 return m_current_display_list_mode;
2300 bool is_composing_display_list() const
2302 return m_current_display_list_handle >= 0;
2304 GLint get_current_display_list_handle() const
2306 return m_current_display_list_handle;
2309 bool new_list(GLuint handle, GLenum mode)
2313 VOGL_ASSERT((mode == GL_COMPILE) || (mode == GL_COMPILE_AND_EXECUTE));
2315 if (m_current_display_list_handle >= 0)
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);
2321 m_current_display_list_handle = handle;
2322 m_current_display_list_mode = mode;
2324 vogl_scoped_context_shadow_lock lock;
2326 get_shared_state()->m_capture_context_params.m_display_lists.new_list(handle, handle);
2335 if (m_current_display_list_handle < 0)
2337 vogl_error_printf("%s: No display list is active!\n", VOGL_METHOD_NAME);
2342 vogl_scoped_context_shadow_lock lock;
2344 get_shared_state()->m_capture_context_params.m_display_lists.end_list(m_current_display_list_handle);
2347 m_current_display_list_handle = -1;
2348 m_current_display_list_mode = GL_NONE;
2353 void gen_lists(GLuint result, GLsizei range)
2360 vogl_scoped_context_shadow_lock lock;
2362 get_shared_state()->m_capture_context_params.m_display_lists.gen_lists(result, range);
2365 void del_lists(GLuint list, GLsizei range)
2372 vogl_scoped_context_shadow_lock lock;
2374 get_shared_state()->m_capture_context_params.m_display_lists.del_lists(list, range);
2377 void glx_font(const char *pFont, int first, int count, int list_base)
2379 vogl_scoped_context_shadow_lock lock;
2381 get_shared_state()->m_capture_context_params.m_display_lists.glx_font(pFont, first, count, list_base);
2384 bool parse_list_and_update_shadows(GLuint handle, vogl_display_list_state::pBind_callback_func_ptr pBind_callback, void *pBind_callback_opaque)
2386 vogl_scoped_context_shadow_lock lock;
2388 return get_shared_state()->m_capture_context_params.m_display_lists.parse_list_and_update_shadows(handle, pBind_callback, pBind_callback_opaque);
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)
2393 vogl_scoped_context_shadow_lock lock;
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);
2398 bool add_packet_to_current_display_list(gl_entrypoint_id_t func, const vogl_trace_packet &packet)
2402 if (m_current_display_list_handle < 0)
2405 if (!vogl_display_list_state::is_call_listable(func, packet))
2407 if (g_vogl_entrypoint_descs[func].m_is_listable)
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);
2412 vogl_error_printf("%s: Failed serializing trace packet into display list shadow! Call with these parameters is not listable.\n", VOGL_FUNCTION_NAME);
2417 vogl_scoped_context_shadow_lock lock;
2419 return get_shared_state()->m_capture_context_params.m_display_lists.add_packet_to_list(m_current_display_list_handle, func, packet);
2424 bool m_deleted_flag;
2425 vogl_context *m_pShared_state;
2427 GLXContext m_context_handle;
2428 GLXContext m_sharelist_handle;
2430 const Display *m_pDpy;
2431 GLXDrawable m_drawable;
2432 GLXDrawable m_read_drawable;
2434 XVisualInfo m_xvisual_info;
2435 GLXFBConfig m_fb_config;
2439 bool m_created_from_attribs;
2440 vogl::vector<int> m_attrib_list;
2442 uint64_t m_current_thread; // as returned by vogl_get_current_kernel_thread_id()
2444 GLuint m_max_vertex_attribs;
2446 bool m_has_been_made_current;
2448 int m_window_width, m_window_height;
2449 uint64_t m_frame_index;
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
2455 extension_id_to_string_map_t m_extension_map;
2457 GLenum m_latched_gl_error;
2459 gl_buffer_desc_map m_buffer_descs;
2461 vogl_capture_context_params m_capture_context_params;
2463 vogl_framebuffer_capturer m_framebuffer_capturer;
2465 GLuint m_cur_program;
2468 bool m_uses_client_side_arrays;
2470 vogl_context_handle_remapper m_handle_remapper;
2472 int m_current_display_list_handle;
2473 GLenum m_current_display_list_mode;
2475 static void debug_callback_arb(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, GLvoid *pUser_param)
2479 char final_message[4096];
2481 vogl_context *pContext = (vogl_context *)(pUser_param);
2483 vogl_format_debug_output_arb(final_message, sizeof(final_message), source, type, id, severity, reinterpret_cast<const char *>(message));
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);
2492 vogl_warning_printf("%s: %s\n", VOGL_FUNCTION_NAME, final_message);
2496 void on_first_make_current()
2498 if ((g_command_line_params.get_value_as_bool("vogl_force_debug_context")) && (m_context_info.is_debug_context()))
2500 if (GL_ENTRYPOINT(glDebugMessageCallbackARB) && m_context_info.supports_extension("GL_ARB_debug_output"))
2502 VOGL_CHECK_GL_ERROR;
2504 GL_ENTRYPOINT(glDebugMessageCallbackARB)(debug_callback_arb, (GLvoid *)this);
2505 GL_ENTRYPOINT(glEnable)(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
2507 VOGL_CHECK_GL_ERROR;
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);
2516 // Note: Check for any GL errors before calling this method.
2517 bool check_program_binding_shadow()
2519 GLint actual_cur_program = 0;
2520 GL_ENTRYPOINT(glGetIntegerv)(GL_CURRENT_PROGRAM, &actual_cur_program);
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);
2525 if (m_cur_program == static_cast<GLuint>(actual_cur_program))
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))
2532 GLint marked_for_deletion = GL_FALSE;
2533 GL_ENTRYPOINT(glGetProgramiv)(m_cur_program, GL_DELETE_STATUS, &marked_for_deletion);
2535 if ((peek_and_drop_gl_error() == GL_NO_ERROR) && (marked_for_deletion))
2539 VOGL_VERIFY(!"m_cur_program appears out of sync with GL's GL_CURRENT_PROGRAM");
2544 typedef vogl::hash_map<GLXContext, vogl_context *, bit_hasher<GLXContext> > glxcontext_map;
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)
2554 uint32 handle = static_cast<uint32>(from_handle);
2556 const vogl_capture_context_params &capture_context_params = m_pContext->get_shared_state()->get_capture_context_params();
2558 // TODO: Support all the object types
2559 if (handle_namespace == VOGL_NAMESPACE_SHADERS)
2561 VOGL_ASSERT(handle == from_handle);
2562 return (capture_context_params.m_objs.get_target(handle) == VOGL_SHADER_OBJECT);
2564 else if (handle_namespace == VOGL_NAMESPACE_PROGRAMS)
2566 VOGL_ASSERT(handle == from_handle);
2567 return (capture_context_params.m_objs.get_target(handle) == VOGL_PROGRAM_OBJECT);
2569 else if (handle_namespace == VOGL_NAMESPACE_TEXTURES)
2571 VOGL_ASSERT(handle == from_handle);
2572 return capture_context_params.m_textures.contains(handle);
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)
2589 uint32 handle = static_cast<uint32>(from_handle);
2591 const vogl_capture_context_params &capture_context_params = m_pContext->get_shared_state()->get_capture_context_params();
2593 // TODO: Support all the object types
2594 if (handle_namespace == VOGL_NAMESPACE_TEXTURES)
2596 if (capture_context_params.m_textures.contains(handle))
2598 target = capture_context_params.m_textures.get_target(handle);
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)
2613 // Latch any errors that are present on the context, if any, so the client will see it later
2615 pContext->peek_and_record_gl_error();
2618 //----------------------------------------------------------------------------------------------------------------------
2619 // vogl_scoped_gl_error_absorber::~vogl_scoped_gl_error_absorber
2620 //----------------------------------------------------------------------------------------------------------------------
2621 vogl_scoped_gl_error_absorber::~vogl_scoped_gl_error_absorber()
2623 // Now get the current GL error and drop it, so the client app doesn't see it
2625 m_pContext->peek_and_drop_gl_error();
2628 //----------------------------------------------------------------------------------------------------------------------
2629 // class vogl_context_manager
2630 //----------------------------------------------------------------------------------------------------------------------
2631 class vogl_context_manager
2633 VOGL_NO_COPY_OR_ASSIGNMENT_OP(vogl_context_manager);
2636 vogl_context_manager()
2637 : m_glx_context_map_lock(0, true)
2641 vogl_context *create_context(GLXContext handle)
2643 VOGL_ASSERT(handle);
2645 vogl_context *pVOGL_context = vogl_new(vogl_context, handle);
2648 scoped_mutex lock(m_glx_context_map_lock);
2649 m_glx_context_map.insert(handle, pVOGL_context);
2652 return pVOGL_context;
2655 vogl_context *lookup_vogl_context(GLXContext handle)
2657 VOGL_ASSERT(handle);
2659 vogl_context *pVOGL_context;
2660 VOGL_NOTE_UNUSED(pVOGL_context);
2661 glxcontext_map::iterator it;
2664 scoped_mutex lock(m_glx_context_map_lock);
2665 it = m_glx_context_map.find(handle);
2668 return (it != m_glx_context_map.end()) ? it->second : NULL;
2671 bool destroy_context(GLXContext handle)
2673 VOGL_ASSERT(handle);
2675 vogl_context *pVOGL_context = lookup_vogl_context(handle);
2680 scoped_mutex lock(m_glx_context_map_lock);
2681 m_glx_context_map.erase(handle);
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;
2688 vogl_delete(pVOGL_context);
2693 vogl_context *get_or_create_context(GLXContext handle)
2695 VOGL_ASSERT(handle);
2697 vogl_context *pVOGL_context = lookup_vogl_context(handle);
2699 pVOGL_context = vogl_new(vogl_context, handle);
2701 return pVOGL_context;
2704 vogl_context *make_current(GLXContext handle)
2706 VOGL_ASSERT(handle);
2708 vogl_context *pVOGL_context = get_or_create_context(handle);
2710 if (pVOGL_context->get_current_thread())
2712 if (pVOGL_context->get_current_thread() != vogl_get_current_kernel_thread_id())
2714 vogl_error_printf("%s: context is being made current, but is already current on another thread\n", VOGL_METHOD_NAME);
2718 vogl_warning_printf("%s: context is already current (redundant call)\n", VOGL_METHOD_NAME);
2722 vogl_get_or_create_thread_local_data()->m_pContext = pVOGL_context;
2724 pVOGL_context->on_make_current();
2726 return pVOGL_context;
2729 vogl_context *get_current()
2731 return static_cast<vogl_context *>(vogl_get_or_create_thread_local_data()->m_pContext);
2734 void release_current()
2736 vogl_context *pVOGL_context = get_current();
2739 if (!pVOGL_context->get_current_thread())
2741 vogl_error_printf("%s: Context manager's current context is not marked as current on any thread\n", VOGL_METHOD_NAME);
2743 pVOGL_context->on_release_current_epilog();
2745 vogl_get_or_create_thread_local_data()->m_pContext = NULL;
2751 m_glx_context_map_lock.lock();
2756 m_glx_context_map_lock.unlock();
2759 const glxcontext_map &get_context_map() const
2761 return m_glx_context_map;
2764 vogl_context *find_context(const Display *dpy, GLXDrawable drawable)
2768 const glxcontext_map &contexts = m_glx_context_map;
2769 for (glxcontext_map::const_iterator it = contexts.begin(); it != contexts.end(); ++it)
2771 vogl_context *p = it->second;
2772 if ((p->get_display() == dpy) && (p->get_drawable() == drawable))
2784 mutex m_glx_context_map_lock;
2785 glxcontext_map m_glx_context_map;
2788 vogl_context_manager g_context_manager;
2790 //----------------------------------------------------------------------------------------------------------------------
2791 // vogl_context_shadow_lock
2792 //----------------------------------------------------------------------------------------------------------------------
2793 static inline void vogl_context_shadow_lock()
2795 g_context_manager.lock();
2798 //----------------------------------------------------------------------------------------------------------------------
2799 // vogl_context_shadow_unlock
2800 //----------------------------------------------------------------------------------------------------------------------
2801 static inline void vogl_context_shadow_unlock()
2803 g_context_manager.unlock();
2806 //----------------------------------------------------------------------------------------------------------------------
2808 //----------------------------------------------------------------------------------------------------------------------
2809 static void vogl_atexit()
2811 vogl_debug_printf("vogl_atexit()\n");
2813 scoped_mutex lock(g_vogl_trace_mutex);
2818 //----------------------------------------------------------------------------------------------------------------------
2820 //----------------------------------------------------------------------------------------------------------------------
2821 static uint32 vogl_backtrace(uint addrs_to_skip)
2823 vogl_backtrace_addrs addrs;
2824 addrs.m_num_addrs = btrace_get(addrs.m_addrs, addrs.cMaxAddrs, addrs_to_skip);
2826 vogl_backtrace_hashmap::insert_result ins_res;
2830 g_backtrace_hashmap_mutex.lock();
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);
2836 index = ins_res.first.get_index();
2837 (ins_res.first)->second++;
2840 g_backtrace_hashmap_mutex.unlock();
2845 //----------------------------------------------------------------------------------------------------------------------
2846 // vogl_flush_backtrace_to_trace_file
2847 //----------------------------------------------------------------------------------------------------------------------
2848 static bool vogl_flush_backtrace_to_trace_file()
2850 scoped_mutex lock(g_vogl_trace_mutex);
2852 if (!g_vogl_trace_writer.is_opened() || (g_vogl_trace_writer.get_trace_archive() == NULL))
2857 g_backtrace_hashmap_mutex.lock();
2859 uint backtrace_hashmap_size = g_backtrace_hashmap.size();
2860 if (backtrace_hashmap_size)
2862 vogl_message_printf("%s: Writing backtrace %u addrs\n", VOGL_FUNCTION_NAME, backtrace_hashmap_size);
2864 json_node *pRoot = doc.get_root();
2865 pRoot->init_array();
2867 for (vogl_backtrace_hashmap::const_iterator it = g_backtrace_hashmap.begin(); it != g_backtrace_hashmap.end(); ++it)
2869 json_node &node = pRoot->add_array();
2871 node.add_key_value("index", it.get_index());
2872 node.add_key_value("count", it->second);
2874 json_node &addrs_arr = node.add_array("addrs");
2875 const vogl_backtrace_addrs &addrs = it->first;
2877 for (uint i = 0; i < addrs.m_num_addrs; i++)
2879 addrs_arr.add_value(to_hex_string(static_cast<uint64_t>(addrs.m_addrs[i])));
2884 g_backtrace_hashmap.reset();
2885 g_backtrace_hashmap_mutex.unlock();
2887 if (backtrace_hashmap_size)
2890 doc.serialize(data, true, 0, false);
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);
2895 vogl_message_printf("%s: Done writing backtrace addrs\n", VOGL_FUNCTION_NAME);
2901 //----------------------------------------------------------------------------------------------------------------------
2902 // vogl_flush_compilerinfo_to_trace_file
2903 //----------------------------------------------------------------------------------------------------------------------
2904 static bool vogl_flush_compilerinfo_to_trace_file()
2906 scoped_mutex lock(g_vogl_trace_mutex);
2908 if (!g_vogl_trace_writer.is_opened() || (g_vogl_trace_writer.get_trace_archive() == NULL))
2913 vogl_message_printf("%s: Begin resolving compilerinfo to symbols\n", VOGL_FUNCTION_NAME);
2915 json_node *pRoot = doc.get_root();
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__);
2921 compiler_info_node.add_key_value("version", __VERSION__);
2924 compiler_info_node.add_key_value("arch", "32bit");
2926 compiler_info_node.add_key_value("arch", "64bit");
2930 doc.serialize(data, true, 0, false);
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);
2935 vogl_message_printf("%s: Done resolving compilerinfo to symbols\n", VOGL_FUNCTION_NAME);
2940 //----------------------------------------------------------------------------------------------------------------------
2941 // vogl_flush_machineinfo_to_trace_file
2942 //----------------------------------------------------------------------------------------------------------------------
2943 static bool vogl_flush_machineinfo_to_trace_file()
2945 scoped_mutex lock(g_vogl_trace_mutex);
2947 if (!g_vogl_trace_writer.is_opened() || (g_vogl_trace_writer.get_trace_archive() == NULL))
2952 vogl_message_printf("%s: Begin resolving machineinfo to symbols\n", VOGL_FUNCTION_NAME);
2954 json_node *pRoot = doc.get_root();
2956 btrace_get_machine_info(pRoot);
2959 doc.serialize(data, true, 0, false);
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);
2964 vogl_message_printf("%s: Done resolving machineinfo to symbols\n", VOGL_FUNCTION_NAME);
2969 //----------------------------------------------------------------------------------------------------------------------
2970 // vogl_entrypoint_serializer::begin
2971 //----------------------------------------------------------------------------------------------------------------------
2972 inline bool vogl_entrypoint_serializer::begin(gl_entrypoint_id_t id, vogl_context *pContext)
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);
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;
2987 m_packet.begin_construction(id, context_id, g_vogl_trace_writer.get_next_gl_call_counter(), thread_id, utils::RDTSC());
2989 if ((g_backtrace_all_calls) && (g_vogl_trace_writer.is_opened()))
2991 // Take a backtrace and store its hashtable index into the packet.
2992 m_packet.set_backtrace_hash_index(vogl_backtrace(1));
2998 //----------------------------------------------------------------------------------------------------------------------
2999 // vogl_is_in_null_mode
3000 //----------------------------------------------------------------------------------------------------------------------
3001 static inline bool vogl_is_in_null_mode()
3006 //----------------------------------------------------------------------------------------------------------------------
3007 // vogl_is_in_null_mode
3008 //----------------------------------------------------------------------------------------------------------------------
3009 static inline bool vogl_func_is_nulled(gl_entrypoint_id_t id)
3011 return vogl_is_in_null_mode() && g_vogl_entrypoint_descs[id].m_is_nullable;
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)
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)
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)
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)
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)
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)
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)
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)
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
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
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
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
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)
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)
3091 if (vogl_get_bound_gl_buffer(GL_PIXEL_UNPACK_BUFFER))
3095 return vogl_get_image_size(format, type, width, height, depth);
3098 size_t vogl_calc_get_tex_image_serialize_size(vogl_context *pContext, GLenum format, GLenum type, GLsizei width, GLsizei height, GLsizei depth)
3102 if (vogl_get_bound_gl_buffer(GL_PIXEL_PACK_BUFFER))
3106 return vogl_get_image_size(format, type, width, height, depth);
3109 size_t vogl_calc_get_tex_target_serialize_size(vogl_context *pContext, GLenum target, GLint level, GLenum format, GLenum type)
3113 if (vogl_get_bound_gl_buffer(GL_PIXEL_PACK_BUFFER))
3117 return vogl_get_tex_target_image_size(target, level, format, type);
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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))
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)
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)
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)
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)
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)
3181 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetAttachedShaders_obj(e, c, rt, r, nu, ne, a, p) ((obj) ? ((count) ? *(count) : (maxCount)) : -1)
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)
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)
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))
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)
3194 GLsizei total_length = 0;
3195 for (uint i = 0; i < count; i++)
3196 total_length += lengths[i];
3197 return total_length;
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)
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
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)
3224 if ((buffer == GL_DEPTH) || (buffer == GL_STENCIL))
3226 else if (utils::is_in_set<GLenum, GLenum>(buffer, GL_COLOR, GL_FRONT, GL_BACK, GL_LEFT, GL_RIGHT, GL_FRONT_AND_BACK))
3229 vogl_warning_printf("%s: Invalid value for buffer parameter passed to glClearBufferfv: 0x%04X\n", VOGL_FUNCTION_NAME, buffer);
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)
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)
3265 //----------------------------------------------------------------------------------------------------------------------
3266 static void vogl_print_hex(const void *p, uint64_t size, uint64_t type_size)
3270 vogl_log_printf("<null>\n");
3274 const uint8_t *ptr = reinterpret_cast<const uint8_t *>(p);
3275 if ((type_size == 2) && (!(size & 1)))
3278 vogl_log_printf("[ ");
3279 for (uint64_t i = 0; i < size; i += 2)
3282 vogl_log_printf(", ");
3283 vogl_log_printf("0x%04X", *reinterpret_cast<const uint16_t *>(ptr + i));
3286 vogl_log_printf("\n");
3288 vogl_log_printf(" ]");
3290 else if ((type_size == 4) && (!(size & 3)))
3293 vogl_log_printf("[ ");
3294 for (uint64_t i = 0; i < size; i += 4)
3297 vogl_log_printf(", ");
3298 vogl_log_printf("0x%08X", *reinterpret_cast<const uint32_t *>(ptr + i));
3301 vogl_log_printf("\n");
3303 vogl_log_printf(" ]");
3305 else if ((type_size == 8) && (!(size & 7)))
3308 vogl_log_printf("[ ");
3309 for (uint64_t i = 0; i < size; i += 8)
3312 vogl_log_printf(", ");
3313 vogl_log_printf("0x%" PRIX64, *reinterpret_cast<const uint64_t *>(ptr + i));
3316 vogl_log_printf("\n");
3318 vogl_log_printf(" ]");
3324 vogl_log_printf("\n");
3326 vogl_log_printf("[ ");
3327 for (uint64_t i = 0; i < size; i++)
3330 vogl_log_printf(", ");
3331 vogl_log_printf("%02X", ptr[i]);
3333 if ((++c & 63) == 63)
3334 vogl_log_printf("\n");
3336 vogl_log_printf(" ]");
3340 //----------------------------------------------------------------------------------------------------------------------
3341 static void vogl_print_string(const char *pStr, uint64_t total_size)
3343 for (uint64_t i = 0; i < total_size; i++)
3345 uint8_t c = reinterpret_cast<const uint8_t *>(pStr)[i];
3347 vogl_log_printf("\n");
3350 if ((c < 32) || (c > 127))
3352 vogl_log_printf("%c", c);
3355 if ((i & 511) == 511)
3356 vogl_log_printf(" \\\n");
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)
3364 VOGL_NOTE_UNUSED(pContext);
3366 int size = sizeof(T);
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);
3371 if (serializer.is_in_begin())
3373 serializer.add_param(param_index, type, &val, sizeof(val));
3376 if (g_dump_gl_calls_flag)
3378 vogl_log_printf("%s: %s %s, ctype: %s, size: %i: ", pDesc, pType, pParam_name, g_vogl_process_gl_ctypes[type].m_pName, size);
3380 if (Loki::TypeTraits<T>::isPointer)
3382 vogl_log_printf("OPAQUE POINTER TYPE");
3386 vogl_log_printf("OPAQUE TYPE");
3390 vogl_print_hex(&val, size, size);
3392 if (((type == VOGL_GLFLOAT) || (type == VOGL_GLCLAMPF)) && (size == sizeof(float)))
3394 float flt_val = *reinterpret_cast<const float *>(&val);
3395 vogl_log_printf(" %f", flt_val);
3397 else if (((type == VOGL_GLDOUBLE) || (type == VOGL_GLCLAMPD)) && (size == sizeof(double)))
3399 double dbl_val = *reinterpret_cast<const double *>(&val);
3400 vogl_log_printf(" %f", dbl_val);
3402 else if ((type == VOGL_GLENUM) && (size == sizeof(int)))
3404 GLenum enum_val = *reinterpret_cast<const GLenum *>(&val);
3405 const char *pName = g_gl_enums.find_name(enum_val);
3407 vogl_log_printf(" %s", pName);
3411 vogl_log_printf("\n");
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)
3419 VOGL_NOTE_UNUSED(pContext);
3421 VOGL_ASSUME(Loki::TypeTraits<T>::isPointer);
3422 int size = sizeof(T);
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);
3427 if (serializer.is_in_begin())
3429 serializer.add_param(param_index, type, &val, sizeof(val));
3432 if (g_dump_gl_calls_flag)
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));
3438 //----------------------------------------------------------------------------------------------------------------------
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)
3442 VOGL_NOTE_UNUSED(pContext);
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);
3447 int obj_size = gl_ctype_sizeof<T>::size;
3449 vogl_ctype_t pointee_type = g_vogl_process_gl_ctypes[type].m_pointee_ctype;
3450 if (pointee_type == VOGL_INVALID_CTYPE)
3452 vogl_error_printf("%s: Type %u doesn't have a pointee ctype\n", VOGL_FUNCTION_NAME, type);
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);
3459 if (serializer.is_in_begin())
3461 serializer.add_param(param_index, type, &pObj, sizeof(pObj));
3463 if ((pObj) && (obj_size > 0))
3465 serializer.add_ref_client_memory(param_index, pointee_type, pObj, obj_size);
3469 if (g_dump_gl_calls_flag)
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);
3474 vogl_log_printf("NULL");
3476 else if (obj_size <= 0)
3478 vogl_log_printf("OPAQUE TYPE");
3482 vogl_print_hex(pObj, obj_size, obj_size);
3485 vogl_log_printf("\n");
3489 //----------------------------------------------------------------------------------------------------------------------
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)
3493 VOGL_NOTE_UNUSED(pContext);
3495 int64_t obj_size = gl_ctype_sizeof<T>::size;
3496 int64_t total_size = obj_size * math::maximum<int64_t>(size, 0);
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))
3506 if (pointee_type == VOGL_INVALID_CTYPE)
3508 vogl_error_printf("%s: Type %u doesn't have a pointee ctype\n", VOGL_FUNCTION_NAME, type);
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);
3516 bool pointee_is_ptr = g_vogl_process_gl_ctypes[pointee_type].m_is_pointer;
3518 if (serializer.is_in_begin())
3520 serializer.add_param(param_index, type, &pArray, sizeof(pArray));
3522 if ((pArray) && (size > 0) && (obj_size > 0))
3524 serializer.add_array_client_memory(param_index, pointee_type, size, pArray, total_size);
3528 if (g_dump_gl_calls_flag)
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);
3534 vogl_log_printf("NULL");
3538 vogl_log_printf("UNKNOWN SIZE");
3540 else if (obj_size <= 0)
3542 vogl_log_printf("OPAQUE TYPE");
3548 vogl_log_printf("POINTEE IS POINTER: \n");
3551 vogl_print_hex(pArray, total_size, obj_size);
3553 switch (pointee_type)
3558 case VOGL_GLCHARARB:
3560 vogl_log_printf("\nAs string: \"");
3561 vogl_print_string(*(const char **)&pArray, total_size);
3562 vogl_log_printf("\"");
3572 vogl_log_printf("\n");
3576 //----------------------------------------------------------------------------------------------------------------------
3577 // Return parameters
3578 //----------------------------------------------------------------------------------------------------------------------
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)
3582 VOGL_NOTE_UNUSED(size);
3584 VOGL_ASSUME(!Loki::TypeTraits<T>::isPointer);
3586 vogl_dump_value_param(pContext, serializer, "RETURN_VALUE", VOGL_RETURN_PARAM_INDEX, "result", pType, type, val);
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)
3591 VOGL_NOTE_UNUSED(size);
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);
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)
3599 VOGL_NOTE_UNUSED(size);
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);
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)
3607 VOGL_NOTE_UNUSED(size);
3610 vogl_dump_ptr_param(pContext, serializer, "RETURN_VOID_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr);
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)
3615 vogl_dump_array_param(pContext, serializer, "RETURN_UINT_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr, size);
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)
3620 vogl_dump_array_param(pContext, serializer, "RETUURN_LUINT_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr, size);
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)
3625 VOGL_NOTE_UNUSED(size);
3627 vogl_dump_ref_param(pContext, serializer, "RETURN_XVISUALINFO_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr);
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)
3632 VOGL_NOTE_UNUSED(size);
3634 vogl_dump_ref_param(pContext, serializer, "RETURN_GLXFBCONFIG_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr);
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)
3639 VOGL_NOTE_UNUSED(size);
3642 vogl_dump_ptr_param(pContext, serializer, "RETURN_GLXCONTEXT", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr);
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)
3647 VOGL_NOTE_UNUSED(size);
3650 vogl_dump_ptr_param(pContext, serializer, "RETURN_XDISPLAY_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr);
3653 //----------------------------------------------------------------------------------------------------------------------
3654 // vogl_should_serialize_call
3655 //----------------------------------------------------------------------------------------------------------------------
3656 static inline bool vogl_should_serialize_call(gl_entrypoint_id_t func, vogl_context *pContext)
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;
3662 if ((is_in_display_list) && (is_listable) && (!is_whitelisted))
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);
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())
3671 return is_in_display_list && is_whitelisted;
3674 //----------------------------------------------------------------------------------------------------------------------
3675 // vogl_write_packet_to_trace
3676 //----------------------------------------------------------------------------------------------------------------------
3677 static inline void vogl_write_packet_to_trace(vogl_trace_packet &packet)
3679 if (!g_vogl_trace_writer.is_opened())
3682 scoped_mutex lock(g_vogl_trace_mutex);
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())
3688 bool success = g_vogl_trace_writer.write_packet(packet);
3692 if ((g_flush_files_after_each_call) ||
3693 ((g_flush_files_after_each_swap) && (packet.get_entrypoint_id() == VOGL_ENTRYPOINT_glXSwapBuffers)))
3695 g_vogl_trace_writer.flush();
3697 if (g_vogl_pLog_stream)
3698 g_vogl_pLog_stream->flush();
3703 vogl_error_printf("%s: Failed writing to trace file! Exiting app.\n", VOGL_FUNCTION_NAME);
3705 // TODO: Add common termination handler func, or just stop writing to the trace? or call abort()
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 //----------------------------------------------------------------------------------------------------------------------
3716 #define DEF_PROTO_EXPORTED(ret, name, args, params) \
3717 static ret VOGL_GLUER(vogl_, name) args \
3719 if (vogl_func_is_nulled(VOGL_ENTRYPOINT_##name)) \
3724 #define DEF_PROTO_EXPORTED_VOID(ret, name, args, params) \
3725 static ret VOGL_GLUER(vogl_, name) args \
3727 if (vogl_func_is_nulled(VOGL_ENTRYPOINT_##name)) \
3729 #define DEF_PROTO_INTERNAL(ret, name, args, params) \
3730 static ret VOGL_GLUER(vogl_, name) args \
3732 if (vogl_func_is_nulled(VOGL_ENTRYPOINT_##name)) \
3737 #define DEF_PROTO_INTERNAL_VOID(ret, name, args, params) \
3738 static ret VOGL_GLUER(vogl_, name) args \
3740 if (vogl_func_is_nulled(VOGL_ENTRYPOINT_##name)) \
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)
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.
3749 // func init (after the optional custom function prolog)
3750 #define VOGL_MASTER_FUNCTION_PROLOG(name, params) \
3751 if (g_dump_gl_calls_flag) \
3753 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "" PRIX64 "\n", #name, vogl_get_current_kernel_thread_id()); \
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) \
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; \
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)) \
3765 if (!trace_serializer.begin(VOGL_ENTRYPOINT_##name, pContext)) \
3767 vogl_warning_printf("%s: Reentrant wrapper call detected!\n", VOGL_FUNCTION_NAME); \
3768 return g_vogl_actual_gl_entrypoints.m_##name params; \
3772 #define VOGL_MASTER_FUNCTION_PROLOG_VOID(name, params) \
3773 if (g_dump_gl_calls_flag) \
3775 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", #name, vogl_get_current_kernel_thread_id()); \
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) \
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; \
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)) \
3788 if (!trace_serializer.begin(VOGL_ENTRYPOINT_##name, pContext)) \
3790 vogl_warning_printf("%s: Reentrant wrapper call detected!\n", VOGL_FUNCTION_NAME); \
3791 g_vogl_actual_gl_entrypoints.m_##name params; \
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)
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);
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);
3807 #define DEF_FUNCTION_RETURN_PARAM(spectype, type, type_enum, size) vogl_dump_return_param(pContext, trace_serializer, #type, type_enum, size, result);
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());
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());
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) \
3828 vogl_message_printf("** END %s res=%s 0x%" PRIX64 "\n", #name, #ret, cast_val_to_uint64(result)); \
3830 if (trace_serializer.is_in_begin()) \
3832 trace_serializer.end(); \
3833 vogl_write_packet_to_trace(trace_serializer.get_packet()); \
3835 pContext->add_packet_to_current_display_list(VOGL_ENTRYPOINT_##name, trace_serializer.get_packet()); \
3840 #define DEF_FUNCTION_END_VOID(exported, category, ret, ret_type_enum, num_params, name, args, params) \
3841 if (g_dump_gl_calls_flag) \
3843 vogl_message_printf("** END %s\n", #name); \
3845 if (trace_serializer.is_in_begin()) \
3847 trace_serializer.end(); \
3848 vogl_write_packet_to_trace(trace_serializer.get_packet()); \
3850 pContext->add_packet_to_current_display_list(VOGL_ENTRYPOINT_##name, trace_serializer.get_packet()); \
3854 //----------------------------------------------------------------------------------------------------------------------
3855 // gl/glx override functions
3856 //----------------------------------------------------------------------------------------------------------------------
3857 static __GLXextFuncPtr vogl_get_proc_address_helper(const GLubyte *procName)
3862 if (g_dump_gl_calls_flag)
3864 vogl_printf("glXGetProcAddress: \"%s\"\n", procName);
3867 if (!GL_ENTRYPOINT(glXGetProcAddress))
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)
3875 for (uint i = 0; i < VOGL_NUM_ENTRYPOINTS; ++i)
3877 if (vogl_strcmp(reinterpret_cast<const char *>(procName), g_vogl_entrypoint_descs[i].m_pName) == 0)
3879 if (g_vogl_entrypoint_descs[i].m_pWrapper_func)
3881 if (!g_vogl_entrypoint_descs[i].m_is_whitelisted)
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);
3887 return reinterpret_cast<__GLXextFuncPtr>(g_vogl_entrypoint_descs[i].m_pWrapper_func);
3894 return pActual_entrypoint;
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)
3903 if (g_dump_gl_calls_flag)
3905 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
3908 if (g_vogl_trace_writer.is_opened())
3910 vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glInternalTraceCommandRAD, NULL);
3912 uint64_t cur_rdtsc = utils::RDTSC();
3913 serializer.set_gl_begin_end_rdtsc(cur_rdtsc, cur_rdtsc + 1);
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));
3921 case cITCRDemarcation:
3925 case cITCRKeyValueMap:
3927 if ((size == sizeof(key_value_map)) && (data))
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);
3934 vogl_error_printf("%s: data pointer is NULL, or invalid key_value_map size %u\n", VOGL_FUNCTION_NAME, size);
3941 vogl_error_printf("%s: Unknown trace command type %u\n", VOGL_FUNCTION_NAME, cmd);
3948 vogl_write_packet_to_trace(serializer.get_packet());
3951 if (g_dump_gl_calls_flag)
3953 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
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)
3962 uint64_t begin_rdtsc = utils::RDTSC();
3964 if (g_dump_gl_calls_flag)
3966 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
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)
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);
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();
3980 if (g_vogl_trace_writer.is_opened())
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));
3988 size_t len = strlen(reinterpret_cast<const char *>(procName)) + 1;
3989 serializer.add_array_client_memory(0, VOGL_GLUBYTE, len, procName, len);
3991 serializer.add_return_param(VOGL_GLXEXTFUNCPTR, &ptr, sizeof(ptr));
3993 vogl_write_packet_to_trace(serializer.get_packet());
3996 if (g_dump_gl_calls_flag)
3998 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
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)
4008 uint64_t begin_rdtsc = utils::RDTSC();
4010 if (g_dump_gl_calls_flag)
4012 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
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)
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);
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();
4026 if (g_vogl_trace_writer.is_opened())
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));
4034 size_t len = strlen(reinterpret_cast<const char *>(procName)) + 1;
4035 serializer.add_array_client_memory(0, VOGL_GLUBYTE, len, procName, len);
4037 serializer.add_return_param(VOGL_GLXEXTFUNCPTR, &ptr, sizeof(ptr));
4039 vogl_write_packet_to_trace(serializer.get_packet());
4042 if (g_dump_gl_calls_flag)
4044 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
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)
4053 if ((result) && (pVOGL_context))
4055 vogl_scoped_gl_error_absorber gl_error_absorber(pVOGL_context);
4056 VOGL_NOTE_UNUSED(gl_error_absorber);
4058 GLint cur_viewport[4];
4059 GL_ENTRYPOINT(glGetIntegerv)(GL_VIEWPORT, cur_viewport);
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]);
4067 if ((pVOGL_context) && (pVOGL_context->get_window_width() < 0))
4069 if ((dpy) && (drawable) && (result))
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)
4076 pVOGL_context->set_window_dimensions(width, height);
4078 serializer.add_key_value(string_hash("win_width"), width);
4079 serializer.add_key_value(string_hash("win_height"), height);
4081 if (g_dump_gl_calls_flag)
4083 vogl_log_printf("** Current window dimensions: %ix%i\n", width, height);
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,
4096 GLenum internalformat,
4100 GL_ENTRYPOINT(glTexParameteri)(target, GL_TEXTURE_BASE_LEVEL, 0);
4101 GL_ENTRYPOINT(glTexParameteri)(target, GL_TEXTURE_MAX_LEVEL, levels - 1);
4103 if (target == GL_TEXTURE_2D)
4105 for (uint i = 0; i < levels; i++)
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());
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)
4120 uint64_t begin_rdtsc = utils::RDTSC();
4122 if (g_dump_gl_calls_flag)
4124 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
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)
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);
4134 if (g_dump_gl_calls_flag)
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));
4139 vogl_context *pCur_context = g_context_manager.get_current();
4141 vogl_context *pNew_context = context ? g_context_manager.lookup_vogl_context(context) : NULL;
4142 if ((context) && (!pNew_context))
4144 vogl_error_printf("%s: Unknown context handle 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(context));
4149 if (pCur_context != pNew_context)
4150 pCur_context->on_release_current_prolog();
4152 vogl_warning_printf("%s: Context 0x%" PRIX64 " is already current (redundant call)\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(context));
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();
4159 if ((result) && (pCur_context != pNew_context))
4162 g_context_manager.release_current();
4166 vogl_context *p = g_context_manager.make_current(context);
4167 VOGL_ASSERT(p == pNew_context);
4168 VOGL_NOTE_UNUSED(p);
4170 pNew_context->set_display(dpy);
4171 pNew_context->set_drawable(drawable);
4172 pNew_context->set_read_drawable(drawable);
4176 if (g_dump_gl_calls_flag)
4178 vogl_log_printf("** glXMakeCurrent result: %i\n", result);
4181 if (g_vogl_trace_writer.is_opened())
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));
4191 vogl_add_make_current_key_value_fields(dpy, drawable, result, pNew_context, serializer);
4194 vogl_write_packet_to_trace(serializer.get_packet());
4197 if (g_dump_gl_calls_flag)
4199 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
4202 static bool s_added_atexit = false;
4203 if (!s_added_atexit)
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;
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)
4219 uint64_t begin_rdtsc = utils::RDTSC();
4221 if (g_dump_gl_calls_flag)
4223 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
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)
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);
4233 if (g_dump_gl_calls_flag)
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));
4238 vogl_context *pCur_context = g_context_manager.get_current();
4240 vogl_context *pNew_context = context ? g_context_manager.lookup_vogl_context(context) : NULL;
4241 if ((context) && (!pNew_context))
4243 vogl_error_printf("%s: Unknown coontext handle 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(context));
4248 if (pCur_context != pNew_context)
4249 pCur_context->on_release_current_prolog();
4251 vogl_warning_printf("%s: Context 0x%" PRIX64 " is already current (redundant call)\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(context));
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();
4258 if ((result) && (pCur_context != pNew_context))
4261 g_context_manager.release_current();
4265 vogl_context *p = g_context_manager.make_current(context);
4266 VOGL_ASSERT(p == pNew_context);
4267 VOGL_NOTE_UNUSED(p);
4269 pNew_context->set_display(dpy);
4270 pNew_context->set_drawable(draw);
4271 pNew_context->set_read_drawable(read);
4275 if (g_dump_gl_calls_flag)
4277 vogl_log_printf("** glXMakeCurrent result: %i\n", result);
4280 if (g_vogl_trace_writer.is_opened())
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));
4291 vogl_add_make_current_key_value_fields(dpy, draw, result, pNew_context, serializer);
4294 vogl_write_packet_to_trace(serializer.get_packet());
4297 if (g_dump_gl_calls_flag)
4299 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
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)
4308 vogl_context *pContext = static_cast<vogl_context *>(pOpaque);
4310 if ((!pContext) || (!width) || (!height))
4316 if ((pixel_format != GL_RGB) || (pixel_type != GL_UNSIGNED_BYTE) || (pitch != width * 3))
4322 if (g_command_line_params.get_value_as_bool("vogl_dump_png_screenshots"))
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);
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))
4330 console::error("Failed writing PNG screenshot to file %s\n", screenshot_filename.get_ptr());
4335 else if (g_command_line_params.get_value_as_bool("vogl_dump_jpeg_screenshots"))
4337 int jpeg_quality = g_command_line_params.get_value_as_int("vogl_jpeg_quality", 0, 80, 1, 100);
4339 long unsigned int jpeg_size = 0;
4340 unsigned char *pJPEG_data = NULL;
4342 tjhandle _jpegCompressor = tjInitCompress();
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);
4348 tjDestroy(_jpegCompressor);
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))
4358 console::error("Failed writing JPEG screenshot to file %s\n", screenshot_filename.get_ptr());
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"))
4367 uint64_t backbuffer_crc64;
4369 if (g_command_line_params.get_value_as_bool("vogl_sum_hashing"))
4371 backbuffer_crc64 = calc_sum64(static_cast<const uint8 *>(pImage), size);
4375 backbuffer_crc64 = calc_crc64(CRC64_INIT, static_cast<const uint8 *>(pImage), size);
4378 console::printf("Frame %" PRIu64 " hash: 0x%016" PRIX64 "\n", cast_val_to_uint64(frame_index), backbuffer_crc64);
4380 dynamic_string backbuffer_hash_file;
4381 if (g_command_line_params.get_value_as_string(backbuffer_hash_file, "vogl_dump_backbuffer_hashes"))
4383 FILE *pFile = vogl_fopen(backbuffer_hash_file.get_ptr(), "a");
4385 console::error("Failed writing to backbuffer hash file %s\n", backbuffer_hash_file.get_ptr());
4388 vogl_fprintf(pFile, "0x%016" PRIX64 "\n", backbuffer_crc64);
4396 //----------------------------------------------------------------------------------------------------------------------
4397 static void vogl_tick_screen_capture(vogl_context *pVOGL_context)
4402 uint width = pVOGL_context->get_window_width();
4403 uint height = pVOGL_context->get_window_height();
4404 if ((!width) || (!height))
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)
4412 vogl_scoped_gl_error_absorber gl_error_absorber(pVOGL_context);
4413 VOGL_NOTE_UNUSED(gl_error_absorber);
4415 if (!pVOGL_context->get_framebuffer_capturer().is_initialized())
4417 if (!pVOGL_context->get_framebuffer_capturer().init(2, vogl_screen_capture_callback, pVOGL_context, GL_RGB, GL_UNSIGNED_BYTE))
4419 vogl_error_printf("%s: Failed initializing context's vogl_framebuffer_capturer!\n", VOGL_FUNCTION_NAME);
4424 if (!pVOGL_context->get_framebuffer_capturer().capture(width, height, 0, GL_BACK, pVOGL_context->get_frame_index()))
4426 vogl_error_printf("%s: vogl_framebuffer_capturer::capture() failed!\n", VOGL_FUNCTION_NAME);
4431 //----------------------------------------------------------------------------------------------------------------------
4432 static vogl_gl_state_snapshot *vogl_snapshot_state(const Display *dpy, GLXDrawable drawable, vogl_context *pCur_context)
4434 VOGL_NOTE_UNUSED(dpy);
4435 VOGL_NOTE_UNUSED(drawable);
4437 // pCur_context may be NULL!
4439 if (!GL_ENTRYPOINT(glXGetCurrentContext) || !GL_ENTRYPOINT(glXGetCurrentDisplay) ||
4440 !GL_ENTRYPOINT(glXGetCurrentDrawable) || !GL_ENTRYPOINT(glXGetCurrentReadDrawable))
4443 timed_scope ts(VOGL_FUNCTION_NAME);
4445 g_context_manager.lock();
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);
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)();
4458 vogl_check_gl_error();
4460 vogl_gl_state_snapshot *pSnapshot = vogl_new(vogl_gl_state_snapshot);
4462 const glxcontext_map &contexts = g_context_manager.get_context_map();
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.
4467 uint win_height = 0;
4470 win_width = pCur_context->get_window_width();
4471 win_height = pCur_context->get_window_height();
4475 glxcontext_map::const_iterator it;
4476 for (it = contexts.begin(); it != contexts.end(); ++it)
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))
4481 win_width = pVOGL_context->get_window_width();
4482 win_height = pVOGL_context->get_window_height();
4487 vogl_message_printf("%s: Beginning capture: width %u, height %u\n", VOGL_FUNCTION_NAME, win_width, win_height);
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))
4491 vogl_error_printf("%s: Failed beginning capture\n", VOGL_FUNCTION_NAME);
4493 vogl_delete(pSnapshot);
4496 g_context_manager.unlock();
4501 vogl_printf("%s: Capturing %u context(s)\n", VOGL_FUNCTION_NAME, contexts.size());
4503 glxcontext_map::const_iterator it;
4504 for (it = contexts.begin(); it != contexts.end(); ++it)
4506 GLXContext glx_context = it->first;
4507 vogl_context *pVOGL_context = it->second;
4509 if (pVOGL_context->get_deleted_flag())
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));
4515 if (pVOGL_context->get_has_been_made_current())
4517 if (!GL_ENTRYPOINT(glXMakeCurrent)(pVOGL_context->get_display(), pVOGL_context->get_drawable(), glx_context))
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));
4523 if (pVOGL_context->get_total_mapped_buffers())
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());
4529 if (pVOGL_context->is_composing_display_list())
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));
4535 if (pVOGL_context->get_in_gl_begin())
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));
4542 vogl_capture_context_params &capture_context_params = pVOGL_context->get_capture_context_params();
4544 if (!pSnapshot->capture_context(pVOGL_context->get_context_desc(), pVOGL_context->get_context_info(), pVOGL_context->get_handle_remapper(), capture_context_params))
4546 vogl_error_printf("%s: Failed capturing trace context 0x%" PRIX64 ", capture failed\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(glx_context));
4551 if ((it == contexts.end()) && (pSnapshot->end_capture()))
4553 vogl_printf("%s: Capture succeeded\n", VOGL_FUNCTION_NAME);
4557 vogl_printf("%s: Capture failed\n", VOGL_FUNCTION_NAME);
4559 vogl_delete(pSnapshot);
4565 GL_ENTRYPOINT(glXMakeContextCurrent)(orig_dpy, orig_drawable, orig_read_drawable, orig_context);
4568 vogl_check_gl_error();
4570 g_context_manager.unlock();
4575 //----------------------------------------------------------------------------------------------------------------------
4577 // Important: This could be called at signal time!
4578 //----------------------------------------------------------------------------------------------------------------------
4579 static void vogl_end_capture(bool inside_signal_handler)
4583 VOGL_NOTE_UNUSED(inside_signal_handler);
4585 vogl_debug_printf("%s\n", VOGL_FUNCTION_NAME);
4587 g_context_manager.lock();
4589 vogl_context *pVOGL_context = g_context_manager.get_current();
4593 pVOGL_context->get_framebuffer_capturer().flush();
4595 if (inside_signal_handler)
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))
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);
4602 if (g_vogl_trace_writer.is_opened())
4604 vogl_entrypoint_serializer &trace_serializer = pTLS_data->m_serializer;
4605 if (trace_serializer.is_in_begin())
4607 vogl_error_printf("%s: Attempting to flush final trace packet\n", VOGL_FUNCTION_NAME);
4609 trace_serializer.end();
4611 vogl_write_packet_to_trace(trace_serializer.get_packet());
4618 g_context_manager.unlock();
4620 scoped_mutex lock(g_vogl_trace_mutex);
4622 if (g_vogl_trace_writer.is_opened())
4624 dynamic_string filename(g_vogl_trace_writer.get_filename());
4626 vogl_flush_compilerinfo_to_trace_file();
4627 vogl_flush_machineinfo_to_trace_file();
4628 vogl_flush_backtrace_to_trace_file();
4630 if (!g_vogl_trace_writer.close())
4632 vogl_error_printf("%s: Failed closing trace file!\n", VOGL_FUNCTION_NAME);
4634 if (g_vogl_pCapture_status_callback)
4635 (*g_vogl_pCapture_status_callback)(NULL, g_vogl_pCapture_status_opaque);
4639 if (g_vogl_pCapture_status_callback)
4640 (*g_vogl_pCapture_status_callback)(filename.get_ptr(), g_vogl_pCapture_status_opaque);
4643 if (g_pJSON_node_pool)
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()));
4650 g_vogl_frames_remaining_to_capture = 0;
4652 g_vogl_pCapture_status_callback = NULL;
4653 g_vogl_pCapture_status_opaque = NULL;
4656 //----------------------------------------------------------------------------------------------------------------------
4657 static bool vogl_write_snapshot_to_trace(const char *pTrace_filename, const Display *dpy, GLXDrawable drawable, vogl_context *pVOGL_context)
4660 vogl_message_printf("%s: Snapshot begin\n", VOGL_FUNCTION_NAME);
4662 // pVOGL_context may be NULL here!
4664 vogl_unique_ptr<vogl_gl_state_snapshot> pSnapshot(vogl_snapshot_state(dpy, drawable, pVOGL_context));
4665 if (!pSnapshot.get())
4667 vogl_error_printf("%s: Failed snapshotting GL/GLX state!\n", VOGL_FUNCTION_NAME);
4674 pSnapshot->set_frame_index(0);
4676 if (!g_vogl_trace_writer.open(pTrace_filename, NULL, true, false))
4678 vogl_error_printf("%s: Failed creating trace file \"%s\"!\n", VOGL_FUNCTION_NAME, pTrace_filename);
4685 vogl_archive_blob_manager &trace_archive = *g_vogl_trace_writer.get_trace_archive();
4687 vogl_message_printf("%s: Serializing snapshot data to JSON document\n", VOGL_FUNCTION_NAME);
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.
4691 if (!pSnapshot->serialize(*doc.get_root(), trace_archive, &g_vogl_process_gl_ctypes))
4693 vogl_error_printf("%s: Failed serializing GL state snapshot!\n", VOGL_FUNCTION_NAME);
4702 vogl_message_printf("%s: Serializing JSON document to UBJ\n", VOGL_FUNCTION_NAME);
4704 uint8_vec binary_snapshot_data;
4705 vogl::vector<char> snapshot_data;
4707 // TODO: This can take a lot of memory
4708 doc.binary_serialize(binary_snapshot_data);
4710 vogl_message_printf("%s: Compressing UBJ data and adding to trace archive\n", VOGL_FUNCTION_NAME);
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())
4715 vogl_error_printf("%s: Failed adding binary GL snapshot file to output blob manager!\n", VOGL_FUNCTION_NAME);
4722 binary_snapshot_data.clear();
4724 snapshot_data.clear();
4727 // TODO: This requires too much temp memory!
4728 doc.serialize(snapshot_data, true, 0, false);
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())
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();
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);
4744 // TODO: This requires too much temp memory!
4745 snapshot_key_value_map.insert("id", snapshot_id);
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)))
4753 vogl_error_printf("%s: Failed writing to trace file!\n", VOGL_FUNCTION_NAME);
4757 if (!vogl_write_glInternalTraceCommandRAD(g_vogl_trace_writer.get_stream(), &trace_gl_ctypes, cITCRDemarcation, 0, NULL))
4761 vogl_error_printf("%s: Failed writing to trace file!\n", VOGL_FUNCTION_NAME);
4767 if (g_pJSON_node_pool)
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()));
4773 vogl_message_printf("%s: Snapshot complete\n", VOGL_FUNCTION_NAME);
4778 //----------------------------------------------------------------------------------------------------------------------
4779 static void vogl_capture_status_callback_func(const char *pFilename, void *pOpaque)
4782 VOGL_ASSERT(pOpaque == (void *)1);
4783 vogl_message_printf("%s: Filename \"%s\", opaque: %p\n", VOGL_FUNCTION_NAME, pFilename ? pFilename : "<null>", pOpaque);
4786 //----------------------------------------------------------------------------------------------------------------------
4787 static bool vogl_check_for_trigger_file(const char *pBase_name, dynamic_string &filename)
4789 filename = pBase_name;
4790 if (!file_utils::does_file_exist(filename.get_ptr()))
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());
4796 if (path_to_check.is_empty())
4799 file_utils::combine_path(filename, path_to_check.get_ptr(), pBase_name);
4800 if (!file_utils::does_file_exist(filename.get_ptr()))
4807 //----------------------------------------------------------------------------------------------------------------------
4808 static void vogl_check_for_capture_stop_file()
4810 if (!vogl_is_capturing())
4813 dynamic_string stop_filename;
4814 if (!vogl_check_for_trigger_file(VOGL_STOP_CAPTURE_FILENAME, stop_filename))
4817 file_utils::delete_file(stop_filename.get_ptr());
4819 vogl_stop_capturing();
4822 //----------------------------------------------------------------------------------------------------------------------
4823 static void vogl_check_for_capture_trigger_file()
4826 scoped_mutex lock(g_vogl_trace_mutex);
4827 if ((g_vogl_frames_remaining_to_capture) || (g_vogl_trace_writer.is_opened()))
4831 dynamic_string trigger_filename;
4832 if (!vogl_check_for_trigger_file(VOGL_TRIGGER_CAPTURE_FILENAME, trigger_filename))
4837 // Lamely try to protected against racing - a better method is probably inotify: http://www.thegeekstuff.com/2010/04/inotify-c-program-example/
4841 file_utils::get_file_size(trigger_filename.get_ptr(), size);
4846 file_utils::get_file_size(trigger_filename.get_ptr(), size1);
4854 uint total_frames = 1;
4855 dynamic_string path;
4856 dynamic_string base_name;
4858 dynamic_string_array lines;
4859 if (!file_utils::read_text_file(trigger_filename.get_ptr(), lines, file_utils::cRTFTrim | file_utils::cRTFIgnoreEmptyLines))
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());
4865 if (lines.size() >= 1)
4867 if (lines[0] == "all")
4868 total_frames = cUINT32_MAX;
4870 total_frames = string_to_uint(lines[0].get_ptr(), 1);
4872 if (lines.size() >= 2)
4876 if (lines.size() >= 3)
4877 base_name = lines[2];
4881 file_utils::delete_file(trigger_filename.get_ptr());
4883 bool success = vogl_capture_on_next_swap(total_frames, path.get_ptr(), base_name.get_ptr(), vogl_capture_status_callback_func, (void *)1);
4886 vogl_error_printf("%s: Failed enabling capture mode\n", VOGL_FUNCTION_NAME);
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());
4891 //----------------------------------------------------------------------------------------------------------------------
4892 // vogl_tick_capture
4893 //----------------------------------------------------------------------------------------------------------------------
4894 static void vogl_tick_capture(const Display *dpy, GLXDrawable drawable, vogl_context *pVOGL_context)
4898 // pVOGL_context may be NULL here!
4900 vogl_check_for_capture_stop_file();
4901 vogl_check_for_capture_trigger_file();
4903 scoped_mutex lock(g_vogl_trace_mutex);
4905 if ((g_vogl_total_frames_to_capture) && (!g_vogl_frames_remaining_to_capture))
4907 g_vogl_frames_remaining_to_capture = g_vogl_total_frames_to_capture;
4908 g_vogl_total_frames_to_capture = 0;
4911 if (g_vogl_stop_capturing)
4913 g_vogl_stop_capturing = false;
4915 if (g_vogl_trace_writer.is_opened())
4923 if (!g_vogl_frames_remaining_to_capture)
4926 if (!g_vogl_trace_writer.is_opened())
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;
4934 time_t t = time(NULL);
4935 struct tm ltm = *localtime(&t);
4937 dynamic_string trace_basename("capture");
4938 if (!g_vogl_capture_basename.is_empty())
4939 trace_basename = g_vogl_capture_basename;
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);
4943 dynamic_string full_trace_filename;
4944 file_utils::combine_path(full_trace_filename, trace_path.get_ptr(), filename.get_ptr());
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());
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());
4951 if (!vogl_write_snapshot_to_trace(full_trace_filename.get_ptr(), dpy, drawable, pVOGL_context))
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);
4959 if (g_vogl_frames_remaining_to_capture != cUINT32_MAX)
4960 g_vogl_frames_remaining_to_capture--;
4962 // See if we should stop capturing.
4963 if (!g_vogl_frames_remaining_to_capture)
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)
4976 // pVOGL_context may be NULL here!
4978 if (!GL_ENTRYPOINT(glXGetCurrentContext) || !GL_ENTRYPOINT(glXGetCurrentDisplay) ||
4979 !GL_ENTRYPOINT(glXGetCurrentDrawable) || !GL_ENTRYPOINT(glXGetCurrentReadDrawable))
4984 bool override_current_context = false;
4986 if ((!pVOGL_context) || ((pVOGL_context->get_display() != dpy) || (pVOGL_context->get_drawable() != drawable)))
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);
4991 pVOGL_context = g_context_manager.find_context(dpy, drawable);
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);
4998 else if (pVOGL_context->get_current_thread() != 0)
5000 vogl_error_printf("%s: The GL context which matches the provided display/drawable is already current on another thread!\n", VOGL_FUNCTION_NAME);
5004 override_current_context = true;
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)
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)();
5021 GL_ENTRYPOINT(glXMakeCurrent)(pVOGL_context->get_display(), pVOGL_context->get_drawable(), pVOGL_context->get_context_handle());
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))
5029 pVOGL_context->set_window_dimensions(width, height);
5031 vogl_tick_screen_capture(pVOGL_context);
5035 console::warning("%s: XGetGeometry() call failed!\n", VOGL_FUNCTION_NAME);
5038 if (trace_serializer.is_in_begin())
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());
5044 if (g_dump_gl_calls_flag)
5046 vogl_log_printf("** Current window dimensions: %ix%i\n", pVOGL_context->get_window_width(), pVOGL_context->get_window_height());
5049 pVOGL_context->inc_frame_index();
5051 if ((override_current_context) && (orig_dpy))
5053 GL_ENTRYPOINT(glXMakeContextCurrent)(orig_dpy, orig_drawable, orig_read_drawable, orig_context);
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)
5061 uint64_t begin_rdtsc = utils::RDTSC();
5063 if (g_dump_gl_calls_flag)
5065 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
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)
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);
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;
5078 if (g_vogl_trace_writer.is_opened())
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));
5085 vogl_glXSwapBuffersGLFuncProlog(dpy, drawable, pTLS_data->m_pContext, serializer);
5087 uint64_t gl_begin_rdtsc = utils::RDTSC();
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);
5092 uint64_t gl_end_rdtsc = utils::RDTSC();
5094 if (g_vogl_trace_writer.is_opened())
5096 serializer.set_begin_rdtsc(begin_rdtsc);
5097 serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
5099 vogl_write_packet_to_trace(serializer.get_packet());
5102 vogl_tick_capture(dpy, drawable, pTLS_data->m_pContext);
5104 if (g_dump_gl_calls_flag)
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));
5109 if (g_dump_gl_calls_flag)
5111 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5114 if (g_command_line_params.has_key("vogl_exit_after_x_frames") && (pTLS_data->m_pContext))
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();
5119 if (cur_num_frames >= max_num_frames)
5121 vogl_message_printf("Number of frames specified by --vogl_exit_after_x_frames param reached, forcing trace to close and calling exit()\n");
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)
5135 uint64_t begin_rdtsc = utils::RDTSC();
5137 if (g_dump_gl_calls_flag)
5139 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
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)
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);
5149 vogl_context_attribs context_attribs;
5151 if (g_command_line_params.get_value_as_bool("vogl_force_debug_context"))
5153 vogl_warning_printf("%s: Forcing debug context\n", VOGL_FUNCTION_NAME);
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);
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;
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);
5167 if (context_major_version_ofs < 0)
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).
5171 else if (context_attribs[context_major_version_ofs] < 3)
5173 context_attribs[context_major_version_ofs] = 3;
5175 if (context_minor_version_ofs < 0)
5176 context_attribs.add_key(GLX_CONTEXT_MINOR_VERSION_ARB, 0);
5178 context_attribs[context_minor_version_ofs] = 0;
5180 vogl_warning_printf("%s: Forcing GL context version up to v3.0 due to debug context usage\n", VOGL_FUNCTION_NAME);
5183 attrib_list = context_attribs.get_vec().get_ptr();
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();
5190 if (g_dump_gl_calls_flag)
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));
5195 if (g_vogl_trace_writer.is_opened())
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));
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);
5210 serializer.add_return_param(VOGL_GLXCONTEXT, &result, sizeof(result));
5212 vogl_write_packet_to_trace(serializer.get_packet());
5219 if (!g_app_uses_sharelists)
5220 vogl_message_printf("%s: sharelist usage detected\n", VOGL_FUNCTION_NAME);
5222 g_app_uses_sharelists = true;
5225 g_context_manager.lock();
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);
5238 vogl_context *pShare_context = g_context_manager.lookup_vogl_context(share_context);
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));
5244 while (!pShare_context->is_root_context())
5245 pShare_context = pShare_context->get_shared_state();
5247 pVOGL_context->set_shared_context(pShare_context);
5249 pShare_context->add_ref();
5253 pVOGL_context->init();
5255 g_context_manager.unlock();
5258 if (g_dump_gl_calls_flag)
5260 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
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)
5273 vogl_context_attribs attribs;
5275 #define GET_CONFIG(attrib) \
5279 GL_ENTRYPOINT(glXGetConfig)(dpy, vis, attrib, &val); \
5281 attribs.add_key(attrib, val); \
5285 GL_ENTRYPOINT(glXGetConfig)(dpy, vis, GLX_RGBA, &is_rgba);
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);
5292 GET_CONFIG(GLX_BUFFER_SIZE);
5294 GET_CONFIG(GLX_LEVEL);
5296 GET_CONFIG(GLX_DOUBLEBUFFER);
5297 GET_CONFIG(GLX_STEREO);
5298 GET_CONFIG(GLX_AUX_BUFFERS);
5301 GET_CONFIG(GLX_RED_SIZE);
5302 GET_CONFIG(GLX_GREEN_SIZE);
5303 GET_CONFIG(GLX_BLUE_SIZE);
5304 GET_CONFIG(GLX_ALPHA_SIZE);
5306 GET_CONFIG(GLX_DEPTH_SIZE);
5307 GET_CONFIG(GLX_STENCIL_SIZE);
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);
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))
5319 GET_CONFIG(GLX_TRANSPARENT_TYPE);
5324 for (uint i = 0; i < attribs.size(); i += 2)
5328 printf("%s 0x%x\n", g_gl_enums.find_glx_name(attribs[i]), attribs[i + 1]);
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;
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)
5341 uint64_t begin_rdtsc = utils::RDTSC();
5343 if (g_dump_gl_calls_flag)
5345 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
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)
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);
5355 if (g_command_line_params.get_value_as_bool("vogl_force_debug_context"))
5357 vogl_warning_printf("%s: Can't enable debug contexts via glXCreateContext(), forcing call to use glXCreateContextsAttribsARB() instead\n", VOGL_FUNCTION_NAME);
5359 GLXFBConfig *pConfig = vogl_get_fb_config_from_xvisual_info(dpy, vis);
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);
5366 int empty_attrib_list[1] = { 0 };
5367 return vogl_glXCreateContextAttribsARB(dpy, pConfig[0], shareList, direct, empty_attrib_list);
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();
5375 if (g_dump_gl_calls_flag)
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));
5380 if (g_vogl_trace_writer.is_opened())
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));
5391 serializer.add_ref_client_memory(1, VOGL_XVISUALINFO, vis, sizeof(XVisualInfo));
5393 vogl_write_packet_to_trace(serializer.get_packet());
5400 if (!g_app_uses_sharelists)
5401 vogl_message_printf("%s: sharelist usage detected\n", VOGL_FUNCTION_NAME);
5403 g_app_uses_sharelists = true;
5406 g_context_manager.lock();
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);
5417 vogl_context *pShare_context = g_context_manager.lookup_vogl_context(shareList);
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));
5423 while (!pShare_context->is_root_context())
5424 pShare_context = pShare_context->get_shared_state();
5426 pVOGL_context->set_shared_context(pShare_context);
5428 pShare_context->add_ref();
5432 pVOGL_context->init();
5434 g_context_manager.unlock();
5437 if (g_dump_gl_calls_flag)
5439 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
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)
5449 if (render_type != GLX_RGBA_TYPE)
5451 vogl_error_printf("%s: Unsupported render type (%s)!\n", VOGL_FUNCTION_NAME, g_gl_enums.find_glx_name(render_type));
5454 if (g_command_line_params.get_value_as_bool("vogl_force_debug_context"))
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);
5458 return vogl_glXCreateContextAttribsARB(dpy, config, share_list, direct, NULL);
5461 uint64_t begin_rdtsc = utils::RDTSC();
5463 if (g_dump_gl_calls_flag)
5465 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
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)
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);
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();
5479 if (g_dump_gl_calls_flag)
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));
5485 if (g_vogl_trace_writer.is_opened())
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));
5497 vogl_write_packet_to_trace(serializer.get_packet());
5504 if (!g_app_uses_sharelists)
5505 vogl_message_printf("%s: sharelist usage detected\n", VOGL_FUNCTION_NAME);
5507 g_app_uses_sharelists = true;
5510 g_context_manager.lock();
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);
5521 vogl_context *pShare_context = g_context_manager.lookup_vogl_context(share_list);
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));
5527 while (!pShare_context->is_root_context())
5528 pShare_context = pShare_context->get_shared_state();
5530 pVOGL_context->set_shared_context(pShare_context);
5532 pShare_context->add_ref();
5536 pVOGL_context->init();
5538 g_context_manager.unlock();
5541 if (g_dump_gl_calls_flag)
5543 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
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)
5553 uint64_t begin_rdtsc = utils::RDTSC();
5555 if (g_dump_gl_calls_flag)
5557 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
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)
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);
5567 if (g_dump_gl_calls_flag)
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));
5572 vogl_context *pContext = context ? g_context_manager.lookup_vogl_context(context) : NULL;
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());
5580 pContext->on_destroy_prolog();
5583 uint64_t gl_begin_rdtsc = utils::RDTSC();
5584 GL_ENTRYPOINT(glXDestroyContext)(dpy, context);
5585 uint64_t gl_end_rdtsc = utils::RDTSC();
5587 if (g_vogl_trace_writer.is_opened())
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));
5595 vogl_write_packet_to_trace(serializer.get_packet());
5596 g_vogl_trace_writer.flush();
5601 g_context_manager.lock();
5603 VOGL_ASSERT(!pContext->get_deleted_flag());
5604 if (!pContext->get_deleted_flag())
5606 pContext->set_deleted_flag(true);
5608 if (pContext->is_share_context())
5610 VOGL_ASSERT(pContext->get_ref_count() == 1);
5613 int new_ref_count = pContext->del_ref();
5614 if (new_ref_count <= 0)
5616 if (pContext->is_share_context())
5618 vogl_context *pRoot_context = pContext->get_shared_state();
5620 pContext->set_shared_context(NULL);
5622 if (pRoot_context->del_ref() == 0)
5624 VOGL_ASSERT(pRoot_context->get_deleted_flag());
5626 bool status = g_context_manager.destroy_context(pRoot_context->get_context_handle());
5627 VOGL_ASSERT(status);
5628 VOGL_NOTE_UNUSED(status);
5632 bool status = g_context_manager.destroy_context(context);
5633 VOGL_ASSERT(status);
5634 VOGL_NOTE_UNUSED(status);
5638 g_context_manager.unlock();
5641 if (g_vogl_pLog_stream)
5643 // TODO: Ensure this is actually thread safe (does the gcc C runtime mutex this?)
5644 g_vogl_pLog_stream->flush();
5647 if (g_dump_gl_calls_flag)
5649 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5653 //----------------------------------------------------------------------------------------------------------------------
5654 #define DEF_FUNCTION_CUSTOM_HANDLER_glGetError(exported, category, ret, ret_type_enum, num_params, name, args, params)
5655 static GLenum vogl_glGetError()
5657 uint64_t begin_rdtsc = utils::RDTSC();
5659 if (g_dump_gl_calls_flag)
5661 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
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)
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)();
5671 if (g_dump_gl_calls_flag)
5673 vogl_log_printf("** glGetError TID: 0x%" PRIX64 "\n", vogl_get_current_kernel_thread_id());
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).
5680 uint64_t gl_begin_rdtsc = utils::RDTSC();
5681 GLenum gl_err = GL_ENTRYPOINT(glGetError)();
5682 uint64_t gl_end_rdtsc = utils::RDTSC();
5684 if (g_vogl_trace_writer.is_opened())
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));
5691 if ((pContext) && (pContext->has_latched_gl_error()))
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());
5698 vogl_write_packet_to_trace(serializer.get_packet());
5699 g_vogl_trace_writer.flush();
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())
5705 if (gl_err != GL_NO_ERROR)
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());
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();
5713 pContext->clear_latched_gl_error();
5716 if (g_dump_gl_calls_flag)
5718 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
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)
5731 if (g_dump_gl_shaders_flag)
5733 vogl_log_printf("Source source code, %i string(s):\n", count);
5734 for (GLsizei i = 0; i < count; i++)
5736 const char *pStr = (const char *)string[i];
5739 str_len = length[i];
5741 str_len = pStr ? (vogl_strlen(pStr) + 1) : 0;
5743 vogl_log_printf("\"");
5744 vogl_print_string(pStr, str_len);
5745 vogl_log_printf("\"\n");
5749 if (trace_serializer.is_in_begin())
5751 for (GLsizei i = 0; i < count; i++)
5753 const char *pStr = (const char *)string[i];
5756 str_len = length[i];
5758 str_len = pStr ? (vogl_strlen(pStr) + 1) : 0;
5760 if ((str_len) && (pStr))
5761 trace_serializer.add_key_value_blob(i, pStr, str_len);
5766 //----------------------------------------------------------------------------------------------------------------------
5767 // vogl_uses_client_side_arrays
5768 //----------------------------------------------------------------------------------------------------------------------
5769 static bool vogl_uses_client_side_arrays(vogl_context *pContext, bool indexed)
5771 if ((!pContext) || (!pContext->get_uses_client_side_arrays()) || (pContext->is_core_profile()))
5774 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
5775 VOGL_NOTE_UNUSED(gl_error_absorber);
5779 GLuint element_array_buffer = vogl_get_bound_gl_buffer(GL_ELEMENT_ARRAY_BUFFER);
5780 if (!element_array_buffer)
5784 bool used_old_style_gl_client_side_arrays = false;
5786 GLint prev_client_active_texture = 0;
5787 GL_ENTRYPOINT(glGetIntegerv)(GL_CLIENT_ACTIVE_TEXTURE, &prev_client_active_texture);
5789 const uint tex_coords = pContext->get_max_texture_coords();
5791 for (uint i = 0; i < VOGL_NUM_CLIENT_SIDE_ARRAY_DESCS; i++)
5793 const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[i];
5794 if (i == vogl_texcoord_pointer_array_id)
5796 for (uint tex_index = 0; tex_index < tex_coords; tex_index++)
5798 GL_ENTRYPOINT(glClientActiveTexture)(GL_TEXTURE0 + tex_index);
5800 GLboolean is_enabled = GL_ENTRYPOINT(glIsEnabled)(desc.m_is_enabled);
5805 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_binding, &binding);
5809 used_old_style_gl_client_side_arrays = true;
5813 if (used_old_style_gl_client_side_arrays)
5818 GLboolean is_enabled = GL_ENTRYPOINT(glIsEnabled)(desc.m_is_enabled);
5823 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_binding, &binding);
5827 used_old_style_gl_client_side_arrays = true;
5832 GL_ENTRYPOINT(glClientActiveTexture)(prev_client_active_texture);
5834 if (used_old_style_gl_client_side_arrays)
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);
5840 for (uint i = 0; i < pContext->get_max_vertex_attribs(); i++)
5842 GLint is_enabled = 0;
5843 GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &is_enabled);
5848 GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &cur_buf);
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)
5865 VOGL_NOTE_UNUSED(mode);
5867 VOGL_NOTE_UNUSED(pFunc);
5869 if ((!pContext) || (pContext->is_core_profile()))
5874 vogl_error_printf("%s: end (%i) must be >= start (%i)\n", VOGL_FUNCTION_NAME, end, start);
5878 uint index_size = vogl_get_gl_type_size(type);
5881 vogl_error_printf("%s: Invalid type parameter 0x%08X\n", VOGL_FUNCTION_NAME, type);
5885 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
5886 VOGL_NOTE_UNUSED(gl_error_absorber);
5888 GLuint element_array_buffer = 0;
5891 element_array_buffer = vogl_get_bound_gl_buffer(GL_ELEMENT_ARRAY_BUFFER);
5892 if (!element_array_buffer)
5896 vogl_error_printf("%s: No bound element array buffer, and indices parameter is NULL\n", VOGL_FUNCTION_NAME);
5901 if (g_dump_gl_buffers_flag)
5903 vogl_log_printf("Client side index data: ");
5904 vogl_print_hex(indices, count * index_size, index_size);
5905 vogl_log_printf("\n");
5908 if (trace_serializer.is_in_begin())
5910 trace_serializer.add_key_value_blob(string_hash("indices"), indices, count * index_size);
5916 const gl_entrypoint_id_t cur_entrypoint = trace_serializer.get_cur_entrypoint();
5917 VOGL_NOTE_UNUSED(cur_entrypoint);
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.
5921 bool used_old_style_gl_client_side_arrays = false;
5923 GLint prev_client_active_texture = 0;
5924 GL_ENTRYPOINT(glGetIntegerv)(GL_CLIENT_ACTIVE_TEXTURE, &prev_client_active_texture);
5926 const uint tex_coords = pContext->get_max_texture_coords();
5928 for (uint i = 0; i < VOGL_NUM_CLIENT_SIDE_ARRAY_DESCS; i++)
5930 const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[i];
5931 if (i == vogl_texcoord_pointer_array_id)
5933 for (uint tex_index = 0; tex_index < tex_coords; tex_index++)
5935 GL_ENTRYPOINT(glClientActiveTexture)(GL_TEXTURE0 + tex_index);
5937 GLboolean is_enabled = GL_ENTRYPOINT(glIsEnabled)(desc.m_is_enabled);
5942 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_binding, &binding);
5946 used_old_style_gl_client_side_arrays = true;
5950 if (used_old_style_gl_client_side_arrays)
5955 GLboolean is_enabled = GL_ENTRYPOINT(glIsEnabled)(desc.m_is_enabled);
5960 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_binding, &binding);
5964 used_old_style_gl_client_side_arrays = true;
5969 GL_ENTRYPOINT(glClientActiveTexture)(prev_client_active_texture);
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);
5974 for (uint i = 0; i < pContext->get_max_vertex_attribs(); i++)
5976 GLint is_enabled = 0;
5977 GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &is_enabled);
5982 GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &cur_buf);
5986 vertex_attrib_client_side_arrays |= (1ULL << i);
5989 if ((!used_old_style_gl_client_side_arrays) && (!vertex_attrib_client_side_arrays))
5994 if (!start_end_valid)
5996 uint total_index_data_size = count * index_size;
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);
6002 if (element_array_buffer)
6004 index_data.resize(total_index_data_size);
6005 pIndices_to_scan = index_data.get_ptr();
6007 GL_ENTRYPOINT(glGetBufferSubData)(GL_ELEMENT_ARRAY_BUFFER, (GLintptr)indices, total_index_data_size, index_data.get_ptr());
6010 start = cUINT32_MAX;
6013 for (int i = 0; i < count; i++)
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];
6028 start = math::minimum(start, v);
6029 end = math::maximum(end, v);
6033 if (trace_serializer.is_in_begin())
6035 trace_serializer.add_key_value(string_hash("start"), start);
6036 trace_serializer.add_key_value(string_hash("end"), end);
6040 if (used_old_style_gl_client_side_arrays)
6042 for (uint client_array_iter = 0; client_array_iter < VOGL_NUM_CLIENT_SIDE_ARRAY_DESCS; client_array_iter++)
6044 const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[client_array_iter];
6047 uint base_key_index = 0x1000 + client_array_iter;
6049 // Special case texcoord pointers, which are accessed via the client active texture.
6050 if (client_array_iter == vogl_texcoord_pointer_array_id)
6053 base_key_index = 0x2000;
6056 for (uint inner_iter = 0; inner_iter < n; inner_iter++)
6058 if (client_array_iter == vogl_texcoord_pointer_array_id)
6060 GL_ENTRYPOINT(glClientActiveTexture)(GL_TEXTURE0 + inner_iter);
6063 GLboolean is_enabled = GL_ENTRYPOINT(glIsEnabled)(desc.m_is_enabled);
6068 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_binding, &binding);
6073 GL_ENTRYPOINT(glGetPointerv)(desc.m_get_pointer, &ptr);
6077 GLint type = GL_BOOL;
6078 if (desc.m_get_type)
6080 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_type, &type);
6084 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_stride, &stride);
6087 if (desc.m_get_size)
6089 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_size, &size);
6092 uint type_size = vogl_get_gl_type_size(type);
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);
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))
6105 else if ((desc.m_entrypoint == VOGL_ENTRYPOINT_glNormalPointer) || (desc.m_entrypoint == VOGL_ENTRYPOINT_glNormalPointerEXT))
6109 else if ((size < 1) || (size > 4))
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);
6116 stride = type_size * size;
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;
6122 if (g_dump_gl_buffers_flag)
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");
6129 if (trace_serializer.is_in_begin())
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);
6136 } // client_array_iter
6138 GL_ENTRYPOINT(glClientActiveTexture)(prev_client_active_texture);
6139 } // used_old_style_gl_client_side_arrays
6141 if (vertex_attrib_client_side_arrays)
6143 for (uint i = 0; i < pContext->get_max_vertex_attribs(); i++)
6145 if ((vertex_attrib_client_side_arrays & (1ULL << i)) == 0)
6148 GLvoid *attrib_ptr = NULL;
6149 GL_ENTRYPOINT(glGetVertexAttribPointerv)(i, GL_VERTEX_ATTRIB_ARRAY_POINTER, &attrib_ptr);
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);
6157 GLint attrib_size = 0;
6158 GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_SIZE, &attrib_size);
6160 GLint attrib_type = 0;
6161 GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_TYPE, &attrib_type);
6163 GLint attrib_stride = 0;
6164 GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &attrib_stride);
6167 if ((attrib_size != GL_BGRA) && (attrib_size < 1) && (attrib_size > 4))
6169 vogl_error_printf("%s: Enabled vertex attribute index %i has invalid size 0x%0X\n", VOGL_FUNCTION_NAME, i, attrib_size);
6172 if ((attrib_size >= 1) && (attrib_size <= 4))
6173 num_comps = attrib_size;
6175 uint type_size = vogl_get_gl_type_size(attrib_type);
6178 vogl_error_printf("%s: Vertex attribute index %i has unsupported type 0x%0X\n", VOGL_FUNCTION_NAME, i, attrib_type);
6182 uint stride = attrib_stride ? attrib_stride : (type_size * num_comps);
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;
6188 if (g_dump_gl_buffers_flag)
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);
6192 vogl_print_hex(static_cast<const uint8_t *>(attrib_ptr) + first_vertex_ofs, vertex_data_size, type_size);
6194 vogl_log_printf("\n");
6197 if (trace_serializer.is_in_begin())
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);
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);
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)
6219 if (trace_serializer.is_in_begin())
6221 vogl_serialize_client_side_arrays_helper(pContext, trace_serializer, pFunc,
6222 mode, start, end, count, type, indices, basevertex, start_end_valid, true);
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)
6231 if (trace_serializer.is_in_begin())
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);
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)
6243 VOGL_NOTE_UNUSED(primcount);
6244 if (trace_serializer.is_in_begin())
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);
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)
6256 if (trace_serializer.is_in_begin())
6258 if (vogl_uses_client_side_arrays(pContext, false))
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);
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)
6271 if (trace_serializer.is_in_begin())
6273 if (vogl_uses_client_side_arrays(pContext, true))
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);
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)
6287 if (!g_disable_gl_program_binary_flag)
6290 if ((pVOGL_context) && (pResult) && (name == GL_EXTENSIONS))
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");
6296 dynamic_string id(cVarArg, "%s_%x_%x", pFunc_name, name, index);
6298 dynamic_string &ext_str = pVOGL_context->get_extension_map()[id];
6299 ext_str.set((char *)pResult);
6301 int ofs = ext_str.find_left("GL_ARB_get_program_binary", true);
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);
6309 pResult = (const GLubyte *)ext_str.get_ptr();
6315 //----------------------------------------------------------------------------------------------------------------------
6316 // Buffer mapping, updating
6317 //----------------------------------------------------------------------------------------------------------------------
6320 // glMapNamedBufferEXT
6321 // glMapNamedBufferRangeEXT
6322 // glFlushMappedNamedBufferRangeEXT
6323 // glUnmapNamedBufferEXT
6324 // glGetNamedBufferSubDataEXT
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)
6329 VOGL_NOTE_UNUSED(trace_serializer);
6334 if (g_dump_gl_buffers_flag)
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");
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;
6345 if (buf_desc.m_pMap)
6347 vogl_warning_printf("%s: Setting buffer's data on an already mapped buffer, buffer will get unmapped by GL\n", VOGL_FUNCTION_NAME);
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);
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)
6365 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6366 VOGL_NOTE_UNUSED(gl_error_absorber);
6368 GLuint buffer = vogl_get_bound_gl_buffer(target);
6371 vogl_error_printf("%s: No mapped buffer at target 0x%08X\n", VOGL_FUNCTION_NAME, target);
6375 vogl_named_buffer_data_ext_helper(pContext, trace_serializer, buffer, size, data, usage);
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)
6381 VOGL_NOTE_UNUSED(buffer);
6382 VOGL_NOTE_UNUSED(trace_serializer);
6383 VOGL_NOTE_UNUSED(pContext);
6385 if (g_dump_gl_buffers_flag)
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");
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)
6399 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6400 VOGL_NOTE_UNUSED(gl_error_absorber);
6402 GLuint buffer = vogl_get_bound_gl_buffer(target);
6405 vogl_error_printf("%s: No mapped buffer at target 0x%08X\n", VOGL_FUNCTION_NAME, target);
6409 vogl_named_buffer_subdata_ext_helper(pContext, trace_serializer, buffer, offset, size, data);
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)
6420 VOGL_NOTE_UNUSED(target);
6421 VOGL_NOTE_UNUSED(pContext);
6423 if (trace_serializer.is_in_begin() || g_dump_gl_buffers_flag)
6425 if (access == GL_WRITE_ONLY)
6427 access = GL_READ_WRITE;
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)
6441 vogl_warning_printf("%s: Map failed!\n", VOGL_FUNCTION_NAME);
6445 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6446 VOGL_NOTE_UNUSED(gl_error_absorber);
6448 GLuint buffer = vogl_get_bound_gl_buffer(target);
6451 vogl_error_printf("%s: No mapped buffer at target 0x%08X\n", VOGL_FUNCTION_NAME, target);
6455 gl_buffer_desc &buf_desc = pContext->get_or_create_buffer_desc(buffer);
6456 if (buf_desc.m_pMap)
6458 vogl_warning_printf("%s: Buffer 0x%08X is already mapped!\n", VOGL_FUNCTION_NAME, buffer);
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);
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;
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)
6479 VOGL_NOTE_UNUSED(length);
6480 VOGL_NOTE_UNUSED(offset);
6481 VOGL_NOTE_UNUSED(target);
6482 VOGL_NOTE_UNUSED(pContext);
6484 if (trace_serializer.is_in_begin() || g_dump_gl_buffers_flag)
6486 if (access & GL_MAP_WRITE_BIT)
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;
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)
6506 vogl_warning_printf("%s: Map failed!\n", VOGL_FUNCTION_NAME);
6510 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6511 VOGL_NOTE_UNUSED(gl_error_absorber);
6513 GLuint buffer = vogl_get_bound_gl_buffer(target);
6516 vogl_error_printf("%s: No mapped buffer at target 0x%08X\n", VOGL_FUNCTION_NAME, target);
6520 gl_buffer_desc &buf_desc = pContext->get_or_create_buffer_desc(buffer);
6521 if (buf_desc.m_pMap)
6523 vogl_error_printf("%s: Buffer 0x%08X is already mapped!\n", VOGL_FUNCTION_NAME, buffer);
6527 if (length > buf_desc.m_size)
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);
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;
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;
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)
6551 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6552 VOGL_NOTE_UNUSED(gl_error_absorber);
6554 GLuint buffer = vogl_get_bound_gl_buffer(target);
6557 vogl_error_printf("%s: No mapped buffer at target 0x%08X\n", VOGL_FUNCTION_NAME, target);
6561 gl_buffer_desc &buf_desc = pContext->get_or_create_buffer_desc(buffer);
6562 if (!buf_desc.m_pMap)
6564 vogl_error_printf("%s: Buffer 0x%08X is not currently mapped!\n", VOGL_FUNCTION_NAME, buffer);
6568 if ((offset + length) > buf_desc.m_map_size)
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);
6574 buf_desc.m_flushed_ranges.push_back(gl_buffer_desc::flushed_range(offset, length));
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)
6584 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6585 VOGL_NOTE_UNUSED(gl_error_absorber);
6587 GLuint buffer = vogl_get_bound_gl_buffer(target);
6590 vogl_error_printf("%s: No mapped buffer at target 0x%08X\n", VOGL_FUNCTION_NAME, target);
6594 gl_buffer_desc &buf_desc = pContext->get_or_create_buffer_desc(buffer);
6595 if (!buf_desc.m_pMap)
6597 vogl_error_printf("%s: Buffer 0x%08X is not currently mapped!\n", VOGL_FUNCTION_NAME, buffer);
6601 bool writable_map = false;
6602 bool explicit_flush = false;
6603 if (buf_desc.m_map_range)
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;
6610 writable_map = (buf_desc.m_map_access != GL_READ_ONLY);
6613 if (trace_serializer.is_in_begin())
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);
6625 if (!buf_desc.m_flushed_ranges.size())
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);
6630 if (g_dump_gl_buffers_flag)
6632 for (uint i = 0; i < buf_desc.m_flushed_ranges.size(); i++)
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");
6640 if (trace_serializer.is_in_begin())
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++)
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);
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));
6656 if (g_dump_gl_buffers_flag)
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");
6663 if (trace_serializer.is_in_begin())
6665 trace_serializer.add_key_value(0, buf_desc.m_map_ofs);
6666 trace_serializer.add_key_value(1, buf_desc.m_map_size);
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));
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);
6681 //----------------------------------------------------------------------------------------------------------------------
6682 // glCreateProgram/glCreateProgramARB function epilog
6683 //----------------------------------------------------------------------------------------------------------------------
6684 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glCreateProgram(e, c, rt, r, nu, ne, a, p) \
6686 vogl_create_program_helper(pContext, result);
6687 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glCreateProgramObjectARB(e, c, rt, r, nu, ne, a, p) \
6689 vogl_create_program_helper(pContext, result);
6690 static inline void vogl_create_program_helper(vogl_context *pContext, GLuint handle)
6692 VOGL_NOTE_UNUSED(pContext);
6693 VOGL_NOTE_UNUSED(handle);
6698 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6699 VOGL_NOTE_UNUSED(gl_error_absorber);
6701 // Ensure program bins are always retrievable
6702 GL_ENTRYPOINT(glProgramParameteri)(handle, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);
6707 //----------------------------------------------------------------------------------------------------------------------
6708 // glProgramParameteri GL prolog
6709 //----------------------------------------------------------------------------------------------------------------------
6710 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glProgramParameteri(e, c, rt, r, nu, ne, a, p) \
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) \
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) \
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)
6721 VOGL_NOTE_UNUSED(pContext);
6722 VOGL_NOTE_UNUSED(program);
6723 VOGL_NOTE_UNUSED(pname);
6724 VOGL_NOTE_UNUSED(value);
6727 if ((pname == GL_PROGRAM_BINARY_RETRIEVABLE_HINT) && (value == GL_FALSE))
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);
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));
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);
6748 //----------------------------------------------------------------------------------------------------------------------
6749 // vogl_dump_program_outputs
6750 //----------------------------------------------------------------------------------------------------------------------
6751 static void vogl_dump_program_outputs(json_node &doc_root, vogl_context *pContext, GLuint program)
6753 if (pContext->get_context_info().supports_extension("GL_ARB_program_interface_query") &&
6754 GL_ENTRYPOINT(glGetProgramInterfaceiv) && GL_ENTRYPOINT(glGetProgramResourceName) && GL_ENTRYPOINT(glGetProgramResourceiv))
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();
6760 doc_root.add_key_value("total_active_outputs", num_active_outputs);
6762 json_node &outputs_object = doc_root.add_array("active_outputs");
6763 for (int i = 0; i < num_active_outputs; i++)
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();
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();
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]);
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)
6797 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6798 VOGL_NOTE_UNUSED(gl_error_absorber);
6800 GLint link_status = 0;
6801 GL_ENTRYPOINT(glGetObjectParameterivARB)(programObj, GL_OBJECT_LINK_STATUS_ARB, &link_status);
6802 pContext->peek_and_drop_gl_error();
6804 if (trace_serializer.is_in_begin())
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);
6812 GLint active_attributes = 0;
6813 GL_ENTRYPOINT(glGetObjectParameterivARB)(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);
6814 pContext->peek_and_drop_gl_error();
6816 doc_root.add_key_value("total_active_attributes", active_attributes);
6818 if (active_attributes)
6820 json_node &attribs_object = doc_root.add_array("active_attribs");
6822 for (int i = 0; i < active_attributes; i++)
6826 GLcharARB name[256];
6828 GL_ENTRYPOINT(glGetActiveAttribARB)(programObj, i, sizeof(name), NULL, &size, &type, name);
6829 pContext->peek_and_drop_gl_error();
6831 if ((!name[0]) || ((name[0] == 'g') && (name[1] == 'l') && (name[2] == '_')))
6834 GLint location = GL_ENTRYPOINT(glGetAttribLocationARB)(programObj, name);
6835 pContext->peek_and_drop_gl_error();
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);
6847 GLint active_uniforms = 0;
6848 GL_ENTRYPOINT(glGetObjectParameterivARB)(programObj, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &active_uniforms);
6849 pContext->peek_and_drop_gl_error();
6851 doc_root.add_key_value("total_active_uniforms", active_uniforms);
6853 if (active_uniforms)
6855 json_node &uniforms_object = doc_root.add_array("active_uniforms");
6857 for (int i = 0; i < active_uniforms; i++)
6862 GLcharARB name[256];
6864 GL_ENTRYPOINT(glGetActiveUniformARB)(programObj, i, sizeof(name), &length, &size, &type, name);
6865 pContext->peek_and_drop_gl_error();
6867 if ((!name[0]) || (!length) || ((name[0] == 'g') && (name[1] == 'l') && (name[2] == '_')))
6870 GLint location = GL_ENTRYPOINT(glGetUniformLocationARB)(programObj, name);
6871 pContext->peek_and_drop_gl_error();
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);
6885 vogl_dump_program_outputs(doc_root, pContext, programObj);
6887 trace_serializer.add_key_value_json_document("metadata", doc);
6892 if ((link_status) || (!pContext->has_linked_program_snapshot(programObj)))
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);
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)
6910 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6911 VOGL_NOTE_UNUSED(gl_error_absorber);
6913 GLint link_status = 0;
6914 GL_ENTRYPOINT(glGetProgramiv)(program, GL_LINK_STATUS, &link_status);
6915 pContext->peek_and_drop_gl_error();
6917 if (trace_serializer.is_in_begin())
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));
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();
6930 doc_root.add_key_value("active_uniform_blocks", active_uniform_blocks);
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();
6937 doc_root.add_key_value("total_active_attributes", active_attributes);
6939 if (active_attributes)
6941 json_node &attribs_object = doc_root.add_array("active_attribs");
6943 for (int i = 0; i < active_attributes; i++)
6949 GL_ENTRYPOINT(glGetActiveAttrib)(program, i, sizeof(name), NULL, &size, &type, name);
6950 pContext->peek_and_drop_gl_error();
6952 if ((!name[0]) || ((name[0] == 'g') && (name[1] == 'l') && (name[2] == '_')))
6955 GLint location = GL_ENTRYPOINT(glGetAttribLocation)(program, name);
6956 pContext->peek_and_drop_gl_error();
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);
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);
6973 if (active_uniforms)
6975 json_node &uniforms_object = doc_root.add_array("active_uniforms");
6977 for (int i = 0; i < active_uniforms; i++)
6984 GL_ENTRYPOINT(glGetActiveUniform)(program, i, sizeof(name), &length, &size, &type, name);
6985 pContext->peek_and_drop_gl_error();
6987 if ((!name[0]) || (!length) || ((name[0] == 'g') && (name[1] == 'l') && (name[2] == '_')))
6990 GLint location = GL_ENTRYPOINT(glGetUniformLocation)(program, name);
6991 pContext->peek_and_drop_gl_error();
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);
7006 vogl_dump_program_outputs(doc_root, pContext, program);
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();
7013 doc_root.add_key_value("transform_feedback_mode", g_gl_enums.find_gl_name(mode));
7015 GLint num_varyings = 0;
7016 GL_ENTRYPOINT(glGetProgramiv)(program, GL_TRANSFORM_FEEDBACK_VARYINGS, &num_varyings);
7017 pContext->peek_and_drop_gl_error();
7019 doc_root.add_key_value("transform_feedback_num_varyings", num_varyings);
7023 json_node &transform_feedback_varyings = doc_root.add_array("transform_feedback_varyings");
7025 for (GLint i = 0; i < num_varyings; i++)
7028 GLsizei length = 0, size = 0;
7029 GLenum type = GL_NONE;
7031 GL_ENTRYPOINT(glGetTransformFeedbackVarying)(program, i, sizeof(name), &length, &size, &type, name);
7032 pContext->peek_and_drop_gl_error();
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);
7042 // Add JSON document to packet
7043 trace_serializer.add_key_value_json_document("metadata", doc);
7048 if ((link_status) || (!pContext->has_linked_program_snapshot(program)))
7050 if (id == VOGL_ENTRYPOINT_glProgramBinary)
7052 if (!pContext->add_linked_program_snapshot(program, binary_format, pBinary, binary_length))
7054 vogl_error_printf("%s: Failed snapshotting binary program into link-time program shadow table, program 0x%X\n", VOGL_FUNCTION_NAME, program);
7059 if (!pContext->add_linked_program_snapshot(program))
7061 vogl_error_printf("%s: Failed snapshotting program into link-time program shadow table, program 0x%X\n", VOGL_FUNCTION_NAME, program);
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)
7071 VOGL_NOTE_UNUSED(binaryFormat);
7073 if (g_disable_gl_program_binary_flag)
7075 vogl_debug_printf("%s: Tracer is forcing a bogus program binary for program %d\n", VOGL_FUNCTION_NAME, program);
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;
7083 //----------------------------------------------------------------------------------------------------------------------
7084 // glTransformFeedbackVaryings func epilog
7085 //----------------------------------------------------------------------------------------------------------------------
7086 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glTransformFeedbackVaryings(e, c, rt, r, nu, ne, a, p) \
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)
7091 VOGL_NOTE_UNUSED(pContext);
7093 if ((!count) || (!pVaryings) || (!trace_serializer.is_in_begin()))
7096 dynamic_string varying;
7097 for (int i = 0; i < count; i++)
7101 varying = reinterpret_cast<const char *>(pVaryings[i]);
7103 trace_serializer.add_key_value(i, varying);
7107 //----------------------------------------------------------------------------------------------------------------------
7108 // ARB program shadowing
7109 //----------------------------------------------------------------------------------------------------------------------
7110 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenProgramsARB(e, c, rt, r, nu, ne, a, p) \
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);
7117 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteProgramsARB(e, c, rt, r, nu, ne, a, p) \
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);
7124 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindProgramARB(e, c, rt, r, nu, ne, a, p) \
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);
7131 //----------------------------------------------------------------------------------------------------------------------
7132 // renderbuffer shadowing
7133 //----------------------------------------------------------------------------------------------------------------------
7134 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenRenderbuffers(e, c, rt, r, nu, ne, a, p) \
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);
7141 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenRenderbuffersEXT(e, c, rt, r, nu, ne, a, p) \
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);
7148 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteRenderbuffers(e, c, rt, r, nu, ne, a, p) \
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);
7155 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteRenderbuffersEXT(e, c, rt, r, nu, ne, a, p) \
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 //----------------------------------------------------------------------------------------------------------------------
7163 //----------------------------------------------------------------------------------------------------------------------
7164 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenBuffers(e, c, rt, r, nu, ne, a, p) \
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);
7171 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenBuffersARB(e, c, rt, r, nu, ne, a, p) \
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);
7178 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBuffer(e, c, rt, r, nu, ne, a, p) \
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);
7185 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferBase(e, c, rt, r, nu, ne, a, p) \
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);
7192 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferBaseEXT(e, c, rt, r, nu, ne, a, p) \
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);
7199 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferBaseNV(e, c, rt, r, nu, ne, a, p) \
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);
7206 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferRange(e, c, rt, r, nu, ne, a, p) \
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);
7213 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferRangeEXT(e, c, rt, r, nu, ne, a, p) \
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);
7220 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferRangeNV(e, c, rt, r, nu, ne, a, p) \
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);
7227 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferARB(e, c, rt, r, nu, ne, a, p) \
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);
7234 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteBuffers(e, c, rt, r, nu, ne, a, p) \
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);
7241 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteBuffersARB(e, c, rt, r, nu, ne, a, p) \
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);
7248 //----------------------------------------------------------------------------------------------------------------------
7249 // Texture handle shadowing
7250 //----------------------------------------------------------------------------------------------------------------------
7251 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenTextures(e, c, rt, r, nu, ne, a, p) \
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);
7258 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenTexturesEXT(e, c, rt, r, nu, ne, a, p) \
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);
7265 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteTextures(e, c, rt, r, nu, ne, a, p) \
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);
7272 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteTexturesEXT(e, c, rt, r, nu, ne, a, p) \
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);
7279 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindTexture(e, c, rt, r, nu, ne, a, p) \
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);
7286 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindTextureEXT(e, c, rt, r, nu, ne, a, p) \
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);
7293 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindMultiTextureEXT(e, c, rt, r, nu, ne, a, p) \
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);
7300 //----------------------------------------------------------------------------------------------------------------------
7301 // Framebuffer handle shadowing
7302 //----------------------------------------------------------------------------------------------------------------------
7303 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenFramebuffers(e, c, rt, r, nu, ne, a, p) \
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);
7310 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenFramebuffersEXT(e, c, rt, r, nu, ne, a, p) \
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);
7317 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteFramebuffers(e, c, rt, r, nu, ne, a, p) \
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);
7324 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteFramebuffersEXT(e, c, rt, r, nu, ne, a, p) \
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);
7331 //----------------------------------------------------------------------------------------------------------------------
7332 // VAO handle shadowing
7333 //----------------------------------------------------------------------------------------------------------------------
7334 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenVertexArrays(e, c, rt, r, nu, ne, a, p) \
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);
7341 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteVertexArrays(e, c, rt, r, nu, ne, a, p) \
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);
7348 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindVertexArray(e, c, rt, r, nu, ne, a, p) \
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);
7355 //----------------------------------------------------------------------------------------------------------------------
7356 // Sync handle shadowing
7357 //----------------------------------------------------------------------------------------------------------------------
7358 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glFenceSync(e, c, rt, r, nu, ne, a, p) \
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);
7365 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteSync(e, c, rt, r, nu, ne, a, p) \
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);
7372 //----------------------------------------------------------------------------------------------------------------------
7373 // Sampler object handle shadowing
7374 //----------------------------------------------------------------------------------------------------------------------
7375 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenSamplers(e, c, rt, r, nu, ne, a, p) \
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);
7382 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteSamplers(e, c, rt, r, nu, ne, a, p) \
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);
7389 //----------------------------------------------------------------------------------------------------------------------
7390 // Query handle shadowing
7391 //----------------------------------------------------------------------------------------------------------------------
7392 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenQueries(e, c, rt, r, nu, ne, a, p) \
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);
7399 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenQueriesARB(e, c, rt, r, nu, ne, a, p) \
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);
7406 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteQueries(e, c, rt, r, nu, ne, a, p) \
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);
7413 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteQueriesARB(e, c, rt, r, nu, ne, a, p) \
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);
7420 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBeginQuery(e, c, rt, r, nu, ne, a, p) \
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);
7427 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBeginQueryARB(e, c, rt, r, nu, ne, a, p) \
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);
7434 //----------------------------------------------------------------------------------------------------------------------
7435 // Display list shadowing
7436 //----------------------------------------------------------------------------------------------------------------------
7437 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenLists(e, c, rt, r, nu, ne, a, p) \
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);
7444 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteLists(e, c, rt, r, nu, ne, a, p) \
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);
7451 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glNewList(e, c, rt, r, nu, ne, a, p) \
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);
7458 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glEndList(e, c, rt, r, nu, ne, a, p) \
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();
7465 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glXUseXFont(e, c, rt, r, nu, ne, a, p) \
7467 pContext->peek_and_record_gl_error();
7469 //----------------------------------------------------------------------------------------------------------------------
7470 // glBegin/glEnd shadowing
7471 //----------------------------------------------------------------------------------------------------------------------
7472 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBegin(e, c, rt, r, nu, ne, a, p) \
7474 pContext->peek_and_record_gl_error();
7475 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBegin(e, c, rt, r, nu, ne, a, p) \
7477 pContext->set_in_gl_begin(true);
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) \
7482 pContext->set_in_gl_begin(false);
7484 //----------------------------------------------------------------------------------------------------------------------
7485 // Program/shader shadowing
7486 //----------------------------------------------------------------------------------------------------------------------
7487 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glCreateProgram(e, c, rt, r, nu, ne, a, p) \
7489 result = pContext->handle_create_program(VOGL_ENTRYPOINT_##ne); \
7492 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glCreateProgramObjectARB(e, c, rt, r, nu, ne, a, p) \
7494 result = pContext->handle_create_program(VOGL_ENTRYPOINT_##ne); \
7498 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glCreateShader(e, c, rt, r, nu, ne, a, p) \
7500 result = pContext->handle_create_shader(VOGL_ENTRYPOINT_##ne, type); \
7503 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glCreateShaderObjectARB(e, c, rt, r, nu, ne, a, p) \
7505 result = pContext->handle_create_shader(VOGL_ENTRYPOINT_##ne, shaderType); \
7509 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glUseProgram(e, c, rt, r, nu, ne, a, p) \
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) \
7514 pContext->handle_use_program(VOGL_ENTRYPOINT_##ne, programObj);
7516 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glDeleteShader(e, c, rt, r, nu, ne, a, p) \
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) \
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) \
7524 pContext->handle_del_object(VOGL_ENTRYPOINT_##ne, obj);
7526 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glDetachShader(e, c, rt, r, nu, ne, a, p) \
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) \
7531 pContext->handle_detach_shader(VOGL_ENTRYPOINT_##ne, containerObj, attachedObj);
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)
7541 VOGL_NOTE_UNUSED(pPointer);
7543 if (pContext->get_uses_client_side_arrays() || pContext->is_core_profile())
7546 pContext->peek_and_record_gl_error();
7548 GLint cur_array_buf_binding = 0;
7549 GL_ENTRYPOINT(glGetIntegerv)(GL_ARRAY_BUFFER_BINDING, &cur_array_buf_binding);
7551 if (pContext->peek_and_drop_gl_error() == GL_NO_ERROR)
7553 if (!cur_array_buf_binding)
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);
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
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)
7595 if (pContext->peek_and_record_gl_error())
7600 if (pContext->get_display())
7602 XFontStruct *pFont_struct = XQueryFont((Display *)pContext->get_display(), font);
7606 unsigned long value = 0;
7607 Bool result = XGetFontProperty(pFont_struct, XA_FONT, &value);
7610 pFont = (char *)XGetAtomName((Display *)pContext->get_display(), (Atom)value);
7611 if ((pFont) && (trace_serializer.is_in_begin()))
7613 trace_serializer.add_key_value("font_name", pFont);
7618 XFreeFontInfo(NULL, pFont_struct, 1);
7621 pContext->glx_font(pFont, first, count, list_base);
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)
7629 vogl_context *pContext = static_cast<vogl_context *>(pOpaque);
7631 // TODO: We don't whitelist anything but texture binds in display lists currently.
7632 switch (handle_namespace)
7634 case VOGL_NAMESPACE_TEXTURES:
7636 if ((handle) && (target != GL_NONE))
7637 pContext->bind_texture_conditionally(target, handle);
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);
7648 //----------------------------------------------------------------------------------------------------------------------
7649 // glCallList shadowing
7650 //----------------------------------------------------------------------------------------------------------------------
7651 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glCallList(e, c, rt, r, nu, ne, a, p) \
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)
7662 pContext->parse_list_and_update_shadows(list, vogl_display_list_bind_callback, pContext);
7665 //----------------------------------------------------------------------------------------------------------------------
7666 // glCallLists shadowing
7667 //----------------------------------------------------------------------------------------------------------------------
7668 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glCallLists(e, c, rt, r, nu, ne, a, p) \
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)
7679 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
7680 VOGL_NOTE_UNUSED(gl_error_absorber);
7682 pContext->parse_lists_and_update_shadows(n, type, lists, vogl_display_list_bind_callback, pContext);
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()
7691 vogl_debug_printf("vogl_check_entrypoints: begin (specify --vogl_debug for more validation)\n");
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;
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
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
7709 vogl::vector<uint> undefined_func_return_array_size_macros;
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
7717 if (vogl::check_for_command_line_param("--vogl_debug"))
7719 for (array_size_macro_hashmap::const_iterator it = undefined_array_size_macros.begin(); it != undefined_array_size_macros.end(); ++it)
7721 uint idx = it->first;
7722 const dynamic_string &name = it->second;
7723 VOGL_NOTE_UNUSED(name);
7725 gl_entrypoint_id_t func = static_cast<gl_entrypoint_id_t>(idx >> 16);
7726 uint param = idx & 0xFFFF;
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);
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;
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)
7739 const dynamic_string &name = it->second;
7740 vogl_debug_printf("%s\n", name.get_ptr());
7742 vogl_debug_printf("---\n");
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++)
7748 vogl_ctype_t return_ctype = g_vogl_entrypoint_descs[i].m_return_ctype;
7750 if (return_ctype == VOGL_VOID)
7752 if (!g_vogl_process_gl_ctypes[return_ctype].m_is_pointer)
7754 //if (g_vogl_process_gl_ctypes[return_ctype].m_is_opaque_pointer)
7757 if (g_vogl_entrypoint_descs[i].m_custom_return_param_array_size_macro_is_missing)
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);
7762 if (g_vogl_entrypoint_descs[i].m_whitelisted_for_displaylists)
7764 if (!g_vogl_entrypoint_descs[i].m_is_listable)
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);
7770 vogl_debug_printf("---\n");
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++)
7776 const gl_entrypoint_desc_t &desc = g_vogl_entrypoint_descs[i];
7777 if ((!desc.m_is_whitelisted) || (desc.m_has_custom_func_handler))
7780 if (desc.m_custom_array_size_macro_is_missing)
7781 vogl_debug_printf("%s\n", desc.m_pName);
7783 vogl_debug_printf("---\n");
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++)
7789 const gl_entrypoint_desc_t &desc = g_vogl_entrypoint_descs[i];
7790 if (desc.m_is_whitelisted)
7793 vogl_ctype_t return_ctype = g_vogl_entrypoint_descs[i].m_return_ctype;
7795 if (return_ctype == VOGL_VOID)
7797 if (!g_vogl_process_gl_ctypes[return_ctype].m_is_pointer)
7799 if (g_vogl_process_gl_ctypes[return_ctype].m_is_opaque_pointer)
7802 if (g_vogl_entrypoint_descs[i].m_custom_return_param_array_size_macro_is_missing)
7804 vogl_debug_printf("%s\n", g_vogl_entrypoint_descs[i].m_pName);
7808 vogl_debug_printf("---\n");
7811 vogl_debug_printf("vogl_check_entrypoints: done\n");
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"
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 \
7828 return VOGL_GLUER(vogl_, name) params; \
7830 #define DEF_PROTO_EXPORTED_VOID(ret, name, args, params) \
7831 VOGL_API_EXPORT ret name args \
7833 VOGL_GLUER(vogl_, name) params; \
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
7853 #include "gl_glx_array_size_macros.inc"
7854 #include "gl_glx_func_defs.inc"
7857 //----------------------------------------------------------------------------------------------------------------------
7858 // Define our exported gliGetProcAddressRAD function
7859 //----------------------------------------------------------------------------------------------------------------------
7860 VOGL_API_EXPORT __GLXextFuncPtr gliGetProcAddressRAD(const GLubyte *procName)
7862 if ((procName) && (!vogl_strcmp(reinterpret_cast<const char *>(procName), "gliGetProcAddressRAD")))
7863 return (__GLXextFuncPtr)gliGetProcAddressRAD;
7865 return vogl_glXGetProcAddressARB(procName);
7868 //----------------------------------------------------------------------------------------------------------------------
7869 // Determine addresses of our gl/glx wrapper functions
7870 //----------------------------------------------------------------------------------------------------------------------
7871 static void vogl_init_wrapper_func_ptrs()
7873 gl_entrypoint_desc_t *pDst = g_vogl_entrypoint_descs;
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); \
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); \
7881 #include "gl_glx_protos.inc"
7883 #undef DEF_PROTO_VOID
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)
7891 VOGL_NOTE_UNUSED(entrypoint_id);
7892 VOGL_NOTE_UNUSED(pUser_data);
7894 if (g_dump_gl_calls_flag)
7895 printf("** GLPROLOG %s\n", g_vogl_entrypoint_descs[entrypoint_id].m_pName);
7897 gl_entrypoint_id_t *pPrev_state = reinterpret_cast<gl_entrypoint_id_t *>(ppStack_data);
7898 *pPrev_state = VOGL_ENTRYPOINT_INVALID;
7900 vogl_thread_local_data *pTLS_data = vogl_get_or_create_thread_local_data();
7903 *pPrev_state = pTLS_data->m_calling_driver_entrypoint_id;
7904 pTLS_data->m_calling_driver_entrypoint_id = entrypoint_id;
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)
7913 VOGL_NOTE_UNUSED(entrypoint_id);
7914 VOGL_NOTE_UNUSED(pUser_data);
7917 if (entrypoint_id == VOGL_ENTRYPOINT_glXMakeCurrent)
7919 // HACK HACK - crude test of the "calling driver entrypoint code"
7920 glXGetCurrentContext();
7924 if (g_dump_gl_calls_flag)
7925 printf("** GLEPILOG %s\n", g_vogl_entrypoint_descs[entrypoint_id].m_pName);
7927 gl_entrypoint_id_t *pPrev_state = reinterpret_cast<gl_entrypoint_id_t *>(ppStack_data);
7929 vogl_thread_local_data *pTLS_data = vogl_get_or_create_thread_local_data();
7932 pTLS_data->m_calling_driver_entrypoint_id = *pPrev_state;
7936 //----------------------------------------------------------------------------------------------------------------------
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()
7942 vogl_init_thread_local_data();
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);
7947 vogl_init_wrapper_func_ptrs();
7949 vogl_check_entrypoints();