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)
3084 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glDebugMessageInsert_buf(e, c, rt, r, nu, ne, a, p) ((length < 0) ? (buf ? strlen((const char *)buf) : 0 ) : length)
3085 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glPushDebugGroup_message(e, c, rt, r, nu, ne, a, p) ((length < 0) ? (message ? strlen((const char *)message) : 0 ) : length)
3086 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glObjectLabel_label(e, c, rt, r, nu, ne, a, p) ((length < 0) ? (label ? strlen((const char *)label) : 0 ) : length)
3087 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glObjectPtrLabel_label(e, c, rt, r, nu, ne, a, p) ((length < 0) ? (label ? strlen((const char *)label) : 0 ) : length)
3089 //----------------------------------------------------------------------------------------------------------------------
3090 // Texture/image API's array size helper macros
3091 // TODO: For glTexImage3DEXT, glTexSubImage1DEXT, etc. - should these check the currently bound GL_PIXEL_UNPACK_BUFFER?
3092 //----------------------------------------------------------------------------------------------------------------------
3093 size_t vogl_calc_set_tex_image_serialize_size(vogl_context *pContext, GLenum format, GLenum type, GLsizei width, GLsizei height, GLsizei depth)
3097 if (vogl_get_bound_gl_buffer(GL_PIXEL_UNPACK_BUFFER))
3101 return vogl_get_image_size(format, type, width, height, depth);
3104 size_t vogl_calc_get_tex_image_serialize_size(vogl_context *pContext, GLenum format, GLenum type, GLsizei width, GLsizei height, GLsizei depth)
3108 if (vogl_get_bound_gl_buffer(GL_PIXEL_PACK_BUFFER))
3112 return vogl_get_image_size(format, type, width, height, depth);
3115 size_t vogl_calc_get_tex_target_serialize_size(vogl_context *pContext, GLenum target, GLint level, GLenum format, GLenum type)
3119 if (vogl_get_bound_gl_buffer(GL_PIXEL_PACK_BUFFER))
3123 return vogl_get_tex_target_image_size(target, level, format, type);
3126 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexImage1D_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, 1, 1)
3127 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexImage2D_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, 1)
3128 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexImage3D_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, depth)
3129 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexImage3DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, depth)
3131 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexSubImage1D_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, 1, 1)
3132 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexSubImage1DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, 1, 1)
3134 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexSubImage2D_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, 1)
3135 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexSubImage2DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, 1)
3137 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexSubImage3D_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, depth)
3138 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexSubImage3DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, depth)
3140 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTextureImage3DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, depth)
3141 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTextureImage2DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, 1)
3142 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTextureImage1DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, 1, 1)
3144 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTextureSubImage3DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, depth)
3145 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTextureSubImage2DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, 1)
3146 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTextureSubImage1DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, 1, 1)
3148 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glMultiTexImage3DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, depth)
3149 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glMultiTexImage2DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, 1)
3150 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glMultiTexImage1DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, 1, 1)
3152 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glMultiTexSubImage3DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, depth)
3153 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glMultiTexSubImage2DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, 1)
3154 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glMultiTexSubImage1DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, 1, 1)
3156 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glDrawPixels_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, 1)
3157 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glConvolutionFilter1D_image(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, 1, 1)
3158 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glConvolutionFilter2D_image(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, 1)
3160 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glColorTable_table(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, 1, 1)
3161 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glColorSubTable_data(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, count, 1, 1)
3163 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glBitmap_size(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, GL_COLOR_INDEX, GL_BITMAP, width, height, 1)
3164 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glPolygonStipple_mask(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, GL_COLOR_INDEX, GL_BITMAP, 32, 32, 1)
3166 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetTexImage_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_get_tex_target_serialize_size(pContext, target, level, format, type)
3168 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glStringMarkerGREMEDY_string(e, c, rt, r, nu, ne, a, p) ((string) ? (!(len) ? (strlen(static_cast<const char *>(string)) + 1) : (len)) : 0)
3170 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glViewportArrayv_v(e, c, rt, r, nu, ne, a, p) (4 * (count))
3171 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glScissorArrayv_v(e, c, rt, r, nu, ne, a, p) (4 * (count))
3172 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glDepthRangeArrayv_v(e, c, rt, r, nu, ne, a, p) (2 * (count))
3174 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetActiveAttrib_name(e, c, rt, r, nu, ne, a, p) ((name) ? (strlen((const char *)(name)) + 1) : -1)
3175 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetActiveAttribARB_name(e, c, rt, r, nu, ne, a, p) ((name) ? (strlen((const char *)(name)) + 1) : -1)
3177 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glReadPixels_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_get_tex_image_serialize_size(pContext, format, type, width, height, 1)
3179 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glBindFragDataLocationIndexed_name(e, c, rt, r, nu, ne, a, p) (name ? (strlen((const char *)(name)) + 1) : -1)
3180 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glBindFragDataLocation_name(e, c, rt, r, nu, ne, a, p) (name ? (strlen((const char *)(name)) + 1) : -1)
3181 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glBindFragDataLocationEXT_name(e, c, rt, r, nu, ne, a, p) (name ? (strlen((const char *)(name)) + 1) : -1)
3183 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glBitmap_bitmap(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, GL_COLOR_INDEX, GL_BITMAP, width, height, 1)
3185 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetActiveUniform_name(e, c, rt, r, nu, ne, a, p) ((name) ? ((length) ? (*(length) + 1) : (bufSize)) : -1)
3187 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetAttachedShaders_obj(e, c, rt, r, nu, ne, a, p) ((obj) ? ((count) ? *(count) : (maxCount)) : -1)
3189 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetProgramInfoLog_infoLog(e, c, rt, r, nu, ne, a, p) ((infoLog) ? ((length) ? (*length + 1) : (bufSize)) : -1)
3191 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetShaderSource_source(e, c, rt, r, nu, ne, a, p) ((source) ? ((length) ? (*(length) + 1) : (bufSize)) : -1)
3193 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glCallLists_lists(e, c, rt, r, nu, ne, a, p) (vogl_get_gl_type_size(type) * (n))
3195 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetDebugMessageLogARB_messageLog(e, c, rt, r, nu, ne, a, p) vogl_compute_message_log_size_in_bytes(count, lengths)
3196 static GLsizei vogl_compute_message_log_size_in_bytes(GLuint count, const GLsizei *lengths)
3200 GLsizei total_length = 0;
3201 for (uint i = 0; i < count; i++)
3202 total_length += lengths[i];
3203 return total_length;
3206 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glSeparableFilter2D_row(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, 1, 1)
3207 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glSeparableFilter2D_column(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, height, 1, 1)
3209 // TODO - These are all gets, so they aren't completely necessary for proper replaying because they have no side effects (except for possibly glError's).
3210 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetUniformfv_params(e, c, rt, r, nu, ne, a, p) -1
3211 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetUniformiv_params(e, c, rt, r, nu, ne, a, p) -1
3212 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetPolygonStipple_mask(e, c, rt, r, nu, ne, a, p) -1
3213 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetMapdv_v(e, c, rt, r, nu, ne, a, p) -1
3214 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetMapfv_v(e, c, rt, r, nu, ne, a, p) -1
3215 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetMapiv_v(e, c, rt, r, nu, ne, a, p) -1
3216 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetColorTable_table(e, c, rt, r, nu, ne, a, p) -1
3217 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetConvolutionFilter_image(e, c, rt, r, nu, ne, a, p) -1
3218 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetSeparableFilter_row(e, c, rt, r, nu, ne, a, p) -1
3219 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetSeparableFilter_column(e, c, rt, r, nu, ne, a, p) -1
3220 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetSeparableFilter_span(e, c, rt, r, nu, ne, a, p) -1
3221 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetHistogram_values(e, c, rt, r, nu, ne, a, p) -1
3222 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetMinmax_values(e, c, rt, r, nu, ne, a, p) -1
3223 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetCompressedTexImage_img(e, c, rt, r, nu, ne, a, p) -1
3225 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glClearBufferfv_value(e, c, rt, r, nu, ne, a, p) vogl_get_clearbuffer_array_size(buffer)
3226 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glClearBufferuiv_value(e, c, rt, r, nu, ne, a, p) vogl_get_clearbuffer_array_size(buffer)
3227 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glClearBufferiv_value(e, c, rt, r, nu, ne, a, p) vogl_get_clearbuffer_array_size(buffer)
3228 static int vogl_get_clearbuffer_array_size(GLenum buffer)
3230 if ((buffer == GL_DEPTH) || (buffer == GL_STENCIL))
3232 else if (utils::is_in_set<GLenum, GLenum>(buffer, GL_COLOR, GL_FRONT, GL_BACK, GL_LEFT, GL_RIGHT, GL_FRONT_AND_BACK))
3235 vogl_warning_printf("%s: Invalid value for buffer parameter passed to glClearBufferfv: 0x%04X\n", VOGL_FUNCTION_NAME, buffer);
3253 //----------------------------------------------------------------------------------------------------------------------
3254 // Custom return parameter array size helper macros
3255 //----------------------------------------------------------------------------------------------------------------------
3256 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXGetFBConfigs(dpy, screen, nelements) (nelements ? *nelements : 1)
3257 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXChooseFBConfig(dpy, screen, attrib_list, nelements) (nelements ? *nelements : 1)
3258 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXChooseVisual(dpy, screen, nelements) 1
3259 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXGetVisualFromFBConfig(dpy, config) 1
3260 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXGetCurrentDisplay() 1
3261 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXGetCurrentDisplayEXT() 1
3262 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXEnumerateVideoCaptureDevicesNV(dpy, screen, nelements) (nelements ? *nelements : 1)
3263 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXEnumerateVideoDevicesNV(dpy, screen, nelements) (nelements ? *nelements : 1)
3265 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetString(name) (result ? (strlen(reinterpret_cast<const char *>(result)) + 1) : 0)
3266 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetStringi(name, idx) (result ? (strlen(reinterpret_cast<const char *>(result)) + 1) : 0)
3267 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXGetClientString(dpy, name) (result ? (strlen(reinterpret_cast<const char *>(result)) + 1) : 0)
3268 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXQueryExtensionsString(dpy, name) (result ? (strlen(reinterpret_cast<const char *>(result)) + 1) : 0)
3269 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXQueryServerString(dpy, screen, name) (result ? (strlen(reinterpret_cast<const char *>(result)) + 1) : 0)
3271 //----------------------------------------------------------------------------------------------------------------------
3272 static void vogl_print_hex(const void *p, uint64_t size, uint64_t type_size)
3276 vogl_log_printf("<null>\n");
3280 const uint8_t *ptr = reinterpret_cast<const uint8_t *>(p);
3281 if ((type_size == 2) && (!(size & 1)))
3284 vogl_log_printf("[ ");
3285 for (uint64_t i = 0; i < size; i += 2)
3288 vogl_log_printf(", ");
3289 vogl_log_printf("0x%04X", *reinterpret_cast<const uint16_t *>(ptr + i));
3292 vogl_log_printf("\n");
3294 vogl_log_printf(" ]");
3296 else if ((type_size == 4) && (!(size & 3)))
3299 vogl_log_printf("[ ");
3300 for (uint64_t i = 0; i < size; i += 4)
3303 vogl_log_printf(", ");
3304 vogl_log_printf("0x%08X", *reinterpret_cast<const uint32_t *>(ptr + i));
3307 vogl_log_printf("\n");
3309 vogl_log_printf(" ]");
3311 else if ((type_size == 8) && (!(size & 7)))
3314 vogl_log_printf("[ ");
3315 for (uint64_t i = 0; i < size; i += 8)
3318 vogl_log_printf(", ");
3319 vogl_log_printf("0x%" PRIX64, *reinterpret_cast<const uint64_t *>(ptr + i));
3322 vogl_log_printf("\n");
3324 vogl_log_printf(" ]");
3330 vogl_log_printf("\n");
3332 vogl_log_printf("[ ");
3333 for (uint64_t i = 0; i < size; i++)
3336 vogl_log_printf(", ");
3337 vogl_log_printf("%02X", ptr[i]);
3339 if ((++c & 63) == 63)
3340 vogl_log_printf("\n");
3342 vogl_log_printf(" ]");
3346 //----------------------------------------------------------------------------------------------------------------------
3347 static void vogl_print_string(const char *pStr, uint64_t total_size)
3349 for (uint64_t i = 0; i < total_size; i++)
3351 uint8_t c = reinterpret_cast<const uint8_t *>(pStr)[i];
3353 vogl_log_printf("\n");
3356 if ((c < 32) || (c > 127))
3358 vogl_log_printf("%c", c);
3361 if ((i & 511) == 511)
3362 vogl_log_printf(" \\\n");
3366 //----------------------------------------------------------------------------------------------------------------------
3367 template <typename T>
3368 static inline void vogl_dump_value_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pDesc, uint param_index, const char *pParam_name, const char *pType, vogl_ctype_t type, const T &val)
3370 VOGL_NOTE_UNUSED(pContext);
3372 int size = sizeof(T);
3374 if (g_vogl_process_gl_ctypes[type].m_size != size)
3375 vogl_error_printf("%s: size mismatch on ctype %u\n", VOGL_FUNCTION_NAME, type);
3377 if (serializer.is_in_begin())
3379 serializer.add_param(param_index, type, &val, sizeof(val));
3382 if (g_dump_gl_calls_flag)
3384 vogl_log_printf("%s: %s %s, ctype: %s, size: %i: ", pDesc, pType, pParam_name, g_vogl_process_gl_ctypes[type].m_pName, size);
3386 if (Loki::TypeTraits<T>::isPointer)
3388 vogl_log_printf("OPAQUE POINTER TYPE");
3392 vogl_log_printf("OPAQUE TYPE");
3396 vogl_print_hex(&val, size, size);
3398 if (((type == VOGL_GLFLOAT) || (type == VOGL_GLCLAMPF)) && (size == sizeof(float)))
3400 float flt_val = *reinterpret_cast<const float *>(&val);
3401 vogl_log_printf(" %f", flt_val);
3403 else if (((type == VOGL_GLDOUBLE) || (type == VOGL_GLCLAMPD)) && (size == sizeof(double)))
3405 double dbl_val = *reinterpret_cast<const double *>(&val);
3406 vogl_log_printf(" %f", dbl_val);
3408 else if ((type == VOGL_GLENUM) && (size == sizeof(int)))
3410 GLenum enum_val = *reinterpret_cast<const GLenum *>(&val);
3411 const char *pName = g_gl_enums.find_name(enum_val);
3413 vogl_log_printf(" %s", pName);
3417 vogl_log_printf("\n");
3421 //----------------------------------------------------------------------------------------------------------------------
3422 template <typename T>
3423 static inline void vogl_dump_ptr_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pDesc, uint param_index, const char *pParam_name, const char *pType, vogl_ctype_t type, const T &val)
3425 VOGL_NOTE_UNUSED(pContext);
3427 VOGL_ASSUME(Loki::TypeTraits<T>::isPointer);
3428 int size = sizeof(T);
3430 if (g_vogl_process_gl_ctypes[type].m_size != size)
3431 vogl_error_printf("%s: size mismatch on ctype %u\n", VOGL_FUNCTION_NAME, type);
3433 if (serializer.is_in_begin())
3435 serializer.add_param(param_index, type, &val, sizeof(val));
3438 if (g_dump_gl_calls_flag)
3440 vogl_log_printf("%s: %s %s, ctype: %s, size: %i, ptr: 0x%" PRIX64 "\n", pDesc, pType, pParam_name, g_vogl_process_gl_ctypes[type].m_pName, size, cast_val_to_uint64(val));
3444 //----------------------------------------------------------------------------------------------------------------------
3446 static inline void vogl_dump_ref_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pDesc, uint param_index, const char *pParam_name, const char *pType, vogl_ctype_t type, const T *pObj)
3448 VOGL_NOTE_UNUSED(pContext);
3450 if (g_vogl_process_gl_ctypes[type].m_size != sizeof(const T *))
3451 vogl_error_printf("%s: size mismatch on ctype %u\n", VOGL_FUNCTION_NAME, type);
3453 int obj_size = gl_ctype_sizeof<T>::size;
3455 vogl_ctype_t pointee_type = g_vogl_process_gl_ctypes[type].m_pointee_ctype;
3456 if (pointee_type == VOGL_INVALID_CTYPE)
3458 vogl_error_printf("%s: Type %u doesn't have a pointee ctype\n", VOGL_FUNCTION_NAME, type);
3462 if (g_vogl_process_gl_ctypes[pointee_type].m_size != obj_size)
3463 vogl_error_printf("%s: size mismatch on pointee ctype %u\n", VOGL_FUNCTION_NAME, type);
3465 if (serializer.is_in_begin())
3467 serializer.add_param(param_index, type, &pObj, sizeof(pObj));
3469 if ((pObj) && (obj_size > 0))
3471 serializer.add_ref_client_memory(param_index, pointee_type, pObj, obj_size);
3475 if (g_dump_gl_calls_flag)
3477 vogl_log_printf("%s: %s %s, ptr: 0x%" PRIX64 ", ctype: %s, pointee_ctype: %s, pointee_size: %i: ", pDesc, pType, pParam_name, cast_val_to_uint64(pObj), g_vogl_process_gl_ctypes[type].m_pName, g_vogl_process_gl_ctypes[pointee_type].m_pName, obj_size);
3480 vogl_log_printf("NULL");
3482 else if (obj_size <= 0)
3484 vogl_log_printf("OPAQUE TYPE");
3488 vogl_print_hex(pObj, obj_size, obj_size);
3491 vogl_log_printf("\n");
3495 //----------------------------------------------------------------------------------------------------------------------
3497 static inline void vogl_dump_array_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pDesc, uint param_index, const char *pParam_name, const char *pType, vogl_ctype_t type, const T *pArray, int64_t size)
3499 VOGL_NOTE_UNUSED(pContext);
3501 int64_t obj_size = gl_ctype_sizeof<T>::size;
3502 int64_t total_size = obj_size * math::maximum<int64_t>(size, 0);
3504 vogl_ctype_t pointee_type = g_vogl_process_gl_ctypes[type].m_pointee_ctype;
3505 if (((type == VOGL_CONST_VOID_PTR) || (type == VOGL_CONST_GLVOID_PTR) || (type == VOGL_GLVOID_PTR)) && (size > 0))
3512 if (pointee_type == VOGL_INVALID_CTYPE)
3514 vogl_error_printf("%s: Type %u doesn't have a pointee ctype\n", VOGL_FUNCTION_NAME, type);
3518 if (g_vogl_process_gl_ctypes[pointee_type].m_size != obj_size)
3519 vogl_error_printf("%s: Size mismatch on ctype %u\n", VOGL_FUNCTION_NAME, type);
3522 bool pointee_is_ptr = g_vogl_process_gl_ctypes[pointee_type].m_is_pointer;
3524 if (serializer.is_in_begin())
3526 serializer.add_param(param_index, type, &pArray, sizeof(pArray));
3528 if ((pArray) && (size > 0) && (obj_size > 0))
3530 serializer.add_array_client_memory(param_index, pointee_type, size, pArray, total_size);
3534 if (g_dump_gl_calls_flag)
3536 vogl_log_printf("%s: %s %s, ptr: 0x%" PRIX64 ", ctype: %s, pointee_ctype: %s, size: %" PRIi64 ", pointee_size: %" PRIi64 ", total size: %" PRIi64 ": ", pDesc, pType, pParam_name, cast_val_to_uint64(pArray), g_vogl_process_gl_ctypes[type].m_pName, g_vogl_process_gl_ctypes[pointee_type].m_pName,
3537 size, obj_size, total_size);
3540 vogl_log_printf("NULL");
3544 vogl_log_printf("UNKNOWN SIZE");
3546 else if (obj_size <= 0)
3548 vogl_log_printf("OPAQUE TYPE");
3554 vogl_log_printf("POINTEE IS POINTER: \n");
3557 vogl_print_hex(pArray, total_size, obj_size);
3559 switch (pointee_type)
3564 case VOGL_GLCHARARB:
3566 vogl_log_printf("\nAs string: \"");
3567 vogl_print_string(*(const char **)&pArray, total_size);
3568 vogl_log_printf("\"");
3578 vogl_log_printf("\n");
3582 //----------------------------------------------------------------------------------------------------------------------
3583 // Return parameters
3584 //----------------------------------------------------------------------------------------------------------------------
3586 static inline void vogl_dump_return_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pType, vogl_ctype_t type, int64_t size, const T &val)
3588 VOGL_NOTE_UNUSED(size);
3590 VOGL_ASSUME(!Loki::TypeTraits<T>::isPointer);
3592 vogl_dump_value_param(pContext, serializer, "RETURN_VALUE", VOGL_RETURN_PARAM_INDEX, "result", pType, type, val);
3595 static inline void vogl_dump_return_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pType, vogl_ctype_t type, int64_t size, unsigned char *pPtr)
3597 VOGL_NOTE_UNUSED(size);
3599 size_t array_size = pPtr ? (strlen(reinterpret_cast<const char *>(pPtr)) + 1) : 0;
3600 vogl_dump_array_param(pContext, serializer, "RETURN_UCHAR_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr, array_size);
3603 static inline void vogl_dump_return_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pType, vogl_ctype_t type, int64_t size, const GLubyte *pPtr)
3605 VOGL_NOTE_UNUSED(size);
3607 size_t array_size = pPtr ? (strlen(reinterpret_cast<const char *>(pPtr)) + 1) : 0;
3608 vogl_dump_array_param(pContext, serializer, "RETURN_GLUBYTE_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr, array_size);
3611 static inline void vogl_dump_return_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pType, vogl_ctype_t type, int64_t size, void *pPtr)
3613 VOGL_NOTE_UNUSED(size);
3616 vogl_dump_ptr_param(pContext, serializer, "RETURN_VOID_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr);
3619 static inline void vogl_dump_return_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pType, vogl_ctype_t type, int64_t size, unsigned int *pPtr)
3621 vogl_dump_array_param(pContext, serializer, "RETURN_UINT_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr, size);
3624 static inline void vogl_dump_return_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pType, vogl_ctype_t type, int64_t size, long unsigned int *pPtr)
3626 vogl_dump_array_param(pContext, serializer, "RETUURN_LUINT_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr, size);
3629 static inline void vogl_dump_return_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pType, vogl_ctype_t type, int64_t size, XVisualInfo *pPtr)
3631 VOGL_NOTE_UNUSED(size);
3633 vogl_dump_ref_param(pContext, serializer, "RETURN_XVISUALINFO_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr);
3636 static inline void vogl_dump_return_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pType, vogl_ctype_t type, int64_t size, GLXFBConfig *pPtr)
3638 VOGL_NOTE_UNUSED(size);
3640 vogl_dump_ref_param(pContext, serializer, "RETURN_GLXFBCONFIG_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr);
3643 static inline void vogl_dump_return_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pType, vogl_ctype_t type, int64_t size, GLXContext pPtr)
3645 VOGL_NOTE_UNUSED(size);
3648 vogl_dump_ptr_param(pContext, serializer, "RETURN_GLXCONTEXT", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr);
3651 static inline void vogl_dump_return_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pType, vogl_ctype_t type, int64_t size, _XDisplay *pPtr)
3653 VOGL_NOTE_UNUSED(size);
3656 vogl_dump_ptr_param(pContext, serializer, "RETURN_XDISPLAY_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr);
3659 //----------------------------------------------------------------------------------------------------------------------
3660 // vogl_should_serialize_call
3661 //----------------------------------------------------------------------------------------------------------------------
3662 static inline bool vogl_should_serialize_call(gl_entrypoint_id_t func, vogl_context *pContext)
3664 bool is_in_display_list = pContext && pContext->is_composing_display_list();
3665 bool is_listable = g_vogl_entrypoint_descs[func].m_is_listable;
3666 bool is_whitelisted = g_vogl_entrypoint_descs[func].m_whitelisted_for_displaylists;
3668 if ((is_in_display_list) && (is_listable) && (!is_whitelisted))
3670 vogl_error_printf("%s: Called GL func %s is not currently supported in display lists! The replay will diverge.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[func].m_pName);
3673 // When we're writing a trace we ALWAYS want to serialize, even if the func is not listable (so we can at least process the trace, etc.)
3674 if (g_vogl_trace_writer.is_opened())
3677 return is_in_display_list && is_whitelisted;
3680 //----------------------------------------------------------------------------------------------------------------------
3681 // vogl_write_packet_to_trace
3682 //----------------------------------------------------------------------------------------------------------------------
3683 static inline void vogl_write_packet_to_trace(vogl_trace_packet &packet)
3685 if (!g_vogl_trace_writer.is_opened())
3688 scoped_mutex lock(g_vogl_trace_mutex);
3690 // The trace got closed on another thread while we where serializing - this is OK I guess.
3691 // This can happen when control+c is pressed.
3692 if (g_vogl_trace_writer.is_opened())
3694 bool success = g_vogl_trace_writer.write_packet(packet);
3698 if ((g_flush_files_after_each_call) ||
3699 ((g_flush_files_after_each_swap) && (packet.get_entrypoint_id() == VOGL_ENTRYPOINT_glXSwapBuffers)))
3701 g_vogl_trace_writer.flush();
3703 if (g_vogl_pLog_stream)
3704 g_vogl_pLog_stream->flush();
3709 vogl_error_printf("%s: Failed writing to trace file! Exiting app.\n", VOGL_FUNCTION_NAME);
3711 // TODO: Add common termination handler func, or just stop writing to the trace? or call abort()
3717 //----------------------------------------------------------------------------------------------------------------------
3718 // Declare gl/glx internal wrapper functions, all start with "vogl_" (so we can safely get the address of our internal
3719 // wrappers, avoiding global symbol naming conflicts that I started to see on test apps when I started building with -fPIC)
3720 //----------------------------------------------------------------------------------------------------------------------
3722 #define DEF_PROTO_EXPORTED(ret, name, args, params) \
3723 static ret VOGL_GLUER(vogl_, name) args \
3725 if (vogl_func_is_nulled(VOGL_ENTRYPOINT_##name)) \
3730 #define DEF_PROTO_EXPORTED_VOID(ret, name, args, params) \
3731 static ret VOGL_GLUER(vogl_, name) args \
3733 if (vogl_func_is_nulled(VOGL_ENTRYPOINT_##name)) \
3735 #define DEF_PROTO_INTERNAL(ret, name, args, params) \
3736 static ret VOGL_GLUER(vogl_, name) args \
3738 if (vogl_func_is_nulled(VOGL_ENTRYPOINT_##name)) \
3743 #define DEF_PROTO_INTERNAL_VOID(ret, name, args, params) \
3744 static ret VOGL_GLUER(vogl_, name) args \
3746 if (vogl_func_is_nulled(VOGL_ENTRYPOINT_##name)) \
3749 #define DEF_FUNCTION_BEGIN(exported, category, ret, ret_type_enum, num_params, name, args, params) exported(ret, name, args, params)
3750 #define DEF_FUNCTION_BEGIN_VOID(exported, category, ret, ret_type_enum, num_params, name, args, params) exported(ret, name, args, params)
3752 // TODO: When serialization is off, the array size determination code is still active (which could involve useless GL calls and in the worst case could trigger errors when/if this code is buggy).
3753 // A completely different code path through the wrapper should be used.
3755 // func init (after the optional custom function prolog)
3756 #define VOGL_MASTER_FUNCTION_PROLOG(name, params) \
3757 if (g_dump_gl_calls_flag) \
3759 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "" PRIX64 "\n", #name, vogl_get_current_kernel_thread_id()); \
3761 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_##name); \
3762 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID) \
3764 vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName); \
3765 return g_vogl_actual_gl_entrypoints.m_##name params; \
3767 vogl_context *pContext = pTLS_data->m_pContext; \
3768 vogl_entrypoint_serializer &trace_serializer = pTLS_data->m_serializer; \
3769 if (vogl_should_serialize_call(VOGL_ENTRYPOINT_##name, pContext)) \
3771 if (!trace_serializer.begin(VOGL_ENTRYPOINT_##name, pContext)) \
3773 vogl_warning_printf("%s: Reentrant wrapper call detected!\n", VOGL_FUNCTION_NAME); \
3774 return g_vogl_actual_gl_entrypoints.m_##name params; \
3778 #define VOGL_MASTER_FUNCTION_PROLOG_VOID(name, params) \
3779 if (g_dump_gl_calls_flag) \
3781 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", #name, vogl_get_current_kernel_thread_id()); \
3783 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_##name); \
3784 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID) \
3786 vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName); \
3787 g_vogl_actual_gl_entrypoints.m_##name params; \
3790 vogl_context *pContext = pTLS_data->m_pContext; \
3791 vogl_entrypoint_serializer &trace_serializer = pTLS_data->m_serializer; \
3792 if (vogl_should_serialize_call(VOGL_ENTRYPOINT_##name, pContext)) \
3794 if (!trace_serializer.begin(VOGL_ENTRYPOINT_##name, pContext)) \
3796 vogl_warning_printf("%s: Reentrant wrapper call detected!\n", VOGL_FUNCTION_NAME); \
3797 g_vogl_actual_gl_entrypoints.m_##name params; \
3802 #define DEF_FUNCTION_INIT(exported, category, ret, ret_type_enum, num_params, name, args, params) VOGL_MASTER_FUNCTION_PROLOG(name, params)
3803 #define DEF_FUNCTION_INIT_VOID(exported, category, ret, ret_type_enum, num_params, name, args, params) VOGL_MASTER_FUNCTION_PROLOG_VOID(name, params)
3806 #define DEF_FUNCTION_INPUT_VALUE_PARAM(idx, spectype, type, type_enum, param) vogl_dump_value_param(pContext, trace_serializer, "INPUT_VALUE", idx, #param, #type, type_enum, param);
3807 #define DEF_FUNCTION_INPUT_REFERENCE_PARAM(idx, spectype, type, type_enum, param) vogl_dump_ref_param(pContext, trace_serializer, "INPUT_REF", idx, #param, #type, type_enum, param);
3808 #define DEF_FUNCTION_INPUT_ARRAY_PARAM(idx, spectype, type, type_enum, param, size) vogl_dump_array_param(pContext, trace_serializer, "INPUT_ARRAY", idx, #param, #type, type_enum, param, size);
3810 #define DEF_FUNCTION_OUTPUT_REFERENCE_PARAM(idx, spectype, type, type_enum, param) vogl_dump_ref_param(pContext, trace_serializer, "OUTPUT_REF", idx, #param, #type, type_enum, param);
3811 #define DEF_FUNCTION_OUTPUT_ARRAY_PARAM(idx, spectype, type, type_enum, param, size) vogl_dump_array_param(pContext, trace_serializer, "OUTPUT_ARRAY", idx, #param, #type, type_enum, param, size);
3813 #define DEF_FUNCTION_RETURN_PARAM(spectype, type, type_enum, size) vogl_dump_return_param(pContext, trace_serializer, #type, type_enum, size, result);
3815 #define DEF_FUNCTION_CALL_GL(exported, category, ret, ret_type_enum, num_params, name, args, params) \
3816 if (trace_serializer.is_in_begin()) \
3817 trace_serializer.set_gl_begin_rdtsc(utils::RDTSC()); \
3818 result = g_vogl_actual_gl_entrypoints.m_##name params; \
3819 if (trace_serializer.is_in_begin()) \
3820 trace_serializer.set_gl_end_rdtsc(utils::RDTSC());
3822 #define DEF_FUNCTION_CALL_GL_VOID(exported, category, ret, ret_type_enum, num_params, name, args, params) \
3823 if (trace_serializer.is_in_begin()) \
3824 trace_serializer.set_gl_begin_rdtsc(utils::RDTSC()); \
3825 g_vogl_actual_gl_entrypoints.m_##name params; \
3826 if (trace_serializer.is_in_begin()) \
3827 trace_serializer.set_gl_end_rdtsc(utils::RDTSC());
3829 // Be careful modifying these END macros. They must be compatible with the logic in the glXSwapBuffers GL end prolog!
3830 // func end (after the optional custom function epilog)
3831 #define DEF_FUNCTION_END(exported, category, ret, ret_type_enum, num_params, name, args, params) \
3832 if (g_dump_gl_calls_flag) \
3834 vogl_message_printf("** END %s res=%s 0x%" PRIX64 "\n", #name, #ret, cast_val_to_uint64(result)); \
3836 if (trace_serializer.is_in_begin()) \
3838 trace_serializer.end(); \
3839 vogl_write_packet_to_trace(trace_serializer.get_packet()); \
3841 pContext->add_packet_to_current_display_list(VOGL_ENTRYPOINT_##name, trace_serializer.get_packet()); \
3846 #define DEF_FUNCTION_END_VOID(exported, category, ret, ret_type_enum, num_params, name, args, params) \
3847 if (g_dump_gl_calls_flag) \
3849 vogl_message_printf("** END %s\n", #name); \
3851 if (trace_serializer.is_in_begin()) \
3853 trace_serializer.end(); \
3854 vogl_write_packet_to_trace(trace_serializer.get_packet()); \
3856 pContext->add_packet_to_current_display_list(VOGL_ENTRYPOINT_##name, trace_serializer.get_packet()); \
3860 //----------------------------------------------------------------------------------------------------------------------
3861 // gl/glx override functions
3862 //----------------------------------------------------------------------------------------------------------------------
3863 static __GLXextFuncPtr vogl_get_proc_address_helper(const GLubyte *procName)
3868 if (g_dump_gl_calls_flag)
3870 vogl_printf("glXGetProcAddress: \"%s\"\n", procName);
3873 if (!GL_ENTRYPOINT(glXGetProcAddress))
3876 // FIXME: We need to make this per-context on OSX (under Linux it doesn't matter, because all GL funcs are statically exported anyway as symbols by the SO)
3877 __GLXextFuncPtr pActual_entrypoint = GL_ENTRYPOINT(glXGetProcAddress)(procName);
3878 if (!pActual_entrypoint)
3881 for (uint i = 0; i < VOGL_NUM_ENTRYPOINTS; ++i)
3883 if (vogl_strcmp(reinterpret_cast<const char *>(procName), g_vogl_entrypoint_descs[i].m_pName) == 0)
3885 if (g_vogl_entrypoint_descs[i].m_pWrapper_func)
3887 if (!g_vogl_entrypoint_descs[i].m_is_whitelisted)
3889 // TODO: Only print this message once
3890 vogl_warning_printf("%s: App has queried the address of non-whitelisted GL func %s (this will only be a problem if this func. is actually called, and will reported during tracing and at exit)\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[i].m_pName);
3893 return reinterpret_cast<__GLXextFuncPtr>(g_vogl_entrypoint_descs[i].m_pWrapper_func);
3900 return pActual_entrypoint;
3903 //----------------------------------------------------------------------------------------------------------------------
3904 // Custom function handler implementations
3905 //----------------------------------------------------------------------------------------------------------------------
3906 #define DEF_FUNCTION_CUSTOM_HANDLER_glInternalTraceCommandRAD(exported, category, ret, ret_type_enum, num_params, name, args, params)
3907 static void vogl_glInternalTraceCommandRAD(GLuint cmd, GLuint size, const GLubyte *data)
3909 if (g_dump_gl_calls_flag)
3911 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
3914 if (g_vogl_trace_writer.is_opened())
3916 vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glInternalTraceCommandRAD, NULL);
3918 uint64_t cur_rdtsc = utils::RDTSC();
3919 serializer.set_gl_begin_end_rdtsc(cur_rdtsc, cur_rdtsc + 1);
3921 serializer.add_param(0, VOGL_GLUINT, &cmd, sizeof(cmd));
3922 serializer.add_param(1, VOGL_GLUINT, &size, sizeof(size));
3923 serializer.add_param(2, VOGL_CONST_GLUBYTE_PTR, &data, sizeof(data));
3927 case cITCRDemarcation:
3931 case cITCRKeyValueMap:
3933 if ((size == sizeof(key_value_map)) && (data))
3935 // Directly jam in the key value map, so it properly serializes as readable JSON.
3936 serializer.get_key_value_map() = *reinterpret_cast<const key_value_map *>(data);
3940 vogl_error_printf("%s: data pointer is NULL, or invalid key_value_map size %u\n", VOGL_FUNCTION_NAME, size);
3947 vogl_error_printf("%s: Unknown trace command type %u\n", VOGL_FUNCTION_NAME, cmd);
3954 vogl_write_packet_to_trace(serializer.get_packet());
3957 if (g_dump_gl_calls_flag)
3959 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
3963 //----------------------------------------------------------------------------------------------------------------------
3964 // TODO: Merge this with vogl_glXGetProcAddressARB to avoid duplicated code
3965 #define DEF_FUNCTION_CUSTOM_HANDLER_glXGetProcAddress(exported, category, ret, ret_type_enum, num_params, name, args, params)
3966 static __GLXextFuncPtr vogl_glXGetProcAddress(const GLubyte *procName)
3968 uint64_t begin_rdtsc = utils::RDTSC();
3970 if (g_dump_gl_calls_flag)
3972 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
3975 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXGetProcAddress);
3976 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
3978 vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName);
3979 return GL_ENTRYPOINT(glXGetProcAddress)(procName);
3982 uint64_t gl_begin_rdtsc = utils::RDTSC();
3983 __GLXextFuncPtr ptr = vogl_get_proc_address_helper(procName);
3984 uint64_t gl_end_rdtsc = utils::RDTSC();
3986 if (g_vogl_trace_writer.is_opened())
3988 vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glXGetProcAddress, g_context_manager.get_current());
3989 serializer.set_begin_rdtsc(begin_rdtsc);
3990 serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
3991 serializer.add_param(0, VOGL_CONST_GLUBYTE_PTR, &procName, sizeof(procName));
3994 size_t len = strlen(reinterpret_cast<const char *>(procName)) + 1;
3995 serializer.add_array_client_memory(0, VOGL_GLUBYTE, len, procName, len);
3997 serializer.add_return_param(VOGL_GLXEXTFUNCPTR, &ptr, sizeof(ptr));
3999 vogl_write_packet_to_trace(serializer.get_packet());
4002 if (g_dump_gl_calls_flag)
4004 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
4010 //----------------------------------------------------------------------------------------------------------------------
4011 #define DEF_FUNCTION_CUSTOM_HANDLER_glXGetProcAddressARB(exported, category, ret, ret_type_enum, num_params, name, args, params)
4012 static __GLXextFuncPtr vogl_glXGetProcAddressARB(const GLubyte *procName)
4014 uint64_t begin_rdtsc = utils::RDTSC();
4016 if (g_dump_gl_calls_flag)
4018 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
4021 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXGetProcAddressARB);
4022 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
4024 vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName);
4025 return GL_ENTRYPOINT(glXGetProcAddressARB)(procName);
4028 uint64_t gl_begin_rdtsc = utils::RDTSC();
4029 __GLXextFuncPtr ptr = vogl_get_proc_address_helper(procName);
4030 uint64_t gl_end_rdtsc = utils::RDTSC();
4032 if (g_vogl_trace_writer.is_opened())
4034 vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glXGetProcAddressARB, g_context_manager.get_current());
4035 serializer.set_begin_rdtsc(begin_rdtsc);
4036 serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
4037 serializer.add_param(0, VOGL_CONST_GLUBYTE_PTR, &procName, sizeof(procName));
4040 size_t len = strlen(reinterpret_cast<const char *>(procName)) + 1;
4041 serializer.add_array_client_memory(0, VOGL_GLUBYTE, len, procName, len);
4043 serializer.add_return_param(VOGL_GLXEXTFUNCPTR, &ptr, sizeof(ptr));
4045 vogl_write_packet_to_trace(serializer.get_packet());
4048 if (g_dump_gl_calls_flag)
4050 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
4056 //----------------------------------------------------------------------------------------------------------------------
4057 static void vogl_add_make_current_key_value_fields(const Display *dpy, GLXDrawable drawable, Bool result, vogl_context *pVOGL_context, vogl_entrypoint_serializer &serializer)
4059 if ((result) && (pVOGL_context))
4061 vogl_scoped_gl_error_absorber gl_error_absorber(pVOGL_context);
4062 VOGL_NOTE_UNUSED(gl_error_absorber);
4064 GLint cur_viewport[4];
4065 GL_ENTRYPOINT(glGetIntegerv)(GL_VIEWPORT, cur_viewport);
4067 serializer.add_key_value(string_hash("viewport_x"), cur_viewport[0]);
4068 serializer.add_key_value(string_hash("viewport_y"), cur_viewport[1]);
4069 serializer.add_key_value(string_hash("viewport_width"), cur_viewport[2]);
4070 serializer.add_key_value(string_hash("viewport_height"), cur_viewport[3]);
4073 if ((pVOGL_context) && (pVOGL_context->get_window_width() < 0))
4075 if ((dpy) && (drawable) && (result))
4079 unsigned int width, height, border_width, depth;
4080 if (XGetGeometry(const_cast<Display *>(dpy), drawable, &root, &x, &y, &width, &height, &border_width, &depth) != False)
4082 pVOGL_context->set_window_dimensions(width, height);
4084 serializer.add_key_value(string_hash("win_width"), width);
4085 serializer.add_key_value(string_hash("win_height"), height);
4087 if (g_dump_gl_calls_flag)
4089 vogl_log_printf("** Current window dimensions: %ix%i\n", width, height);
4097 //----------------------------------------------------------------------------------------------------------------------
4098 // HACK HACK - for NS2 experiment in AMD
4099 #define DEF_FUNCTION_CUSTOM_HANDLER_glTexStorage2D(exported, category, ret, ret_type_enum, num_params, name, args, params)
4100 static void vogl_glTexStorage2D( GLenum target,
4102 GLenum internalformat,
4106 GL_ENTRYPOINT(glTexParameteri)(target, GL_TEXTURE_BASE_LEVEL, 0);
4107 GL_ENTRYPOINT(glTexParameteri)(target, GL_TEXTURE_MAX_LEVEL, levels - 1);
4109 if (target == GL_TEXTURE_2D)
4111 for (uint i = 0; i < levels; i++)
4113 uint w = math::maximum<uint>(width >> i, 1);
4114 uint h = math::maximum<uint>(height >> i, 1);
4115 vogl::vector<uint8> pixels(w * h * 4);
4116 GL_ENTRYPOINT(glTexImage2D)(GL_TEXTURE_2D, i, internalformat, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, pixels.get_ptr());
4122 //----------------------------------------------------------------------------------------------------------------------
4123 #define DEF_FUNCTION_CUSTOM_HANDLER_glXMakeCurrent(exported, category, ret, ret_type_enum, num_params, name, args, params)
4124 static Bool vogl_glXMakeCurrent(const Display *dpy, GLXDrawable drawable, GLXContext context)
4126 uint64_t begin_rdtsc = utils::RDTSC();
4128 if (g_dump_gl_calls_flag)
4130 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
4133 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXMakeCurrent);
4134 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
4136 vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName);
4137 return GL_ENTRYPOINT(glXMakeCurrent)(dpy, drawable, context);
4140 if (g_dump_gl_calls_flag)
4142 vogl_log_printf("** glXMakeCurrent TID: 0x%" PRIX64 " dpy: 0x%" PRIX64 " drawable: 0x%" PRIX64 " context: 0x%" PRIX64 "\n", vogl_get_current_kernel_thread_id(), cast_val_to_uint64(dpy), cast_val_to_uint64(drawable), cast_val_to_uint64(context));
4145 vogl_context *pCur_context = g_context_manager.get_current();
4147 vogl_context *pNew_context = context ? g_context_manager.lookup_vogl_context(context) : NULL;
4148 if ((context) && (!pNew_context))
4150 vogl_error_printf("%s: Unknown context handle 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(context));
4155 if (pCur_context != pNew_context)
4156 pCur_context->on_release_current_prolog();
4158 vogl_warning_printf("%s: Context 0x%" PRIX64 " is already current (redundant call)\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(context));
4161 uint64_t gl_begin_rdtsc = utils::RDTSC();
4162 Bool result = GL_ENTRYPOINT(glXMakeCurrent)(dpy, drawable, context);
4163 uint64_t gl_end_rdtsc = utils::RDTSC();
4165 if ((result) && (pCur_context != pNew_context))
4168 g_context_manager.release_current();
4172 vogl_context *p = g_context_manager.make_current(context);
4173 VOGL_ASSERT(p == pNew_context);
4174 VOGL_NOTE_UNUSED(p);
4176 pNew_context->set_display(dpy);
4177 pNew_context->set_drawable(drawable);
4178 pNew_context->set_read_drawable(drawable);
4182 if (g_dump_gl_calls_flag)
4184 vogl_log_printf("** glXMakeCurrent result: %i\n", result);
4187 if (g_vogl_trace_writer.is_opened())
4189 vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glXMakeCurrent, pCur_context);
4190 serializer.set_begin_rdtsc(begin_rdtsc);
4191 serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
4192 serializer.add_param(0, VOGL_CONST_DISPLAY_PTR, &dpy, sizeof(dpy));
4193 serializer.add_param(1, VOGL_GLXDRAWABLE, &drawable, sizeof(drawable));
4194 serializer.add_param(2, VOGL_GLXCONTEXT, &context, sizeof(context));
4195 serializer.add_return_param(VOGL_BOOL, &result, sizeof(result));
4197 vogl_add_make_current_key_value_fields(dpy, drawable, result, pNew_context, serializer);
4200 vogl_write_packet_to_trace(serializer.get_packet());
4203 if (g_dump_gl_calls_flag)
4205 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
4208 static bool s_added_atexit = false;
4209 if (!s_added_atexit)
4211 // atexit routines are called in the reverse order in which they were registered. We would like
4212 // our vogl_atexit() routine to be called before anything else (Ie C++ destructors, etc.) So we
4213 // put atexit at the end of vogl_global_init() and another at the end of glXMakeCurrent.
4214 atexit(vogl_atexit);
4215 s_added_atexit = true;
4221 //----------------------------------------------------------------------------------------------------------------------
4222 #define DEF_FUNCTION_CUSTOM_HANDLER_glXMakeContextCurrent(exported, category, ret, ret_type_enum, num_params, name, args, params)
4223 static Bool vogl_glXMakeContextCurrent(const Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext context)
4225 uint64_t begin_rdtsc = utils::RDTSC();
4227 if (g_dump_gl_calls_flag)
4229 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
4232 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXMakeContextCurrent);
4233 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
4235 vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName);
4236 return GL_ENTRYPOINT(glXMakeContextCurrent)(dpy, draw, read, context);
4239 if (g_dump_gl_calls_flag)
4241 vogl_log_printf("** glXMakeContextCurrent TID: 0x%" PRIX64 " dpy: 0x%" PRIX64 " draw: 0x%" PRIX64 " read: 0x%" PRIX64 " context: 0x%" PRIX64 "\n", vogl_get_current_kernel_thread_id(), cast_val_to_uint64(dpy), cast_val_to_uint64(draw), cast_val_to_uint64(read), cast_val_to_uint64(context));
4244 vogl_context *pCur_context = g_context_manager.get_current();
4246 vogl_context *pNew_context = context ? g_context_manager.lookup_vogl_context(context) : NULL;
4247 if ((context) && (!pNew_context))
4249 vogl_error_printf("%s: Unknown coontext handle 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(context));
4254 if (pCur_context != pNew_context)
4255 pCur_context->on_release_current_prolog();
4257 vogl_warning_printf("%s: Context 0x%" PRIX64 " is already current (redundant call)\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(context));
4260 uint64_t gl_begin_rdtsc = utils::RDTSC();
4261 Bool result = GL_ENTRYPOINT(glXMakeContextCurrent)(dpy, draw, read, context);
4262 uint64_t gl_end_rdtsc = utils::RDTSC();
4264 if ((result) && (pCur_context != pNew_context))
4267 g_context_manager.release_current();
4271 vogl_context *p = g_context_manager.make_current(context);
4272 VOGL_ASSERT(p == pNew_context);
4273 VOGL_NOTE_UNUSED(p);
4275 pNew_context->set_display(dpy);
4276 pNew_context->set_drawable(draw);
4277 pNew_context->set_read_drawable(read);
4281 if (g_dump_gl_calls_flag)
4283 vogl_log_printf("** glXMakeCurrent result: %i\n", result);
4286 if (g_vogl_trace_writer.is_opened())
4288 vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glXMakeContextCurrent, pCur_context);
4289 serializer.set_begin_rdtsc(begin_rdtsc);
4290 serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
4291 serializer.add_param(0, VOGL_CONST_DISPLAY_PTR, &dpy, sizeof(dpy));
4292 serializer.add_param(1, VOGL_GLXDRAWABLE, &draw, sizeof(draw));
4293 serializer.add_param(2, VOGL_GLXDRAWABLE, &read, sizeof(read));
4294 serializer.add_param(3, VOGL_GLXCONTEXT, &context, sizeof(context));
4295 serializer.add_return_param(VOGL_BOOL, &result, sizeof(result));
4297 vogl_add_make_current_key_value_fields(dpy, draw, result, pNew_context, serializer);
4300 vogl_write_packet_to_trace(serializer.get_packet());
4303 if (g_dump_gl_calls_flag)
4305 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
4311 //----------------------------------------------------------------------------------------------------------------------
4312 static bool vogl_screen_capture_callback(uint width, uint height, uint pitch, size_t size, GLenum pixel_format, GLenum pixel_type, const void *pImage, void *pOpaque, uint64_t frame_index)
4314 vogl_context *pContext = static_cast<vogl_context *>(pOpaque);
4316 if ((!pContext) || (!width) || (!height))
4322 if ((pixel_format != GL_RGB) || (pixel_type != GL_UNSIGNED_BYTE) || (pitch != width * 3))
4328 if (g_command_line_params.get_value_as_bool("vogl_dump_png_screenshots"))
4330 size_t png_size = 0;
4331 void *pPNG_data = tdefl_write_image_to_png_file_in_memory_ex(pImage, width, height, 3, &png_size, 1, true);
4333 dynamic_string screenshot_filename(cVarArg, "%s__%08" PRIx64 "_%08" PRIu64 ".png", g_command_line_params.get_value_as_string("vogl_screenshot_prefix", 0, "screenshot").get_ptr(), cast_val_to_uint64(pContext->get_context_handle()), cast_val_to_uint64(frame_index));
4334 if (!file_utils::write_buf_to_file(screenshot_filename.get_ptr(), pPNG_data, png_size))
4336 console::error("Failed writing PNG screenshot to file %s\n", screenshot_filename.get_ptr());
4341 else if (g_command_line_params.get_value_as_bool("vogl_dump_jpeg_screenshots"))
4343 int jpeg_quality = g_command_line_params.get_value_as_int("vogl_jpeg_quality", 0, 80, 1, 100);
4345 long unsigned int jpeg_size = 0;
4346 unsigned char *pJPEG_data = NULL;
4348 tjhandle _jpegCompressor = tjInitCompress();
4350 int status = tjCompress2(_jpegCompressor, (unsigned char *)pImage, width, pitch, height, TJPF_RGB,
4351 &pJPEG_data, &jpeg_size, TJSAMP_422, jpeg_quality,
4352 TJFLAG_FASTDCT | TJFLAG_BOTTOMUP);
4354 tjDestroy(_jpegCompressor);
4358 dynamic_string screenshot_filename(cVarArg, "%s_%08" PRIx64 "_%08" PRIu64 ".jpg",
4359 g_command_line_params.get_value_as_string("vogl_screenshot_prefix", 0, "screenshot").get_ptr(),
4360 cast_val_to_uint64(pContext->get_context_handle()),
4361 cast_val_to_uint64(frame_index));
4362 if (!file_utils::write_buf_to_file(screenshot_filename.get_ptr(), pJPEG_data, jpeg_size))
4364 console::error("Failed writing JPEG screenshot to file %s\n", screenshot_filename.get_ptr());
4371 if (g_command_line_params.get_value_as_bool("vogl_dump_backbuffer_hashes") || g_command_line_params.get_value_as_bool("vogl_hash_backbuffer"))
4373 uint64_t backbuffer_crc64;
4375 if (g_command_line_params.get_value_as_bool("vogl_sum_hashing"))
4377 backbuffer_crc64 = calc_sum64(static_cast<const uint8 *>(pImage), size);
4381 backbuffer_crc64 = calc_crc64(CRC64_INIT, static_cast<const uint8 *>(pImage), size);
4384 console::printf("Frame %" PRIu64 " hash: 0x%016" PRIX64 "\n", cast_val_to_uint64(frame_index), backbuffer_crc64);
4386 dynamic_string backbuffer_hash_file;
4387 if (g_command_line_params.get_value_as_string(backbuffer_hash_file, "vogl_dump_backbuffer_hashes"))
4389 FILE *pFile = vogl_fopen(backbuffer_hash_file.get_ptr(), "a");
4391 console::error("Failed writing to backbuffer hash file %s\n", backbuffer_hash_file.get_ptr());
4394 vogl_fprintf(pFile, "0x%016" PRIX64 "\n", backbuffer_crc64);
4402 //----------------------------------------------------------------------------------------------------------------------
4403 static void vogl_tick_screen_capture(vogl_context *pVOGL_context)
4408 uint width = pVOGL_context->get_window_width();
4409 uint height = pVOGL_context->get_window_height();
4410 if ((!width) || (!height))
4413 bool grab_backbuffer = g_command_line_params.get_value_as_bool("vogl_dump_backbuffer_hashes") || g_command_line_params.get_value_as_bool("vogl_hash_backbuffer") ||
4414 g_command_line_params.get_value_as_bool("vogl_dump_jpeg_screenshots") || g_command_line_params.get_value_as_bool("vogl_dump_png_screenshots");
4415 if (!grab_backbuffer)
4418 vogl_scoped_gl_error_absorber gl_error_absorber(pVOGL_context);
4419 VOGL_NOTE_UNUSED(gl_error_absorber);
4421 if (!pVOGL_context->get_framebuffer_capturer().is_initialized())
4423 if (!pVOGL_context->get_framebuffer_capturer().init(2, vogl_screen_capture_callback, pVOGL_context, GL_RGB, GL_UNSIGNED_BYTE))
4425 vogl_error_printf("%s: Failed initializing context's vogl_framebuffer_capturer!\n", VOGL_FUNCTION_NAME);
4430 if (!pVOGL_context->get_framebuffer_capturer().capture(width, height, 0, GL_BACK, pVOGL_context->get_frame_index()))
4432 vogl_error_printf("%s: vogl_framebuffer_capturer::capture() failed!\n", VOGL_FUNCTION_NAME);
4437 //----------------------------------------------------------------------------------------------------------------------
4438 static vogl_gl_state_snapshot *vogl_snapshot_state(const Display *dpy, GLXDrawable drawable, vogl_context *pCur_context)
4440 VOGL_NOTE_UNUSED(dpy);
4441 VOGL_NOTE_UNUSED(drawable);
4443 // pCur_context may be NULL!
4445 if (!GL_ENTRYPOINT(glXGetCurrentContext) || !GL_ENTRYPOINT(glXGetCurrentDisplay) ||
4446 !GL_ENTRYPOINT(glXGetCurrentDrawable) || !GL_ENTRYPOINT(glXGetCurrentReadDrawable))
4449 timed_scope ts(VOGL_FUNCTION_NAME);
4451 g_context_manager.lock();
4453 if (vogl_check_gl_error())
4454 vogl_error_printf("%s: A GL error occured sometime before this function was called\n", VOGL_FUNCTION_NAME);
4456 const Display *orig_dpy = GL_ENTRYPOINT(glXGetCurrentDisplay)();
4457 GLXDrawable orig_drawable = GL_ENTRYPOINT(glXGetCurrentDrawable)();
4458 GLXDrawable orig_read_drawable = GL_ENTRYPOINT(glXGetCurrentReadDrawable)();
4459 GLXContext orig_context = GL_ENTRYPOINT(glXGetCurrentContext)();
4464 vogl_check_gl_error();
4466 vogl_gl_state_snapshot *pSnapshot = vogl_new(vogl_gl_state_snapshot);
4468 const glxcontext_map &contexts = g_context_manager.get_context_map();
4470 // TODO: Find a better way of determining which window dimensions to use.
4471 // No context is current, let's just find the biggest window.
4473 uint win_height = 0;
4476 win_width = pCur_context->get_window_width();
4477 win_height = pCur_context->get_window_height();
4481 glxcontext_map::const_iterator it;
4482 for (it = contexts.begin(); it != contexts.end(); ++it)
4484 vogl_context *pVOGL_context = it->second;
4485 if ((pVOGL_context->get_window_width() > (int)win_width) || (pVOGL_context->get_window_height() > (int)win_height))
4487 win_width = pVOGL_context->get_window_width();
4488 win_height = pVOGL_context->get_window_height();
4493 vogl_message_printf("%s: Beginning capture: width %u, height %u\n", VOGL_FUNCTION_NAME, win_width, win_height);
4495 if (!pSnapshot->begin_capture(win_width, win_height, pCur_context ? (uint64_t)pCur_context->get_context_handle() : 0, 0, g_vogl_trace_writer.get_cur_gl_call_counter(), true))
4497 vogl_error_printf("%s: Failed beginning capture\n", VOGL_FUNCTION_NAME);
4499 vogl_delete(pSnapshot);
4502 g_context_manager.unlock();
4507 vogl_printf("%s: Capturing %u context(s)\n", VOGL_FUNCTION_NAME, contexts.size());
4509 glxcontext_map::const_iterator it;
4510 for (it = contexts.begin(); it != contexts.end(); ++it)
4512 GLXContext glx_context = it->first;
4513 vogl_context *pVOGL_context = it->second;
4515 if (pVOGL_context->get_deleted_flag())
4517 vogl_error_printf("%s: Context 0x%" PRIX64 " has been deleted but is the root of a sharelist group - this scenario is not yet supported for state snapshotting.\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(glx_context));
4521 if (pVOGL_context->get_has_been_made_current())
4523 if (!GL_ENTRYPOINT(glXMakeCurrent)(pVOGL_context->get_display(), pVOGL_context->get_drawable(), glx_context))
4525 vogl_error_printf("%s: Failed switching to trace context 0x%" PRIX64 ". (This context may be current on another thread.) Capture failed!\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(glx_context));
4529 if (pVOGL_context->get_total_mapped_buffers())
4531 vogl_error_printf("%s: Trace context 0x%" PRIX64 " has %u buffer(s) mapped across a call to glXSwapBuffers(), which is not currently supported!\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(glx_context), pVOGL_context->get_total_mapped_buffers());
4535 if (pVOGL_context->is_composing_display_list())
4537 vogl_error_printf("%s: Trace context 0x%" PRIX64 " is currently composing a display list across a call to glXSwapBuffers()!\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(glx_context));
4541 if (pVOGL_context->get_in_gl_begin())
4543 vogl_error_printf("%s: Trace context 0x%" PRIX64 " is currently in a glBegin() across a call to glXSwapBuffers(), which is not supported!\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(glx_context));
4548 vogl_capture_context_params &capture_context_params = pVOGL_context->get_capture_context_params();
4550 if (!pSnapshot->capture_context(pVOGL_context->get_context_desc(), pVOGL_context->get_context_info(), pVOGL_context->get_handle_remapper(), capture_context_params))
4552 vogl_error_printf("%s: Failed capturing trace context 0x%" PRIX64 ", capture failed\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(glx_context));
4557 if ((it == contexts.end()) && (pSnapshot->end_capture()))
4559 vogl_printf("%s: Capture succeeded\n", VOGL_FUNCTION_NAME);
4563 vogl_printf("%s: Capture failed\n", VOGL_FUNCTION_NAME);
4565 vogl_delete(pSnapshot);
4571 GL_ENTRYPOINT(glXMakeContextCurrent)(orig_dpy, orig_drawable, orig_read_drawable, orig_context);
4574 vogl_check_gl_error();
4576 g_context_manager.unlock();
4581 //----------------------------------------------------------------------------------------------------------------------
4583 // Important: This could be called at signal time!
4584 //----------------------------------------------------------------------------------------------------------------------
4585 static void vogl_end_capture(bool inside_signal_handler)
4589 VOGL_NOTE_UNUSED(inside_signal_handler);
4591 vogl_debug_printf("%s\n", VOGL_FUNCTION_NAME);
4593 g_context_manager.lock();
4595 vogl_context *pVOGL_context = g_context_manager.get_current();
4599 pVOGL_context->get_framebuffer_capturer().flush();
4601 if (inside_signal_handler)
4603 vogl_thread_local_data *pTLS_data = vogl_get_thread_local_data();
4604 if ((pTLS_data) && (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID))
4606 vogl_error_printf("%s: Signal handler called while the tracer was calling OpenGL in func %s!\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName);
4608 if (g_vogl_trace_writer.is_opened())
4610 vogl_entrypoint_serializer &trace_serializer = pTLS_data->m_serializer;
4611 if (trace_serializer.is_in_begin())
4613 vogl_error_printf("%s: Attempting to flush final trace packet\n", VOGL_FUNCTION_NAME);
4615 trace_serializer.end();
4617 vogl_write_packet_to_trace(trace_serializer.get_packet());
4624 g_context_manager.unlock();
4626 scoped_mutex lock(g_vogl_trace_mutex);
4628 if (g_vogl_trace_writer.is_opened())
4630 dynamic_string filename(g_vogl_trace_writer.get_filename());
4632 vogl_flush_compilerinfo_to_trace_file();
4633 vogl_flush_machineinfo_to_trace_file();
4634 vogl_flush_backtrace_to_trace_file();
4636 if (!g_vogl_trace_writer.close())
4638 vogl_error_printf("%s: Failed closing trace file!\n", VOGL_FUNCTION_NAME);
4640 if (g_vogl_pCapture_status_callback)
4641 (*g_vogl_pCapture_status_callback)(NULL, g_vogl_pCapture_status_opaque);
4645 if (g_vogl_pCapture_status_callback)
4646 (*g_vogl_pCapture_status_callback)(filename.get_ptr(), g_vogl_pCapture_status_opaque);
4649 if (g_pJSON_node_pool)
4651 uint64_t total_bytes_freed = static_cast<uint64_t>(g_pJSON_node_pool->free_unused_blocks());
4652 vogl_debug_printf("%s: Freed %" PRIu64 " bytes from the JSON object pool (%" PRIu64 " bytes remaining)\n", VOGL_FUNCTION_NAME, total_bytes_freed, static_cast<uint64_t>(g_pJSON_node_pool->get_total_heap_bytes()));
4656 g_vogl_frames_remaining_to_capture = 0;
4658 g_vogl_pCapture_status_callback = NULL;
4659 g_vogl_pCapture_status_opaque = NULL;
4662 //----------------------------------------------------------------------------------------------------------------------
4663 static bool vogl_write_snapshot_to_trace(const char *pTrace_filename, const Display *dpy, GLXDrawable drawable, vogl_context *pVOGL_context)
4666 vogl_message_printf("%s: Snapshot begin\n", VOGL_FUNCTION_NAME);
4668 // pVOGL_context may be NULL here!
4670 vogl_unique_ptr<vogl_gl_state_snapshot> pSnapshot(vogl_snapshot_state(dpy, drawable, pVOGL_context));
4671 if (!pSnapshot.get())
4673 vogl_error_printf("%s: Failed snapshotting GL/GLX state!\n", VOGL_FUNCTION_NAME);
4680 pSnapshot->set_frame_index(0);
4682 if (!g_vogl_trace_writer.open(pTrace_filename, NULL, true, false))
4684 vogl_error_printf("%s: Failed creating trace file \"%s\"!\n", VOGL_FUNCTION_NAME, pTrace_filename);
4691 vogl_archive_blob_manager &trace_archive = *g_vogl_trace_writer.get_trace_archive();
4693 vogl_message_printf("%s: Serializing snapshot data to JSON document\n", VOGL_FUNCTION_NAME);
4695 // TODO: This can take a lot of memory, probably better off to split the snapshot into separate smaller binary json or whatever files stored directly in the archive.
4697 if (!pSnapshot->serialize(*doc.get_root(), trace_archive, &g_vogl_process_gl_ctypes))
4699 vogl_error_printf("%s: Failed serializing GL state snapshot!\n", VOGL_FUNCTION_NAME);
4708 vogl_message_printf("%s: Serializing JSON document to UBJ\n", VOGL_FUNCTION_NAME);
4710 uint8_vec binary_snapshot_data;
4711 vogl::vector<char> snapshot_data;
4713 // TODO: This can take a lot of memory
4714 doc.binary_serialize(binary_snapshot_data);
4716 vogl_message_printf("%s: Compressing UBJ data and adding to trace archive\n", VOGL_FUNCTION_NAME);
4718 dynamic_string binary_snapshot_id(trace_archive.add_buf_compute_unique_id(binary_snapshot_data.get_ptr(), binary_snapshot_data.size(), "binary_state_snapshot", VOGL_BINARY_JSON_EXTENSION));
4719 if (binary_snapshot_id.is_empty())
4721 vogl_error_printf("%s: Failed adding binary GL snapshot file to output blob manager!\n", VOGL_FUNCTION_NAME);
4728 binary_snapshot_data.clear();
4730 snapshot_data.clear();
4733 // TODO: This requires too much temp memory!
4734 doc.serialize(snapshot_data, true, 0, false);
4736 dynamic_string snapshot_id(trace_archive.add_buf_compute_unique_id(snapshot_data.get_ptr(), snapshot_data.size(), "state_snapshot", VOGL_TEXT_JSON_EXTENSION));
4737 if (snapshot_id.is_empty())
4739 vogl_error_printf("%s: Failed adding binary GL snapshot file to output blob manager!\n", VOGL_FUNCTION_NAME);
4740 g_vogl_trace_writer.deinit();
4745 key_value_map snapshot_key_value_map;
4746 snapshot_key_value_map.insert("command_type", "state_snapshot");
4747 snapshot_key_value_map.insert("binary_id", binary_snapshot_id);
4750 // TODO: This requires too much temp memory!
4751 snapshot_key_value_map.insert("id", snapshot_id);
4754 vogl_ctypes &trace_gl_ctypes = g_vogl_process_gl_ctypes;
4755 if (!vogl_write_glInternalTraceCommandRAD(g_vogl_trace_writer.get_stream(), &trace_gl_ctypes, cITCRKeyValueMap, sizeof(snapshot_key_value_map), reinterpret_cast<const GLubyte *>(&snapshot_key_value_map)))
4759 vogl_error_printf("%s: Failed writing to trace file!\n", VOGL_FUNCTION_NAME);
4763 if (!vogl_write_glInternalTraceCommandRAD(g_vogl_trace_writer.get_stream(), &trace_gl_ctypes, cITCRDemarcation, 0, NULL))
4767 vogl_error_printf("%s: Failed writing to trace file!\n", VOGL_FUNCTION_NAME);
4773 if (g_pJSON_node_pool)
4775 uint64_t total_bytes_freed = static_cast<uint64_t>(g_pJSON_node_pool->free_unused_blocks());
4776 vogl_debug_printf("%s: Freed %" PRIu64 " bytes from the JSON object pool (%" PRIu64 " bytes remaining)\n", VOGL_FUNCTION_NAME, total_bytes_freed, static_cast<uint64_t>(g_pJSON_node_pool->get_total_heap_bytes()));
4779 vogl_message_printf("%s: Snapshot complete\n", VOGL_FUNCTION_NAME);
4784 //----------------------------------------------------------------------------------------------------------------------
4785 static void vogl_capture_status_callback_func(const char *pFilename, void *pOpaque)
4788 VOGL_ASSERT(pOpaque == (void *)1);
4789 vogl_message_printf("%s: Filename \"%s\", opaque: %p\n", VOGL_FUNCTION_NAME, pFilename ? pFilename : "<null>", pOpaque);
4792 //----------------------------------------------------------------------------------------------------------------------
4793 static bool vogl_check_for_trigger_file(const char *pBase_name, dynamic_string &filename)
4795 filename = pBase_name;
4796 if (!file_utils::does_file_exist(filename.get_ptr()))
4798 dynamic_string path_to_check(g_command_line_params.get_value_as_string_or_empty("vogl_tracepath"));
4799 if (path_to_check.is_empty())
4800 path_to_check = file_utils::get_pathname(g_command_line_params.get_value_as_string_or_empty("vogl_tracefile").get_ptr());
4802 if (path_to_check.is_empty())
4805 file_utils::combine_path(filename, path_to_check.get_ptr(), pBase_name);
4806 if (!file_utils::does_file_exist(filename.get_ptr()))
4813 //----------------------------------------------------------------------------------------------------------------------
4814 static void vogl_check_for_capture_stop_file()
4816 if (!vogl_is_capturing())
4819 dynamic_string stop_filename;
4820 if (!vogl_check_for_trigger_file(VOGL_STOP_CAPTURE_FILENAME, stop_filename))
4823 file_utils::delete_file(stop_filename.get_ptr());
4825 vogl_stop_capturing();
4828 //----------------------------------------------------------------------------------------------------------------------
4829 static void vogl_check_for_capture_trigger_file()
4832 scoped_mutex lock(g_vogl_trace_mutex);
4833 if ((g_vogl_frames_remaining_to_capture) || (g_vogl_trace_writer.is_opened()))
4837 dynamic_string trigger_filename;
4838 if (!vogl_check_for_trigger_file(VOGL_TRIGGER_CAPTURE_FILENAME, trigger_filename))
4843 // Lamely try to protected against racing - a better method is probably inotify: http://www.thegeekstuff.com/2010/04/inotify-c-program-example/
4847 file_utils::get_file_size(trigger_filename.get_ptr(), size);
4852 file_utils::get_file_size(trigger_filename.get_ptr(), size1);
4860 uint total_frames = 1;
4861 dynamic_string path;
4862 dynamic_string base_name;
4864 dynamic_string_array lines;
4865 if (!file_utils::read_text_file(trigger_filename.get_ptr(), lines, file_utils::cRTFTrim | file_utils::cRTFIgnoreEmptyLines))
4867 vogl_error_printf("%s: Failed reading from trigger file \"%s\", using default parameters to trigger a capture.\n", VOGL_FUNCTION_NAME, trigger_filename.get_ptr());
4871 if (lines.size() >= 1)
4873 if (lines[0] == "all")
4874 total_frames = cUINT32_MAX;
4876 total_frames = string_to_uint(lines[0].get_ptr(), 1);
4878 if (lines.size() >= 2)
4882 if (lines.size() >= 3)
4883 base_name = lines[2];
4887 file_utils::delete_file(trigger_filename.get_ptr());
4889 bool success = vogl_capture_on_next_swap(total_frames, path.get_ptr(), base_name.get_ptr(), vogl_capture_status_callback_func, (void *)1);
4892 vogl_error_printf("%s: Failed enabling capture mode\n", VOGL_FUNCTION_NAME);
4894 vogl_message_printf("%s: Successfully enabled capture mode, will capture up to %u frame(s), override path \"%s\", override base_name \"%s\"\n", VOGL_FUNCTION_NAME, total_frames, path.get_ptr(), base_name.get_ptr());
4897 //----------------------------------------------------------------------------------------------------------------------
4898 // vogl_tick_capture
4899 //----------------------------------------------------------------------------------------------------------------------
4900 static void vogl_tick_capture(const Display *dpy, GLXDrawable drawable, vogl_context *pVOGL_context)
4904 // pVOGL_context may be NULL here!
4906 vogl_check_for_capture_stop_file();
4907 vogl_check_for_capture_trigger_file();
4909 scoped_mutex lock(g_vogl_trace_mutex);
4911 if ((g_vogl_total_frames_to_capture) && (!g_vogl_frames_remaining_to_capture))
4913 g_vogl_frames_remaining_to_capture = g_vogl_total_frames_to_capture;
4914 g_vogl_total_frames_to_capture = 0;
4917 if (g_vogl_stop_capturing)
4919 g_vogl_stop_capturing = false;
4921 if (g_vogl_trace_writer.is_opened())
4929 if (!g_vogl_frames_remaining_to_capture)
4932 if (!g_vogl_trace_writer.is_opened())
4934 dynamic_string trace_path(g_command_line_params.get_value_as_string_or_empty("vogl_tracepath"));
4935 if (trace_path.is_empty())
4936 trace_path = "/tmp";
4937 if (!g_vogl_capture_path.is_empty())
4938 trace_path = g_vogl_capture_path;
4940 time_t t = time(NULL);
4941 struct tm ltm = *localtime(&t);
4943 dynamic_string trace_basename("capture");
4944 if (!g_vogl_capture_basename.is_empty())
4945 trace_basename = g_vogl_capture_basename;
4947 dynamic_string filename(cVarArg, "%s_%04d_%02d_%02d_%02d_%02d_%02d.bin", trace_basename.get_ptr(), ltm.tm_year + 1900, ltm.tm_mon + 1, ltm.tm_mday, ltm.tm_hour, ltm.tm_min, ltm.tm_sec);
4949 dynamic_string full_trace_filename;
4950 file_utils::combine_path(full_trace_filename, trace_path.get_ptr(), filename.get_ptr());
4952 if (g_vogl_frames_remaining_to_capture == cUINT32_MAX)
4953 vogl_message_printf("%s: Initiating capture of all remaining frames to file \"%s\"\n", VOGL_FUNCTION_NAME, full_trace_filename.get_ptr());
4955 vogl_message_printf("%s: Initiating capture of up to %u frame(s) to file \"%s\"\n", VOGL_FUNCTION_NAME, g_vogl_frames_remaining_to_capture, full_trace_filename.get_ptr());
4957 if (!vogl_write_snapshot_to_trace(full_trace_filename.get_ptr(), dpy, drawable, pVOGL_context))
4959 file_utils::delete_file(full_trace_filename.get_ptr());
4960 vogl_error_printf("%s: Failed creating GL state snapshot, closing and deleting trace file\n", VOGL_FUNCTION_NAME);
4965 if (g_vogl_frames_remaining_to_capture != cUINT32_MAX)
4966 g_vogl_frames_remaining_to_capture--;
4968 // See if we should stop capturing.
4969 if (!g_vogl_frames_remaining_to_capture)
4977 //----------------------------------------------------------------------------------------------------------------------
4978 // vogl_glXSwapBuffersGLFuncProlog
4979 //----------------------------------------------------------------------------------------------------------------------
4980 static inline void vogl_glXSwapBuffersGLFuncProlog(const Display *dpy, GLXDrawable drawable, vogl_context *pVOGL_context, vogl_entrypoint_serializer &trace_serializer)
4982 // pVOGL_context may be NULL here!
4984 if (!GL_ENTRYPOINT(glXGetCurrentContext) || !GL_ENTRYPOINT(glXGetCurrentDisplay) ||
4985 !GL_ENTRYPOINT(glXGetCurrentDrawable) || !GL_ENTRYPOINT(glXGetCurrentReadDrawable))
4990 bool override_current_context = false;
4992 if ((!pVOGL_context) || ((pVOGL_context->get_display() != dpy) || (pVOGL_context->get_drawable() != drawable)))
4994 // NVidia/AMD closed source don't seem to care if a context is current when glXSwapBuffer()'s is called. But Mesa doesn't like it.
4995 vogl_warning_printf_once("%s: No context is current, or the current context's display/drawable don't match the provided display/drawable. Will try to find the first context which matches the provided params, but this may not work reliably.\n", VOGL_FUNCTION_NAME);
4997 pVOGL_context = g_context_manager.find_context(dpy, drawable);
5001 vogl_error_printf("%s: Unable to determine which GL context is associated with the indicated drawable/display! Will not be able to take a screen capture, or record context related information to the trace!\n", VOGL_FUNCTION_NAME);
5004 else if (pVOGL_context->get_current_thread() != 0)
5006 vogl_error_printf("%s: The GL context which matches the provided display/drawable is already current on another thread!\n", VOGL_FUNCTION_NAME);
5010 override_current_context = true;
5013 GLXContext orig_context = 0;
5014 const Display *orig_dpy = NULL;
5015 GLXDrawable orig_drawable = 0;
5016 GLXDrawable orig_read_drawable = 0;
5017 if (override_current_context)
5019 orig_context = GL_ENTRYPOINT(glXGetCurrentContext)();
5020 orig_dpy = GL_ENTRYPOINT(glXGetCurrentDisplay)();
5021 orig_drawable = GL_ENTRYPOINT(glXGetCurrentDrawable)();
5022 orig_read_drawable = GL_ENTRYPOINT(glXGetCurrentReadDrawable)();
5027 GL_ENTRYPOINT(glXMakeCurrent)(pVOGL_context->get_display(), pVOGL_context->get_drawable(), pVOGL_context->get_context_handle());
5032 unsigned int width = 0, height = 0, border_width = 0, depth = 0;
5033 if ((dpy) && (XGetGeometry(const_cast<Display *>(dpy), drawable, &root, &x, &y, &width, &height, &border_width, &depth) != False))
5035 pVOGL_context->set_window_dimensions(width, height);
5037 vogl_tick_screen_capture(pVOGL_context);
5041 console::warning("%s: XGetGeometry() call failed!\n", VOGL_FUNCTION_NAME);
5044 if (trace_serializer.is_in_begin())
5046 trace_serializer.add_key_value(string_hash("win_width"), pVOGL_context->get_window_width());
5047 trace_serializer.add_key_value(string_hash("win_height"), pVOGL_context->get_window_height());
5050 if (g_dump_gl_calls_flag)
5052 vogl_log_printf("** Current window dimensions: %ix%i\n", pVOGL_context->get_window_width(), pVOGL_context->get_window_height());
5055 pVOGL_context->inc_frame_index();
5057 if ((override_current_context) && (orig_dpy))
5059 GL_ENTRYPOINT(glXMakeContextCurrent)(orig_dpy, orig_drawable, orig_read_drawable, orig_context);
5063 //----------------------------------------------------------------------------------------------------------------------
5064 #define DEF_FUNCTION_CUSTOM_HANDLER_glXSwapBuffers(exported, category, ret, ret_type_enum, num_params, name, args, params)
5065 static void vogl_glXSwapBuffers(const Display *dpy, GLXDrawable drawable)
5067 uint64_t begin_rdtsc = utils::RDTSC();
5069 if (g_dump_gl_calls_flag)
5071 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5074 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXSwapBuffers);
5075 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
5077 vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName);
5078 return GL_ENTRYPOINT(glXSwapBuffers)(dpy, drawable);
5081 // Use a local serializer because the call to glXSwapBuffer()'s will make GL calls if something like the Steam Overlay is active.
5082 vogl_entrypoint_serializer serializer;
5084 if (g_vogl_trace_writer.is_opened())
5086 serializer.begin(VOGL_ENTRYPOINT_glXSwapBuffers, g_context_manager.get_current());
5087 serializer.add_param(0, VOGL_CONST_DISPLAY_PTR, &dpy, sizeof(dpy));
5088 serializer.add_param(1, VOGL_GLXDRAWABLE, &drawable, sizeof(drawable));
5091 vogl_glXSwapBuffersGLFuncProlog(dpy, drawable, pTLS_data->m_pContext, serializer);
5093 uint64_t gl_begin_rdtsc = utils::RDTSC();
5095 // Call the driver directly, bypassing our GL/GLX wrappers which set m_calling_driver_entrypoint_id. The Steam Overlay may call us back!
5096 DIRECT_GL_ENTRYPOINT(glXSwapBuffers)(dpy, drawable);
5098 uint64_t gl_end_rdtsc = utils::RDTSC();
5100 if (g_vogl_trace_writer.is_opened())
5102 serializer.set_begin_rdtsc(begin_rdtsc);
5103 serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
5105 vogl_write_packet_to_trace(serializer.get_packet());
5108 vogl_tick_capture(dpy, drawable, pTLS_data->m_pContext);
5110 if (g_dump_gl_calls_flag)
5112 vogl_log_printf("** glXSwapBuffers TID: 0x%" PRIX64 " Display: 0x%" PRIX64 " drawable: 0x%" PRIX64 "\n", vogl_get_current_kernel_thread_id(), cast_val_to_uint64(dpy), cast_val_to_uint64(drawable));
5115 if (g_dump_gl_calls_flag)
5117 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5120 if (g_command_line_params.has_key("vogl_exit_after_x_frames") && (pTLS_data->m_pContext))
5122 uint64_t max_num_frames = g_command_line_params.get_value_as_uint64("vogl_exit_after_x_frames");
5123 uint64_t cur_num_frames = pTLS_data->m_pContext->get_frame_index();
5125 if (cur_num_frames >= max_num_frames)
5127 vogl_message_printf("Number of frames specified by --vogl_exit_after_x_frames param reached, forcing trace to close and calling exit()\n");
5137 //----------------------------------------------------------------------------------------------------------------------
5138 #define DEF_FUNCTION_CUSTOM_HANDLER_glXCreateContextAttribsARB(exported, category, ret, ret_type_enum, num_params, name, args, params)
5139 static GLXContext vogl_glXCreateContextAttribsARB(const Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list)
5141 uint64_t begin_rdtsc = utils::RDTSC();
5143 if (g_dump_gl_calls_flag)
5145 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5148 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXCreateContextAttribsARB);
5149 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
5151 vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName);
5152 return GL_ENTRYPOINT(glXCreateContextAttribsARB)(dpy, config, share_context, direct, attrib_list);
5155 vogl_context_attribs context_attribs;
5157 if (g_command_line_params.get_value_as_bool("vogl_force_debug_context"))
5159 vogl_warning_printf("%s: Forcing debug context\n", VOGL_FUNCTION_NAME);
5161 context_attribs.init(attrib_list);
5162 if (!context_attribs.has_key(GLX_CONTEXT_FLAGS_ARB))
5163 context_attribs.add_key(GLX_CONTEXT_FLAGS_ARB, 0);
5165 int context_flags_value_ofs = context_attribs.find_value_ofs(GLX_CONTEXT_FLAGS_ARB);
5166 VOGL_ASSERT(context_flags_value_ofs >= 0);
5167 if (context_flags_value_ofs >= 0)
5168 context_attribs[context_flags_value_ofs] |= GLX_CONTEXT_DEBUG_BIT_ARB;
5170 int context_major_version_ofs = context_attribs.find_value_ofs(GLX_CONTEXT_MAJOR_VERSION_ARB);
5171 int context_minor_version_ofs = context_attribs.find_value_ofs(GLX_CONTEXT_MINOR_VERSION_ARB);
5173 if (context_major_version_ofs < 0)
5175 // Don't slam up if they haven't requested a specific GL version, the driver will give us the most recent version that is backwards compatible with 1.0 (i.e. 4.3 for NVidia's current dirver).
5177 else if (context_attribs[context_major_version_ofs] < 3)
5179 context_attribs[context_major_version_ofs] = 3;
5181 if (context_minor_version_ofs < 0)
5182 context_attribs.add_key(GLX_CONTEXT_MINOR_VERSION_ARB, 0);
5184 context_attribs[context_minor_version_ofs] = 0;
5186 vogl_warning_printf("%s: Forcing GL context version up to v3.0 due to debug context usage\n", VOGL_FUNCTION_NAME);
5189 attrib_list = context_attribs.get_vec().get_ptr();
5192 uint64_t gl_begin_rdtsc = utils::RDTSC();
5193 GLXContext result = GL_ENTRYPOINT(glXCreateContextAttribsARB)(dpy, config, share_context, direct, attrib_list);
5194 uint64_t gl_end_rdtsc = utils::RDTSC();
5196 if (g_dump_gl_calls_flag)
5198 vogl_log_printf("** glXCreateContextAttribsARB TID: 0x%" PRIX64 " Display: 0x%" PRIX64 " config: 0x%" PRIX64 " share_context: 0x%" PRIX64 " direct %i attrib_list: 0x%" PRIX64 ", result: 0x%" PRIX64 "\n", vogl_get_current_kernel_thread_id(), cast_val_to_uint64(dpy), cast_val_to_uint64(config), cast_val_to_uint64(share_context), (int)direct, cast_val_to_uint64(attrib_list), cast_val_to_uint64(result));
5201 if (g_vogl_trace_writer.is_opened())
5203 vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glXCreateContextAttribsARB, g_context_manager.get_current());
5204 serializer.set_begin_rdtsc(begin_rdtsc);
5205 serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
5206 serializer.add_param(0, VOGL_CONST_DISPLAY_PTR, &dpy, sizeof(dpy));
5207 serializer.add_param(1, VOGL_GLXFBCONFIG, &config, sizeof(config));
5208 serializer.add_param(2, VOGL_GLXCONTEXT, &share_context, sizeof(share_context));
5209 serializer.add_param(3, VOGL_BOOL, &direct, sizeof(direct));
5210 serializer.add_param(4, VOGL_CONST_INT_PTR, &attrib_list, sizeof(attrib_list));
5213 uint n = vogl_determine_attrib_list_array_size(attrib_list);
5214 serializer.add_array_client_memory(4, VOGL_INT, n, attrib_list, sizeof(int) * n);
5216 serializer.add_return_param(VOGL_GLXCONTEXT, &result, sizeof(result));
5218 vogl_write_packet_to_trace(serializer.get_packet());
5225 if (!g_app_uses_sharelists)
5226 vogl_message_printf("%s: sharelist usage detected\n", VOGL_FUNCTION_NAME);
5228 g_app_uses_sharelists = true;
5231 g_context_manager.lock();
5233 vogl_context *pVOGL_context = g_context_manager.create_context(result);
5234 pVOGL_context->set_display(dpy);
5235 pVOGL_context->set_fb_config(config);
5236 pVOGL_context->set_sharelist_handle(share_context);
5237 pVOGL_context->set_direct(direct);
5238 pVOGL_context->set_attrib_list(attrib_list);
5239 pVOGL_context->set_created_from_attribs(true);
5240 pVOGL_context->set_creation_func(VOGL_ENTRYPOINT_glXCreateContextAttribsARB);
5244 vogl_context *pShare_context = g_context_manager.lookup_vogl_context(share_context);
5246 if (!pShare_context)
5247 vogl_error_printf("%s: Failed finding share context 0x%" PRIx64 " in context manager's hashmap! This handle is probably invalid.\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(share_context));
5250 while (!pShare_context->is_root_context())
5251 pShare_context = pShare_context->get_shared_state();
5253 pVOGL_context->set_shared_context(pShare_context);
5255 pShare_context->add_ref();
5259 pVOGL_context->init();
5261 g_context_manager.unlock();
5264 if (g_dump_gl_calls_flag)
5266 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5272 //----------------------------------------------------------------------------------------------------------------------
5273 // vogl_get_fb_config_from_xvisual_info
5274 // Attempts to find the GLXFBConfig corresponding to a particular visual.
5275 // TODO: Test this more!
5276 //----------------------------------------------------------------------------------------------------------------------
5277 static GLXFBConfig *vogl_get_fb_config_from_xvisual_info(const Display *dpy, const XVisualInfo *vis)
5279 vogl_context_attribs attribs;
5281 #define GET_CONFIG(attrib) \
5285 GL_ENTRYPOINT(glXGetConfig)(dpy, vis, attrib, &val); \
5287 attribs.add_key(attrib, val); \
5291 GL_ENTRYPOINT(glXGetConfig)(dpy, vis, GLX_RGBA, &is_rgba);
5293 attribs.add_key(GLX_RENDER_TYPE, is_rgba ? GLX_RGBA_BIT : GLX_COLOR_INDEX_BIT);
5294 attribs.add_key(GLX_X_RENDERABLE, True);
5295 attribs.add_key(GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT);
5298 GET_CONFIG(GLX_BUFFER_SIZE);
5300 GET_CONFIG(GLX_LEVEL);
5302 GET_CONFIG(GLX_DOUBLEBUFFER);
5303 GET_CONFIG(GLX_STEREO);
5304 GET_CONFIG(GLX_AUX_BUFFERS);
5307 GET_CONFIG(GLX_RED_SIZE);
5308 GET_CONFIG(GLX_GREEN_SIZE);
5309 GET_CONFIG(GLX_BLUE_SIZE);
5310 GET_CONFIG(GLX_ALPHA_SIZE);
5312 GET_CONFIG(GLX_DEPTH_SIZE);
5313 GET_CONFIG(GLX_STENCIL_SIZE);
5315 GET_CONFIG(GLX_TRANSPARENT_INDEX_VALUE);
5316 GET_CONFIG(GLX_TRANSPARENT_RED_VALUE);
5317 GET_CONFIG(GLX_TRANSPARENT_GREEN_VALUE);
5318 GET_CONFIG(GLX_TRANSPARENT_BLUE_VALUE);
5319 GET_CONFIG(GLX_TRANSPARENT_ALPHA_VALUE);
5321 if (attribs.get_value_or_default(GLX_TRANSPARENT_INDEX_VALUE) || attribs.get_value_or_default(GLX_TRANSPARENT_RED_VALUE) ||
5322 attribs.get_value_or_default(GLX_TRANSPARENT_GREEN_VALUE) || attribs.get_value_or_default(GLX_TRANSPARENT_BLUE_VALUE) ||
5323 attribs.get_value_or_default(GLX_TRANSPARENT_ALPHA_VALUE))
5325 GET_CONFIG(GLX_TRANSPARENT_TYPE);
5330 for (uint i = 0; i < attribs.size(); i += 2)
5334 printf("%s 0x%x\n", g_gl_enums.find_glx_name(attribs[i]), attribs[i + 1]);
5338 int num_configs = 0;
5339 GLXFBConfig *pConfigs = GL_ENTRYPOINT(glXChooseFBConfig)(dpy, vis->screen, attribs.get_ptr(), &num_configs);
5340 return num_configs ? pConfigs : NULL;
5343 //----------------------------------------------------------------------------------------------------------------------
5344 #define DEF_FUNCTION_CUSTOM_HANDLER_glXCreateContext(exported, category, ret, ret_type_enum, num_params, name, args, params)
5345 static GLXContext vogl_glXCreateContext(const Display *dpy, const XVisualInfo *vis, GLXContext shareList, Bool direct)
5347 uint64_t begin_rdtsc = utils::RDTSC();
5349 if (g_dump_gl_calls_flag)
5351 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5354 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXCreateContext);
5355 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
5357 vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName);
5358 return GL_ENTRYPOINT(glXCreateContext)(dpy, vis, shareList, direct);
5361 if (g_command_line_params.get_value_as_bool("vogl_force_debug_context"))
5363 vogl_warning_printf("%s: Can't enable debug contexts via glXCreateContext(), forcing call to use glXCreateContextsAttribsARB() instead\n", VOGL_FUNCTION_NAME);
5365 GLXFBConfig *pConfig = vogl_get_fb_config_from_xvisual_info(dpy, vis);
5368 vogl_error_printf("%s: Can't enable debug contexts: Unable to find the FB config that matches the passed in XVisualInfo!\n", VOGL_FUNCTION_NAME);
5372 int empty_attrib_list[1] = { 0 };
5373 return vogl_glXCreateContextAttribsARB(dpy, pConfig[0], shareList, direct, empty_attrib_list);
5377 uint64_t gl_begin_rdtsc = utils::RDTSC();
5378 GLXContext result = GL_ENTRYPOINT(glXCreateContext)(dpy, vis, shareList, direct);
5379 uint64_t gl_end_rdtsc = utils::RDTSC();
5381 if (g_dump_gl_calls_flag)
5383 vogl_log_printf("** glXCreateContext TID: 0x%" PRIX64 " dpy: 0x%" PRIX64 " vis: 0x%" PRIX64 " shareList: 0x%" PRIX64 " direct %i, result: 0x%" PRIX64 "\n", vogl_get_current_kernel_thread_id(), cast_val_to_uint64(dpy), cast_val_to_uint64(vis), cast_val_to_uint64(shareList), (int)direct, cast_val_to_uint64(result));
5386 if (g_vogl_trace_writer.is_opened())
5388 vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glXCreateContext, g_context_manager.get_current());
5389 serializer.set_begin_rdtsc(begin_rdtsc);
5390 serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
5391 serializer.add_param(0, VOGL_CONST_DISPLAY_PTR, &dpy, sizeof(dpy));
5392 serializer.add_param(1, VOGL_CONST_XVISUALINFO_PTR, &vis, sizeof(vis));
5393 serializer.add_param(2, VOGL_GLXCONTEXT, &shareList, sizeof(shareList));
5394 serializer.add_param(3, VOGL_BOOL, &direct, sizeof(direct));
5395 serializer.add_return_param(VOGL_GLXCONTEXT, &result, sizeof(result));
5397 serializer.add_ref_client_memory(1, VOGL_XVISUALINFO, vis, sizeof(XVisualInfo));
5399 vogl_write_packet_to_trace(serializer.get_packet());
5406 if (!g_app_uses_sharelists)
5407 vogl_message_printf("%s: sharelist usage detected\n", VOGL_FUNCTION_NAME);
5409 g_app_uses_sharelists = true;
5412 g_context_manager.lock();
5414 vogl_context *pVOGL_context = g_context_manager.create_context(result);
5415 pVOGL_context->set_display(dpy);
5416 pVOGL_context->set_xvisual_info(vis);
5417 pVOGL_context->set_sharelist_handle(shareList);
5418 pVOGL_context->set_direct(direct);
5419 pVOGL_context->set_creation_func(VOGL_ENTRYPOINT_glXCreateContext);
5423 vogl_context *pShare_context = g_context_manager.lookup_vogl_context(shareList);
5425 if (!pShare_context)
5426 vogl_error_printf("%s: Failed finding share context 0x%" PRIx64 " in context manager's hashmap! This handle is probably invalid.\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(shareList));
5429 while (!pShare_context->is_root_context())
5430 pShare_context = pShare_context->get_shared_state();
5432 pVOGL_context->set_shared_context(pShare_context);
5434 pShare_context->add_ref();
5438 pVOGL_context->init();
5440 g_context_manager.unlock();
5443 if (g_dump_gl_calls_flag)
5445 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5451 //----------------------------------------------------------------------------------------------------------------------
5452 #define DEF_FUNCTION_CUSTOM_HANDLER_glXCreateNewContext(exported, category, ret, ret_type_enum, num_params, name, args, params)
5453 static GLXContext vogl_glXCreateNewContext(const Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct)
5455 if (render_type != GLX_RGBA_TYPE)
5457 vogl_error_printf("%s: Unsupported render type (%s)!\n", VOGL_FUNCTION_NAME, g_gl_enums.find_glx_name(render_type));
5460 if (g_command_line_params.get_value_as_bool("vogl_force_debug_context"))
5462 vogl_warning_printf("%s: Redirecting call from glxCreateNewContext() to glxCreateContextAttribsARB because --vogl_force_debug_context was specified. Note this may fail if glXCreateWindow() was called.\n", VOGL_FUNCTION_NAME);
5464 return vogl_glXCreateContextAttribsARB(dpy, config, share_list, direct, NULL);
5467 uint64_t begin_rdtsc = utils::RDTSC();
5469 if (g_dump_gl_calls_flag)
5471 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5474 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXCreateNewContext);
5475 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
5477 vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName);
5478 return GL_ENTRYPOINT(glXCreateNewContext)(dpy, config, render_type, share_list, direct);
5481 uint64_t gl_begin_rdtsc = utils::RDTSC();
5482 GLXContext result = GL_ENTRYPOINT(glXCreateNewContext)(dpy, config, render_type, share_list, direct);
5483 uint64_t gl_end_rdtsc = utils::RDTSC();
5485 if (g_dump_gl_calls_flag)
5487 vogl_log_printf("** glXCreateNewContext TID: 0x%" PRIX64 " dpy: 0x%" PRIX64 " config: 0x%" PRIX64 " render_type: %i shareList: 0x%" PRIX64 " direct %i, result: 0x%" PRIX64 "\n",
5488 vogl_get_current_kernel_thread_id(), cast_val_to_uint64(dpy), cast_val_to_uint64(config), render_type, cast_val_to_uint64(share_list), static_cast<int>(direct), cast_val_to_uint64(result));
5491 if (g_vogl_trace_writer.is_opened())
5493 vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glXCreateNewContext, g_context_manager.get_current());
5494 serializer.set_begin_rdtsc(begin_rdtsc);
5495 serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
5496 serializer.add_param(0, VOGL_CONST_DISPLAY_PTR, &dpy, sizeof(dpy));
5497 serializer.add_param(1, VOGL_GLXFBCONFIG, &config, sizeof(config));
5498 serializer.add_param(2, VOGL_INT, &render_type, sizeof(render_type));
5499 serializer.add_param(3, VOGL_GLXCONTEXT, &share_list, sizeof(share_list));
5500 serializer.add_param(4, VOGL_BOOL, &direct, sizeof(direct));
5501 serializer.add_return_param(VOGL_GLXCONTEXT, &result, sizeof(result));
5503 vogl_write_packet_to_trace(serializer.get_packet());
5510 if (!g_app_uses_sharelists)
5511 vogl_message_printf("%s: sharelist usage detected\n", VOGL_FUNCTION_NAME);
5513 g_app_uses_sharelists = true;
5516 g_context_manager.lock();
5518 vogl_context *pVOGL_context = g_context_manager.create_context(result);
5519 pVOGL_context->set_display(dpy);
5520 pVOGL_context->set_fb_config(config);
5521 pVOGL_context->set_sharelist_handle(share_list);
5522 pVOGL_context->set_direct(direct);
5523 pVOGL_context->set_creation_func(VOGL_ENTRYPOINT_glXCreateNewContext);
5527 vogl_context *pShare_context = g_context_manager.lookup_vogl_context(share_list);
5529 if (!pShare_context)
5530 vogl_error_printf("%s: Failed finding share context 0x%" PRIx64 " in context manager's hashmap! This handle is probably invalid.\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(share_list));
5533 while (!pShare_context->is_root_context())
5534 pShare_context = pShare_context->get_shared_state();
5536 pVOGL_context->set_shared_context(pShare_context);
5538 pShare_context->add_ref();
5542 pVOGL_context->init();
5544 g_context_manager.unlock();
5547 if (g_dump_gl_calls_flag)
5549 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5555 //----------------------------------------------------------------------------------------------------------------------
5556 #define DEF_FUNCTION_CUSTOM_HANDLER_glXDestroyContext(exported, category, ret, ret_type_enum, num_params, name, args, params)
5557 static void vogl_glXDestroyContext(const Display *dpy, GLXContext context)
5559 uint64_t begin_rdtsc = utils::RDTSC();
5561 if (g_dump_gl_calls_flag)
5563 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5566 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXDestroyContext);
5567 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
5569 vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName);
5570 return GL_ENTRYPOINT(glXDestroyContext)(dpy, context);
5573 if (g_dump_gl_calls_flag)
5575 vogl_log_printf("** glXDestroyContext TID: 0x%" PRIX64 " Display: 0x%" PRIX64 " context: 0x%" PRIX64 "\n", vogl_get_current_kernel_thread_id(), cast_val_to_uint64(dpy), cast_val_to_uint64(context));
5578 vogl_context *pContext = context ? g_context_manager.lookup_vogl_context(context) : NULL;
5580 vogl_error_printf("%s: glXDestroyContext() called on an unknown context handle 0x%" PRIX64 "!\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(context));
5581 else if (pContext->get_current_thread())
5582 vogl_error_printf("%s: glXDestroyContext() called on a handle 0x%" PRIX64 " that is still current on thread 0x%" PRIX64 "! This may cause the asynchronous framebuffer capturing system to miss frames!\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(context), pContext->get_current_thread());
5586 pContext->on_destroy_prolog();
5589 uint64_t gl_begin_rdtsc = utils::RDTSC();
5590 GL_ENTRYPOINT(glXDestroyContext)(dpy, context);
5591 uint64_t gl_end_rdtsc = utils::RDTSC();
5593 if (g_vogl_trace_writer.is_opened())
5595 vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glXDestroyContext, g_context_manager.get_current());
5596 serializer.set_begin_rdtsc(begin_rdtsc);
5597 serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
5598 serializer.add_param(0, VOGL_CONST_DISPLAY_PTR, &dpy, sizeof(dpy));
5599 serializer.add_param(1, VOGL_GLXCONTEXT, &context, sizeof(context));
5601 vogl_write_packet_to_trace(serializer.get_packet());
5602 g_vogl_trace_writer.flush();
5607 g_context_manager.lock();
5609 VOGL_ASSERT(!pContext->get_deleted_flag());
5610 if (!pContext->get_deleted_flag())
5612 pContext->set_deleted_flag(true);
5614 if (pContext->is_share_context())
5616 VOGL_ASSERT(pContext->get_ref_count() == 1);
5619 int new_ref_count = pContext->del_ref();
5620 if (new_ref_count <= 0)
5622 if (pContext->is_share_context())
5624 vogl_context *pRoot_context = pContext->get_shared_state();
5626 pContext->set_shared_context(NULL);
5628 if (pRoot_context->del_ref() == 0)
5630 VOGL_ASSERT(pRoot_context->get_deleted_flag());
5632 bool status = g_context_manager.destroy_context(pRoot_context->get_context_handle());
5633 VOGL_ASSERT(status);
5634 VOGL_NOTE_UNUSED(status);
5638 bool status = g_context_manager.destroy_context(context);
5639 VOGL_ASSERT(status);
5640 VOGL_NOTE_UNUSED(status);
5644 g_context_manager.unlock();
5647 if (g_vogl_pLog_stream)
5649 // TODO: Ensure this is actually thread safe (does the gcc C runtime mutex this?)
5650 g_vogl_pLog_stream->flush();
5653 if (g_dump_gl_calls_flag)
5655 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5659 //----------------------------------------------------------------------------------------------------------------------
5660 #define DEF_FUNCTION_CUSTOM_HANDLER_glGetError(exported, category, ret, ret_type_enum, num_params, name, args, params)
5661 static GLenum vogl_glGetError()
5663 uint64_t begin_rdtsc = utils::RDTSC();
5665 if (g_dump_gl_calls_flag)
5667 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5670 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glGetError);
5671 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
5673 vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName);
5674 return GL_ENTRYPOINT(glGetError)();
5677 if (g_dump_gl_calls_flag)
5679 vogl_log_printf("** glGetError TID: 0x%" PRIX64 "\n", vogl_get_current_kernel_thread_id());
5682 vogl_context *pContext = pTLS_data->m_pContext;
5683 // pContext may be NULL here if the user has called glGetError() incorrectly, we've already printed the error message, but we're still going to call the driver (which will probably just immediately return).
5684 // Also, even if we have a latched error for this context, we MUST call glGetError() to guarantee there are no current errors on the context (to preserve the original behavior if the tracer wasn't present).
5686 uint64_t gl_begin_rdtsc = utils::RDTSC();
5687 GLenum gl_err = GL_ENTRYPOINT(glGetError)();
5688 uint64_t gl_end_rdtsc = utils::RDTSC();
5690 if (g_vogl_trace_writer.is_opened())
5692 vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glGetError, g_context_manager.get_current());
5693 serializer.set_begin_rdtsc(begin_rdtsc);
5694 serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
5695 serializer.add_return_param(VOGL_GLENUM, &gl_err, sizeof(gl_err));
5697 if ((pContext) && (pContext->has_latched_gl_error()))
5699 // Record the latched error too, so the replayer knows what's going on.
5700 serializer.add_key_value("latched_gl_error", pContext->get_latched_gl_error());
5704 vogl_write_packet_to_trace(serializer.get_packet());
5705 g_vogl_trace_writer.flush();
5708 // See if our context's shadow has a latched GL error recorded by the tracer in an earlier call. If so, it must override this GL error.
5709 if (pContext && pContext->has_latched_gl_error())
5711 if (gl_err != GL_NO_ERROR)
5713 vogl_warning_printf("%s: glGetError() called with a GL error latched on the context by the tracer. Current error is 0x%04X, latched error is 0x%04X. Note the queued error will suppress the current error.\n", VOGL_FUNCTION_NAME, gl_err, pContext->get_latched_gl_error());
5716 // We're going to replace the current GL error with our previously latched error, which *would have* masked this error if the tracer wasn't present.
5717 gl_err = pContext->get_latched_gl_error();
5719 pContext->clear_latched_gl_error();
5722 if (g_dump_gl_calls_flag)
5724 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5730 //----------------------------------------------------------------------------------------------------------------------
5731 // shader source code
5732 //----------------------------------------------------------------------------------------------------------------------
5733 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glShaderSourceARB(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_serialize_shader_source(trace_serializer, count, string, length);
5734 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glShaderSource(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_serialize_shader_source(trace_serializer, count, (const GLcharARB *const *)string, length);
5735 static void vogl_serialize_shader_source(vogl_entrypoint_serializer &trace_serializer, GLsizei count, const GLcharARB *const *string, const GLint *length)
5737 if (g_dump_gl_shaders_flag)
5739 vogl_log_printf("Source source code, %i string(s):\n", count);
5740 for (GLsizei i = 0; i < count; i++)
5742 const char *pStr = (const char *)string[i];
5745 str_len = length[i];
5747 str_len = pStr ? (vogl_strlen(pStr) + 1) : 0;
5749 vogl_log_printf("\"");
5750 vogl_print_string(pStr, str_len);
5751 vogl_log_printf("\"\n");
5755 if (trace_serializer.is_in_begin())
5757 for (GLsizei i = 0; i < count; i++)
5759 const char *pStr = (const char *)string[i];
5762 str_len = length[i];
5764 str_len = pStr ? (vogl_strlen(pStr) + 1) : 0;
5766 if ((str_len) && (pStr))
5767 trace_serializer.add_key_value_blob(i, pStr, str_len);
5772 //----------------------------------------------------------------------------------------------------------------------
5773 // vogl_uses_client_side_arrays
5774 //----------------------------------------------------------------------------------------------------------------------
5775 static bool vogl_uses_client_side_arrays(vogl_context *pContext, bool indexed)
5777 if ((!pContext) || (!pContext->get_uses_client_side_arrays()) || (pContext->is_core_profile()))
5780 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
5781 VOGL_NOTE_UNUSED(gl_error_absorber);
5785 GLuint element_array_buffer = vogl_get_bound_gl_buffer(GL_ELEMENT_ARRAY_BUFFER);
5786 if (!element_array_buffer)
5790 bool used_old_style_gl_client_side_arrays = false;
5792 GLint prev_client_active_texture = 0;
5793 GL_ENTRYPOINT(glGetIntegerv)(GL_CLIENT_ACTIVE_TEXTURE, &prev_client_active_texture);
5795 const uint tex_coords = pContext->get_max_texture_coords();
5797 for (uint i = 0; i < VOGL_NUM_CLIENT_SIDE_ARRAY_DESCS; i++)
5799 const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[i];
5800 if (i == vogl_texcoord_pointer_array_id)
5802 for (uint tex_index = 0; tex_index < tex_coords; tex_index++)
5804 GL_ENTRYPOINT(glClientActiveTexture)(GL_TEXTURE0 + tex_index);
5806 GLboolean is_enabled = GL_ENTRYPOINT(glIsEnabled)(desc.m_is_enabled);
5811 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_binding, &binding);
5815 used_old_style_gl_client_side_arrays = true;
5819 if (used_old_style_gl_client_side_arrays)
5824 GLboolean is_enabled = GL_ENTRYPOINT(glIsEnabled)(desc.m_is_enabled);
5829 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_binding, &binding);
5833 used_old_style_gl_client_side_arrays = true;
5838 GL_ENTRYPOINT(glClientActiveTexture)(prev_client_active_texture);
5840 if (used_old_style_gl_client_side_arrays)
5843 uint64_t vertex_attrib_client_side_arrays = 0;
5844 VOGL_ASSUME(VOGL_MAX_SUPPORTED_GL_VERTEX_ATTRIBUTES <= sizeof(vertex_attrib_client_side_arrays) * 8);
5846 for (uint i = 0; i < pContext->get_max_vertex_attribs(); i++)
5848 GLint is_enabled = 0;
5849 GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &is_enabled);
5854 GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &cur_buf);
5864 //----------------------------------------------------------------------------------------------------------------------
5865 // vogl_serialize_client_side_arrays_helper
5866 //----------------------------------------------------------------------------------------------------------------------
5867 static void vogl_serialize_client_side_arrays_helper(
5868 vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, const char *pFunc,
5869 GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex, bool start_end_valid, bool indexed)
5871 VOGL_NOTE_UNUSED(mode);
5873 VOGL_NOTE_UNUSED(pFunc);
5875 if ((!pContext) || (pContext->is_core_profile()))
5880 vogl_error_printf("%s: end (%i) must be >= start (%i)\n", VOGL_FUNCTION_NAME, end, start);
5884 uint index_size = vogl_get_gl_type_size(type);
5887 vogl_error_printf("%s: Invalid type parameter 0x%08X\n", VOGL_FUNCTION_NAME, type);
5891 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
5892 VOGL_NOTE_UNUSED(gl_error_absorber);
5894 GLuint element_array_buffer = 0;
5897 element_array_buffer = vogl_get_bound_gl_buffer(GL_ELEMENT_ARRAY_BUFFER);
5898 if (!element_array_buffer)
5902 vogl_error_printf("%s: No bound element array buffer, and indices parameter is NULL\n", VOGL_FUNCTION_NAME);
5907 if (g_dump_gl_buffers_flag)
5909 vogl_log_printf("Client side index data: ");
5910 vogl_print_hex(indices, count * index_size, index_size);
5911 vogl_log_printf("\n");
5914 if (trace_serializer.is_in_begin())
5916 trace_serializer.add_key_value_blob(string_hash("indices"), indices, count * index_size);
5922 const gl_entrypoint_id_t cur_entrypoint = trace_serializer.get_cur_entrypoint();
5923 VOGL_NOTE_UNUSED(cur_entrypoint);
5925 // TODO: Have the glSet*Pointer()'s funcs set a flag when the client uses this old shit, so we can avoid checking for it on apps that don't.
5927 bool used_old_style_gl_client_side_arrays = false;
5929 GLint prev_client_active_texture = 0;
5930 GL_ENTRYPOINT(glGetIntegerv)(GL_CLIENT_ACTIVE_TEXTURE, &prev_client_active_texture);
5932 const uint tex_coords = pContext->get_max_texture_coords();
5934 for (uint i = 0; i < VOGL_NUM_CLIENT_SIDE_ARRAY_DESCS; i++)
5936 const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[i];
5937 if (i == vogl_texcoord_pointer_array_id)
5939 for (uint tex_index = 0; tex_index < tex_coords; tex_index++)
5941 GL_ENTRYPOINT(glClientActiveTexture)(GL_TEXTURE0 + tex_index);
5943 GLboolean is_enabled = GL_ENTRYPOINT(glIsEnabled)(desc.m_is_enabled);
5948 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_binding, &binding);
5952 used_old_style_gl_client_side_arrays = true;
5956 if (used_old_style_gl_client_side_arrays)
5961 GLboolean is_enabled = GL_ENTRYPOINT(glIsEnabled)(desc.m_is_enabled);
5966 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_binding, &binding);
5970 used_old_style_gl_client_side_arrays = true;
5975 GL_ENTRYPOINT(glClientActiveTexture)(prev_client_active_texture);
5977 uint64_t vertex_attrib_client_side_arrays = 0;
5978 VOGL_ASSUME(VOGL_MAX_SUPPORTED_GL_VERTEX_ATTRIBUTES <= sizeof(vertex_attrib_client_side_arrays) * 8);
5980 for (uint i = 0; i < pContext->get_max_vertex_attribs(); i++)
5982 GLint is_enabled = 0;
5983 GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &is_enabled);
5988 GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &cur_buf);
5992 vertex_attrib_client_side_arrays |= (1ULL << i);
5995 if ((!used_old_style_gl_client_side_arrays) && (!vertex_attrib_client_side_arrays))
6000 if (!start_end_valid)
6002 uint total_index_data_size = count * index_size;
6004 // FIXME: Move index_data array to context state
6005 vogl::vector<uint8> index_data;
6006 const uint8 *pIndices_to_scan = static_cast<const uint8 *>(indices);
6008 if (element_array_buffer)
6010 index_data.resize(total_index_data_size);
6011 pIndices_to_scan = index_data.get_ptr();
6013 GL_ENTRYPOINT(glGetBufferSubData)(GL_ELEMENT_ARRAY_BUFFER, (GLintptr)indices, total_index_data_size, index_data.get_ptr());
6016 start = cUINT32_MAX;
6019 for (int i = 0; i < count; i++)
6023 if (type == GL_UNSIGNED_BYTE)
6024 v = pIndices_to_scan[i];
6025 else if (type == GL_UNSIGNED_SHORT)
6026 v = reinterpret_cast<const uint16 *>(pIndices_to_scan)[i];
6027 else if (type == GL_UNSIGNED_INT)
6028 v = reinterpret_cast<const uint32 *>(pIndices_to_scan)[i];
6034 start = math::minimum(start, v);
6035 end = math::maximum(end, v);
6039 if (trace_serializer.is_in_begin())
6041 trace_serializer.add_key_value(string_hash("start"), start);
6042 trace_serializer.add_key_value(string_hash("end"), end);
6046 if (used_old_style_gl_client_side_arrays)
6048 for (uint client_array_iter = 0; client_array_iter < VOGL_NUM_CLIENT_SIDE_ARRAY_DESCS; client_array_iter++)
6050 const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[client_array_iter];
6053 uint base_key_index = 0x1000 + client_array_iter;
6055 // Special case texcoord pointers, which are accessed via the client active texture.
6056 if (client_array_iter == vogl_texcoord_pointer_array_id)
6059 base_key_index = 0x2000;
6062 for (uint inner_iter = 0; inner_iter < n; inner_iter++)
6064 if (client_array_iter == vogl_texcoord_pointer_array_id)
6066 GL_ENTRYPOINT(glClientActiveTexture)(GL_TEXTURE0 + inner_iter);
6069 GLboolean is_enabled = GL_ENTRYPOINT(glIsEnabled)(desc.m_is_enabled);
6074 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_binding, &binding);
6079 GL_ENTRYPOINT(glGetPointerv)(desc.m_get_pointer, &ptr);
6083 GLint type = GL_BOOL;
6084 if (desc.m_get_type)
6086 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_type, &type);
6090 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_stride, &stride);
6093 if (desc.m_get_size)
6095 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_size, &size);
6098 uint type_size = vogl_get_gl_type_size(type);
6101 vogl_error_printf("%s: Can't determine type size of enabled client side array set by func %s\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[desc.m_entrypoint].m_pName);
6105 if ((desc.m_entrypoint == VOGL_ENTRYPOINT_glIndexPointer) || (desc.m_entrypoint == VOGL_ENTRYPOINT_glIndexPointerEXT) ||
6106 (desc.m_entrypoint == VOGL_ENTRYPOINT_glFogCoordPointer) || (desc.m_entrypoint == VOGL_ENTRYPOINT_glFogCoordPointerEXT) ||
6107 (desc.m_entrypoint == VOGL_ENTRYPOINT_glEdgeFlagPointer) || (desc.m_entrypoint == VOGL_ENTRYPOINT_glEdgeFlagPointerEXT))
6111 else if ((desc.m_entrypoint == VOGL_ENTRYPOINT_glNormalPointer) || (desc.m_entrypoint == VOGL_ENTRYPOINT_glNormalPointerEXT))
6115 else if ((size < 1) || (size > 4))
6117 vogl_error_printf("%s: Size of client side array set by func %s must be between 1 and 4\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[desc.m_entrypoint].m_pName);
6122 stride = type_size * size;
6124 uint first_vertex_ofs = (start + basevertex) * stride;
6125 uint last_vertex_ofs = (end + basevertex) * stride;
6126 uint vertex_data_size = (last_vertex_ofs + stride) - first_vertex_ofs;
6128 if (g_dump_gl_buffers_flag)
6130 vogl_log_printf("Client side vertex data from %s index %u (comps: %i type_size: %i stride: %i):\n", g_vogl_entrypoint_descs[desc.m_entrypoint].m_pName, inner_iter, size, type_size, stride);
6131 vogl_print_hex(static_cast<const uint8_t *>(ptr) + first_vertex_ofs, vertex_data_size, type_size);
6132 vogl_log_printf("\n");
6135 if (trace_serializer.is_in_begin())
6137 uint key_index = base_key_index + inner_iter;
6138 trace_serializer.add_key_value_blob(static_cast<uint16>(key_index), static_cast<const uint8_t *>(ptr) + first_vertex_ofs, vertex_data_size);
6142 } // client_array_iter
6144 GL_ENTRYPOINT(glClientActiveTexture)(prev_client_active_texture);
6145 } // used_old_style_gl_client_side_arrays
6147 if (vertex_attrib_client_side_arrays)
6149 for (uint i = 0; i < pContext->get_max_vertex_attribs(); i++)
6151 if ((vertex_attrib_client_side_arrays & (1ULL << i)) == 0)
6154 GLvoid *attrib_ptr = NULL;
6155 GL_ENTRYPOINT(glGetVertexAttribPointerv)(i, GL_VERTEX_ATTRIB_ARRAY_POINTER, &attrib_ptr);
6159 vogl_error_printf("%s: Enabled vertex attribute index %i has no vertex array buffer, and attribute pointer is NULL\n", VOGL_FUNCTION_NAME, i);
6163 GLint attrib_size = 0;
6164 GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_SIZE, &attrib_size);
6166 GLint attrib_type = 0;
6167 GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_TYPE, &attrib_type);
6169 GLint attrib_stride = 0;
6170 GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &attrib_stride);
6173 if ((attrib_size != GL_BGRA) && (attrib_size < 1) && (attrib_size > 4))
6175 vogl_error_printf("%s: Enabled vertex attribute index %i has invalid size 0x%0X\n", VOGL_FUNCTION_NAME, i, attrib_size);
6178 if ((attrib_size >= 1) && (attrib_size <= 4))
6179 num_comps = attrib_size;
6181 uint type_size = vogl_get_gl_type_size(attrib_type);
6184 vogl_error_printf("%s: Vertex attribute index %i has unsupported type 0x%0X\n", VOGL_FUNCTION_NAME, i, attrib_type);
6188 uint stride = attrib_stride ? attrib_stride : (type_size * num_comps);
6190 uint first_vertex_ofs = (start + basevertex) * stride;
6191 uint last_vertex_ofs = (end + basevertex) * stride;
6192 uint vertex_data_size = (last_vertex_ofs + stride) - first_vertex_ofs;
6194 if (g_dump_gl_buffers_flag)
6196 vogl_log_printf("Client side vertex data for attrib %i (comps: %i type_size: %i stride: %i):\n", i, num_comps, type_size, stride);
6198 vogl_print_hex(static_cast<const uint8_t *>(attrib_ptr) + first_vertex_ofs, vertex_data_size, type_size);
6200 vogl_log_printf("\n");
6203 if (trace_serializer.is_in_begin())
6205 // TODO: Also send down start/end/first_vertex_ofs for debugging/verification purposes
6206 trace_serializer.add_key_value_blob(static_cast<uint16>(i), static_cast<const uint8_t *>(attrib_ptr) + first_vertex_ofs, vertex_data_size);
6212 //----------------------------------------------------------------------------------------------------------------------
6213 // glDrawRangeElements, glDrawRangeElementsBaseVertex, glDrawRangeElementsEXT
6214 //----------------------------------------------------------------------------------------------------------------------
6215 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDrawRangeElementsBaseVertex(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_draw_range_elements_base_vertex_helper(pContext, trace_serializer, #name, mode, start, end, count, type, indices, 0, true);
6216 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDrawRangeElements(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_draw_range_elements_base_vertex_helper(pContext, trace_serializer, #name, mode, start, end, count, type, indices, 0, true);
6217 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDrawRangeElementsEXT(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_draw_range_elements_base_vertex_helper(pContext, trace_serializer, #name, mode, start, end, count, type, indices, 0, true);
6218 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDrawElements(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_draw_range_elements_base_vertex_helper(pContext, trace_serializer, #name, mode, 0, 0, count, type, indices, 0, false);
6219 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDrawElementsInstanced(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_draw_range_elements_base_vertex_helper(pContext, trace_serializer, #name, mode, 0, 0, count, type, indices, 0, false);
6221 static inline void vogl_draw_range_elements_base_vertex_helper(
6222 vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, const char *pFunc,
6223 GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex, bool start_end_valid)
6225 if (trace_serializer.is_in_begin())
6227 vogl_serialize_client_side_arrays_helper(pContext, trace_serializer, pFunc,
6228 mode, start, end, count, type, indices, basevertex, start_end_valid, true);
6232 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDrawArrays(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_draw_arrays_helper(pContext, trace_serializer, #name, mode, first, count);
6233 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDrawArraysEXT(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_draw_arrays_helper(pContext, trace_serializer, #name, mode, first, count);
6234 static void vogl_draw_arrays_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, const char *pFunc,
6235 GLenum mode, GLint first, GLsizei count)
6237 if (trace_serializer.is_in_begin())
6239 vogl_serialize_client_side_arrays_helper(pContext, trace_serializer, pFunc,
6240 mode, first, first + count - 1, count, GL_UNSIGNED_BYTE, NULL, 0, true, false);
6244 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDrawArraysInstanced(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_draw_arrays_instanced_helper(pContext, trace_serializer, #name, mode, first, count, instancecount);
6245 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDrawArraysInstancedEXT(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_draw_arrays_instanced_helper(pContext, trace_serializer, #name, mode, start, count, primcount);
6246 static void vogl_draw_arrays_instanced_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, const char *pFunc,
6247 GLenum mode, GLint first, GLsizei count, GLsizei primcount)
6249 VOGL_NOTE_UNUSED(primcount);
6250 if (trace_serializer.is_in_begin())
6252 vogl_serialize_client_side_arrays_helper(pContext, trace_serializer, pFunc,
6253 mode, first, first + count - 1, count, GL_UNSIGNED_BYTE, NULL, 0, true, false);
6257 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glMultiDrawArrays(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_multi_draw_arrays_helper(pContext, trace_serializer, #name);
6258 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glMultiDrawArraysEXT(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_multi_draw_arrays_helper(pContext, trace_serializer, #name);
6259 static inline void vogl_multi_draw_arrays_helper(
6260 vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, const char *pFunc)
6262 if (trace_serializer.is_in_begin())
6264 if (vogl_uses_client_side_arrays(pContext, false))
6266 vogl_warning_printf("%s: Function \"%s\" uses client side arrays, which is not currently supported. This call will not replay properly.\n", VOGL_FUNCTION_NAME, pFunc);
6271 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glMultiDrawElements(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_multi_draw_elements_helper(pContext, trace_serializer, #name);
6272 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glMultiDrawElementsEXT(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_multi_draw_elements_helper(pContext, trace_serializer, #name);
6273 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glMultiDrawElementsBaseVertex(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_multi_draw_elements_helper(pContext, trace_serializer, #name);
6274 static void vogl_multi_draw_elements_helper(
6275 vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, const char *pFunc)
6277 if (trace_serializer.is_in_begin())
6279 if (vogl_uses_client_side_arrays(pContext, true))
6281 vogl_warning_printf("%s: Function \"%s\" uses client side arrays, which is not currently supported. This call will not replay properly.\n", VOGL_FUNCTION_NAME, pFunc);
6286 //----------------------------------------------------------------------------------------------------------------------
6287 // String (extension manipulation)
6288 //----------------------------------------------------------------------------------------------------------------------
6289 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGetString(exported, category, ret, ret_type_enum, num_params, func_name, args, params) vogl_get_string_helper(#func_name, pContext, result, name, 0);
6290 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGetStringi(exported, category, ret, ret_type_enum, num_params, func_name, args, params) vogl_get_string_helper(#func_name, pContext, result, name, index);
6291 static inline void vogl_get_string_helper(const char *pFunc_name, vogl_context *pVOGL_context, const GLubyte *&pResult, GLenum name, GLuint index)
6293 if (!g_disable_gl_program_binary_flag)
6296 if ((pVOGL_context) && (pResult) && (name == GL_EXTENSIONS))
6298 // Can't modify the driver's string directly, results in random crashes on my system. So we need to make a copy.
6299 char *pLoc = strstr((char *)pResult, "GL_ARB_get_program_binary");
6302 dynamic_string id(cVarArg, "%s_%x_%x", pFunc_name, name, index);
6304 dynamic_string &ext_str = pVOGL_context->get_extension_map()[id];
6305 ext_str.set((char *)pResult);
6307 int ofs = ext_str.find_left("GL_ARB_get_program_binary", true);
6310 ext_str.set_char(ofs + 3, 'X');
6311 ext_str.set_char(ofs + 4, 'X');
6312 ext_str.set_char(ofs + 5, 'X');
6313 vogl_warning_printf("%s: Disabled GL_ARB_get_program_binary by changing its name to GL_XXX_get_program_binary.\n", VOGL_FUNCTION_NAME);
6315 pResult = (const GLubyte *)ext_str.get_ptr();
6321 //----------------------------------------------------------------------------------------------------------------------
6322 // Buffer mapping, updating
6323 //----------------------------------------------------------------------------------------------------------------------
6326 // glMapNamedBufferEXT
6327 // glMapNamedBufferRangeEXT
6328 // glFlushMappedNamedBufferRangeEXT
6329 // glUnmapNamedBufferEXT
6330 // glGetNamedBufferSubDataEXT
6332 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glNamedBufferDataEXT(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_named_buffer_data_ext_helper(pContext, trace_serializer, buffer, size, data, usage);
6333 static inline void vogl_named_buffer_data_ext_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLuint buffer, GLsizeiptr size, const GLvoid *data, GLenum usage)
6335 VOGL_NOTE_UNUSED(trace_serializer);
6340 if (g_dump_gl_buffers_flag)
6342 vogl_log_printf("Buffer data (size: %" PRIu64 "):\n", static_cast<uint64_t>(size));
6343 vogl_print_hex(data, size, 1);
6344 vogl_log_printf("\n");
6347 gl_buffer_desc &buf_desc = pContext->get_or_create_buffer_desc(buffer);
6348 buf_desc.m_size = size;
6349 buf_desc.m_usage = usage;
6351 if (buf_desc.m_pMap)
6353 vogl_warning_printf("%s: Setting buffer's data on an already mapped buffer, buffer will get unmapped by GL\n", VOGL_FUNCTION_NAME);
6356 buf_desc.m_pMap = NULL;
6357 buf_desc.m_map_ofs = 0;
6358 buf_desc.m_map_size = 0;
6359 buf_desc.m_map_access = 0;
6360 buf_desc.m_map_range = 0;
6361 buf_desc.m_flushed_ranges.resize(0);
6364 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glBufferData(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_buffer_data_helper(pContext, trace_serializer, target, size, data, usage);
6365 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glBufferDataARB(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_buffer_data_helper(pContext, trace_serializer, target, size, data, usage);
6366 static inline void vogl_buffer_data_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage)
6371 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6372 VOGL_NOTE_UNUSED(gl_error_absorber);
6374 GLuint buffer = vogl_get_bound_gl_buffer(target);
6377 vogl_error_printf("%s: No mapped buffer at target 0x%08X\n", VOGL_FUNCTION_NAME, target);
6381 vogl_named_buffer_data_ext_helper(pContext, trace_serializer, buffer, size, data, usage);
6384 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glNamedBufferSubDataEXT(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_named_buffer_subdata_ext_helper(pContext, trace_serializer, buffer, offset, size, data);
6385 static inline void vogl_named_buffer_subdata_ext_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLuint buffer, GLintptr offset, GLsizeiptr size, const GLvoid *data)
6387 VOGL_NOTE_UNUSED(buffer);
6388 VOGL_NOTE_UNUSED(trace_serializer);
6389 VOGL_NOTE_UNUSED(pContext);
6391 if (g_dump_gl_buffers_flag)
6393 vogl_log_printf("Buffer sub data (offset: %" PRIu64 " size: %" PRIu64 "):\n", static_cast<uint64_t>(offset), static_cast<uint64_t>(size));
6394 vogl_print_hex(data, size, 1);
6395 vogl_log_printf("\n");
6399 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glBufferSubData(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_buffer_subdata_helper(pContext, trace_serializer, target, offset, size, data);
6400 static inline void vogl_buffer_subdata_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data)
6405 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6406 VOGL_NOTE_UNUSED(gl_error_absorber);
6408 GLuint buffer = vogl_get_bound_gl_buffer(target);
6411 vogl_error_printf("%s: No mapped buffer at target 0x%08X\n", VOGL_FUNCTION_NAME, target);
6415 vogl_named_buffer_subdata_ext_helper(pContext, trace_serializer, buffer, offset, size, data);
6418 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glMapBuffer(exported, category, ret, ret_type_enum, num_params, name, args, params) \
6419 GLenum orig_access = access; \
6420 vogl_map_buffer_gl_prolog_helper(pContext, trace_serializer, target, access);
6421 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glMapBufferARB(exported, category, ret, ret_type_enum, num_params, name, args, params) \
6422 GLenum orig_access = access; \
6423 vogl_map_buffer_gl_prolog_helper(pContext, trace_serializer, target, access);
6424 static inline void vogl_map_buffer_gl_prolog_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLenum target, GLenum &access)
6426 VOGL_NOTE_UNUSED(target);
6427 VOGL_NOTE_UNUSED(pContext);
6429 if (trace_serializer.is_in_begin() || g_dump_gl_buffers_flag)
6431 if (access == GL_WRITE_ONLY)
6433 access = GL_READ_WRITE;
6438 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glMapBuffer(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_map_buffer_gl_epilog_helper(pContext, target, orig_access, result);
6439 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glMapBufferARB(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_map_buffer_gl_epilog_helper(pContext, target, orig_access, result);
6440 static inline void vogl_map_buffer_gl_epilog_helper(vogl_context *pContext, GLenum target, GLenum access, GLvoid *pPtr)
6447 vogl_warning_printf("%s: Map failed!\n", VOGL_FUNCTION_NAME);
6451 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6452 VOGL_NOTE_UNUSED(gl_error_absorber);
6454 GLuint buffer = vogl_get_bound_gl_buffer(target);
6457 vogl_error_printf("%s: No mapped buffer at target 0x%08X\n", VOGL_FUNCTION_NAME, target);
6461 gl_buffer_desc &buf_desc = pContext->get_or_create_buffer_desc(buffer);
6462 if (buf_desc.m_pMap)
6464 vogl_warning_printf("%s: Buffer 0x%08X is already mapped!\n", VOGL_FUNCTION_NAME, buffer);
6468 // We need to sync with the underlying GL here to retreive the actual, true size of the mapped buffer in case an error occurred earlier and we didn't actually record the true size of the buffer.
6469 GLint64 actual_buf_size = buf_desc.m_size;
6470 GL_ENTRYPOINT(glGetBufferParameteri64v)(target, GL_BUFFER_SIZE, &actual_buf_size);
6472 buf_desc.m_size = actual_buf_size;
6473 buf_desc.m_pMap = pPtr;
6474 buf_desc.m_map_ofs = 0;
6475 buf_desc.m_map_size = actual_buf_size;
6476 buf_desc.m_map_access = access;
6477 buf_desc.m_map_range = false;
6480 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glMapBufferRange(exported, category, ret, ret_type_enum, num_params, name, args, params) \
6481 GLbitfield orig_access = access; \
6482 vogl_map_buffer_range_gl_prolog_helper(pContext, trace_serializer, target, offset, length, access);
6483 static inline void vogl_map_buffer_range_gl_prolog_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield &access)
6485 VOGL_NOTE_UNUSED(length);
6486 VOGL_NOTE_UNUSED(offset);
6487 VOGL_NOTE_UNUSED(target);
6488 VOGL_NOTE_UNUSED(pContext);
6490 if (trace_serializer.is_in_begin() || g_dump_gl_buffers_flag)
6492 if (access & GL_MAP_WRITE_BIT)
6494 // They are going to write, so we need to be able to read the data.
6495 // TODO: Warn user that we're going to not invalidate, which is definitely going to slow the GL driver down with CPU/GPU syncs.
6496 access &= ~GL_MAP_INVALIDATE_RANGE_BIT;
6497 access &= ~GL_MAP_INVALIDATE_BUFFER_BIT;
6498 access &= ~GL_MAP_UNSYNCHRONIZED_BIT;
6499 access |= GL_MAP_READ_BIT;
6504 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glMapBufferRange(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_map_buffer_range_gl_epilog_helper(pContext, target, offset, length, orig_access, result);
6505 static inline void vogl_map_buffer_range_gl_epilog_helper(vogl_context *pContext, GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield &access, GLvoid *pPtr)
6512 vogl_warning_printf("%s: Map failed!\n", VOGL_FUNCTION_NAME);
6516 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6517 VOGL_NOTE_UNUSED(gl_error_absorber);
6519 GLuint buffer = vogl_get_bound_gl_buffer(target);
6522 vogl_error_printf("%s: No mapped buffer at target 0x%08X\n", VOGL_FUNCTION_NAME, target);
6526 gl_buffer_desc &buf_desc = pContext->get_or_create_buffer_desc(buffer);
6527 if (buf_desc.m_pMap)
6529 vogl_error_printf("%s: Buffer 0x%08X is already mapped!\n", VOGL_FUNCTION_NAME, buffer);
6533 if (length > buf_desc.m_size)
6535 vogl_warning_printf("%s: passed in length parameter (%" PRIi64 ") is larger the buffer 0x%08X's recorded size (%" PRIi64 ")!\n",
6536 VOGL_FUNCTION_NAME, static_cast<int64_t>(length), buffer, buf_desc.m_size);
6538 GLint64 actual_buf_size = buf_desc.m_size;
6539 GL_ENTRYPOINT(glGetBufferParameteri64v)(target, GL_BUFFER_SIZE, &actual_buf_size);
6540 buf_desc.m_size = actual_buf_size;
6543 buf_desc.m_pMap = pPtr;
6544 buf_desc.m_map_ofs = offset;
6545 buf_desc.m_map_size = length;
6546 buf_desc.m_map_access = access;
6547 buf_desc.m_map_range = true;
6550 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glFlushMappedBufferRange(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_flush_mapped_buffer_range(pContext, target, offset, length);
6551 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glFlushMappedBufferRangeAPPLE(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_flush_mapped_buffer_range(pContext, target, offset, size);
6552 static inline void vogl_flush_mapped_buffer_range(vogl_context *pContext, GLenum target, GLintptr offset, GLsizeiptr length)
6557 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6558 VOGL_NOTE_UNUSED(gl_error_absorber);
6560 GLuint buffer = vogl_get_bound_gl_buffer(target);
6563 vogl_error_printf("%s: No mapped buffer at target 0x%08X\n", VOGL_FUNCTION_NAME, target);
6567 gl_buffer_desc &buf_desc = pContext->get_or_create_buffer_desc(buffer);
6568 if (!buf_desc.m_pMap)
6570 vogl_error_printf("%s: Buffer 0x%08X is not currently mapped!\n", VOGL_FUNCTION_NAME, buffer);
6574 if ((offset + length) > buf_desc.m_map_size)
6576 vogl_warning_printf("%s: passed in offset (%" PRIi64 ") and/or length (%" PRIi64 ") parameters are out of range vs. buffer 0x%08X's recorded map size (%" PRIi64 ")!\n",
6577 VOGL_FUNCTION_NAME, static_cast<int64_t>(offset), static_cast<int64_t>(length), buffer, buf_desc.m_map_size);
6580 buf_desc.m_flushed_ranges.push_back(gl_buffer_desc::flushed_range(offset, length));
6583 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glUnmapBuffer(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_unmap_buffer_helper(pContext, trace_serializer, target);
6584 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glUnmapBufferARB(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_unmap_buffer_helper(pContext, trace_serializer, target);
6585 static inline void vogl_unmap_buffer_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLenum target)
6590 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6591 VOGL_NOTE_UNUSED(gl_error_absorber);
6593 GLuint buffer = vogl_get_bound_gl_buffer(target);
6596 vogl_error_printf("%s: No mapped buffer at target 0x%08X\n", VOGL_FUNCTION_NAME, target);
6600 gl_buffer_desc &buf_desc = pContext->get_or_create_buffer_desc(buffer);
6601 if (!buf_desc.m_pMap)
6603 vogl_error_printf("%s: Buffer 0x%08X is not currently mapped!\n", VOGL_FUNCTION_NAME, buffer);
6607 bool writable_map = false;
6608 bool explicit_flush = false;
6609 if (buf_desc.m_map_range)
6611 writable_map = (buf_desc.m_map_access & GL_MAP_WRITE_BIT) != 0;
6612 explicit_flush = (buf_desc.m_map_access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0;
6616 writable_map = (buf_desc.m_map_access != GL_READ_ONLY);
6619 if (trace_serializer.is_in_begin())
6621 trace_serializer.add_key_value(string_hash("map_access"), buf_desc.m_map_access);
6622 trace_serializer.add_key_value(string_hash("map_range"), buf_desc.m_map_range);
6623 trace_serializer.add_key_value(string_hash("explicit_flush"), explicit_flush);
6624 trace_serializer.add_key_value(string_hash("writable_map"), writable_map);
6631 if (!buf_desc.m_flushed_ranges.size())
6633 vogl_warning_printf("%s: Mapped buffer at target 0x%08X was mapped with GL_MAP_FLUSH_EXPLICIT_BIT, but no ranges where actually flushed\n", VOGL_FUNCTION_NAME, target);
6636 if (g_dump_gl_buffers_flag)
6638 for (uint i = 0; i < buf_desc.m_flushed_ranges.size(); i++)
6640 vogl_log_printf("Flushed buffer data (ofs: %" PRIu64 " size: %" PRIu64 "):\n", buf_desc.m_flushed_ranges[i].m_ofs, buf_desc.m_flushed_ranges[i].m_size);
6641 vogl_print_hex(static_cast<const uint8_t *>(buf_desc.m_pMap) + buf_desc.m_flushed_ranges[i].m_ofs, buf_desc.m_flushed_ranges[i].m_size, 1);
6642 vogl_log_printf("\n");
6646 if (trace_serializer.is_in_begin())
6648 trace_serializer.add_key_value(string_hash("flushed_ranges"), buf_desc.m_flushed_ranges.size());
6649 for (uint i = 0; i < buf_desc.m_flushed_ranges.size(); i++)
6651 int key_index = i * 4;
6652 trace_serializer.add_key_value(key_index, buf_desc.m_flushed_ranges[i].m_ofs);
6653 trace_serializer.add_key_value(key_index + 1, buf_desc.m_flushed_ranges[i].m_size);
6655 VOGL_ASSERT(buf_desc.m_flushed_ranges[i].m_size <= cUINT32_MAX);
6656 trace_serializer.add_key_value_blob(key_index + 2, static_cast<const uint8_t *>(buf_desc.m_pMap) + buf_desc.m_flushed_ranges[i].m_ofs, static_cast<uint>(buf_desc.m_flushed_ranges[i].m_size));
6662 if (g_dump_gl_buffers_flag)
6664 vogl_log_printf("Flushed buffer data (ofs: %" PRIu64 " size: %" PRIu64 "):\n", cast_val_to_uint64(buf_desc.m_map_ofs), cast_val_to_uint64(buf_desc.m_map_size));
6665 vogl_print_hex(static_cast<const uint8_t *>(buf_desc.m_pMap), buf_desc.m_map_size, 1);
6666 vogl_log_printf("\n");
6669 if (trace_serializer.is_in_begin())
6671 trace_serializer.add_key_value(0, buf_desc.m_map_ofs);
6672 trace_serializer.add_key_value(1, buf_desc.m_map_size);
6674 VOGL_ASSERT(buf_desc.m_map_size <= cUINT32_MAX);
6675 trace_serializer.add_key_value_blob(2, static_cast<const uint8_t *>(buf_desc.m_pMap), static_cast<uint>(buf_desc.m_map_size));
6680 buf_desc.m_pMap = NULL;
6681 buf_desc.m_map_ofs = 0;
6682 buf_desc.m_map_size = 0;
6683 buf_desc.m_map_access = 0;
6684 buf_desc.m_flushed_ranges.resize(0);
6687 //----------------------------------------------------------------------------------------------------------------------
6688 // glCreateProgram/glCreateProgramARB function epilog
6689 //----------------------------------------------------------------------------------------------------------------------
6690 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glCreateProgram(e, c, rt, r, nu, ne, a, p) \
6692 vogl_create_program_helper(pContext, result);
6693 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glCreateProgramObjectARB(e, c, rt, r, nu, ne, a, p) \
6695 vogl_create_program_helper(pContext, result);
6696 static inline void vogl_create_program_helper(vogl_context *pContext, GLuint handle)
6698 VOGL_NOTE_UNUSED(pContext);
6699 VOGL_NOTE_UNUSED(handle);
6704 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6705 VOGL_NOTE_UNUSED(gl_error_absorber);
6707 // Ensure program bins are always retrievable
6708 GL_ENTRYPOINT(glProgramParameteri)(handle, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);
6713 //----------------------------------------------------------------------------------------------------------------------
6714 // glProgramParameteri GL prolog
6715 //----------------------------------------------------------------------------------------------------------------------
6716 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glProgramParameteri(e, c, rt, r, nu, ne, a, p) \
6718 vogl_program_parameteri_prolog(pContext, program, pname, value);
6719 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glProgramParameteriARB(e, c, rt, r, nu, ne, a, p) \
6721 vogl_program_parameteri_prolog(pContext, program, pname, value);
6722 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glProgramParameteriEXT(e, c, rt, r, nu, ne, a, p) \
6724 vogl_program_parameteri_prolog(pContext, program, pname, value);
6725 static void vogl_program_parameteri_prolog(vogl_context *pContext, GLuint program, GLenum pname, GLint &value)
6727 VOGL_NOTE_UNUSED(pContext);
6728 VOGL_NOTE_UNUSED(program);
6729 VOGL_NOTE_UNUSED(pname);
6730 VOGL_NOTE_UNUSED(value);
6733 if ((pname == GL_PROGRAM_BINARY_RETRIEVABLE_HINT) && (value == GL_FALSE))
6735 vogl_warning_printf("%s: Client is trying to set program %u's GL_PROGRAM_BINARY_RETRIEVABLE_HINT to GL_FALSE, the tracer is overriding this to GL_TRUE\n", VOGL_FUNCTION_NAME, program);
6742 //----------------------------------------------------------------------------------------------------------------------
6743 // glBindAttribLocationARB/glBindAttribLocation function epilog
6744 //----------------------------------------------------------------------------------------------------------------------
6745 //#define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glBindAttribLocationARB(e, c, rt, r, nu, ne, a, p) if (pContext) pContext->bind_attrib_location(programObj, index, name);
6746 //#define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glBindAttribLocation(e, c, rt, r, nu, ne, a, p) if (pContext) pContext->bind_attrib_location(program, index, reinterpret_cast<const char *>(name));
6748 //----------------------------------------------------------------------------------------------------------------------
6749 // glDeleteProgramsARB/glDeleteProgram function epilog
6750 //----------------------------------------------------------------------------------------------------------------------
6751 //#define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDeleteProgramsARB(e, c, rt, r, nu, ne, a, p) if (pContext) pContext->delete_program_attrib_locations(n, programs);
6752 //#define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDeleteProgram(e, c, rt, r, nu, ne, a, p) if (pContext) pContext->delete_program_attrib_locations(1, &program);
6754 //----------------------------------------------------------------------------------------------------------------------
6755 // vogl_dump_program_outputs
6756 //----------------------------------------------------------------------------------------------------------------------
6757 static void vogl_dump_program_outputs(json_node &doc_root, vogl_context *pContext, GLuint program)
6759 if (pContext->get_context_info().supports_extension("GL_ARB_program_interface_query") &&
6760 GL_ENTRYPOINT(glGetProgramInterfaceiv) && GL_ENTRYPOINT(glGetProgramResourceName) && GL_ENTRYPOINT(glGetProgramResourceiv))
6762 GLint num_active_outputs = 0;
6763 GL_ENTRYPOINT(glGetProgramInterfaceiv)(program, GL_PROGRAM_OUTPUT, GL_ACTIVE_RESOURCES, &num_active_outputs);
6764 pContext->peek_and_drop_gl_error();
6766 doc_root.add_key_value("total_active_outputs", num_active_outputs);
6768 json_node &outputs_object = doc_root.add_array("active_outputs");
6769 for (int i = 0; i < num_active_outputs; i++)
6772 GLsizei name_len = 0;
6773 GL_ENTRYPOINT(glGetProgramResourceName)(program, GL_PROGRAM_OUTPUT, i, sizeof(name), &name_len, name);
6774 pContext->peek_and_drop_gl_error();
6776 const GLenum props_to_query[5] = { GL_LOCATION, GL_LOCATION_INDEX, GL_TYPE, GL_ARRAY_SIZE, GL_IS_PER_PATCH }; // TODO: GL_LOCATION_COMPONENT
6777 GLint props[5] = { 0, 0, 0, 0, 0 };
6778 GL_ENTRYPOINT(glGetProgramResourceiv)(program, GL_PROGRAM_OUTPUT, i, VOGL_ARRAY_SIZE(props_to_query), props_to_query, VOGL_ARRAY_SIZE(props), NULL, props);
6779 pContext->peek_and_drop_gl_error();
6781 json_node &output_node = outputs_object.add_object();
6782 output_node.add_key_value("index", i);
6783 output_node.add_key_value("name", reinterpret_cast<const char *>(name));
6784 output_node.add_key_value("location", props[0]);
6785 output_node.add_key_value("location_index", props[1]);
6786 output_node.add_key_value("type", props[2]);
6787 output_node.add_key_value("array_size", props[3]);
6788 output_node.add_key_value("is_per_patch", props[4]);
6789 //output_node.add_key_value("location_component", props[5]);
6794 //----------------------------------------------------------------------------------------------------------------------
6795 // glLinkProgramARB function epilog
6796 //----------------------------------------------------------------------------------------------------------------------
6797 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glLinkProgramARB(e, c, rt, r, nu, ne, a, p) vogl_link_program_arb(pContext, trace_serializer, programObj);
6798 static inline void vogl_link_program_arb(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLhandleARB programObj)
6803 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6804 VOGL_NOTE_UNUSED(gl_error_absorber);
6806 GLint link_status = 0;
6807 GL_ENTRYPOINT(glGetObjectParameterivARB)(programObj, GL_OBJECT_LINK_STATUS_ARB, &link_status);
6808 pContext->peek_and_drop_gl_error();
6810 if (trace_serializer.is_in_begin())
6813 json_node &doc_root = *doc.get_root();
6814 doc_root.add_key_value("program", programObj);
6815 doc_root.add_key_value("link_status", link_status);
6816 doc_root.add_key_value("func_id", VOGL_ENTRYPOINT_glLinkProgramARB);
6818 GLint active_attributes = 0;
6819 GL_ENTRYPOINT(glGetObjectParameterivARB)(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);
6820 pContext->peek_and_drop_gl_error();
6822 doc_root.add_key_value("total_active_attributes", active_attributes);
6824 if (active_attributes)
6826 json_node &attribs_object = doc_root.add_array("active_attribs");
6828 for (int i = 0; i < active_attributes; i++)
6832 GLcharARB name[256];
6834 GL_ENTRYPOINT(glGetActiveAttribARB)(programObj, i, sizeof(name), NULL, &size, &type, name);
6835 pContext->peek_and_drop_gl_error();
6837 if ((!name[0]) || ((name[0] == 'g') && (name[1] == 'l') && (name[2] == '_')))
6840 GLint location = GL_ENTRYPOINT(glGetAttribLocationARB)(programObj, name);
6841 pContext->peek_and_drop_gl_error();
6846 json_node &attrib_node = attribs_object.add_object();
6847 attrib_node.add_key_value("index", i);
6848 attrib_node.add_key_value("name", reinterpret_cast<const char *>(name));
6849 attrib_node.add_key_value("location", location);
6853 GLint active_uniforms = 0;
6854 GL_ENTRYPOINT(glGetObjectParameterivARB)(programObj, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &active_uniforms);
6855 pContext->peek_and_drop_gl_error();
6857 doc_root.add_key_value("total_active_uniforms", active_uniforms);
6859 if (active_uniforms)
6861 json_node &uniforms_object = doc_root.add_array("active_uniforms");
6863 for (int i = 0; i < active_uniforms; i++)
6868 GLcharARB name[256];
6870 GL_ENTRYPOINT(glGetActiveUniformARB)(programObj, i, sizeof(name), &length, &size, &type, name);
6871 pContext->peek_and_drop_gl_error();
6873 if ((!name[0]) || (!length) || ((name[0] == 'g') && (name[1] == 'l') && (name[2] == '_')))
6876 GLint location = GL_ENTRYPOINT(glGetUniformLocationARB)(programObj, name);
6877 pContext->peek_and_drop_gl_error();
6882 json_node &uniform_node = uniforms_object.add_object();
6883 uniform_node.add_key_value("index", i);
6884 uniform_node.add_key_value("name", reinterpret_cast<const char *>(name));
6885 uniform_node.add_key_value("location", location);
6886 uniform_node.add_key_value("size", size);
6887 uniform_node.add_key_value("type", type);
6891 vogl_dump_program_outputs(doc_root, pContext, programObj);
6893 trace_serializer.add_key_value_json_document("metadata", doc);
6898 if ((link_status) || (!pContext->has_linked_program_snapshot(programObj)))
6900 if (!pContext->add_linked_program_snapshot(programObj))
6901 vogl_error_printf("%s: Failed snapshotting program into link-time program shadow table, program 0x%X\n", VOGL_FUNCTION_NAME, programObj);
6906 //----------------------------------------------------------------------------------------------------------------------
6907 // glLinkProgram/glProgramBinary function epilog
6908 //----------------------------------------------------------------------------------------------------------------------
6909 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glLinkProgram(e, c, rt, r, nu, ne, a, p) vogl_link_program_epilog_helper(pContext, trace_serializer, program, VOGL_ENTRYPOINT_##ne, GL_NONE, NULL, 0);
6910 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glProgramBinary(e, c, rt, r, nu, ne, a, p) vogl_link_program_epilog_helper(pContext, trace_serializer, program, VOGL_ENTRYPOINT_##ne, binaryFormat, binary, length);
6911 static inline void vogl_link_program_epilog_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLuint program, gl_entrypoint_id_t id, GLenum binary_format, const GLvoid *pBinary, GLsizei binary_length)
6916 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6917 VOGL_NOTE_UNUSED(gl_error_absorber);
6919 GLint link_status = 0;
6920 GL_ENTRYPOINT(glGetProgramiv)(program, GL_LINK_STATUS, &link_status);
6921 pContext->peek_and_drop_gl_error();
6923 if (trace_serializer.is_in_begin())
6926 json_node &doc_root = *doc.get_root();
6927 doc_root.add_key_value("program", program);
6928 doc_root.add_key_value("link_status", link_status);
6929 doc_root.add_key_value("func_id", static_cast<uint32>(id));
6931 // Active uniform blocks
6932 GLint active_uniform_blocks = 0;
6933 GL_ENTRYPOINT(glGetProgramiv)(program, GL_ACTIVE_UNIFORM_BLOCKS, &active_uniform_blocks);
6934 pContext->peek_and_drop_gl_error();
6936 doc_root.add_key_value("active_uniform_blocks", active_uniform_blocks);
6938 // Active attributes
6939 GLint active_attributes = 0;
6940 GL_ENTRYPOINT(glGetProgramiv)(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);
6941 pContext->peek_and_drop_gl_error();
6943 doc_root.add_key_value("total_active_attributes", active_attributes);
6945 if (active_attributes)
6947 json_node &attribs_object = doc_root.add_array("active_attribs");
6949 for (int i = 0; i < active_attributes; i++)
6955 GL_ENTRYPOINT(glGetActiveAttrib)(program, i, sizeof(name), NULL, &size, &type, name);
6956 pContext->peek_and_drop_gl_error();
6958 if ((!name[0]) || ((name[0] == 'g') && (name[1] == 'l') && (name[2] == '_')))
6961 GLint location = GL_ENTRYPOINT(glGetAttribLocation)(program, name);
6962 pContext->peek_and_drop_gl_error();
6967 json_node &attrib_node = attribs_object.add_object();
6968 attrib_node.add_key_value("index", i);
6969 attrib_node.add_key_value("name", reinterpret_cast<const char *>(name));
6970 attrib_node.add_key_value("location", location);
6975 GLint active_uniforms = 0;
6976 GL_ENTRYPOINT(glGetProgramiv)(program, GL_ACTIVE_UNIFORMS, &active_uniforms);
6977 doc_root.add_key_value("total_active_uniforms", active_uniforms);
6979 if (active_uniforms)
6981 json_node &uniforms_object = doc_root.add_array("active_uniforms");
6983 for (int i = 0; i < active_uniforms; i++)
6990 GL_ENTRYPOINT(glGetActiveUniform)(program, i, sizeof(name), &length, &size, &type, name);
6991 pContext->peek_and_drop_gl_error();
6993 if ((!name[0]) || (!length) || ((name[0] == 'g') && (name[1] == 'l') && (name[2] == '_')))
6996 GLint location = GL_ENTRYPOINT(glGetUniformLocation)(program, name);
6997 pContext->peek_and_drop_gl_error();
7002 json_node &uniform_node = uniforms_object.add_object();
7003 uniform_node.add_key_value("index", i);
7004 uniform_node.add_key_value("name", reinterpret_cast<const char *>(name));
7005 uniform_node.add_key_value("location", location);
7006 uniform_node.add_key_value("size", size);
7007 uniform_node.add_key_value("type", type);
7012 vogl_dump_program_outputs(doc_root, pContext, program);
7014 // Transform feedback
7015 GLint mode = GL_NONE;
7016 GL_ENTRYPOINT(glGetProgramiv)(program, GL_TRANSFORM_FEEDBACK_BUFFER_MODE, &mode);
7017 pContext->peek_and_drop_gl_error();
7019 doc_root.add_key_value("transform_feedback_mode", g_gl_enums.find_gl_name(mode));
7021 GLint num_varyings = 0;
7022 GL_ENTRYPOINT(glGetProgramiv)(program, GL_TRANSFORM_FEEDBACK_VARYINGS, &num_varyings);
7023 pContext->peek_and_drop_gl_error();
7025 doc_root.add_key_value("transform_feedback_num_varyings", num_varyings);
7029 json_node &transform_feedback_varyings = doc_root.add_array("transform_feedback_varyings");
7031 for (GLint i = 0; i < num_varyings; i++)
7034 GLsizei length = 0, size = 0;
7035 GLenum type = GL_NONE;
7037 GL_ENTRYPOINT(glGetTransformFeedbackVarying)(program, i, sizeof(name), &length, &size, &type, name);
7038 pContext->peek_and_drop_gl_error();
7040 json_node &uniform_node = transform_feedback_varyings.add_object();
7041 uniform_node.add_key_value("index", i);
7042 uniform_node.add_key_value("name", reinterpret_cast<const char *>(name));
7043 uniform_node.add_key_value("size", size);
7044 uniform_node.add_key_value("type", type);
7048 // Add JSON document to packet
7049 trace_serializer.add_key_value_json_document("metadata", doc);
7054 if ((link_status) || (!pContext->has_linked_program_snapshot(program)))
7056 if (id == VOGL_ENTRYPOINT_glProgramBinary)
7058 if (!pContext->add_linked_program_snapshot(program, binary_format, pBinary, binary_length))
7060 vogl_error_printf("%s: Failed snapshotting binary program into link-time program shadow table, program 0x%X\n", VOGL_FUNCTION_NAME, program);
7065 if (!pContext->add_linked_program_snapshot(program))
7067 vogl_error_printf("%s: Failed snapshotting program into link-time program shadow table, program 0x%X\n", VOGL_FUNCTION_NAME, program);
7074 #define DEF_FUNCTION_CUSTOM_FUNC_PROLOG_glProgramBinary(e, c, rt, r, nu, ne, a, p) vogl_glProgramBinary_prolog(program, binaryFormat, binary, length);
7075 static inline void vogl_glProgramBinary_prolog(GLuint program, GLenum binaryFormat, const void *&pBinary, GLsizei &length)
7077 VOGL_NOTE_UNUSED(binaryFormat);
7079 if (g_disable_gl_program_binary_flag)
7081 vogl_debug_printf("%s: Tracer is forcing a bogus program binary for program %d\n", VOGL_FUNCTION_NAME, program);
7083 // These will intentionally cause the program binary to not link, forcing the application to use shader strings instead of binaries.
7084 pBinary = &g_dummy_program;
7089 //----------------------------------------------------------------------------------------------------------------------
7090 // glTransformFeedbackVaryings func epilog
7091 //----------------------------------------------------------------------------------------------------------------------
7092 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glTransformFeedbackVaryings(e, c, rt, r, nu, ne, a, p) \
7094 vogl_transform_feedback_varyings(pContext, trace_serializer, count, varyings);
7095 static inline void vogl_transform_feedback_varyings(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLsizei count, GLchar *const *pVaryings)
7097 VOGL_NOTE_UNUSED(pContext);
7099 if ((!count) || (!pVaryings) || (!trace_serializer.is_in_begin()))
7102 dynamic_string varying;
7103 for (int i = 0; i < count; i++)
7107 varying = reinterpret_cast<const char *>(pVaryings[i]);
7109 trace_serializer.add_key_value(i, varying);
7113 //----------------------------------------------------------------------------------------------------------------------
7114 // ARB program shadowing
7115 //----------------------------------------------------------------------------------------------------------------------
7116 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenProgramsARB(e, c, rt, r, nu, ne, a, p) \
7118 pContext->peek_and_record_gl_error();
7119 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenProgramsARB(e, c, rt, r, nu, ne, a, p) \
7120 if (pContext && !pContext->peek_and_record_gl_error()) \
7121 pContext->gen_arb_programs(n, programs);
7123 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteProgramsARB(e, c, rt, r, nu, ne, a, p) \
7125 pContext->peek_and_record_gl_error();
7126 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteProgramsARB(e, c, rt, r, nu, ne, a, p) \
7127 if (pContext && !pContext->peek_and_record_gl_error()) \
7128 pContext->del_arb_programs(n, programs);
7130 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindProgramARB(e, c, rt, r, nu, ne, a, p) \
7132 pContext->peek_and_record_gl_error();
7133 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindProgramARB(e, c, rt, r, nu, ne, a, p) \
7134 if (pContext && !pContext->peek_and_record_gl_error()) \
7135 pContext->bind_arb_program(target, program);
7137 //----------------------------------------------------------------------------------------------------------------------
7138 // renderbuffer shadowing
7139 //----------------------------------------------------------------------------------------------------------------------
7140 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenRenderbuffers(e, c, rt, r, nu, ne, a, p) \
7142 pContext->peek_and_record_gl_error();
7143 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenRenderbuffers(e, c, rt, r, nu, ne, a, p) \
7144 if (pContext && !pContext->peek_and_record_gl_error()) \
7145 pContext->gen_render_buffers(n, renderbuffers);
7147 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenRenderbuffersEXT(e, c, rt, r, nu, ne, a, p) \
7149 pContext->peek_and_record_gl_error();
7150 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenRenderbuffersEXT(e, c, rt, r, nu, ne, a, p) \
7151 if (pContext && !pContext->peek_and_record_gl_error()) \
7152 pContext->gen_render_buffers(n, renderbuffers);
7154 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteRenderbuffers(e, c, rt, r, nu, ne, a, p) \
7156 pContext->peek_and_record_gl_error();
7157 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteRenderbuffers(e, c, rt, r, nu, ne, a, p) \
7158 if (pContext && !pContext->peek_and_record_gl_error()) \
7159 pContext->del_render_buffers(n, renderbuffers);
7161 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteRenderbuffersEXT(e, c, rt, r, nu, ne, a, p) \
7163 pContext->peek_and_record_gl_error();
7164 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteRenderbuffersEXT(e, c, rt, r, nu, ne, a, p) \
7165 if (pContext && !pContext->peek_and_record_gl_error()) \
7166 pContext->del_render_buffers(n, renderbuffers);
7167 //----------------------------------------------------------------------------------------------------------------------
7169 //----------------------------------------------------------------------------------------------------------------------
7170 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenBuffers(e, c, rt, r, nu, ne, a, p) \
7172 pContext->peek_and_record_gl_error();
7173 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenBuffers(e, c, rt, r, nu, ne, a, p) \
7174 if (pContext && !pContext->peek_and_record_gl_error()) \
7175 pContext->gen_buffers(n, buffers);
7177 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenBuffersARB(e, c, rt, r, nu, ne, a, p) \
7179 pContext->peek_and_record_gl_error();
7180 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenBuffersARB(e, c, rt, r, nu, ne, a, p) \
7181 if (pContext && !pContext->peek_and_record_gl_error()) \
7182 pContext->gen_buffers(n, buffers);
7184 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBuffer(e, c, rt, r, nu, ne, a, p) \
7186 pContext->peek_and_record_gl_error();
7187 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindBuffer(e, c, rt, r, nu, ne, a, p) \
7188 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7189 pContext->bind_buffer(target, buffer);
7191 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferBase(e, c, rt, r, nu, ne, a, p) \
7193 pContext->peek_and_record_gl_error();
7194 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindBufferBase(e, c, rt, r, nu, ne, a, p) \
7195 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7196 pContext->bind_buffer(target, buffer);
7198 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferBaseEXT(e, c, rt, r, nu, ne, a, p) \
7200 pContext->peek_and_record_gl_error();
7201 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindBufferBaseEXT(e, c, rt, r, nu, ne, a, p) \
7202 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7203 pContext->bind_buffer(target, buffer);
7205 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferBaseNV(e, c, rt, r, nu, ne, a, p) \
7207 pContext->peek_and_record_gl_error();
7208 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindBufferBaseNV(e, c, rt, r, nu, ne, a, p) \
7209 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7210 pContext->bind_buffer(target, buffer);
7212 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferRange(e, c, rt, r, nu, ne, a, p) \
7214 pContext->peek_and_record_gl_error();
7215 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindBufferRange(e, c, rt, r, nu, ne, a, p) \
7216 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7217 pContext->bind_buffer(target, buffer);
7219 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferRangeEXT(e, c, rt, r, nu, ne, a, p) \
7221 pContext->peek_and_record_gl_error();
7222 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindBufferRangeEXT(e, c, rt, r, nu, ne, a, p) \
7223 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7224 pContext->bind_buffer(target, buffer);
7226 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferRangeNV(e, c, rt, r, nu, ne, a, p) \
7228 pContext->peek_and_record_gl_error();
7229 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindBufferRangeNV(e, c, rt, r, nu, ne, a, p) \
7230 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7231 pContext->bind_buffer(target, buffer);
7233 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferARB(e, c, rt, r, nu, ne, a, p) \
7235 pContext->peek_and_record_gl_error();
7236 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindBufferARB(e, c, rt, r, nu, ne, a, p) \
7237 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7238 pContext->bind_buffer(target, buffer);
7240 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteBuffers(e, c, rt, r, nu, ne, a, p) \
7242 pContext->peek_and_record_gl_error();
7243 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteBuffers(e, c, rt, r, nu, ne, a, p) \
7244 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7245 pContext->delete_buffers(n, buffers);
7247 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteBuffersARB(e, c, rt, r, nu, ne, a, p) \
7249 pContext->peek_and_record_gl_error();
7250 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteBuffersARB(e, c, rt, r, nu, ne, a, p) \
7251 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7252 pContext->delete_buffers(n, buffers);
7254 //----------------------------------------------------------------------------------------------------------------------
7255 // Texture handle shadowing
7256 //----------------------------------------------------------------------------------------------------------------------
7257 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenTextures(e, c, rt, r, nu, ne, a, p) \
7259 pContext->peek_and_record_gl_error();
7260 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenTextures(e, c, rt, r, nu, ne, a, p) \
7261 if (pContext && !pContext->peek_and_record_gl_error()) \
7262 pContext->gen_textures(n, textures);
7264 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenTexturesEXT(e, c, rt, r, nu, ne, a, p) \
7266 pContext->peek_and_record_gl_error();
7267 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenTexturesEXT(e, c, rt, r, nu, ne, a, p) \
7268 if (pContext && !pContext->peek_and_record_gl_error()) \
7269 pContext->gen_textures(n, textures);
7271 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteTextures(e, c, rt, r, nu, ne, a, p) \
7273 pContext->peek_and_record_gl_error();
7274 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteTextures(e, c, rt, r, nu, ne, a, p) \
7275 if (pContext && !pContext->peek_and_record_gl_error()) \
7276 pContext->del_textures(n, textures);
7278 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteTexturesEXT(e, c, rt, r, nu, ne, a, p) \
7280 pContext->peek_and_record_gl_error();
7281 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteTexturesEXT(e, c, rt, r, nu, ne, a, p) \
7282 if (pContext && !pContext->peek_and_record_gl_error()) \
7283 pContext->del_textures(n, textures);
7285 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindTexture(e, c, rt, r, nu, ne, a, p) \
7287 pContext->peek_and_record_gl_error();
7288 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindTexture(e, c, rt, r, nu, ne, a, p) \
7289 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7290 pContext->bind_texture(target, texture);
7292 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindTextureEXT(e, c, rt, r, nu, ne, a, p) \
7294 pContext->peek_and_record_gl_error();
7295 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindTextureEXT(e, c, rt, r, nu, ne, a, p) \
7296 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7297 pContext->bind_texture(target, texture);
7299 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindMultiTextureEXT(e, c, rt, r, nu, ne, a, p) \
7301 pContext->peek_and_record_gl_error();
7302 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindMultiTextureEXT(e, c, rt, r, nu, ne, a, p) \
7303 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7304 pContext->bind_texture(target, texture);
7306 //----------------------------------------------------------------------------------------------------------------------
7307 // Framebuffer handle shadowing
7308 //----------------------------------------------------------------------------------------------------------------------
7309 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenFramebuffers(e, c, rt, r, nu, ne, a, p) \
7311 pContext->peek_and_record_gl_error();
7312 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenFramebuffers(e, c, rt, r, nu, ne, a, p) \
7313 if (pContext && !pContext->peek_and_record_gl_error()) \
7314 pContext->gen_framebuffers(n, framebuffers);
7316 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenFramebuffersEXT(e, c, rt, r, nu, ne, a, p) \
7318 pContext->peek_and_record_gl_error();
7319 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenFramebuffersEXT(e, c, rt, r, nu, ne, a, p) \
7320 if (pContext && !pContext->peek_and_record_gl_error()) \
7321 pContext->gen_framebuffers(n, framebuffers);
7323 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteFramebuffers(e, c, rt, r, nu, ne, a, p) \
7325 pContext->peek_and_record_gl_error();
7326 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteFramebuffers(e, c, rt, r, nu, ne, a, p) \
7327 if (pContext && !pContext->peek_and_record_gl_error()) \
7328 pContext->del_framebuffers(n, framebuffers);
7330 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteFramebuffersEXT(e, c, rt, r, nu, ne, a, p) \
7332 pContext->peek_and_record_gl_error();
7333 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteFramebuffersEXT(e, c, rt, r, nu, ne, a, p) \
7334 if (pContext && !pContext->peek_and_record_gl_error()) \
7335 pContext->del_framebuffers(n, framebuffers);
7337 //----------------------------------------------------------------------------------------------------------------------
7338 // VAO handle shadowing
7339 //----------------------------------------------------------------------------------------------------------------------
7340 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenVertexArrays(e, c, rt, r, nu, ne, a, p) \
7342 pContext->peek_and_record_gl_error();
7343 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenVertexArrays(e, c, rt, r, nu, ne, a, p) \
7344 if (pContext && !pContext->peek_and_record_gl_error()) \
7345 pContext->gen_vertexarrays(n, arrays);
7347 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteVertexArrays(e, c, rt, r, nu, ne, a, p) \
7349 pContext->peek_and_record_gl_error();
7350 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteVertexArrays(e, c, rt, r, nu, ne, a, p) \
7351 if (pContext && !pContext->peek_and_record_gl_error()) \
7352 pContext->del_vertexarrays(n, arrays);
7354 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindVertexArray(e, c, rt, r, nu, ne, a, p) \
7356 pContext->peek_and_record_gl_error();
7357 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindVertexArray(e, c, rt, r, nu, ne, a, p) \
7358 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7359 pContext->bind_vertexarray(array);
7361 //----------------------------------------------------------------------------------------------------------------------
7362 // Sync handle shadowing
7363 //----------------------------------------------------------------------------------------------------------------------
7364 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glFenceSync(e, c, rt, r, nu, ne, a, p) \
7366 pContext->peek_and_record_gl_error();
7367 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glFenceSync(e, c, rt, r, nu, ne, a, p) \
7368 if (pContext && !pContext->peek_and_record_gl_error()) \
7369 pContext->gen_sync(result);
7371 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteSync(e, c, rt, r, nu, ne, a, p) \
7373 pContext->peek_and_record_gl_error();
7374 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteSync(e, c, rt, r, nu, ne, a, p) \
7375 if (pContext && !pContext->peek_and_record_gl_error()) \
7376 pContext->del_sync(sync);
7378 //----------------------------------------------------------------------------------------------------------------------
7379 // Sampler object handle shadowing
7380 //----------------------------------------------------------------------------------------------------------------------
7381 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenSamplers(e, c, rt, r, nu, ne, a, p) \
7383 pContext->peek_and_record_gl_error();
7384 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenSamplers(e, c, rt, r, nu, ne, a, p) \
7385 if (pContext && !pContext->peek_and_record_gl_error()) \
7386 pContext->gen_samplers(count, samplers);
7388 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteSamplers(e, c, rt, r, nu, ne, a, p) \
7390 pContext->peek_and_record_gl_error();
7391 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteSamplers(e, c, rt, r, nu, ne, a, p) \
7392 if (pContext && !pContext->peek_and_record_gl_error()) \
7393 pContext->del_samplers(count, samplers);
7395 //----------------------------------------------------------------------------------------------------------------------
7396 // Query handle shadowing
7397 //----------------------------------------------------------------------------------------------------------------------
7398 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenQueries(e, c, rt, r, nu, ne, a, p) \
7400 pContext->peek_and_record_gl_error();
7401 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenQueries(e, c, rt, r, nu, ne, a, p) \
7402 if (pContext && !pContext->peek_and_record_gl_error()) \
7403 pContext->gen_queries(n, ids);
7405 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenQueriesARB(e, c, rt, r, nu, ne, a, p) \
7407 pContext->peek_and_record_gl_error();
7408 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenQueriesARB(e, c, rt, r, nu, ne, a, p) \
7409 if (pContext && !pContext->peek_and_record_gl_error()) \
7410 pContext->gen_queries(n, ids);
7412 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteQueries(e, c, rt, r, nu, ne, a, p) \
7414 pContext->peek_and_record_gl_error();
7415 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteQueries(e, c, rt, r, nu, ne, a, p) \
7416 if (pContext && !pContext->peek_and_record_gl_error()) \
7417 pContext->del_queries(n, ids);
7419 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteQueriesARB(e, c, rt, r, nu, ne, a, p) \
7421 pContext->peek_and_record_gl_error();
7422 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteQueriesARB(e, c, rt, r, nu, ne, a, p) \
7423 if (pContext && !pContext->peek_and_record_gl_error()) \
7424 pContext->del_queries(n, ids);
7426 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBeginQuery(e, c, rt, r, nu, ne, a, p) \
7428 pContext->peek_and_record_gl_error();
7429 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBeginQuery(e, c, rt, r, nu, ne, a, p) \
7430 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7431 pContext->begin_query(target, id);
7433 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBeginQueryARB(e, c, rt, r, nu, ne, a, p) \
7435 pContext->peek_and_record_gl_error();
7436 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBeginQueryARB(e, c, rt, r, nu, ne, a, p) \
7437 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7438 pContext->begin_query(target, id);
7440 //----------------------------------------------------------------------------------------------------------------------
7441 // Display list shadowing
7442 //----------------------------------------------------------------------------------------------------------------------
7443 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenLists(e, c, rt, r, nu, ne, a, p) \
7445 pContext->peek_and_record_gl_error();
7446 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenLists(e, c, rt, r, nu, ne, a, p) \
7447 if (pContext && !pContext->peek_and_record_gl_error()) \
7448 pContext->gen_lists(result, range);
7450 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteLists(e, c, rt, r, nu, ne, a, p) \
7452 pContext->peek_and_record_gl_error();
7453 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteLists(e, c, rt, r, nu, ne, a, p) \
7454 if (pContext && !pContext->peek_and_record_gl_error()) \
7455 pContext->del_lists(list, range);
7457 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glNewList(e, c, rt, r, nu, ne, a, p) \
7459 pContext->peek_and_record_gl_error();
7460 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glNewList(e, c, rt, r, nu, ne, a, p) \
7461 if (pContext && !pContext->peek_and_record_gl_error()) \
7462 pContext->new_list(list, mode);
7464 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glEndList(e, c, rt, r, nu, ne, a, p) \
7466 pContext->peek_and_record_gl_error();
7467 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glEndList(e, c, rt, r, nu, ne, a, p) \
7468 if (pContext && !pContext->peek_and_record_gl_error()) \
7469 pContext->end_list();
7471 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glXUseXFont(e, c, rt, r, nu, ne, a, p) \
7473 pContext->peek_and_record_gl_error();
7475 //----------------------------------------------------------------------------------------------------------------------
7476 // glBegin/glEnd shadowing
7477 //----------------------------------------------------------------------------------------------------------------------
7478 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBegin(e, c, rt, r, nu, ne, a, p) \
7480 pContext->peek_and_record_gl_error();
7481 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBegin(e, c, rt, r, nu, ne, a, p) \
7483 pContext->set_in_gl_begin(true);
7485 //#define DEF_FUNCTION_CUSTOM_GL_PROLOG_glEnd(e, c, rt, r, nu, ne, a, p)
7486 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glEnd(e, c, rt, r, nu, ne, a, p) \
7488 pContext->set_in_gl_begin(false);
7490 //----------------------------------------------------------------------------------------------------------------------
7491 // Program/shader shadowing
7492 //----------------------------------------------------------------------------------------------------------------------
7493 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glCreateProgram(e, c, rt, r, nu, ne, a, p) \
7495 result = pContext->handle_create_program(VOGL_ENTRYPOINT_##ne); \
7498 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glCreateProgramObjectARB(e, c, rt, r, nu, ne, a, p) \
7500 result = pContext->handle_create_program(VOGL_ENTRYPOINT_##ne); \
7504 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glCreateShader(e, c, rt, r, nu, ne, a, p) \
7506 result = pContext->handle_create_shader(VOGL_ENTRYPOINT_##ne, type); \
7509 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glCreateShaderObjectARB(e, c, rt, r, nu, ne, a, p) \
7511 result = pContext->handle_create_shader(VOGL_ENTRYPOINT_##ne, shaderType); \
7515 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glUseProgram(e, c, rt, r, nu, ne, a, p) \
7517 pContext->handle_use_program(VOGL_ENTRYPOINT_##ne, program);
7518 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glUseProgramObjectARB(e, c, rt, r, nu, ne, a, p) \
7520 pContext->handle_use_program(VOGL_ENTRYPOINT_##ne, programObj);
7522 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glDeleteShader(e, c, rt, r, nu, ne, a, p) \
7524 pContext->handle_del_shader(VOGL_ENTRYPOINT_##ne, shader);
7525 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glDeleteProgram(e, c, rt, r, nu, ne, a, p) \
7527 pContext->handle_del_program(VOGL_ENTRYPOINT_##ne, program);
7528 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glDeleteObjectARB(e, c, rt, r, nu, ne, a, p) \
7530 pContext->handle_del_object(VOGL_ENTRYPOINT_##ne, obj);
7532 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glDetachShader(e, c, rt, r, nu, ne, a, p) \
7534 pContext->handle_detach_shader(VOGL_ENTRYPOINT_##ne, program, shader);
7535 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glDetachObjectARB(e, c, rt, r, nu, ne, a, p) \
7537 pContext->handle_detach_shader(VOGL_ENTRYPOINT_##ne, containerObj, attachedObj);
7539 //----------------------------------------------------------------------------------------------------------------------
7540 // Client side array usage detection
7541 //----------------------------------------------------------------------------------------------------------------------
7542 #define VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE \
7543 if ((!g_disable_client_side_array_tracing) && (pContext) && (pointer)) \
7544 vogl_check_for_client_side_array_usage(pContext, pointer);
7545 static inline void vogl_check_for_client_side_array_usage(vogl_context *pContext, const void *pPointer)
7547 VOGL_NOTE_UNUSED(pPointer);
7549 if (pContext->get_uses_client_side_arrays() || pContext->is_core_profile())
7552 pContext->peek_and_record_gl_error();
7554 GLint cur_array_buf_binding = 0;
7555 GL_ENTRYPOINT(glGetIntegerv)(GL_ARRAY_BUFFER_BINDING, &cur_array_buf_binding);
7557 if (pContext->peek_and_drop_gl_error() == GL_NO_ERROR)
7559 if (!cur_array_buf_binding)
7561 pContext->set_uses_client_side_arrays(true);
7562 vogl_warning_printf("%s: Client side array usage has been detected, this will negatively impact tracing performance, use --vogl_disable_client_side_array_tracing to disable\n", VOGL_FUNCTION_NAME);
7567 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7568 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glNormalPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7569 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glColorPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7570 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glIndexPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7571 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glTexCoordPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7572 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glEdgeFlagPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7573 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glFogCoordPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7574 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glSecondaryColorPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7575 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glInterleavedArrays(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7576 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7577 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glNormalPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7578 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glColorPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7579 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glIndexPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7580 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glTexCoordPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7581 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glEdgeFlagPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7582 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glFogCoordPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7583 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glSecondaryColorPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7584 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexAttribPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7585 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexAttribPointerARB(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7586 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexAttribPointerNV(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7587 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexAttribIPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7588 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexAttribIPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7589 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexAttribLPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7590 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexAttribLPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7592 //----------------------------------------------------------------------------------------------------------------------
7593 // glXUseXFont shadowing
7594 //----------------------------------------------------------------------------------------------------------------------
7595 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glXUseXFont(e, c, rt, r, nu, ne, a, p) vogl_glx_use_xfont_epilog_helper(pContext, trace_serializer, font, first, count, list_base);
7596 static void vogl_glx_use_xfont_epilog_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, Font font, int first, int count, int list_base)
7601 if (pContext->peek_and_record_gl_error())
7606 if (pContext->get_display())
7608 XFontStruct *pFont_struct = XQueryFont((Display *)pContext->get_display(), font);
7612 unsigned long value = 0;
7613 Bool result = XGetFontProperty(pFont_struct, XA_FONT, &value);
7616 pFont = (char *)XGetAtomName((Display *)pContext->get_display(), (Atom)value);
7617 if ((pFont) && (trace_serializer.is_in_begin()))
7619 trace_serializer.add_key_value("font_name", pFont);
7624 XFreeFontInfo(NULL, pFont_struct, 1);
7627 pContext->glx_font(pFont, first, count, list_base);
7630 //----------------------------------------------------------------------------------------------------------------------
7631 // vogl_display_list_bind_callback
7632 //----------------------------------------------------------------------------------------------------------------------
7633 static void vogl_display_list_bind_callback(vogl_namespace_t handle_namespace, GLenum target, GLuint handle, void *pOpaque)
7635 vogl_context *pContext = static_cast<vogl_context *>(pOpaque);
7637 // TODO: We don't whitelist anything but texture binds in display lists currently.
7638 switch (handle_namespace)
7640 case VOGL_NAMESPACE_TEXTURES:
7642 if ((handle) && (target != GL_NONE))
7643 pContext->bind_texture_conditionally(target, handle);
7648 vogl_warning_printf("%s: TODO: Unsupported bind in display list, namespace %s target %s handle %u\n", VOGL_FUNCTION_NAME, vogl_get_namespace_name(handle_namespace), g_gl_enums.find_gl_name(target), handle);
7654 //----------------------------------------------------------------------------------------------------------------------
7655 // glCallList shadowing
7656 //----------------------------------------------------------------------------------------------------------------------
7657 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glCallList(e, c, rt, r, nu, ne, a, p) \
7659 pContext->peek_and_record_gl_error();
7660 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glCallList(e, c, rt, r, nu, ne, a, p) \
7661 if (pContext && !pContext->peek_and_record_gl_error()) \
7662 vogl_gl_call_list_helper(pContext, list);
7663 static void vogl_gl_call_list_helper(vogl_context *pContext, GLuint list)
7668 pContext->parse_list_and_update_shadows(list, vogl_display_list_bind_callback, pContext);
7671 //----------------------------------------------------------------------------------------------------------------------
7672 // glCallLists shadowing
7673 //----------------------------------------------------------------------------------------------------------------------
7674 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glCallLists(e, c, rt, r, nu, ne, a, p) \
7676 pContext->peek_and_record_gl_error();
7677 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glCallLists(e, c, rt, r, nu, ne, a, p) \
7678 if (pContext && !pContext->peek_and_record_gl_error()) \
7679 vogl_gl_call_lists_helper(pContext, n, type, lists);
7680 static void vogl_gl_call_lists_helper(vogl_context *pContext, GLsizei n, GLenum type, const GLvoid *lists)
7685 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
7686 VOGL_NOTE_UNUSED(gl_error_absorber);
7688 pContext->parse_lists_and_update_shadows(n, type, lists, vogl_display_list_bind_callback, pContext);
7691 //----------------------------------------------------------------------------------------------------------------------
7692 // Ensure all entrypoints are fully serializable
7693 // This function MUST appear before #include "gl_glx_array_size_macros.inc", below
7694 //----------------------------------------------------------------------------------------------------------------------
7695 static void vogl_check_entrypoints()
7697 vogl_debug_printf("vogl_check_entrypoints: begin (specify --vogl_debug for more validation)\n");
7699 typedef vogl::hash_map<uint, dynamic_string> array_size_macro_hashmap;
7700 array_size_macro_hashmap defined_array_size_macros;
7701 array_size_macro_hashmap undefined_array_size_macros;
7703 #define CUSTOM_FUNC_HANDLER_DEFINED(id) g_vogl_entrypoint_descs[id].m_has_custom_func_handler = true; //printf("%u %s\n", id, g_vogl_entrypoint_descs[id].m_pName);
7704 #define CUSTOM_FUNC_HANDLER_NOT_DEFINED(id)
7705 #include "gl_glx_custom_func_handler_validator.inc"
7706 #undef CUSTOM_FUNC_HANDLER_DEFINED
7707 #undef CUSTOM_FUNC_HANDLER_NOT_DEFINED
7709 #define VALIDATE_ARRAY_SIZE_MACRO_DEFINED(name, index) defined_array_size_macros.insert(index, #name);
7710 #define VALIDATE_ARRAY_SIZE_MACRO_NOT_DEFINED(name, index) undefined_array_size_macros.insert(index, #name);
7711 #include "gl_glx_array_size_macros_validator.inc"
7712 #undef VALIDATE_ARRAY_SIZE_MACRO_DEFINED
7713 #undef VALIDATE_ARRAY_SIZE_MACRO_NOT_DEFINED
7715 vogl::vector<uint> undefined_func_return_array_size_macros;
7717 #define CUSTOM_FUNC_RETURN_PARAM_ARRAY_SIZE_HANDLER_DEFINED(macro_name, func_name)
7718 #define CUSTOM_FUNC_RETURN_PARAM_ARRAY_SIZE_HANDLER_NOT_DEFINED(macro_name, func_name) g_vogl_entrypoint_descs[VOGL_ENTRYPOINT_##func_name].m_custom_return_param_array_size_macro_is_missing = true;
7719 #include "gl_glx_custom_return_param_array_size_macro_validator.inc"
7720 #undef CUSTOM_FUNC_RETURN_PARAM_ARRAY_SIZE_HANDLER_DEFINED
7721 #undef CUSTOM_FUNC_RETURN_PARAM_ARRAY_SIZE_HANDLER_NOT_DEFINED
7723 if (vogl::check_for_command_line_param("--vogl_debug"))
7725 for (array_size_macro_hashmap::const_iterator it = undefined_array_size_macros.begin(); it != undefined_array_size_macros.end(); ++it)
7727 uint idx = it->first;
7728 const dynamic_string &name = it->second;
7729 VOGL_NOTE_UNUSED(name);
7731 gl_entrypoint_id_t func = static_cast<gl_entrypoint_id_t>(idx >> 16);
7732 uint param = idx & 0xFFFF;
7734 vogl_warning_printf("%s: Custom array size macro for func %u \"%s\" param %u has not been defined, this function cannot be traced\n",
7735 VOGL_FUNCTION_NAME, func, g_vogl_entrypoint_descs[func].m_pName, param);
7737 g_vogl_entrypoint_param_descs[func][param].m_custom_array_size_macro_is_missing = true;
7738 g_vogl_entrypoint_descs[func].m_custom_array_size_macro_is_missing = true;
7741 vogl_debug_printf("Undefined array size macros:\n");
7742 vogl_debug_printf("---\n");
7743 for (array_size_macro_hashmap::const_iterator it = undefined_array_size_macros.begin(); it != undefined_array_size_macros.end(); ++it)
7745 const dynamic_string &name = it->second;
7746 vogl_debug_printf("%s\n", name.get_ptr());
7748 vogl_debug_printf("---\n");
7750 vogl_debug_printf("Undefined return param array size macros:\n");
7751 vogl_debug_printf("---\n");
7752 for (uint i = 0; i < VOGL_NUM_ENTRYPOINTS; i++)
7754 vogl_ctype_t return_ctype = g_vogl_entrypoint_descs[i].m_return_ctype;
7756 if (return_ctype == VOGL_VOID)
7758 if (!g_vogl_process_gl_ctypes[return_ctype].m_is_pointer)
7760 //if (g_vogl_process_gl_ctypes[return_ctype].m_is_opaque_pointer)
7763 if (g_vogl_entrypoint_descs[i].m_custom_return_param_array_size_macro_is_missing)
7765 vogl_debug_printf("%s, opaque_ptr: %u\n", g_vogl_entrypoint_descs[i].m_pName, g_vogl_process_gl_ctypes[return_ctype].m_is_opaque_pointer);
7768 if (g_vogl_entrypoint_descs[i].m_whitelisted_for_displaylists)
7770 if (!g_vogl_entrypoint_descs[i].m_is_listable)
7772 vogl_debug_printf("Function %s is marked as whitelistable in display lists, but is not a listable function!\n", g_vogl_entrypoint_descs[i].m_pName);
7776 vogl_debug_printf("---\n");
7778 vogl_debug_printf("Whitelisted funcs with undefined array size macros:\n");
7779 vogl_debug_printf("---\n");
7780 for (uint i = 0; i < VOGL_NUM_ENTRYPOINTS; i++)
7782 const gl_entrypoint_desc_t &desc = g_vogl_entrypoint_descs[i];
7783 if ((!desc.m_is_whitelisted) || (desc.m_has_custom_func_handler))
7786 if (desc.m_custom_array_size_macro_is_missing)
7787 vogl_debug_printf("%s\n", desc.m_pName);
7789 vogl_debug_printf("---\n");
7791 vogl_debug_printf("Whitelisted funcs with undefined return param array size macros:\n");
7792 vogl_debug_printf("---\n");
7793 for (uint i = 0; i < VOGL_NUM_ENTRYPOINTS; i++)
7795 const gl_entrypoint_desc_t &desc = g_vogl_entrypoint_descs[i];
7796 if (desc.m_is_whitelisted)
7799 vogl_ctype_t return_ctype = g_vogl_entrypoint_descs[i].m_return_ctype;
7801 if (return_ctype == VOGL_VOID)
7803 if (!g_vogl_process_gl_ctypes[return_ctype].m_is_pointer)
7805 if (g_vogl_process_gl_ctypes[return_ctype].m_is_opaque_pointer)
7808 if (g_vogl_entrypoint_descs[i].m_custom_return_param_array_size_macro_is_missing)
7810 vogl_debug_printf("%s\n", g_vogl_entrypoint_descs[i].m_pName);
7814 vogl_debug_printf("---\n");
7817 vogl_debug_printf("vogl_check_entrypoints: done\n");
7820 //----------------------------------------------------------------------------------------------------------------------
7821 // Include generated macros to define the internal entrypoint funcs
7822 //----------------------------------------------------------------------------------------------------------------------
7823 #include "gl_glx_array_size_macros.inc"
7824 #include "gl_glx_func_return_param_array_size_macros.inc"
7825 #include "gl_glx_func_defs.inc"
7827 #ifndef NO_PUBLIC_EXPORTS
7828 //----------------------------------------------------------------------------------------------------------------------
7829 // Declare exported gl/glx functions (each exported func immediately calls one of the internal vogl_* functions)
7830 //----------------------------------------------------------------------------------------------------------------------
7831 #define DEF_PROTO_EXPORTED(ret, name, args, params) \
7832 VOGL_API_EXPORT ret name args \
7834 return VOGL_GLUER(vogl_, name) params; \
7836 #define DEF_PROTO_EXPORTED_VOID(ret, name, args, params) \
7837 VOGL_API_EXPORT ret name args \
7839 VOGL_GLUER(vogl_, name) params; \
7841 #define DEF_PROTO_INTERNAL(ret, name, args, params)
7842 #define DEF_PROTO_INTERNAL_VOID(ret, name, args, params)
7843 #define DEF_FUNCTION_BEGIN(exported, category, ret, ret_type_enum, num_params, name, args, params) exported(ret, name, args, params)
7844 #define DEF_FUNCTION_BEGIN_VOID(exported, category, ret, ret_type_enum, num_params, name, args, params) exported(ret, name, args, params)
7845 #define DEF_FUNCTION_INIT(exported, category, ret, ret_type_enum, num_params, name, args, params)
7846 #define DEF_FUNCTION_INIT_VOID(exported, category, ret, ret_type_enum, num_params, name, args, params)
7847 #define DEF_FUNCTION_INPUT_VALUE_PARAM(idx, spectype, type, type_enum, param)
7848 #define DEF_FUNCTION_INPUT_REFERENCE_PARAM(idx, spectype, type, type_enum, param)
7849 #define DEF_FUNCTION_INPUT_ARRAY_PARAM(idx, spectype, type, type_enum, param, size)
7850 #define DEF_FUNCTION_OUTPUT_REFERENCE_PARAM(idx, spectype, type, type_enum, param)
7851 #define DEF_FUNCTION_OUTPUT_ARRAY_PARAM(idx, spectype, type, type_enum, param, size)
7852 #define DEF_FUNCTION_RETURN_PARAM(spectype, type, type_enum, size)
7853 #define DEF_FUNCTION_CALL_GL(exported, category, ret, ret_type_enum, num_params, name, args, params)
7854 #define DEF_FUNCTION_CALL_GL_VOID(exported, category, ret, ret_type_enum, num_params, name, args, params)
7855 #define DEF_FUNCTION_END(exported, category, ret, ret_type_enum, num_params, name, args, params)
7856 #define DEF_FUNCTION_END_VOID(exported, category, ret, ret_type_enum, num_params, name, args, params)
7857 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_GL_ENUM(pname) -1
7859 #include "gl_glx_array_size_macros.inc"
7860 #include "gl_glx_func_defs.inc"
7863 //----------------------------------------------------------------------------------------------------------------------
7864 // Define our exported gliGetProcAddressRAD function
7865 //----------------------------------------------------------------------------------------------------------------------
7866 VOGL_API_EXPORT __GLXextFuncPtr gliGetProcAddressRAD(const GLubyte *procName)
7868 if ((procName) && (!vogl_strcmp(reinterpret_cast<const char *>(procName), "gliGetProcAddressRAD")))
7869 return (__GLXextFuncPtr)gliGetProcAddressRAD;
7871 return vogl_glXGetProcAddressARB(procName);
7874 //----------------------------------------------------------------------------------------------------------------------
7875 // Determine addresses of our gl/glx wrapper functions
7876 //----------------------------------------------------------------------------------------------------------------------
7877 static void vogl_init_wrapper_func_ptrs()
7879 gl_entrypoint_desc_t *pDst = g_vogl_entrypoint_descs;
7881 #define DEF_PROTO(exported, category, ret, ret_type, num_params, name, args, params) \
7882 pDst->m_pWrapper_func = reinterpret_cast<vogl_void_func_ptr_t>(vogl_##name); \
7884 #define DEF_PROTO_VOID(exported, category, ret, ret_type, num_params, name, args, params) \
7885 pDst->m_pWrapper_func = reinterpret_cast<vogl_void_func_ptr_t>(vogl_##name); \
7887 #include "gl_glx_protos.inc"
7889 #undef DEF_PROTO_VOID
7892 //----------------------------------------------------------------------------------------------------------------------
7893 // vogl_direct_gl_func_prolog - This function is called before EVERY single GL/GLX function call we make.
7894 //----------------------------------------------------------------------------------------------------------------------
7895 static void vogl_direct_gl_func_prolog(gl_entrypoint_id_t entrypoint_id, void *pUser_data, void **ppStack_data)
7897 VOGL_NOTE_UNUSED(entrypoint_id);
7898 VOGL_NOTE_UNUSED(pUser_data);
7900 if (g_dump_gl_calls_flag)
7901 printf("** GLPROLOG %s\n", g_vogl_entrypoint_descs[entrypoint_id].m_pName);
7903 gl_entrypoint_id_t *pPrev_state = reinterpret_cast<gl_entrypoint_id_t *>(ppStack_data);
7904 *pPrev_state = VOGL_ENTRYPOINT_INVALID;
7906 vogl_thread_local_data *pTLS_data = vogl_get_or_create_thread_local_data();
7909 *pPrev_state = pTLS_data->m_calling_driver_entrypoint_id;
7910 pTLS_data->m_calling_driver_entrypoint_id = entrypoint_id;
7914 //----------------------------------------------------------------------------------------------------------------------
7915 // vogl_direct_gl_func_epilog - This function is called immediately after EVERY single GL/GLX function call we make.
7916 //----------------------------------------------------------------------------------------------------------------------
7917 static void vogl_direct_gl_func_epilog(gl_entrypoint_id_t entrypoint_id, void *pUser_data, void **ppStack_data)
7919 VOGL_NOTE_UNUSED(entrypoint_id);
7920 VOGL_NOTE_UNUSED(pUser_data);
7923 if (entrypoint_id == VOGL_ENTRYPOINT_glXMakeCurrent)
7925 // HACK HACK - crude test of the "calling driver entrypoint code"
7926 glXGetCurrentContext();
7930 if (g_dump_gl_calls_flag)
7931 printf("** GLEPILOG %s\n", g_vogl_entrypoint_descs[entrypoint_id].m_pName);
7933 gl_entrypoint_id_t *pPrev_state = reinterpret_cast<gl_entrypoint_id_t *>(ppStack_data);
7935 vogl_thread_local_data *pTLS_data = vogl_get_or_create_thread_local_data();
7938 pTLS_data->m_calling_driver_entrypoint_id = *pPrev_state;
7942 //----------------------------------------------------------------------------------------------------------------------
7944 // Note: Be VERY careful what you do in here! It's called very early during init (long before main, during c++ init)
7945 //----------------------------------------------------------------------------------------------------------------------
7946 void vogl_early_init()
7948 vogl_init_thread_local_data();
7950 vogl_set_direct_gl_func_prolog(vogl_direct_gl_func_prolog, NULL);
7951 vogl_set_direct_gl_func_epilog(vogl_direct_gl_func_epilog, NULL);
7953 vogl_init_wrapper_func_ptrs();
7955 vogl_check_entrypoints();