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();
1246 inline GLuint get_max_texture_units() const
1248 return m_context_info.get_max_texture_units();
1251 const vogl_context_desc &get_context_desc() const
1253 return m_context_desc;
1255 const vogl_context_info &get_context_info() const
1257 return m_context_info;
1260 const vogl_capture_context_params &get_capture_context_params() const
1262 return m_capture_context_params;
1264 vogl_capture_context_params &get_capture_context_params()
1266 return m_capture_context_params;
1269 const vogl_framebuffer_capturer &get_framebuffer_capturer() const
1271 return m_framebuffer_capturer;
1273 vogl_framebuffer_capturer &get_framebuffer_capturer()
1275 return m_framebuffer_capturer;
1278 inline void on_make_current()
1280 set_current_thread(vogl_get_current_kernel_thread_id());
1282 if (!m_has_been_made_current)
1284 vogl_scoped_gl_error_absorber gl_error_absorber(this);
1285 VOGL_NOTE_UNUSED(gl_error_absorber);
1287 m_max_vertex_attribs = vogl_get_gl_integer(GL_MAX_VERTEX_ATTRIBS);
1288 if (m_max_vertex_attribs > VOGL_MAX_SUPPORTED_GL_VERTEX_ATTRIBUTES)
1290 vogl_error_printf("%s: GL_MAX_VERTEX_ATTRIBS is larger than supported (%u, max supported is %u), trace may not contain all client side vertex attribs\n", VOGL_METHOD_NAME, m_max_vertex_attribs, VOGL_MAX_SUPPORTED_GL_VERTEX_ATTRIBUTES);
1291 m_max_vertex_attribs = VOGL_MAX_SUPPORTED_GL_VERTEX_ATTRIBUTES;
1294 if (!m_context_info.init(m_context_desc))
1296 vogl_error_printf("%s: Failed initializing m_context_info!\n", VOGL_METHOD_NAME);
1299 if (!m_has_been_made_current)
1301 on_first_make_current();
1304 m_has_been_made_current = true;
1308 bool is_context_current()
1310 if (!GL_ENTRYPOINT(glXGetCurrentContext))
1313 // Double check that the context that we think is current is actually current.
1314 GLXContext cur_context = GL_ENTRYPOINT(glXGetCurrentContext)();
1317 VOGL_ASSERT(!m_current_thread);
1321 if (get_context_handle() != cur_context)
1323 VOGL_ASSERT(!m_current_thread);
1327 VOGL_ASSERT(vogl_get_current_kernel_thread_id() == m_current_thread);
1332 // This will be called with the context made current, however the TLS struct won't indicate that this context is current, and m_current_thread will not reflect this either!
1333 // Note this will be called before glXMakeCurrent() when contexts are switching, and it's possible the call could fail (and this context could remain current). So don't do anything drastic here.
1334 void on_release_current_prolog()
1336 if (!is_context_current())
1339 peek_and_record_gl_error();
1341 m_framebuffer_capturer.flush();
1343 peek_and_drop_gl_error();
1346 void on_release_current_epilog()
1348 set_current_thread(0);
1351 void on_destroy_prolog()
1353 if (!is_context_current())
1355 m_framebuffer_capturer.deinit(false);
1359 peek_and_record_gl_error();
1361 m_framebuffer_capturer.deinit(true);
1363 peek_and_drop_gl_error();
1366 // buffer handle and target shadowing
1367 void gen_buffers(GLsizei n, GLuint *pIDs)
1372 vogl_scoped_context_shadow_lock lock;
1374 for (GLsizei i = 0; i < n; i++)
1376 GLuint id = pIDs[i];
1379 if (!get_shared_state()->m_capture_context_params.m_buffer_targets.insert(id, GL_NONE).second)
1381 vogl_error_printf("%s: Can't insert buffer handle 0x%04X into buffer target map!\n", VOGL_METHOD_NAME, id);
1387 void bind_buffer(GLenum target, GLuint id)
1392 vogl_scoped_context_shadow_lock lock;
1394 GLenum *pTarget = get_shared_state()->m_capture_context_params.m_buffer_targets.find_value(id);
1397 vogl_error_printf("%s: Unable to find buffer handle 0x%04X in buffer target map!\n", VOGL_METHOD_NAME, id);
1401 if (*pTarget == GL_NONE)
1403 // This is the first bind, so record the target. Otherwise they are rebinding to a different target, which shouldn't matter to us for snapshotting purposes (right??).
1408 void delete_buffers(GLsizei n, const GLuint *buffers)
1410 if ((!n) || (!buffers))
1413 vogl_scoped_context_shadow_lock lock;
1415 for (GLsizei i = 0; i < n; i++)
1417 GLuint buffer = buffers[i];
1421 get_shared_state()->m_buffer_descs.erase(buffer);
1423 if (!get_shared_state()->m_capture_context_params.m_buffer_targets.erase(buffer))
1425 vogl_error_printf("%s: Can't erase buffer handle 0x%04X from buffer target map!\n", VOGL_METHOD_NAME, buffer);
1430 inline gl_buffer_desc &get_or_create_buffer_desc(GLuint handle)
1432 vogl_scoped_context_shadow_lock lock;
1434 gl_buffer_desc_map::iterator buf_it(get_shared_state()->m_buffer_descs.find(handle));
1435 if (buf_it != get_shared_state()->m_buffer_descs.end())
1436 return buf_it->second;
1438 gl_buffer_desc desc(handle);
1439 return (get_shared_state()->m_buffer_descs.insert(handle, desc).first)->second;
1442 inline uint get_total_mapped_buffers() const
1444 vogl_scoped_context_shadow_lock lock;
1447 for (gl_buffer_desc_map::const_iterator it = get_shared_state()->m_buffer_descs.begin(); it != get_shared_state()->m_buffer_descs.end(); ++it)
1449 if (it->second.m_pMap)
1455 inline void set_window_dimensions(int width, int height)
1457 m_window_width = width;
1458 m_window_height = height;
1461 inline int get_window_width() const
1463 return m_window_width;
1465 inline int get_window_height() const
1467 return m_window_height;
1470 uint64_t get_frame_index() const
1472 return m_frame_index;
1474 void set_frame_index(uint f)
1478 void inc_frame_index()
1483 GLuint get_cur_program() const
1485 return m_cur_program;
1487 void set_cur_program(GLuint program)
1489 m_cur_program = program;
1492 GLenum get_latched_gl_error() const
1494 return m_latched_gl_error;
1496 bool has_latched_gl_error() const
1498 return m_latched_gl_error != GL_NO_ERROR;
1500 void clear_latched_gl_error()
1502 m_latched_gl_error = GL_NO_ERROR;
1504 void set_latched_gl_error(GLenum err)
1506 m_latched_gl_error = err;
1509 // Returns the context's most recent GL error, NOT the currently latched error.
1510 GLenum peek_and_record_gl_error()
1515 GLenum gl_err = GL_ENTRYPOINT(glGetError)();
1517 if (gl_err != GL_NO_ERROR)
1519 if (!has_latched_gl_error())
1521 set_latched_gl_error(gl_err);
1523 vogl_warning_printf("%s: GL error %s occurred sometime before this function was called. This error has been latched by the tracer onto the tracer's context shadow struct. This error will be reported to the caller the next time glGetError() is called, and will mask any GL error returned by that future call.\n",
1524 VOGL_METHOD_NAME, g_gl_enums.find_gl_error_name(gl_err));
1528 vogl_warning_printf("%s: GL error %s occurred sometime before this function was called. The tracer already had a latched GL error of %s. This error will be suppressed by the tracer (because it would have been by GL itself if the tracer was not present).\n",
1529 VOGL_METHOD_NAME, g_gl_enums.find_gl_error_name(gl_err), g_gl_enums.find_gl_error_name(get_latched_gl_error()));
1536 // Gets and drops the current GL error (this is done to "hide" any errors we've introduced by tracing from the client app).
1537 // Be sure to retrieve and latch any client errors by calling peek_and_record_gl_error() first!
1538 GLenum peek_and_drop_gl_error()
1543 GLenum gl_err = GL_ENTRYPOINT(glGetError)();
1545 if (gl_err != GL_NO_ERROR)
1547 vogl_error_printf("%s: GL error %s occurred internally while libvogltrace was making GL calls. This GL error will not be seen by the client app (THIS SHOULD NOT HAPPEN)\n", VOGL_METHOD_NAME, g_gl_enums.find_gl_error_name(gl_err));
1553 // TODO: Modify each shadowing method to print detailed error messages
1554 // TODO: Move all these shadow methods right into vogl_capture_context_params
1556 // Texture handle shadowing
1557 void gen_textures(GLsizei n, GLuint *pTextures)
1562 vogl_scoped_context_shadow_lock lock;
1564 for (GLsizei i = 0; i < n; i++)
1566 GLuint handle = pTextures[i];
1569 if (!get_shared_state()->m_capture_context_params.m_textures.insert(handle, handle, GL_NONE))
1571 vogl_warning_printf("%s: Unable to add texture handle %u to texture handle shadow map!\n", VOGL_METHOD_NAME, handle);
1577 void del_textures(GLsizei n, const GLuint *pTextures)
1582 vogl_scoped_context_shadow_lock lock;
1584 for (GLsizei i = 0; i < n; i++)
1586 GLuint handle = pTextures[i];
1589 if (!get_shared_state()->m_capture_context_params.m_textures.erase(handle))
1591 vogl_warning_printf("%s: Failed erasing handle %u from texture handle shadow map!\n", VOGL_METHOD_NAME, handle);
1597 void bind_texture(GLenum target, GLuint texture)
1601 vogl_scoped_context_shadow_lock lock;
1603 get_shared_state()->m_capture_context_params.m_textures.update(texture, target);
1607 void bind_texture_conditionally(GLenum target, GLuint texture)
1611 vogl_scoped_context_shadow_lock lock;
1613 get_shared_state()->m_capture_context_params.m_textures.conditional_update(texture, GL_NONE, target);
1617 // Framebuffer handle shadowing
1618 void gen_framebuffers(GLsizei n, GLuint *pFramebuffers)
1622 for (GLsizei i = 0; i < n; i++)
1624 GLuint handle = pFramebuffers[i];
1626 get_context_state()->m_capture_context_params.m_framebuffers.insert(handle);
1630 void del_framebuffers(GLsizei n, const GLuint *pFramebuffers)
1634 for (GLsizei i = 0; i < n; i++)
1636 GLuint handle = pFramebuffers[i];
1638 get_context_state()->m_capture_context_params.m_framebuffers.erase(handle);
1642 // VAO handle shadowing
1643 void gen_vertexarrays(GLsizei n, GLuint *pArrays)
1647 for (GLsizei i = 0; i < n; i++)
1649 GLuint handle = pArrays[i];
1651 get_context_state()->m_capture_context_params.m_vaos.insert(handle);
1655 void del_vertexarrays(GLsizei n, const GLuint *pArrays)
1659 for (GLsizei i = 0; i < n; i++)
1661 GLuint handle = pArrays[i];
1663 get_context_state()->m_capture_context_params.m_vaos.erase(handle);
1667 void bind_vertexarray(GLuint array)
1670 get_context_state()->m_capture_context_params.m_vaos.insert(array);
1673 // sync handle shadowing
1674 void gen_sync(GLsync sync)
1678 vogl_scoped_context_shadow_lock lock;
1680 get_shared_state()->m_capture_context_params.m_syncs.insert((uint64_t)sync);
1684 void del_sync(GLsync sync)
1688 vogl_scoped_context_shadow_lock lock;
1690 get_shared_state()->m_capture_context_params.m_syncs.erase((uint64_t)sync);
1694 // sampler handle shadowing
1695 void gen_samplers(GLsizei n, const GLuint *pSamplers)
1700 vogl_scoped_context_shadow_lock lock;
1702 for (GLsizei i = 0; i < n; i++)
1704 GLuint handle = pSamplers[i];
1706 get_shared_state()->m_capture_context_params.m_samplers.insert(handle);
1710 void del_samplers(GLsizei n, const GLuint *pSamplers)
1715 vogl_scoped_context_shadow_lock lock;
1717 for (GLsizei i = 0; i < n; i++)
1719 GLuint handle = pSamplers[i];
1721 get_shared_state()->m_capture_context_params.m_samplers.erase(handle);
1725 // query handle and target shadowing
1726 void gen_queries(GLsizei n, GLuint *pIDs)
1731 vogl_scoped_context_shadow_lock lock;
1733 for (GLsizei i = 0; i < n; i++)
1735 GLuint id = pIDs[i];
1737 get_shared_state()->m_capture_context_params.m_query_targets.insert(id, GL_NONE);
1741 void del_queries(GLsizei n, const GLuint *pIDs)
1746 vogl_scoped_context_shadow_lock lock;
1748 for (GLsizei i = 0; i < n; i++)
1750 GLuint id = pIDs[i];
1752 get_shared_state()->m_capture_context_params.m_query_targets.erase(id);
1756 void begin_query(GLenum target, GLuint id)
1760 vogl_scoped_context_shadow_lock lock;
1762 if (get_shared_state()->m_capture_context_params.m_query_targets.contains(id))
1764 get_shared_state()->m_capture_context_params.m_query_targets[id] = target;
1768 vogl_error_printf("%s: Unable to find query target handle %u in query target handle shadow\n", VOGL_METHOD_NAME, id);
1774 void gen_arb_programs(GLsizei n, const GLuint *pHandles)
1779 vogl_scoped_context_shadow_lock lock;
1781 for (GLsizei i = 0; i < n; i++)
1783 GLuint handle = pHandles[i];
1785 get_shared_state()->m_capture_context_params.m_arb_program_targets.insert(handle, GL_NONE);
1789 void bind_arb_program(GLenum target, GLuint handle)
1793 vogl_scoped_context_shadow_lock lock;
1795 get_shared_state()->m_capture_context_params.m_arb_program_targets[handle] = target;
1799 void del_arb_programs(GLsizei n, const GLuint *pHandles)
1804 vogl_scoped_context_shadow_lock lock;
1806 for (GLsizei i = 0; i < n; i++)
1808 GLuint handle = pHandles[i];
1810 get_shared_state()->m_capture_context_params.m_arb_program_targets.erase(handle);
1814 // renderbuffer handle shadowing
1815 void gen_render_buffers(GLsizei n, GLuint *pIDs)
1820 vogl_scoped_context_shadow_lock lock;
1822 for (GLsizei i = 0; i < n; i++)
1824 GLuint id = pIDs[i];
1827 if (!get_shared_state()->m_capture_context_params.m_rbos.insert(id, id, GL_NONE))
1829 vogl_error_printf("%s: Can't insert render buffer handle 0x%04X into render buffer shadow!\n", VOGL_METHOD_NAME, id);
1835 void del_render_buffers(GLsizei n, const GLuint *buffers)
1837 if ((!n) || (!buffers))
1840 vogl_scoped_context_shadow_lock lock;
1842 for (GLsizei i = 0; i < n; i++)
1844 GLuint buffer = buffers[i];
1848 if (!get_shared_state()->m_capture_context_params.m_rbos.erase(buffer))
1850 vogl_error_printf("%s: Can't erase render buffer handle 0x%04X from render buffer shadow!\n", VOGL_METHOD_NAME, buffer);
1855 // program/shader shadowing
1856 GLuint handle_create_program(gl_entrypoint_id_t id)
1860 if (id == VOGL_ENTRYPOINT_glCreateProgram)
1861 handle = GL_ENTRYPOINT(glCreateProgram)();
1864 VOGL_ASSERT(id == VOGL_ENTRYPOINT_glCreateProgramObjectARB);
1865 handle = GL_ENTRYPOINT(glCreateProgramObjectARB)();
1868 vogl_scoped_context_shadow_lock lock;
1872 if (!get_shared_state()->m_capture_context_params.m_objs.update(handle, handle, VOGL_PROGRAM_OBJECT))
1873 vogl_error_printf("%s: Failed inserting program handle %u into object shadow!\n", VOGL_METHOD_NAME, handle);
1877 vogl_error_printf("%s: glCreateProgram/glCreateProgramObjectARB on handle %u failed!\n", VOGL_METHOD_NAME, handle);
1883 GLuint handle_create_shader(gl_entrypoint_id_t id, GLenum type)
1887 if (id == VOGL_ENTRYPOINT_glCreateShader)
1888 handle = GL_ENTRYPOINT(glCreateShader)(type);
1891 VOGL_ASSERT(id == VOGL_ENTRYPOINT_glCreateShaderObjectARB);
1892 handle = GL_ENTRYPOINT(glCreateShaderObjectARB)(type);
1895 vogl_scoped_context_shadow_lock lock;
1899 if (!get_shared_state()->m_capture_context_params.m_objs.update(handle, handle, VOGL_SHADER_OBJECT))
1900 vogl_error_printf("%s: Failed inserting shader handle %u into object shadow! (type=%s)\n", VOGL_METHOD_NAME, handle, g_gl_enums.find_gl_name(type));
1904 vogl_error_printf("%s: glCreateShader/glCreateShaderObjectARB on handle %u failed! (type=%s)\n", VOGL_METHOD_NAME, handle, g_gl_enums.find_gl_name(type));
1910 bool has_linked_program_snapshot(GLuint handle)
1912 vogl_scoped_context_shadow_lock lock;
1914 return get_shared_state()->m_capture_context_params.m_linked_programs.find_snapshot(handle) != NULL;
1917 bool add_linked_program_snapshot(GLuint handle, GLenum binary_format = GL_NONE, const void *pBinary = NULL, uint binary_size = 0)
1919 vogl_scoped_context_shadow_lock lock;
1921 return get_shared_state()->m_capture_context_params.m_linked_programs.add_snapshot(m_context_info, m_handle_remapper, handle, binary_format, pBinary, binary_size);
1924 void handle_use_program(gl_entrypoint_id_t id, GLuint program)
1926 // Note: This mixes ARB and non-ARB funcs. to probe around, which is evil.
1928 peek_and_record_gl_error();
1930 check_program_binding_shadow();
1932 vogl_scoped_context_shadow_lock lock;
1934 VOGL_ASSERT(!program || (get_shared_state()->m_capture_context_params.m_objs.get_target(program) == VOGL_PROGRAM_OBJECT));
1936 GLuint prev_program = m_cur_program;
1938 bool prev_is_program = false;
1939 GLint prev_is_marked_for_deletion = false;
1940 vogl::growable_array<GLuint, 8> prev_attached_replay_shaders;
1942 if ((prev_program) && (program != prev_program))
1944 prev_is_program = GL_ENTRYPOINT(glIsProgram)(prev_program);
1945 peek_and_drop_gl_error();
1947 if (prev_is_program)
1949 GL_ENTRYPOINT(glGetProgramiv)(prev_program, GL_DELETE_STATUS, &prev_is_marked_for_deletion);
1950 peek_and_drop_gl_error();
1952 if (prev_is_marked_for_deletion)
1954 // The currently bound program is marked for deletion, so record which shaders are attached to it in case the program is actually deleted by the driver on the UseProgram() call.
1955 GLint num_attached_shaders = 0;
1956 GL_ENTRYPOINT(glGetProgramiv)(prev_program, GL_ATTACHED_SHADERS, &num_attached_shaders);
1957 peek_and_drop_gl_error();
1959 if (num_attached_shaders)
1961 prev_attached_replay_shaders.resize(num_attached_shaders);
1963 GLsizei actual_count = 0;
1964 GL_ENTRYPOINT(glGetAttachedShaders)(prev_program, num_attached_shaders, &actual_count, prev_attached_replay_shaders.get_ptr());
1965 peek_and_drop_gl_error();
1967 VOGL_ASSERT(actual_count == num_attached_shaders);
1973 if (id == VOGL_ENTRYPOINT_glUseProgram)
1974 GL_ENTRYPOINT(glUseProgram)(program);
1977 VOGL_ASSERT(id == VOGL_ENTRYPOINT_glUseProgramObjectARB);
1978 GL_ENTRYPOINT(glUseProgramObjectARB)(program);
1981 GLenum gl_err = peek_and_record_gl_error();
1982 if (gl_err != GL_NO_ERROR)
1984 vogl_error_printf("%s: glUseProgram/glUseProgramObjectARB on handle %u returned GL error %s\n", VOGL_METHOD_NAME, program, g_gl_enums.find_gl_error_name(gl_err));
1988 if ((prev_program) && (prev_program != program))
1990 bool is_prev_still_program = GL_ENTRYPOINT(glIsProgram)(prev_program);
1991 if (!is_prev_still_program)
1993 VOGL_ASSERT(prev_is_program);
1994 VOGL_ASSERT(prev_is_marked_for_deletion);
1996 // The previously bound program is really dead now, kill it from our tables and also check up on any shaders it was attached to.
1997 bool was_deleted = get_shared_state()->m_capture_context_params.m_objs.erase(prev_program);
1998 VOGL_ASSERT(was_deleted);
1999 VOGL_NOTE_UNUSED(was_deleted);
2001 get_shared_state()->m_capture_context_params.m_linked_programs.remove_snapshot(prev_program);
2003 for (uint i = 0; i < prev_attached_replay_shaders.size(); i++)
2005 GLuint shader_handle = prev_attached_replay_shaders[i];
2007 bool is_still_shader = GL_ENTRYPOINT(glIsShader)(shader_handle);
2008 peek_and_drop_gl_error();
2010 if (is_still_shader)
2013 if (!get_shared_state()->m_capture_context_params.m_objs.contains(shader_handle))
2015 // We didn't create this shader handle, the AMD driver did on a program binary link, so ignore it.
2019 // The attached shader is now really dead.
2020 VOGL_ASSERT(get_shared_state()->m_capture_context_params.m_objs.get_target(shader_handle) == VOGL_SHADER_OBJECT);
2021 if (!get_shared_state()->m_capture_context_params.m_objs.erase(shader_handle))
2023 vogl_error_printf("%s: Failed finding attached shader %u in objects hash table, while handling the actual deletion of program %u\n", VOGL_METHOD_NAME, shader_handle, prev_program);
2029 m_cur_program = program;
2031 check_program_binding_shadow();
2034 void handle_del_shader(gl_entrypoint_id_t id, GLuint obj)
2036 // Note: This mixes ARB and non-ARB funcs. to probe around, which is evil.
2038 peek_and_record_gl_error();
2040 check_program_binding_shadow();
2042 vogl_scoped_context_shadow_lock lock;
2044 VOGL_ASSERT(!obj || (get_shared_state()->m_capture_context_params.m_objs.get_target(obj) == VOGL_SHADER_OBJECT));
2046 if (id == VOGL_ENTRYPOINT_glDeleteObjectARB)
2047 GL_ENTRYPOINT(glDeleteObjectARB)(obj);
2049 GL_ENTRYPOINT(glDeleteShader)(obj);
2051 GLenum gl_err = peek_and_record_gl_error();
2052 if (gl_err != GL_NO_ERROR)
2054 vogl_error_printf("%s: glDeleteShader/glDeleteObjectARB on handle %u returned GL error %s\n", VOGL_METHOD_NAME, obj, g_gl_enums.find_gl_error_name(gl_err));
2061 bool is_still_shader = GL_ENTRYPOINT(glIsShader)(obj);
2062 peek_and_drop_gl_error();
2064 if (!is_still_shader)
2066 // The shader is really gone.
2067 bool was_deleted = get_shared_state()->m_capture_context_params.m_objs.erase(obj);
2068 VOGL_ASSERT(was_deleted);
2069 VOGL_NOTE_UNUSED(was_deleted);
2073 GLint marked_for_deletion = 0;
2074 GL_ENTRYPOINT(glGetShaderiv)(obj, GL_DELETE_STATUS, &marked_for_deletion);
2075 peek_and_drop_gl_error();
2077 VOGL_VERIFY(marked_for_deletion);
2079 // The shader is attached to a live program object (which may or may not be actually in the marked_as_deleted state)
2080 // we'll get around to it when the program object is deleted, or when they remove the program object from the current state.
2084 void handle_del_program(gl_entrypoint_id_t id, GLuint obj)
2086 // Note: This mixes ARB and non-ARB funcs. to probe around, which is evil.
2088 peek_and_record_gl_error();
2090 check_program_binding_shadow();
2092 vogl_scoped_context_shadow_lock lock;
2094 VOGL_ASSERT(!obj || (get_shared_state()->m_capture_context_params.m_objs.get_target(obj) == VOGL_PROGRAM_OBJECT));
2096 bool is_program = GL_ENTRYPOINT(glIsProgram)(obj) != 0;
2097 peek_and_drop_gl_error();
2099 vogl::growable_array<GLuint, 8> attached_replay_shaders;
2101 if ((is_program) && (obj))
2103 GLint num_attached_shaders = 0;
2104 GL_ENTRYPOINT(glGetProgramiv)(obj, GL_ATTACHED_SHADERS, &num_attached_shaders);
2105 peek_and_drop_gl_error();
2107 if (num_attached_shaders)
2109 attached_replay_shaders.resize(num_attached_shaders);
2111 GLsizei actual_count = 0;
2112 GL_ENTRYPOINT(glGetAttachedShaders)(obj, num_attached_shaders, &actual_count, attached_replay_shaders.get_ptr());
2113 peek_and_drop_gl_error();
2115 VOGL_ASSERT(actual_count == num_attached_shaders);
2119 if (id == VOGL_ENTRYPOINT_glDeleteObjectARB)
2120 GL_ENTRYPOINT(glDeleteObjectARB)(obj);
2122 GL_ENTRYPOINT(glDeleteProgram)(obj);
2124 GLenum gl_err = peek_and_record_gl_error();
2125 if (gl_err != GL_NO_ERROR)
2127 vogl_error_printf("%s: glDeleteProgram/glDeleteObjectARB on handle %u returned GL error %s\n", VOGL_METHOD_NAME, obj, g_gl_enums.find_gl_error_name(gl_err));
2134 bool is_still_program = GL_ENTRYPOINT(glIsProgram)(obj) != 0;
2135 peek_and_drop_gl_error();
2137 GLint marked_for_deletion = 0;
2138 if (is_still_program)
2140 // It must still be bound to the context, or referred to in some other way that we don't know about.
2141 GL_ENTRYPOINT(glGetProgramiv)(obj, GL_DELETE_STATUS, &marked_for_deletion);
2142 bool delete_status_check_succeeded = (peek_and_drop_gl_error() == GL_NO_ERROR);
2144 VOGL_VERIFY(delete_status_check_succeeded);
2145 VOGL_VERIFY(marked_for_deletion);
2147 else if (!is_still_program)
2149 VOGL_ASSERT(is_program);
2151 // The program is really gone now.
2152 bool was_deleted = get_shared_state()->m_capture_context_params.m_objs.erase(obj);
2153 VOGL_ASSERT(was_deleted);
2154 VOGL_NOTE_UNUSED(was_deleted);
2156 get_shared_state()->m_capture_context_params.m_linked_programs.remove_snapshot(obj);
2158 if (m_cur_program == obj)
2160 // This shouldn't happen - if the program is still bound to the context then it should still be a program.
2165 for (uint i = 0; i < attached_replay_shaders.size(); i++)
2167 GLuint shader_handle = attached_replay_shaders[i];
2169 bool is_still_shader = GL_ENTRYPOINT(glIsShader)(shader_handle) != 0;
2170 peek_and_drop_gl_error();
2172 if (is_still_shader)
2175 if (!get_shared_state()->m_capture_context_params.m_objs.contains(shader_handle))
2177 // We didn't create this shader handle, the AMD driver did on a program binary link, so ignore it.
2181 // The attached shader is now really dead.
2182 VOGL_ASSERT(get_shared_state()->m_capture_context_params.m_objs.get_target(shader_handle) == VOGL_SHADER_OBJECT);
2183 if (!get_shared_state()->m_capture_context_params.m_objs.erase(shader_handle))
2185 vogl_error_printf("%s: Failed finding attached shader %u in objects shadow, while handling the deletion of program %u\n", VOGL_METHOD_NAME, shader_handle, obj);
2190 check_program_binding_shadow();
2193 void handle_del_object(gl_entrypoint_id_t id, GLuint obj)
2195 vogl_scoped_context_shadow_lock lock;
2200 GLenum target = get_shared_state()->m_capture_context_params.m_objs.get_target(obj);
2202 if (target == VOGL_PROGRAM_OBJECT)
2203 handle_del_program(id, obj);
2204 else if (target == VOGL_SHADER_OBJECT)
2205 handle_del_shader(id, obj);
2208 vogl_error_printf("%s: glDeleteObjectARB: Unable to find object handle %u in object shadow\n", VOGL_METHOD_NAME, obj);
2210 GL_ENTRYPOINT(glDeleteObjectARB)(obj);
2214 void handle_detach_shader(gl_entrypoint_id_t id, GLuint program, GLuint shader)
2216 vogl_scoped_context_shadow_lock lock;
2218 peek_and_record_gl_error();
2220 // Note: This mixes ARB and non-ARB funcs. to probe around, which is evil.
2222 GLboolean was_shader = GL_ENTRYPOINT(glIsShader)(shader);
2223 peek_and_drop_gl_error();
2225 GLint marked_for_deletion = 0;
2226 GL_ENTRYPOINT(glGetShaderiv)(shader, GL_DELETE_STATUS, &marked_for_deletion);
2227 peek_and_drop_gl_error();
2229 if (id == VOGL_ENTRYPOINT_glDetachObjectARB)
2230 GL_ENTRYPOINT(glDetachObjectARB)(program, shader);
2233 VOGL_ASSERT(id == VOGL_ENTRYPOINT_glDetachShader);
2234 GL_ENTRYPOINT(glDetachShader)(program, shader);
2237 GLenum gl_err = peek_and_record_gl_error();
2238 if (gl_err != GL_NO_ERROR)
2240 vogl_error_printf("%s: glDetachShader/glDetachObjectARB on program handle %u shader handle %u returned GL error %s\n", VOGL_METHOD_NAME, program, shader, g_gl_enums.find_gl_error_name(gl_err));
2244 GLboolean is_shader = GL_ENTRYPOINT(glIsShader)(shader);
2245 peek_and_drop_gl_error();
2247 if ((marked_for_deletion) && (was_shader) && (!is_shader))
2249 // The shader is really gone now.
2250 bool was_deleted = get_shared_state()->m_capture_context_params.m_objs.erase(shader);
2251 VOGL_ASSERT(was_deleted);
2252 VOGL_NOTE_UNUSED(was_deleted);
2256 // glBegin/glEnd shadowing
2258 // Note: This flag gets set even when the client is composing a display list!
2259 void set_in_gl_begin(bool value)
2261 m_in_gl_begin = value;
2263 bool get_in_gl_begin() const
2265 return m_in_gl_begin;
2268 void set_uses_client_side_arrays(bool value)
2270 m_uses_client_side_arrays = value;
2272 bool get_uses_client_side_arrays() const
2274 return m_uses_client_side_arrays;
2277 typedef vogl::map<dynamic_string, dynamic_string, dynamic_string_less_than_case_sensitive, dynamic_string_equal_to_case_sensitive> extension_id_to_string_map_t;
2278 extension_id_to_string_map_t &get_extension_map()
2280 return m_extension_map;
2283 const vogl_context_handle_remapper &get_handle_remapper() const
2285 return m_handle_remapper;
2287 vogl_context_handle_remapper &get_handle_remapper()
2289 return m_handle_remapper;
2292 // Display list shadowing
2294 GLenum get_current_display_list_mode() const
2296 return m_current_display_list_mode;
2298 bool is_composing_display_list() const
2300 return m_current_display_list_handle >= 0;
2302 GLint get_current_display_list_handle() const
2304 return m_current_display_list_handle;
2307 bool new_list(GLuint handle, GLenum mode)
2311 VOGL_ASSERT((mode == GL_COMPILE) || (mode == GL_COMPILE_AND_EXECUTE));
2313 if (m_current_display_list_handle >= 0)
2315 vogl_error_printf("%s: Can't define new display list %u while display list %i is already being defined!\n", VOGL_METHOD_NAME, handle, m_current_display_list_handle);
2319 m_current_display_list_handle = handle;
2320 m_current_display_list_mode = mode;
2322 vogl_scoped_context_shadow_lock lock;
2324 get_shared_state()->m_capture_context_params.m_display_lists.new_list(handle, handle);
2333 if (m_current_display_list_handle < 0)
2335 vogl_error_printf("%s: No display list is active!\n", VOGL_METHOD_NAME);
2340 vogl_scoped_context_shadow_lock lock;
2342 get_shared_state()->m_capture_context_params.m_display_lists.end_list(m_current_display_list_handle);
2345 m_current_display_list_handle = -1;
2346 m_current_display_list_mode = GL_NONE;
2351 void gen_lists(GLuint result, GLsizei range)
2358 vogl_scoped_context_shadow_lock lock;
2360 get_shared_state()->m_capture_context_params.m_display_lists.gen_lists(result, range);
2363 void del_lists(GLuint list, GLsizei range)
2370 vogl_scoped_context_shadow_lock lock;
2372 get_shared_state()->m_capture_context_params.m_display_lists.del_lists(list, range);
2375 void glx_font(const char *pFont, int first, int count, int list_base)
2377 vogl_scoped_context_shadow_lock lock;
2379 get_shared_state()->m_capture_context_params.m_display_lists.glx_font(pFont, first, count, list_base);
2382 bool parse_list_and_update_shadows(GLuint handle, vogl_display_list_state::pBind_callback_func_ptr pBind_callback, void *pBind_callback_opaque)
2384 vogl_scoped_context_shadow_lock lock;
2386 return get_shared_state()->m_capture_context_params.m_display_lists.parse_list_and_update_shadows(handle, pBind_callback, pBind_callback_opaque);
2389 bool parse_lists_and_update_shadows(GLsizei n, GLenum type, const GLvoid *lists, vogl_display_list_state::pBind_callback_func_ptr pBind_callback, void *pBind_callback_opaque)
2391 vogl_scoped_context_shadow_lock lock;
2393 return get_shared_state()->m_capture_context_params.m_display_lists.parse_lists_and_update_shadows(n, type, lists, pBind_callback, pBind_callback_opaque);
2396 bool add_packet_to_current_display_list(gl_entrypoint_id_t func, const vogl_trace_packet &packet)
2400 if (m_current_display_list_handle < 0)
2403 if (!vogl_display_list_state::is_call_listable(func, packet))
2405 if (g_vogl_entrypoint_descs[func].m_is_listable)
2407 if (!g_vogl_entrypoint_descs[func].m_whitelisted_for_displaylists)
2408 vogl_error_printf("%s: Failed serializing trace packet into display list shadow! Call is not listable.\n", VOGL_FUNCTION_NAME);
2410 vogl_error_printf("%s: Failed serializing trace packet into display list shadow! Call with these parameters is not listable.\n", VOGL_FUNCTION_NAME);
2415 vogl_scoped_context_shadow_lock lock;
2417 return get_shared_state()->m_capture_context_params.m_display_lists.add_packet_to_list(m_current_display_list_handle, func, packet);
2422 bool m_deleted_flag;
2423 vogl_context *m_pShared_state;
2425 GLXContext m_context_handle;
2426 GLXContext m_sharelist_handle;
2428 const Display *m_pDpy;
2429 GLXDrawable m_drawable;
2430 GLXDrawable m_read_drawable;
2432 XVisualInfo m_xvisual_info;
2433 GLXFBConfig m_fb_config;
2437 bool m_created_from_attribs;
2438 vogl::vector<int> m_attrib_list;
2440 uint64_t m_current_thread; // as returned by vogl_get_current_kernel_thread_id()
2442 GLuint m_max_vertex_attribs;
2444 bool m_has_been_made_current;
2446 int m_window_width, m_window_height;
2447 uint64_t m_frame_index;
2449 gl_entrypoint_id_t m_creation_func;
2450 vogl_context_desc m_context_desc;
2451 vogl_context_info m_context_info; // only valid after first MakeCurrent
2453 extension_id_to_string_map_t m_extension_map;
2455 GLenum m_latched_gl_error;
2457 gl_buffer_desc_map m_buffer_descs;
2459 vogl_capture_context_params m_capture_context_params;
2461 vogl_framebuffer_capturer m_framebuffer_capturer;
2463 GLuint m_cur_program;
2466 bool m_uses_client_side_arrays;
2468 vogl_context_handle_remapper m_handle_remapper;
2470 int m_current_display_list_handle;
2471 GLenum m_current_display_list_mode;
2473 static void debug_callback_arb(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, GLvoid *pUser_param)
2477 char final_message[4096];
2479 vogl_context *pContext = (vogl_context *)(pUser_param);
2481 vogl_format_debug_output_arb(final_message, sizeof(final_message), source, type, id, severity, reinterpret_cast<const char *>(message));
2485 vogl_warning_printf("%s: Trace context: 0x%" PRIX64 ", Thread id: 0x%" PRIX64 "\n%s\n", VOGL_FUNCTION_NAME,
2486 cast_val_to_uint64(pContext->m_context_handle), vogl_get_current_kernel_thread_id(), final_message);
2490 vogl_warning_printf("%s: %s\n", VOGL_FUNCTION_NAME, final_message);
2494 void on_first_make_current()
2496 if ((g_command_line_params.get_value_as_bool("vogl_force_debug_context")) && (m_context_info.is_debug_context()))
2498 if (GL_ENTRYPOINT(glDebugMessageCallbackARB) && m_context_info.supports_extension("GL_ARB_debug_output"))
2500 VOGL_CHECK_GL_ERROR;
2502 GL_ENTRYPOINT(glDebugMessageCallbackARB)(debug_callback_arb, (GLvoid *)this);
2503 GL_ENTRYPOINT(glEnable)(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
2505 VOGL_CHECK_GL_ERROR;
2509 vogl_error_printf("%s: Can't enable debug context, either glDebugMessageCallbackARB func or the GL_ARB_debug_output extension is not available!\n", VOGL_METHOD_NAME);
2514 // Note: Check for any GL errors before calling this method.
2515 bool check_program_binding_shadow()
2517 GLint actual_cur_program = 0;
2518 GL_ENTRYPOINT(glGetIntegerv)(GL_CURRENT_PROGRAM, &actual_cur_program);
2520 if (peek_and_drop_gl_error() != GL_NO_ERROR)
2521 vogl_error_printf("%s: GL error checking program binding shadow!\n", VOGL_METHOD_NAME);
2523 if (m_cur_program == static_cast<GLuint>(actual_cur_program))
2526 // OK, on AMD it plays games with GL_CURRENT_PROGRAM when the currently bound program is deleted. Check for this scenario.
2527 bool is_still_program = GL_ENTRYPOINT(glIsProgram)(m_cur_program) != 0;
2528 if ((peek_and_drop_gl_error() == GL_NO_ERROR) && (is_still_program))
2530 GLint marked_for_deletion = GL_FALSE;
2531 GL_ENTRYPOINT(glGetProgramiv)(m_cur_program, GL_DELETE_STATUS, &marked_for_deletion);
2533 if ((peek_and_drop_gl_error() == GL_NO_ERROR) && (marked_for_deletion))
2537 VOGL_VERIFY(!"m_cur_program appears out of sync with GL's GL_CURRENT_PROGRAM");
2542 typedef vogl::hash_map<GLXContext, vogl_context *, bit_hasher<GLXContext> > glxcontext_map;
2544 //----------------------------------------------------------------------------------------------------------------------
2545 // vogl_context_handle_remapper::is_valid_handle
2546 //----------------------------------------------------------------------------------------------------------------------
2547 bool vogl_context_handle_remapper::is_valid_handle(vogl_namespace_t handle_namespace, uint64_t from_handle)
2552 uint32 handle = static_cast<uint32>(from_handle);
2554 const vogl_capture_context_params &capture_context_params = m_pContext->get_shared_state()->get_capture_context_params();
2556 // TODO: Support all the object types
2557 if (handle_namespace == VOGL_NAMESPACE_SHADERS)
2559 VOGL_ASSERT(handle == from_handle);
2560 return (capture_context_params.m_objs.get_target(handle) == VOGL_SHADER_OBJECT);
2562 else if (handle_namespace == VOGL_NAMESPACE_PROGRAMS)
2564 VOGL_ASSERT(handle == from_handle);
2565 return (capture_context_params.m_objs.get_target(handle) == VOGL_PROGRAM_OBJECT);
2567 else if (handle_namespace == VOGL_NAMESPACE_TEXTURES)
2569 VOGL_ASSERT(handle == from_handle);
2570 return capture_context_params.m_textures.contains(handle);
2577 //----------------------------------------------------------------------------------------------------------------------
2578 // vogl_context_handle_remapper::determine_from_object_target
2579 //----------------------------------------------------------------------------------------------------------------------
2580 bool vogl_context_handle_remapper::determine_from_object_target(vogl_namespace_t handle_namespace, uint64_t from_handle, GLenum &target)
2587 uint32 handle = static_cast<uint32>(from_handle);
2589 const vogl_capture_context_params &capture_context_params = m_pContext->get_shared_state()->get_capture_context_params();
2591 // TODO: Support all the object types
2592 if (handle_namespace == VOGL_NAMESPACE_TEXTURES)
2594 if (capture_context_params.m_textures.contains(handle))
2596 target = capture_context_params.m_textures.get_target(handle);
2605 //----------------------------------------------------------------------------------------------------------------------
2606 // vogl_scoped_gl_error_absorber::vogl_scoped_gl_error_absorber
2607 //----------------------------------------------------------------------------------------------------------------------
2608 vogl_scoped_gl_error_absorber::vogl_scoped_gl_error_absorber(vogl_context *pContext)
2609 : m_pContext(pContext)
2611 // Latch any errors that are present on the context, if any, so the client will see it later
2613 pContext->peek_and_record_gl_error();
2616 //----------------------------------------------------------------------------------------------------------------------
2617 // vogl_scoped_gl_error_absorber::~vogl_scoped_gl_error_absorber
2618 //----------------------------------------------------------------------------------------------------------------------
2619 vogl_scoped_gl_error_absorber::~vogl_scoped_gl_error_absorber()
2621 // Now get the current GL error and drop it, so the client app doesn't see it
2623 m_pContext->peek_and_drop_gl_error();
2626 //----------------------------------------------------------------------------------------------------------------------
2627 // class vogl_context_manager
2628 //----------------------------------------------------------------------------------------------------------------------
2629 class vogl_context_manager
2631 VOGL_NO_COPY_OR_ASSIGNMENT_OP(vogl_context_manager);
2634 vogl_context_manager()
2635 : m_glx_context_map_lock(0, true)
2639 vogl_context *create_context(GLXContext handle)
2641 VOGL_ASSERT(handle);
2643 vogl_context *pVOGL_context = vogl_new(vogl_context, handle);
2646 scoped_mutex lock(m_glx_context_map_lock);
2647 m_glx_context_map.insert(handle, pVOGL_context);
2650 return pVOGL_context;
2653 vogl_context *lookup_vogl_context(GLXContext handle)
2655 VOGL_ASSERT(handle);
2657 vogl_context *pVOGL_context;
2658 VOGL_NOTE_UNUSED(pVOGL_context);
2659 glxcontext_map::iterator it;
2662 scoped_mutex lock(m_glx_context_map_lock);
2663 it = m_glx_context_map.find(handle);
2666 return (it != m_glx_context_map.end()) ? it->second : NULL;
2669 bool destroy_context(GLXContext handle)
2671 VOGL_ASSERT(handle);
2673 vogl_context *pVOGL_context = lookup_vogl_context(handle);
2678 scoped_mutex lock(m_glx_context_map_lock);
2679 m_glx_context_map.erase(handle);
2682 vogl_thread_local_data *pTLS_data = vogl_get_or_create_thread_local_data();
2683 if ((pTLS_data) && (pTLS_data->m_pContext == pVOGL_context))
2684 pTLS_data->m_pContext = NULL;
2686 vogl_delete(pVOGL_context);
2691 vogl_context *get_or_create_context(GLXContext handle)
2693 VOGL_ASSERT(handle);
2695 vogl_context *pVOGL_context = lookup_vogl_context(handle);
2697 pVOGL_context = vogl_new(vogl_context, handle);
2699 return pVOGL_context;
2702 vogl_context *make_current(GLXContext handle)
2704 VOGL_ASSERT(handle);
2706 vogl_context *pVOGL_context = get_or_create_context(handle);
2708 if (pVOGL_context->get_current_thread())
2710 if (pVOGL_context->get_current_thread() != vogl_get_current_kernel_thread_id())
2712 vogl_error_printf("%s: context is being made current, but is already current on another thread\n", VOGL_METHOD_NAME);
2716 vogl_warning_printf("%s: context is already current (redundant call)\n", VOGL_METHOD_NAME);
2720 vogl_get_or_create_thread_local_data()->m_pContext = pVOGL_context;
2722 pVOGL_context->on_make_current();
2724 return pVOGL_context;
2727 vogl_context *get_current()
2729 return static_cast<vogl_context *>(vogl_get_or_create_thread_local_data()->m_pContext);
2732 void release_current()
2734 vogl_context *pVOGL_context = get_current();
2737 if (!pVOGL_context->get_current_thread())
2739 vogl_error_printf("%s: Context manager's current context is not marked as current on any thread\n", VOGL_METHOD_NAME);
2741 pVOGL_context->on_release_current_epilog();
2743 vogl_get_or_create_thread_local_data()->m_pContext = NULL;
2749 m_glx_context_map_lock.lock();
2754 m_glx_context_map_lock.unlock();
2757 const glxcontext_map &get_context_map() const
2759 return m_glx_context_map;
2762 vogl_context *find_context(const Display *dpy, GLXDrawable drawable)
2766 const glxcontext_map &contexts = m_glx_context_map;
2767 for (glxcontext_map::const_iterator it = contexts.begin(); it != contexts.end(); ++it)
2769 vogl_context *p = it->second;
2770 if ((p->get_display() == dpy) && (p->get_drawable() == drawable))
2782 mutex m_glx_context_map_lock;
2783 glxcontext_map m_glx_context_map;
2786 vogl_context_manager g_context_manager;
2788 //----------------------------------------------------------------------------------------------------------------------
2789 // vogl_context_shadow_lock
2790 //----------------------------------------------------------------------------------------------------------------------
2791 static inline void vogl_context_shadow_lock()
2793 g_context_manager.lock();
2796 //----------------------------------------------------------------------------------------------------------------------
2797 // vogl_context_shadow_unlock
2798 //----------------------------------------------------------------------------------------------------------------------
2799 static inline void vogl_context_shadow_unlock()
2801 g_context_manager.unlock();
2804 //----------------------------------------------------------------------------------------------------------------------
2806 //----------------------------------------------------------------------------------------------------------------------
2807 static void vogl_atexit()
2809 vogl_debug_printf("vogl_atexit()\n");
2811 scoped_mutex lock(g_vogl_trace_mutex);
2816 //----------------------------------------------------------------------------------------------------------------------
2818 //----------------------------------------------------------------------------------------------------------------------
2819 static uint32 vogl_backtrace(uint addrs_to_skip)
2821 vogl_backtrace_addrs addrs;
2822 addrs.m_num_addrs = btrace_get(addrs.m_addrs, addrs.cMaxAddrs, addrs_to_skip);
2824 vogl_backtrace_hashmap::insert_result ins_res;
2828 g_backtrace_hashmap_mutex.lock();
2830 if (!g_backtrace_hashmap.insert_no_grow(ins_res, addrs))
2831 vogl_error_printf("%s: Backtrace hashmap exhausted! Please increase VOGL_BACKTRACE_HASHMAP_CAPACITY. Some backtraces in this trace will not have symbols.\n", VOGL_FUNCTION_NAME);
2834 index = ins_res.first.get_index();
2835 (ins_res.first)->second++;
2838 g_backtrace_hashmap_mutex.unlock();
2843 //----------------------------------------------------------------------------------------------------------------------
2844 // vogl_flush_backtrace_to_trace_file
2845 //----------------------------------------------------------------------------------------------------------------------
2846 static bool vogl_flush_backtrace_to_trace_file()
2848 scoped_mutex lock(g_vogl_trace_mutex);
2850 if (!g_vogl_trace_writer.is_opened() || (g_vogl_trace_writer.get_trace_archive() == NULL))
2855 g_backtrace_hashmap_mutex.lock();
2857 uint backtrace_hashmap_size = g_backtrace_hashmap.size();
2858 if (backtrace_hashmap_size)
2860 vogl_message_printf("%s: Writing backtrace %u addrs\n", VOGL_FUNCTION_NAME, backtrace_hashmap_size);
2862 json_node *pRoot = doc.get_root();
2863 pRoot->init_array();
2865 for (vogl_backtrace_hashmap::const_iterator it = g_backtrace_hashmap.begin(); it != g_backtrace_hashmap.end(); ++it)
2867 json_node &node = pRoot->add_array();
2869 node.add_key_value("index", it.get_index());
2870 node.add_key_value("count", it->second);
2872 json_node &addrs_arr = node.add_array("addrs");
2873 const vogl_backtrace_addrs &addrs = it->first;
2875 for (uint i = 0; i < addrs.m_num_addrs; i++)
2877 addrs_arr.add_value(to_hex_string(static_cast<uint64_t>(addrs.m_addrs[i])));
2882 g_backtrace_hashmap.reset();
2883 g_backtrace_hashmap_mutex.unlock();
2885 if (backtrace_hashmap_size)
2888 doc.serialize(data, true, 0, false);
2890 if (g_vogl_trace_writer.get_trace_archive()->add_buf_using_id(data.get_ptr(), data.size(), VOGL_TRACE_ARCHIVE_BACKTRACE_MAP_ADDRS_FILENAME).is_empty())
2891 vogl_error_printf("%s: Failed adding serialized backtrace addrs to trace archive\n", VOGL_FUNCTION_NAME);
2893 vogl_message_printf("%s: Done writing backtrace addrs\n", VOGL_FUNCTION_NAME);
2899 //----------------------------------------------------------------------------------------------------------------------
2900 // vogl_flush_compilerinfo_to_trace_file
2901 //----------------------------------------------------------------------------------------------------------------------
2902 static bool vogl_flush_compilerinfo_to_trace_file()
2904 scoped_mutex lock(g_vogl_trace_mutex);
2906 if (!g_vogl_trace_writer.is_opened() || (g_vogl_trace_writer.get_trace_archive() == NULL))
2911 vogl_message_printf("%s: Begin resolving compilerinfo to symbols\n", VOGL_FUNCTION_NAME);
2913 json_node *pRoot = doc.get_root();
2915 vogl::json_node &compiler_info_node = pRoot->add_array("compiler_info");
2916 compiler_info_node.add_key_value("time", __TIME__);
2917 compiler_info_node.add_key_value("date", __DATE__);
2919 compiler_info_node.add_key_value("version", __VERSION__);
2922 compiler_info_node.add_key_value("arch", "32bit");
2924 compiler_info_node.add_key_value("arch", "64bit");
2928 doc.serialize(data, true, 0, false);
2930 if (g_vogl_trace_writer.get_trace_archive()->add_buf_using_id(data.get_ptr(), data.size(), VOGL_TRACE_ARCHIVE_COMPILER_INFO_FILENAME).is_empty())
2931 vogl_error_printf("%s: Failed adding serialized compilerinfo to trace archive\n", VOGL_FUNCTION_NAME);
2933 vogl_message_printf("%s: Done resolving compilerinfo to symbols\n", VOGL_FUNCTION_NAME);
2938 //----------------------------------------------------------------------------------------------------------------------
2939 // vogl_flush_machineinfo_to_trace_file
2940 //----------------------------------------------------------------------------------------------------------------------
2941 static bool vogl_flush_machineinfo_to_trace_file()
2943 scoped_mutex lock(g_vogl_trace_mutex);
2945 if (!g_vogl_trace_writer.is_opened() || (g_vogl_trace_writer.get_trace_archive() == NULL))
2950 vogl_message_printf("%s: Begin resolving machineinfo to symbols\n", VOGL_FUNCTION_NAME);
2952 json_node *pRoot = doc.get_root();
2954 btrace_get_machine_info(pRoot);
2957 doc.serialize(data, true, 0, false);
2959 if (g_vogl_trace_writer.get_trace_archive()->add_buf_using_id(data.get_ptr(), data.size(), VOGL_TRACE_ARCHIVE_MACHINE_INFO_FILENAME).is_empty())
2960 vogl_error_printf("%s: Failed adding serialized machineinfo to trace archive\n", VOGL_FUNCTION_NAME);
2962 vogl_message_printf("%s: Done resolving machineinfo to symbols\n", VOGL_FUNCTION_NAME);
2967 //----------------------------------------------------------------------------------------------------------------------
2968 // vogl_entrypoint_serializer::begin
2969 //----------------------------------------------------------------------------------------------------------------------
2970 inline bool vogl_entrypoint_serializer::begin(gl_entrypoint_id_t id, vogl_context *pContext)
2974 // Nothing good will come of this - the output will be fucked.
2975 vogl_error_printf("%s: begin() call not matched with end() - something is very wrong!)\n", VOGL_METHOD_NAME);
2982 uint64_t thread_id = vogl_get_current_kernel_thread_id();
2983 uint64_t context_id = pContext ? reinterpret_cast<uint64_t>(pContext->get_context_handle()) : 0;
2985 m_packet.begin_construction(id, context_id, g_vogl_trace_writer.get_next_gl_call_counter(), thread_id, utils::RDTSC());
2987 if ((g_backtrace_all_calls) && (g_vogl_trace_writer.is_opened()))
2989 // Take a backtrace and store its hashtable index into the packet.
2990 m_packet.set_backtrace_hash_index(vogl_backtrace(1));
2996 //----------------------------------------------------------------------------------------------------------------------
2997 // vogl_is_in_null_mode
2998 //----------------------------------------------------------------------------------------------------------------------
2999 static inline bool vogl_is_in_null_mode()
3004 //----------------------------------------------------------------------------------------------------------------------
3005 // vogl_is_in_null_mode
3006 //----------------------------------------------------------------------------------------------------------------------
3007 static inline bool vogl_func_is_nulled(gl_entrypoint_id_t id)
3009 return vogl_is_in_null_mode() && g_vogl_entrypoint_descs[id].m_is_nullable;
3012 //----------------------------------------------------------------------------------------------------------------------
3013 // Custom array parameter size helper macros
3014 // IMPORTANT: These helpers need to not crash or return weird shit if there is no context current, in case the client
3015 // messes up and makes a GL call without an active context.
3016 //----------------------------------------------------------------------------------------------------------------------
3017 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_GL_ENUM(pname) g_gl_enums.get_pname_count(pname)
3019 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXChooseFBConfig_attrib_list(e, c, rt, r, nu, ne, a, p) vogl_determine_attrib_list_array_size(attrib_list)
3020 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXChooseVisual_attribList(e, c, rt, r, nu, ne, a, p) vogl_determine_attrib_list_array_size(attribList)
3021 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXCreateWindow_attrib_list(e, c, rt, r, nu, ne, a, p) vogl_determine_attrib_list_array_size(attrib_list)
3022 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXCreatePixmap_attrib_list(e, c, rt, r, nu, ne, a, p) vogl_determine_attrib_list_array_size(attrib_list)
3023 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXCreatePbuffer_attrib_list(e, c, rt, r, nu, ne, a, p) vogl_determine_attrib_list_array_size(attrib_list)
3024 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXCreateContextAttribsARB_attrib_list(e, c, rt, r, nu, ne, a, p) vogl_determine_attrib_list_array_size(attrib_list)
3026 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXBindVideoDeviceNV_attrib_list(e, c, rt, r, nu, ne, a, p) vogl_determine_attrib_list_array_size(attrib_list)
3027 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXBindTexImageEXT_attrib_list(e, c, rt, r, nu, ne, a, p) vogl_determine_attrib_list_array_size(attrib_list)
3029 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetUniformLocation_name(e, c, rt, r, nu, ne, a, p) (name ? (strlen((const char *)name) + 1) : -1)
3030 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetUniformLocationARB_name(e, c, rt, r, nu, ne, a, p) (name ? (strlen(name) + 1) : -1)
3032 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glBindAttribLocation_name(e, c, rt, r, nu, ne, a, p) (name ? (strlen((const char *)name) + 1) : -1)
3033 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glBindAttribLocationARB_name(e, c, rt, r, nu, ne, a, p) (name ? (strlen(name) + 1) : -1)
3035 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetAttribLocationARB_name(e, c, rt, r, nu, ne, a, p) (name ? (strlen((const char *)name) + 1) : -1)
3036 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetAttribLocation_name(e, c, rt, r, nu, ne, a, p) (name ? (strlen((const char *)name) + 1) : -1)
3038 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetShaderInfoLog_infoLog(e, c, rt, r, nu, ne, a, p) (length ? (*length + 1) : bufSize)
3039 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetInfoLogARB_infoLog(e, c, rt, r, nu, ne, a, p) (length ? (*length + 1) : maxLength)
3041 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glClearBufferData_data(e, c, rt, r, nu, ne, a, p) vogl_get_image_format_size_in_bytes(format, type)
3043 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glVertexPointer_pointer(e, c, rt, r, nu, ne, a, p) 0
3044 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glVertexPointerEXT_pointer(e, c, rt, r, nu, ne, a, p) 0
3045 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glColorPointer_pointer(e, c, rt, r, nu, ne, a, p) 0
3046 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glColorPointerEXT_pointer(e, c, rt, r, nu, ne, a, p) 0
3047 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glSecondaryColorPointer_pointer(e, c, rt, r, nu, ne, a, p) 0
3048 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexCoordPointer_pointer(e, c, rt, r, nu, ne, a, p) 0
3049 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexCoordPointerEXT_pointer(e, c, rt, r, nu, ne, a, p) 0
3050 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glFogCoordPointer_pointer(e, c, rt, r, nu, ne, a, p) 0
3051 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glFogCoordPointerEXT_pointer(e, c, rt, r, nu, ne, a, p) 0
3052 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glIndexPointer_pointer(e, c, rt, r, nu, ne, a, p) 0
3053 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glIndexPointerEXT_pointer(e, c, rt, r, nu, ne, a, p) 0
3054 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glNormalPointer_pointer(e, c, rt, r, nu, ne, a, p) 0
3055 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glNormalPointerEXT_pointer(e, c, rt, r, nu, ne, a, p) 0
3056 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glEdgeFlagPointer_pointer(e, c, rt, r, nu, ne, a, p) 0
3057 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glEdgeFlagPointerEXT_pointer(e, c, rt, r, nu, ne, a, p) 0
3058 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glInterleavedArrays_pointer(e, c, rt, r, nu, ne, a, p) 0
3060 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glVertexAttribPointer_pointer(e, c, rt, r, nu, ne, a, p) 0
3061 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glVertexAttribIPointer_pointer(e, c, rt, r, nu, ne, a, p) 0
3062 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glVertexAttribPointerARB_pointer(e, c, rt, r, nu, ne, a, p) 0
3064 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glDrawRangeElements_indices(e, c, rt, r, nu, ne, a, p) 0
3065 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glDrawRangeElementsBaseVertex_indices(e, c, rt, r, nu, ne, a, p) 0
3066 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glDrawRangeElementsEXT_indices(e, c, rt, r, nu, ne, a, p) 0
3067 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glDrawElements_indices(e, c, rt, r, nu, ne, a, p) 0
3068 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glDrawElementsInstanced_indices(e, c, rt, r, nu, ne, a, p) 0
3069 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glDrawElementsInstancedARB_indices(e, c, rt, r, nu, ne, a, p) 0
3070 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glDrawElementsInstancedEXT_indices(e, c, rt, r, nu, ne, a, p) 0
3071 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glDrawElementsBaseVertex_indices(e, c, rt, r, nu, ne, a, p) 0
3073 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glNamedBufferDataEXT_data(e, c, rt, r, nu, ne, a, p) size
3074 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glNamedBufferSubDataEXT_data(e, c, rt, r, nu, ne, a, p) size
3076 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glMap1f_points(e, c, rt, r, nu, ne, a, p) vogl_determine_glMap1_size(target, stride, order)
3077 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glMap1d_points(e, c, rt, r, nu, ne, a, p) vogl_determine_glMap1_size(target, stride, order)
3078 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glMap2f_points(e, c, rt, r, nu, ne, a, p) vogl_determine_glMap2_size(target, ustride, uorder, vstride, vorder)
3079 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glMap2d_points(e, c, rt, r, nu, ne, a, p) vogl_determine_glMap2_size(target, ustride, uorder, vstride, vorder)
3081 //----------------------------------------------------------------------------------------------------------------------
3082 // Texture/image API's array size helper macros
3083 //----------------------------------------------------------------------------------------------------------------------
3084 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexImage1D_pixels(e, c, rt, r, nu, ne, a, p) vogl_get_image_size(format, type, width, 1, 1)
3085 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexImage2D_pixels(e, c, rt, r, nu, ne, a, p) vogl_get_image_size(format, type, width, height, 1)
3086 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexImage3D_pixels(e, c, rt, r, nu, ne, a, p) vogl_get_image_size(format, type, width, height, depth)
3087 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexImage3DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_get_image_size(format, type, width, height, depth)
3089 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexSubImage1D_pixels(e, c, rt, r, nu, ne, a, p) vogl_get_image_size(format, type, width, 1, 1)
3090 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexSubImage1DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_get_image_size(format, type, width, 1, 1)
3092 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexSubImage2D_pixels(e, c, rt, r, nu, ne, a, p) vogl_get_image_size(format, type, width, height, 1)
3093 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexSubImage2DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_get_image_size(format, type, width, height, 1)
3095 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexSubImage3D_pixels(e, c, rt, r, nu, ne, a, p) vogl_get_image_size(format, type, width, height, depth)
3096 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexSubImage3DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_get_image_size(format, type, width, height, depth)
3098 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTextureImage3DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_get_image_size(format, type, width, height, depth)
3099 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTextureImage2DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_get_image_size(format, type, width, height, 1)
3100 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTextureImage1DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_get_image_size(format, type, width, 1, 1)
3102 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTextureSubImage3DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_get_image_size(format, type, width, height, depth)
3103 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTextureSubImage2DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_get_image_size(format, type, width, height, 1)
3104 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTextureSubImage1DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_get_image_size(format, type, width, 1, 1)
3106 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glMultiTexImage3DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_get_image_size(format, type, width, height, depth)
3107 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glMultiTexImage2DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_get_image_size(format, type, width, height, 1)
3108 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glMultiTexImage1DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_get_image_size(format, type, width, 1, 1)
3110 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glMultiTexSubImage3DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_get_image_size(format, type, width, height, depth)
3111 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glMultiTexSubImage2DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_get_image_size(format, type, width, height, 1)
3112 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glMultiTexSubImage1DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_get_image_size(format, type, width, 1, 1)
3114 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glDrawPixels_pixels(e, c, rt, r, nu, ne, a, p) vogl_get_image_size(format, type, width, height, 1)
3115 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glConvolutionFilter1D_image(e, c, rt, r, nu, ne, a, p) vogl_get_image_size(format, type, width, 1, 1)
3116 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glConvolutionFilter2D_image(e, c, rt, r, nu, ne, a, p) vogl_get_image_size(format, type, width, height, 1)
3118 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glColorTable_table(e, c, rt, r, nu, ne, a, p) vogl_get_image_size(format, type, width, 1, 1)
3119 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glColorSubTable_data(e, c, rt, r, nu, ne, a, p) vogl_get_image_size(format, type, count, 1, 1)
3121 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glBitmap_size(e, c, rt, r, nu, ne, a, p) vogl_get_image_size(GL_COLOR_INDEX, GL_BITMAP, width, height, 1)
3122 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glPolygonStipple_mask(e, c, rt, r, nu, ne, a, p) vogl_get_image_size(GL_COLOR_INDEX, GL_BITMAP, 32, 32, 1)
3124 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetTexImage_pixels(e, c, rt, r, nu, ne, a, p) vogl_get_tex_target_image_size(target, level, format, type)
3126 #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)
3128 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glViewportArrayv_v(e, c, rt, r, nu, ne, a, p) (4 * (count))
3129 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glScissorArrayv_v(e, c, rt, r, nu, ne, a, p) (4 * (count))
3130 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glDepthRangeArrayv_v(e, c, rt, r, nu, ne, a, p) (2 * (count))
3132 #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)
3133 #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)
3135 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glReadPixels_pixels(e, c, rt, r, nu, ne, a, p) vogl_get_image_size(format, type, width, height, 1)
3137 #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)
3138 #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)
3139 #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)
3141 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glBitmap_bitmap(e, c, rt, r, nu, ne, a, p) vogl_get_image_size(GL_COLOR_INDEX, GL_BITMAP, width, height, 1)
3143 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetActiveUniform_name(e, c, rt, r, nu, ne, a, p) ((name) ? ((length) ? (*(length) + 1) : (bufSize)) : -1)
3145 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetAttachedShaders_obj(e, c, rt, r, nu, ne, a, p) ((obj) ? ((count) ? *(count) : (maxCount)) : -1)
3147 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetProgramInfoLog_infoLog(e, c, rt, r, nu, ne, a, p) ((infoLog) ? ((length) ? (*length + 1) : (bufSize)) : -1)
3149 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetShaderSource_source(e, c, rt, r, nu, ne, a, p) ((source) ? ((length) ? (*(length) + 1) : (bufSize)) : -1)
3151 #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))
3153 #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)
3154 static GLsizei vogl_compute_message_log_size_in_bytes(GLuint count, const GLsizei *lengths)
3158 GLsizei total_length = 0;
3159 for (uint i = 0; i < count; i++)
3160 total_length += lengths[i];
3161 return total_length;
3164 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glSeparableFilter2D_row(e, c, rt, r, nu, ne, a, p) vogl_get_image_size(format, type, width, 1, 1)
3165 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glSeparableFilter2D_column(e, c, rt, r, nu, ne, a, p) vogl_get_image_size(format, type, height, 1, 1)
3167 // 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).
3168 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetUniformfv_params(e, c, rt, r, nu, ne, a, p) -1
3169 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetUniformiv_params(e, c, rt, r, nu, ne, a, p) -1
3170 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetPolygonStipple_mask(e, c, rt, r, nu, ne, a, p) -1
3171 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetMapdv_v(e, c, rt, r, nu, ne, a, p) -1
3172 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetMapfv_v(e, c, rt, r, nu, ne, a, p) -1
3173 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetMapiv_v(e, c, rt, r, nu, ne, a, p) -1
3174 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetColorTable_table(e, c, rt, r, nu, ne, a, p) -1
3175 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetConvolutionFilter_image(e, c, rt, r, nu, ne, a, p) -1
3176 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetSeparableFilter_row(e, c, rt, r, nu, ne, a, p) -1
3177 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetSeparableFilter_column(e, c, rt, r, nu, ne, a, p) -1
3178 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetSeparableFilter_span(e, c, rt, r, nu, ne, a, p) -1
3179 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetHistogram_values(e, c, rt, r, nu, ne, a, p) -1
3180 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetMinmax_values(e, c, rt, r, nu, ne, a, p) -1
3181 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetCompressedTexImage_img(e, c, rt, r, nu, ne, a, p) -1
3183 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glClearBufferfv_value(e, c, rt, r, nu, ne, a, p) vogl_get_clearbuffer_array_size(buffer)
3184 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glClearBufferuiv_value(e, c, rt, r, nu, ne, a, p) vogl_get_clearbuffer_array_size(buffer)
3185 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glClearBufferiv_value(e, c, rt, r, nu, ne, a, p) vogl_get_clearbuffer_array_size(buffer)
3186 static int vogl_get_clearbuffer_array_size(GLenum buffer)
3188 if ((buffer == GL_DEPTH) || (buffer == GL_STENCIL))
3190 else if (utils::is_in_set<GLenum, GLenum>(buffer, GL_COLOR, GL_FRONT, GL_BACK, GL_LEFT, GL_RIGHT, GL_FRONT_AND_BACK))
3193 vogl_warning_printf("%s: Invalid value for buffer parameter passed to glClearBufferfv: 0x%04X\n", VOGL_FUNCTION_NAME, buffer);
3211 //----------------------------------------------------------------------------------------------------------------------
3212 // Custom return parameter array size helper macros
3213 //----------------------------------------------------------------------------------------------------------------------
3214 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXGetFBConfigs(dpy, screen, nelements) (nelements ? *nelements : 1)
3215 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXChooseFBConfig(dpy, screen, attrib_list, nelements) (nelements ? *nelements : 1)
3216 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXChooseVisual(dpy, screen, nelements) 1
3217 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXGetVisualFromFBConfig(dpy, config) 1
3218 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXGetCurrentDisplay() 1
3219 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXGetCurrentDisplayEXT() 1
3220 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXEnumerateVideoCaptureDevicesNV(dpy, screen, nelements) (nelements ? *nelements : 1)
3221 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXEnumerateVideoDevicesNV(dpy, screen, nelements) (nelements ? *nelements : 1)
3223 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetString(name) (result ? (strlen(reinterpret_cast<const char *>(result)) + 1) : 0)
3224 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetStringi(name, idx) (result ? (strlen(reinterpret_cast<const char *>(result)) + 1) : 0)
3225 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXGetClientString(dpy, name) (result ? (strlen(reinterpret_cast<const char *>(result)) + 1) : 0)
3226 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXQueryExtensionsString(dpy, name) (result ? (strlen(reinterpret_cast<const char *>(result)) + 1) : 0)
3227 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXQueryServerString(dpy, screen, name) (result ? (strlen(reinterpret_cast<const char *>(result)) + 1) : 0)
3229 //----------------------------------------------------------------------------------------------------------------------
3230 static void vogl_print_hex(const void *p, uint64_t size, uint64_t type_size)
3234 vogl_log_printf("<null>\n");
3238 const uint8_t *ptr = reinterpret_cast<const uint8_t *>(p);
3239 if ((type_size == 2) && (!(size & 1)))
3242 vogl_log_printf("[ ");
3243 for (uint64_t i = 0; i < size; i += 2)
3246 vogl_log_printf(", ");
3247 vogl_log_printf("0x%04X", *reinterpret_cast<const uint16_t *>(ptr + i));
3250 vogl_log_printf("\n");
3252 vogl_log_printf(" ]");
3254 else if ((type_size == 4) && (!(size & 3)))
3257 vogl_log_printf("[ ");
3258 for (uint64_t i = 0; i < size; i += 4)
3261 vogl_log_printf(", ");
3262 vogl_log_printf("0x%08X", *reinterpret_cast<const uint32_t *>(ptr + i));
3265 vogl_log_printf("\n");
3267 vogl_log_printf(" ]");
3269 else if ((type_size == 8) && (!(size & 7)))
3272 vogl_log_printf("[ ");
3273 for (uint64_t i = 0; i < size; i += 8)
3276 vogl_log_printf(", ");
3277 vogl_log_printf("0x%" PRIX64, *reinterpret_cast<const uint64_t *>(ptr + i));
3280 vogl_log_printf("\n");
3282 vogl_log_printf(" ]");
3288 vogl_log_printf("\n");
3290 vogl_log_printf("[ ");
3291 for (uint64_t i = 0; i < size; i++)
3294 vogl_log_printf(", ");
3295 vogl_log_printf("%02X", ptr[i]);
3297 if ((++c & 63) == 63)
3298 vogl_log_printf("\n");
3300 vogl_log_printf(" ]");
3304 //----------------------------------------------------------------------------------------------------------------------
3305 static void vogl_print_string(const char *pStr, uint64_t total_size)
3307 for (uint64_t i = 0; i < total_size; i++)
3309 uint8_t c = reinterpret_cast<const uint8_t *>(pStr)[i];
3311 vogl_log_printf("\n");
3314 if ((c < 32) || (c > 127))
3316 vogl_log_printf("%c", c);
3319 if ((i & 511) == 511)
3320 vogl_log_printf(" \\\n");
3324 //----------------------------------------------------------------------------------------------------------------------
3325 template <typename T>
3326 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)
3328 VOGL_NOTE_UNUSED(pContext);
3330 int size = sizeof(T);
3332 if (g_vogl_process_gl_ctypes[type].m_size != size)
3333 vogl_error_printf("%s: size mismatch on ctype %u\n", VOGL_FUNCTION_NAME, type);
3335 if (serializer.is_in_begin())
3337 serializer.add_param(param_index, type, &val, sizeof(val));
3340 if (g_dump_gl_calls_flag)
3342 vogl_log_printf("%s: %s %s, ctype: %s, size: %i: ", pDesc, pType, pParam_name, g_vogl_process_gl_ctypes[type].m_pName, size);
3344 if (Loki::TypeTraits<T>::isPointer)
3346 vogl_log_printf("OPAQUE POINTER TYPE");
3350 vogl_log_printf("OPAQUE TYPE");
3354 vogl_print_hex(&val, size, size);
3356 if (((type == VOGL_GLFLOAT) || (type == VOGL_GLCLAMPF)) && (size == sizeof(float)))
3358 float flt_val = *reinterpret_cast<const float *>(&val);
3359 vogl_log_printf(" %f", flt_val);
3361 else if (((type == VOGL_GLDOUBLE) || (type == VOGL_GLCLAMPD)) && (size == sizeof(double)))
3363 double dbl_val = *reinterpret_cast<const double *>(&val);
3364 vogl_log_printf(" %f", dbl_val);
3366 else if ((type == VOGL_GLENUM) && (size == sizeof(int)))
3368 GLenum enum_val = *reinterpret_cast<const GLenum *>(&val);
3369 const char *pName = g_gl_enums.find_name(enum_val);
3371 vogl_log_printf(" %s", pName);
3375 vogl_log_printf("\n");
3379 //----------------------------------------------------------------------------------------------------------------------
3380 template <typename T>
3381 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)
3383 VOGL_NOTE_UNUSED(pContext);
3385 VOGL_ASSUME(Loki::TypeTraits<T>::isPointer);
3386 int size = sizeof(T);
3388 if (g_vogl_process_gl_ctypes[type].m_size != size)
3389 vogl_error_printf("%s: size mismatch on ctype %u\n", VOGL_FUNCTION_NAME, type);
3391 if (serializer.is_in_begin())
3393 serializer.add_param(param_index, type, &val, sizeof(val));
3396 if (g_dump_gl_calls_flag)
3398 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));
3402 //----------------------------------------------------------------------------------------------------------------------
3404 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)
3406 VOGL_NOTE_UNUSED(pContext);
3408 if (g_vogl_process_gl_ctypes[type].m_size != sizeof(const T *))
3409 vogl_error_printf("%s: size mismatch on ctype %u\n", VOGL_FUNCTION_NAME, type);
3411 int obj_size = gl_ctype_sizeof<T>::size;
3413 vogl_ctype_t pointee_type = g_vogl_process_gl_ctypes[type].m_pointee_ctype;
3414 if (pointee_type == VOGL_INVALID_CTYPE)
3416 vogl_error_printf("%s: Type %u doesn't have a pointee ctype\n", VOGL_FUNCTION_NAME, type);
3420 if (g_vogl_process_gl_ctypes[pointee_type].m_size != obj_size)
3421 vogl_error_printf("%s: size mismatch on pointee ctype %u\n", VOGL_FUNCTION_NAME, type);
3423 if (serializer.is_in_begin())
3425 serializer.add_param(param_index, type, &pObj, sizeof(pObj));
3427 if ((pObj) && (obj_size > 0))
3429 serializer.add_ref_client_memory(param_index, pointee_type, pObj, obj_size);
3433 if (g_dump_gl_calls_flag)
3435 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);
3438 vogl_log_printf("NULL");
3440 else if (obj_size <= 0)
3442 vogl_log_printf("OPAQUE TYPE");
3446 vogl_print_hex(pObj, obj_size, obj_size);
3449 vogl_log_printf("\n");
3453 //----------------------------------------------------------------------------------------------------------------------
3455 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)
3457 VOGL_NOTE_UNUSED(pContext);
3459 int64_t obj_size = gl_ctype_sizeof<T>::size;
3460 int64_t total_size = obj_size * math::maximum<int64_t>(size, 0);
3462 vogl_ctype_t pointee_type = g_vogl_process_gl_ctypes[type].m_pointee_ctype;
3463 if (((type == VOGL_CONST_VOID_PTR) || (type == VOGL_CONST_GLVOID_PTR) || (type == VOGL_GLVOID_PTR)) && (size > 0))
3470 if (pointee_type == VOGL_INVALID_CTYPE)
3472 vogl_error_printf("%s: Type %u doesn't have a pointee ctype\n", VOGL_FUNCTION_NAME, type);
3476 if (g_vogl_process_gl_ctypes[pointee_type].m_size != obj_size)
3477 vogl_error_printf("%s: Size mismatch on ctype %u\n", VOGL_FUNCTION_NAME, type);
3480 bool pointee_is_ptr = g_vogl_process_gl_ctypes[pointee_type].m_is_pointer;
3482 if (serializer.is_in_begin())
3484 serializer.add_param(param_index, type, &pArray, sizeof(pArray));
3486 if ((pArray) && (size > 0) && (obj_size > 0))
3488 serializer.add_array_client_memory(param_index, pointee_type, size, pArray, total_size);
3492 if (g_dump_gl_calls_flag)
3494 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,
3495 size, obj_size, total_size);
3498 vogl_log_printf("NULL");
3502 vogl_log_printf("UNKNOWN SIZE");
3504 else if (obj_size <= 0)
3506 vogl_log_printf("OPAQUE TYPE");
3512 vogl_log_printf("POINTEE IS POINTER: \n");
3515 vogl_print_hex(pArray, total_size, obj_size);
3517 switch (pointee_type)
3522 case VOGL_GLCHARARB:
3524 vogl_log_printf("\nAs string: \"");
3525 vogl_print_string(*(const char **)&pArray, total_size);
3526 vogl_log_printf("\"");
3536 vogl_log_printf("\n");
3540 //----------------------------------------------------------------------------------------------------------------------
3541 // Return parameters
3542 //----------------------------------------------------------------------------------------------------------------------
3544 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)
3546 VOGL_NOTE_UNUSED(size);
3548 VOGL_ASSUME(!Loki::TypeTraits<T>::isPointer);
3550 vogl_dump_value_param(pContext, serializer, "RETURN_VALUE", VOGL_RETURN_PARAM_INDEX, "result", pType, type, val);
3553 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)
3555 VOGL_NOTE_UNUSED(size);
3557 size_t array_size = pPtr ? (strlen(reinterpret_cast<const char *>(pPtr)) + 1) : 0;
3558 vogl_dump_array_param(pContext, serializer, "RETURN_UCHAR_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr, array_size);
3561 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)
3563 VOGL_NOTE_UNUSED(size);
3565 size_t array_size = pPtr ? (strlen(reinterpret_cast<const char *>(pPtr)) + 1) : 0;
3566 vogl_dump_array_param(pContext, serializer, "RETURN_GLUBYTE_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr, array_size);
3569 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)
3571 VOGL_NOTE_UNUSED(size);
3574 vogl_dump_ptr_param(pContext, serializer, "RETURN_VOID_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr);
3577 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)
3579 vogl_dump_array_param(pContext, serializer, "RETURN_UINT_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr, size);
3582 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)
3584 vogl_dump_array_param(pContext, serializer, "RETUURN_LUINT_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr, size);
3587 static inline void vogl_dump_return_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pType, vogl_ctype_t type, int64_t size, XVisualInfo *pPtr)
3589 VOGL_NOTE_UNUSED(size);
3591 vogl_dump_ref_param(pContext, serializer, "RETURN_XVISUALINFO_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr);
3594 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)
3596 VOGL_NOTE_UNUSED(size);
3598 vogl_dump_ref_param(pContext, serializer, "RETURN_GLXFBCONFIG_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr);
3601 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)
3603 VOGL_NOTE_UNUSED(size);
3606 vogl_dump_ptr_param(pContext, serializer, "RETURN_GLXCONTEXT", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr);
3609 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)
3611 VOGL_NOTE_UNUSED(size);
3614 vogl_dump_ptr_param(pContext, serializer, "RETURN_XDISPLAY_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr);
3617 //----------------------------------------------------------------------------------------------------------------------
3618 // vogl_should_serialize_call
3619 //----------------------------------------------------------------------------------------------------------------------
3620 static inline bool vogl_should_serialize_call(gl_entrypoint_id_t func, vogl_context *pContext)
3622 bool is_in_display_list = pContext && pContext->is_composing_display_list();
3623 bool is_listable = g_vogl_entrypoint_descs[func].m_is_listable;
3624 bool is_whitelisted = g_vogl_entrypoint_descs[func].m_whitelisted_for_displaylists;
3626 if ((is_in_display_list) && (is_listable) && (!is_whitelisted))
3628 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);
3631 // 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.)
3632 if (g_vogl_trace_writer.is_opened())
3635 return is_in_display_list && is_whitelisted;
3638 //----------------------------------------------------------------------------------------------------------------------
3639 // vogl_write_packet_to_trace
3640 //----------------------------------------------------------------------------------------------------------------------
3641 static inline void vogl_write_packet_to_trace(vogl_trace_packet &packet)
3643 if (!g_vogl_trace_writer.is_opened())
3646 scoped_mutex lock(g_vogl_trace_mutex);
3648 // The trace got closed on another thread while we where serializing - this is OK I guess.
3649 // This can happen when control+c is pressed.
3650 if (g_vogl_trace_writer.is_opened())
3652 bool success = g_vogl_trace_writer.write_packet(packet);
3656 if ((g_flush_files_after_each_call) ||
3657 ((g_flush_files_after_each_swap) && (packet.get_entrypoint_id() == VOGL_ENTRYPOINT_glXSwapBuffers)))
3659 g_vogl_trace_writer.flush();
3661 if (g_vogl_pLog_stream)
3662 g_vogl_pLog_stream->flush();
3667 vogl_error_printf("%s: Failed writing to trace file! Exiting app.\n", VOGL_FUNCTION_NAME);
3669 // TODO: Add common termination handler func, or just stop writing to the trace? or call abort()
3675 //----------------------------------------------------------------------------------------------------------------------
3676 // Declare gl/glx internal wrapper functions, all start with "vogl_" (so we can safely get the address of our internal
3677 // wrappers, avoiding global symbol naming conflicts that I started to see on test apps when I started building with -fPIC)
3678 //----------------------------------------------------------------------------------------------------------------------
3680 #define DEF_PROTO_EXPORTED(ret, name, args, params) \
3681 static ret VOGL_GLUER(vogl_, name) args \
3683 if (vogl_func_is_nulled(VOGL_ENTRYPOINT_##name)) \
3688 #define DEF_PROTO_EXPORTED_VOID(ret, name, args, params) \
3689 static ret VOGL_GLUER(vogl_, name) args \
3691 if (vogl_func_is_nulled(VOGL_ENTRYPOINT_##name)) \
3693 #define DEF_PROTO_INTERNAL(ret, name, args, params) \
3694 static ret VOGL_GLUER(vogl_, name) args \
3696 if (vogl_func_is_nulled(VOGL_ENTRYPOINT_##name)) \
3701 #define DEF_PROTO_INTERNAL_VOID(ret, name, args, params) \
3702 static ret VOGL_GLUER(vogl_, name) args \
3704 if (vogl_func_is_nulled(VOGL_ENTRYPOINT_##name)) \
3707 #define DEF_FUNCTION_BEGIN(exported, category, ret, ret_type_enum, num_params, name, args, params) exported(ret, name, args, params)
3708 #define DEF_FUNCTION_BEGIN_VOID(exported, category, ret, ret_type_enum, num_params, name, args, params) exported(ret, name, args, params)
3710 // 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).
3711 // A completely different code path through the wrapper should be used.
3713 // func init (after the optional custom function prolog)
3714 #define VOGL_MASTER_FUNCTION_PROLOG(name, params) \
3715 if (g_dump_gl_calls_flag) \
3717 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "" PRIX64 "\n", #name, vogl_get_current_kernel_thread_id()); \
3719 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_##name); \
3720 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID) \
3722 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); \
3723 return g_vogl_actual_gl_entrypoints.m_##name params; \
3725 vogl_context *pContext = pTLS_data->m_pContext; \
3726 vogl_entrypoint_serializer &trace_serializer = pTLS_data->m_serializer; \
3727 if (vogl_should_serialize_call(VOGL_ENTRYPOINT_##name, pContext)) \
3729 if (!trace_serializer.begin(VOGL_ENTRYPOINT_##name, pContext)) \
3731 vogl_warning_printf("%s: Reentrant wrapper call detected!\n", VOGL_FUNCTION_NAME); \
3732 return g_vogl_actual_gl_entrypoints.m_##name params; \
3736 #define VOGL_MASTER_FUNCTION_PROLOG_VOID(name, params) \
3737 if (g_dump_gl_calls_flag) \
3739 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", #name, vogl_get_current_kernel_thread_id()); \
3741 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_##name); \
3742 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID) \
3744 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); \
3745 g_vogl_actual_gl_entrypoints.m_##name params; \
3748 vogl_context *pContext = pTLS_data->m_pContext; \
3749 vogl_entrypoint_serializer &trace_serializer = pTLS_data->m_serializer; \
3750 if (vogl_should_serialize_call(VOGL_ENTRYPOINT_##name, pContext)) \
3752 if (!trace_serializer.begin(VOGL_ENTRYPOINT_##name, pContext)) \
3754 vogl_warning_printf("%s: Reentrant wrapper call detected!\n", VOGL_FUNCTION_NAME); \
3755 g_vogl_actual_gl_entrypoints.m_##name params; \
3760 #define DEF_FUNCTION_INIT(exported, category, ret, ret_type_enum, num_params, name, args, params) VOGL_MASTER_FUNCTION_PROLOG(name, params)
3761 #define DEF_FUNCTION_INIT_VOID(exported, category, ret, ret_type_enum, num_params, name, args, params) VOGL_MASTER_FUNCTION_PROLOG_VOID(name, params)
3764 #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);
3765 #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);
3766 #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);
3768 #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);
3769 #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);
3771 #define DEF_FUNCTION_RETURN_PARAM(spectype, type, type_enum, size) vogl_dump_return_param(pContext, trace_serializer, #type, type_enum, size, result);
3773 #define DEF_FUNCTION_CALL_GL(exported, category, ret, ret_type_enum, num_params, name, args, params) \
3774 if (trace_serializer.is_in_begin()) \
3775 trace_serializer.set_gl_begin_rdtsc(utils::RDTSC()); \
3776 result = g_vogl_actual_gl_entrypoints.m_##name params; \
3777 if (trace_serializer.is_in_begin()) \
3778 trace_serializer.set_gl_end_rdtsc(utils::RDTSC());
3780 #define DEF_FUNCTION_CALL_GL_VOID(exported, category, ret, ret_type_enum, num_params, name, args, params) \
3781 if (trace_serializer.is_in_begin()) \
3782 trace_serializer.set_gl_begin_rdtsc(utils::RDTSC()); \
3783 g_vogl_actual_gl_entrypoints.m_##name params; \
3784 if (trace_serializer.is_in_begin()) \
3785 trace_serializer.set_gl_end_rdtsc(utils::RDTSC());
3787 // Be careful modifying these END macros. They must be compatible with the logic in the glXSwapBuffers GL end prolog!
3788 // func end (after the optional custom function epilog)
3789 #define DEF_FUNCTION_END(exported, category, ret, ret_type_enum, num_params, name, args, params) \
3790 if (g_dump_gl_calls_flag) \
3792 vogl_message_printf("** END %s res=%s 0x%" PRIX64 "\n", #name, #ret, cast_val_to_uint64(result)); \
3794 if (trace_serializer.is_in_begin()) \
3796 trace_serializer.end(); \
3797 vogl_write_packet_to_trace(trace_serializer.get_packet()); \
3799 pContext->add_packet_to_current_display_list(VOGL_ENTRYPOINT_##name, trace_serializer.get_packet()); \
3804 #define DEF_FUNCTION_END_VOID(exported, category, ret, ret_type_enum, num_params, name, args, params) \
3805 if (g_dump_gl_calls_flag) \
3807 vogl_message_printf("** END %s\n", #name); \
3809 if (trace_serializer.is_in_begin()) \
3811 trace_serializer.end(); \
3812 vogl_write_packet_to_trace(trace_serializer.get_packet()); \
3814 pContext->add_packet_to_current_display_list(VOGL_ENTRYPOINT_##name, trace_serializer.get_packet()); \
3818 //----------------------------------------------------------------------------------------------------------------------
3819 // gl/glx override functions
3820 //----------------------------------------------------------------------------------------------------------------------
3821 static __GLXextFuncPtr vogl_get_proc_address_helper(const GLubyte *procName)
3826 if (g_dump_gl_calls_flag)
3828 vogl_printf("glXGetProcAddress: \"%s\"\n", procName);
3831 if (!GL_ENTRYPOINT(glXGetProcAddress))
3834 // 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)
3835 __GLXextFuncPtr pActual_entrypoint = GL_ENTRYPOINT(glXGetProcAddress)(procName);
3836 if (!pActual_entrypoint)
3839 for (uint i = 0; i < VOGL_NUM_ENTRYPOINTS; ++i)
3841 if (vogl_strcmp(reinterpret_cast<const char *>(procName), g_vogl_entrypoint_descs[i].m_pName) == 0)
3843 if (g_vogl_entrypoint_descs[i].m_pWrapper_func)
3845 if (!g_vogl_entrypoint_descs[i].m_is_whitelisted)
3847 // TODO: Only print this message once
3848 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);
3851 return reinterpret_cast<__GLXextFuncPtr>(g_vogl_entrypoint_descs[i].m_pWrapper_func);
3858 return pActual_entrypoint;
3861 //----------------------------------------------------------------------------------------------------------------------
3862 // Custom function handler implementations
3863 //----------------------------------------------------------------------------------------------------------------------
3864 #define DEF_FUNCTION_CUSTOM_HANDLER_glInternalTraceCommandRAD(exported, category, ret, ret_type_enum, num_params, name, args, params)
3865 static void vogl_glInternalTraceCommandRAD(GLuint cmd, GLuint size, const GLubyte *data)
3867 if (g_dump_gl_calls_flag)
3869 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
3872 if (g_vogl_trace_writer.is_opened())
3874 vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glInternalTraceCommandRAD, NULL);
3876 uint64_t cur_rdtsc = utils::RDTSC();
3877 serializer.set_gl_begin_end_rdtsc(cur_rdtsc, cur_rdtsc + 1);
3879 serializer.add_param(0, VOGL_GLUINT, &cmd, sizeof(cmd));
3880 serializer.add_param(1, VOGL_GLUINT, &size, sizeof(size));
3881 serializer.add_param(2, VOGL_CONST_GLUBYTE_PTR, &data, sizeof(data));
3885 case cITCRDemarcation:
3889 case cITCRKeyValueMap:
3891 if ((size == sizeof(key_value_map)) && (data))
3893 // Directly jam in the key value map, so it properly serializes as readable JSON.
3894 serializer.get_key_value_map() = *reinterpret_cast<const key_value_map *>(data);
3898 vogl_error_printf("%s: data pointer is NULL, or invalid key_value_map size %u\n", VOGL_FUNCTION_NAME, size);
3905 vogl_error_printf("%s: Unknown trace command type %u\n", VOGL_FUNCTION_NAME, cmd);
3912 vogl_write_packet_to_trace(serializer.get_packet());
3915 if (g_dump_gl_calls_flag)
3917 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
3921 //----------------------------------------------------------------------------------------------------------------------
3922 // TODO: Merge this with vogl_glXGetProcAddressARB to avoid duplicated code
3923 #define DEF_FUNCTION_CUSTOM_HANDLER_glXGetProcAddress(exported, category, ret, ret_type_enum, num_params, name, args, params)
3924 static __GLXextFuncPtr vogl_glXGetProcAddress(const GLubyte *procName)
3926 uint64_t begin_rdtsc = utils::RDTSC();
3928 if (g_dump_gl_calls_flag)
3930 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
3933 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXGetProcAddress);
3934 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
3936 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);
3937 return GL_ENTRYPOINT(glXGetProcAddress)(procName);
3940 uint64_t gl_begin_rdtsc = utils::RDTSC();
3941 __GLXextFuncPtr ptr = vogl_get_proc_address_helper(procName);
3942 uint64_t gl_end_rdtsc = utils::RDTSC();
3944 if (g_vogl_trace_writer.is_opened())
3946 vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glXGetProcAddress, g_context_manager.get_current());
3947 serializer.set_begin_rdtsc(begin_rdtsc);
3948 serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
3949 serializer.add_param(0, VOGL_CONST_GLUBYTE_PTR, &procName, sizeof(procName));
3952 size_t len = strlen(reinterpret_cast<const char *>(procName)) + 1;
3953 serializer.add_array_client_memory(0, VOGL_GLUBYTE, len, procName, len);
3955 serializer.add_return_param(VOGL_GLXEXTFUNCPTR, &ptr, sizeof(ptr));
3957 vogl_write_packet_to_trace(serializer.get_packet());
3960 if (g_dump_gl_calls_flag)
3962 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
3968 //----------------------------------------------------------------------------------------------------------------------
3969 #define DEF_FUNCTION_CUSTOM_HANDLER_glXGetProcAddressARB(exported, category, ret, ret_type_enum, num_params, name, args, params)
3970 static __GLXextFuncPtr vogl_glXGetProcAddressARB(const GLubyte *procName)
3972 uint64_t begin_rdtsc = utils::RDTSC();
3974 if (g_dump_gl_calls_flag)
3976 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
3979 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXGetProcAddressARB);
3980 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
3982 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);
3983 return GL_ENTRYPOINT(glXGetProcAddressARB)(procName);
3986 uint64_t gl_begin_rdtsc = utils::RDTSC();
3987 __GLXextFuncPtr ptr = vogl_get_proc_address_helper(procName);
3988 uint64_t gl_end_rdtsc = utils::RDTSC();
3990 if (g_vogl_trace_writer.is_opened())
3992 vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glXGetProcAddressARB, g_context_manager.get_current());
3993 serializer.set_begin_rdtsc(begin_rdtsc);
3994 serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
3995 serializer.add_param(0, VOGL_CONST_GLUBYTE_PTR, &procName, sizeof(procName));
3998 size_t len = strlen(reinterpret_cast<const char *>(procName)) + 1;
3999 serializer.add_array_client_memory(0, VOGL_GLUBYTE, len, procName, len);
4001 serializer.add_return_param(VOGL_GLXEXTFUNCPTR, &ptr, sizeof(ptr));
4003 vogl_write_packet_to_trace(serializer.get_packet());
4006 if (g_dump_gl_calls_flag)
4008 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
4014 //----------------------------------------------------------------------------------------------------------------------
4015 static void vogl_add_make_current_key_value_fields(const Display *dpy, GLXDrawable drawable, Bool result, vogl_context *pVOGL_context, vogl_entrypoint_serializer &serializer)
4017 if ((result) && (pVOGL_context))
4019 vogl_scoped_gl_error_absorber gl_error_absorber(pVOGL_context);
4020 VOGL_NOTE_UNUSED(gl_error_absorber);
4022 GLint cur_viewport[4];
4023 GL_ENTRYPOINT(glGetIntegerv)(GL_VIEWPORT, cur_viewport);
4025 serializer.add_key_value(string_hash("viewport_x"), cur_viewport[0]);
4026 serializer.add_key_value(string_hash("viewport_y"), cur_viewport[1]);
4027 serializer.add_key_value(string_hash("viewport_width"), cur_viewport[2]);
4028 serializer.add_key_value(string_hash("viewport_height"), cur_viewport[3]);
4031 if ((pVOGL_context) && (pVOGL_context->get_window_width() < 0))
4033 if ((dpy) && (drawable) && (result))
4037 unsigned int width, height, border_width, depth;
4038 if (XGetGeometry(const_cast<Display *>(dpy), drawable, &root, &x, &y, &width, &height, &border_width, &depth) != False)
4040 pVOGL_context->set_window_dimensions(width, height);
4042 serializer.add_key_value(string_hash("win_width"), width);
4043 serializer.add_key_value(string_hash("win_height"), height);
4045 if (g_dump_gl_calls_flag)
4047 vogl_log_printf("** Current window dimensions: %ix%i\n", width, height);
4055 //----------------------------------------------------------------------------------------------------------------------
4056 // HACK HACK - for NS2 experiment in AMD
4057 #define DEF_FUNCTION_CUSTOM_HANDLER_glTexStorage2D(exported, category, ret, ret_type_enum, num_params, name, args, params)
4058 static void vogl_glTexStorage2D( GLenum target,
4060 GLenum internalformat,
4064 GL_ENTRYPOINT(glTexParameteri)(target, GL_TEXTURE_BASE_LEVEL, 0);
4065 GL_ENTRYPOINT(glTexParameteri)(target, GL_TEXTURE_MAX_LEVEL, levels - 1);
4067 if (target == GL_TEXTURE_2D)
4069 for (uint i = 0; i < levels; i++)
4071 uint w = math::maximum<uint>(width >> i, 1);
4072 uint h = math::maximum<uint>(height >> i, 1);
4073 vogl::vector<uint8> pixels(w * h * 4);
4074 GL_ENTRYPOINT(glTexImage2D)(GL_TEXTURE_2D, i, internalformat, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, pixels.get_ptr());
4080 //----------------------------------------------------------------------------------------------------------------------
4081 #define DEF_FUNCTION_CUSTOM_HANDLER_glXMakeCurrent(exported, category, ret, ret_type_enum, num_params, name, args, params)
4082 static Bool vogl_glXMakeCurrent(const Display *dpy, GLXDrawable drawable, GLXContext context)
4084 uint64_t begin_rdtsc = utils::RDTSC();
4086 if (g_dump_gl_calls_flag)
4088 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
4091 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXMakeCurrent);
4092 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
4094 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);
4095 return GL_ENTRYPOINT(glXMakeCurrent)(dpy, drawable, context);
4098 if (g_dump_gl_calls_flag)
4100 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));
4103 vogl_context *pCur_context = g_context_manager.get_current();
4105 vogl_context *pNew_context = context ? g_context_manager.lookup_vogl_context(context) : NULL;
4106 if ((context) && (!pNew_context))
4108 vogl_error_printf("%s: Unknown context handle 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(context));
4113 if (pCur_context != pNew_context)
4114 pCur_context->on_release_current_prolog();
4116 vogl_warning_printf("%s: Context 0x%" PRIX64 " is already current (redundant call)\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(context));
4119 uint64_t gl_begin_rdtsc = utils::RDTSC();
4120 Bool result = GL_ENTRYPOINT(glXMakeCurrent)(dpy, drawable, context);
4121 uint64_t gl_end_rdtsc = utils::RDTSC();
4123 if ((result) && (pCur_context != pNew_context))
4126 g_context_manager.release_current();
4130 vogl_context *p = g_context_manager.make_current(context);
4131 VOGL_ASSERT(p == pNew_context);
4132 VOGL_NOTE_UNUSED(p);
4134 pNew_context->set_display(dpy);
4135 pNew_context->set_drawable(drawable);
4136 pNew_context->set_read_drawable(drawable);
4140 if (g_dump_gl_calls_flag)
4142 vogl_log_printf("** glXMakeCurrent result: %i\n", result);
4145 if (g_vogl_trace_writer.is_opened())
4147 vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glXMakeCurrent, pCur_context);
4148 serializer.set_begin_rdtsc(begin_rdtsc);
4149 serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
4150 serializer.add_param(0, VOGL_CONST_DISPLAY_PTR, &dpy, sizeof(dpy));
4151 serializer.add_param(1, VOGL_GLXDRAWABLE, &drawable, sizeof(drawable));
4152 serializer.add_param(2, VOGL_GLXCONTEXT, &context, sizeof(context));
4153 serializer.add_return_param(VOGL_BOOL, &result, sizeof(result));
4155 vogl_add_make_current_key_value_fields(dpy, drawable, result, pNew_context, serializer);
4158 vogl_write_packet_to_trace(serializer.get_packet());
4161 if (g_dump_gl_calls_flag)
4163 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
4166 static bool s_added_atexit = false;
4167 if (!s_added_atexit)
4169 // atexit routines are called in the reverse order in which they were registered. We would like
4170 // our vogl_atexit() routine to be called before anything else (Ie C++ destructors, etc.) So we
4171 // put atexit at the end of vogl_global_init() and another at the end of glXMakeCurrent.
4172 atexit(vogl_atexit);
4173 s_added_atexit = true;
4179 //----------------------------------------------------------------------------------------------------------------------
4180 #define DEF_FUNCTION_CUSTOM_HANDLER_glXMakeContextCurrent(exported, category, ret, ret_type_enum, num_params, name, args, params)
4181 static Bool vogl_glXMakeContextCurrent(const Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext context)
4183 uint64_t begin_rdtsc = utils::RDTSC();
4185 if (g_dump_gl_calls_flag)
4187 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
4190 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXMakeContextCurrent);
4191 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
4193 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);
4194 return GL_ENTRYPOINT(glXMakeContextCurrent)(dpy, draw, read, context);
4197 if (g_dump_gl_calls_flag)
4199 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));
4202 vogl_context *pCur_context = g_context_manager.get_current();
4204 vogl_context *pNew_context = context ? g_context_manager.lookup_vogl_context(context) : NULL;
4205 if ((context) && (!pNew_context))
4207 vogl_error_printf("%s: Unknown coontext handle 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(context));
4212 if (pCur_context != pNew_context)
4213 pCur_context->on_release_current_prolog();
4215 vogl_warning_printf("%s: Context 0x%" PRIX64 " is already current (redundant call)\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(context));
4218 uint64_t gl_begin_rdtsc = utils::RDTSC();
4219 Bool result = GL_ENTRYPOINT(glXMakeContextCurrent)(dpy, draw, read, context);
4220 uint64_t gl_end_rdtsc = utils::RDTSC();
4222 if ((result) && (pCur_context != pNew_context))
4225 g_context_manager.release_current();
4229 vogl_context *p = g_context_manager.make_current(context);
4230 VOGL_ASSERT(p == pNew_context);
4231 VOGL_NOTE_UNUSED(p);
4233 pNew_context->set_display(dpy);
4234 pNew_context->set_drawable(draw);
4235 pNew_context->set_read_drawable(read);
4239 if (g_dump_gl_calls_flag)
4241 vogl_log_printf("** glXMakeCurrent result: %i\n", result);
4244 if (g_vogl_trace_writer.is_opened())
4246 vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glXMakeContextCurrent, pCur_context);
4247 serializer.set_begin_rdtsc(begin_rdtsc);
4248 serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
4249 serializer.add_param(0, VOGL_CONST_DISPLAY_PTR, &dpy, sizeof(dpy));
4250 serializer.add_param(1, VOGL_GLXDRAWABLE, &draw, sizeof(draw));
4251 serializer.add_param(2, VOGL_GLXDRAWABLE, &read, sizeof(read));
4252 serializer.add_param(3, VOGL_GLXCONTEXT, &context, sizeof(context));
4253 serializer.add_return_param(VOGL_BOOL, &result, sizeof(result));
4255 vogl_add_make_current_key_value_fields(dpy, draw, result, pNew_context, serializer);
4258 vogl_write_packet_to_trace(serializer.get_packet());
4261 if (g_dump_gl_calls_flag)
4263 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
4269 //----------------------------------------------------------------------------------------------------------------------
4270 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)
4272 vogl_context *pContext = static_cast<vogl_context *>(pOpaque);
4274 if ((!pContext) || (!width) || (!height))
4280 if ((pixel_format != GL_RGB) || (pixel_type != GL_UNSIGNED_BYTE) || (pitch != width * 3))
4286 if (g_command_line_params.get_value_as_bool("vogl_dump_png_screenshots"))
4288 size_t png_size = 0;
4289 void *pPNG_data = tdefl_write_image_to_png_file_in_memory_ex(pImage, width, height, 3, &png_size, 1, true);
4291 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));
4292 if (!file_utils::write_buf_to_file(screenshot_filename.get_ptr(), pPNG_data, png_size))
4294 console::error("Failed writing PNG screenshot to file %s\n", screenshot_filename.get_ptr());
4299 else if (g_command_line_params.get_value_as_bool("vogl_dump_jpeg_screenshots"))
4301 int jpeg_quality = g_command_line_params.get_value_as_int("vogl_jpeg_quality", 0, 80, 1, 100);
4303 long unsigned int jpeg_size = 0;
4304 unsigned char *pJPEG_data = NULL;
4306 tjhandle _jpegCompressor = tjInitCompress();
4308 int status = tjCompress2(_jpegCompressor, (unsigned char *)pImage, width, pitch, height, TJPF_RGB,
4309 &pJPEG_data, &jpeg_size, TJSAMP_422, jpeg_quality,
4310 TJFLAG_FASTDCT | TJFLAG_BOTTOMUP);
4312 tjDestroy(_jpegCompressor);
4316 dynamic_string screenshot_filename(cVarArg, "%s_%08" PRIx64 "_%08" PRIu64 ".jpg",
4317 g_command_line_params.get_value_as_string("vogl_screenshot_prefix", 0, "screenshot").get_ptr(),
4318 cast_val_to_uint64(pContext->get_context_handle()),
4319 cast_val_to_uint64(frame_index));
4320 if (!file_utils::write_buf_to_file(screenshot_filename.get_ptr(), pJPEG_data, jpeg_size))
4322 console::error("Failed writing JPEG screenshot to file %s\n", screenshot_filename.get_ptr());
4329 if (g_command_line_params.get_value_as_bool("vogl_dump_backbuffer_hashes") || g_command_line_params.get_value_as_bool("vogl_hash_backbuffer"))
4331 uint64_t backbuffer_crc64;
4333 if (g_command_line_params.get_value_as_bool("vogl_sum_hashing"))
4335 backbuffer_crc64 = calc_sum64(static_cast<const uint8 *>(pImage), size);
4339 backbuffer_crc64 = calc_crc64(CRC64_INIT, static_cast<const uint8 *>(pImage), size);
4342 console::printf("Frame %" PRIu64 " hash: 0x%016" PRIX64 "\n", cast_val_to_uint64(frame_index), backbuffer_crc64);
4344 dynamic_string backbuffer_hash_file;
4345 if (g_command_line_params.get_value_as_string(backbuffer_hash_file, "vogl_dump_backbuffer_hashes"))
4347 FILE *pFile = vogl_fopen(backbuffer_hash_file.get_ptr(), "a");
4349 console::error("Failed writing to backbuffer hash file %s\n", backbuffer_hash_file.get_ptr());
4352 vogl_fprintf(pFile, "0x%016" PRIX64 "\n", backbuffer_crc64);
4360 //----------------------------------------------------------------------------------------------------------------------
4361 static void vogl_tick_screen_capture(vogl_context *pVOGL_context)
4366 uint width = pVOGL_context->get_window_width();
4367 uint height = pVOGL_context->get_window_height();
4368 if ((!width) || (!height))
4371 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") ||
4372 g_command_line_params.get_value_as_bool("vogl_dump_jpeg_screenshots") || g_command_line_params.get_value_as_bool("vogl_dump_png_screenshots");
4373 if (!grab_backbuffer)
4376 vogl_scoped_gl_error_absorber gl_error_absorber(pVOGL_context);
4377 VOGL_NOTE_UNUSED(gl_error_absorber);
4379 if (!pVOGL_context->get_framebuffer_capturer().is_initialized())
4381 if (!pVOGL_context->get_framebuffer_capturer().init(2, vogl_screen_capture_callback, pVOGL_context, GL_RGB, GL_UNSIGNED_BYTE))
4383 vogl_error_printf("%s: Failed initializing context's vogl_framebuffer_capturer!\n", VOGL_FUNCTION_NAME);
4388 if (!pVOGL_context->get_framebuffer_capturer().capture(width, height, 0, GL_BACK, pVOGL_context->get_frame_index()))
4390 vogl_error_printf("%s: vogl_framebuffer_capturer::capture() failed!\n", VOGL_FUNCTION_NAME);
4395 //----------------------------------------------------------------------------------------------------------------------
4396 static vogl_gl_state_snapshot *vogl_snapshot_state(const Display *dpy, GLXDrawable drawable, vogl_context *pCur_context)
4398 VOGL_NOTE_UNUSED(dpy);
4399 VOGL_NOTE_UNUSED(drawable);
4401 // pCur_context may be NULL!
4403 if (!GL_ENTRYPOINT(glXGetCurrentContext) || !GL_ENTRYPOINT(glXGetCurrentDisplay) ||
4404 !GL_ENTRYPOINT(glXGetCurrentDrawable) || !GL_ENTRYPOINT(glXGetCurrentReadDrawable))
4407 timed_scope ts(VOGL_FUNCTION_NAME);
4409 g_context_manager.lock();
4411 if (vogl_check_gl_error())
4412 vogl_error_printf("%s: A GL error occured sometime before this function was called\n", VOGL_FUNCTION_NAME);
4414 const Display *orig_dpy = GL_ENTRYPOINT(glXGetCurrentDisplay)();
4415 GLXDrawable orig_drawable = GL_ENTRYPOINT(glXGetCurrentDrawable)();
4416 GLXDrawable orig_read_drawable = GL_ENTRYPOINT(glXGetCurrentReadDrawable)();
4417 GLXContext orig_context = GL_ENTRYPOINT(glXGetCurrentContext)();
4422 vogl_check_gl_error();
4424 vogl_gl_state_snapshot *pSnapshot = vogl_new(vogl_gl_state_snapshot);
4426 const glxcontext_map &contexts = g_context_manager.get_context_map();
4428 // TODO: Find a better way of determining which window dimensions to use.
4429 // No context is current, let's just find the biggest window.
4431 uint win_height = 0;
4434 win_width = pCur_context->get_window_width();
4435 win_height = pCur_context->get_window_height();
4439 glxcontext_map::const_iterator it;
4440 for (it = contexts.begin(); it != contexts.end(); ++it)
4442 vogl_context *pVOGL_context = it->second;
4443 if ((pVOGL_context->get_window_width() > (int)win_width) || (pVOGL_context->get_window_height() > (int)win_height))
4445 win_width = pVOGL_context->get_window_width();
4446 win_height = pVOGL_context->get_window_height();
4451 vogl_message_printf("%s: Beginning capture: width %u, height %u\n", VOGL_FUNCTION_NAME, win_width, win_height);
4453 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))
4455 vogl_error_printf("%s: Failed beginning capture\n", VOGL_FUNCTION_NAME);
4457 vogl_delete(pSnapshot);
4460 g_context_manager.unlock();
4465 vogl_printf("%s: Capturing %u context(s)\n", VOGL_FUNCTION_NAME, contexts.size());
4467 glxcontext_map::const_iterator it;
4468 for (it = contexts.begin(); it != contexts.end(); ++it)
4470 GLXContext glx_context = it->first;
4471 vogl_context *pVOGL_context = it->second;
4473 if (pVOGL_context->get_deleted_flag())
4475 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));
4479 if (pVOGL_context->get_has_been_made_current())
4481 if (!GL_ENTRYPOINT(glXMakeCurrent)(pVOGL_context->get_display(), pVOGL_context->get_drawable(), glx_context))
4483 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));
4487 if (pVOGL_context->get_total_mapped_buffers())
4489 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());
4493 if (pVOGL_context->is_composing_display_list())
4495 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));
4499 if (pVOGL_context->get_in_gl_begin())
4501 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));
4506 vogl_capture_context_params &capture_context_params = pVOGL_context->get_capture_context_params();
4508 if (!pSnapshot->capture_context(pVOGL_context->get_context_desc(), pVOGL_context->get_context_info(), pVOGL_context->get_handle_remapper(), capture_context_params))
4510 vogl_error_printf("%s: Failed capturing trace context 0x%" PRIX64 ", capture failed\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(glx_context));
4515 if ((it == contexts.end()) && (pSnapshot->end_capture()))
4517 vogl_printf("%s: Capture succeeded\n", VOGL_FUNCTION_NAME);
4521 vogl_printf("%s: Capture failed\n", VOGL_FUNCTION_NAME);
4523 vogl_delete(pSnapshot);
4529 GL_ENTRYPOINT(glXMakeContextCurrent)(orig_dpy, orig_drawable, orig_read_drawable, orig_context);
4532 vogl_check_gl_error();
4534 g_context_manager.unlock();
4539 //----------------------------------------------------------------------------------------------------------------------
4541 // Important: This could be called at signal time!
4542 //----------------------------------------------------------------------------------------------------------------------
4543 static void vogl_end_capture(bool inside_signal_handler)
4547 VOGL_NOTE_UNUSED(inside_signal_handler);
4549 vogl_debug_printf("%s\n", VOGL_FUNCTION_NAME);
4551 g_context_manager.lock();
4553 vogl_context *pVOGL_context = g_context_manager.get_current();
4557 pVOGL_context->get_framebuffer_capturer().flush();
4559 if (inside_signal_handler)
4561 vogl_thread_local_data *pTLS_data = vogl_get_thread_local_data();
4562 if ((pTLS_data) && (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID))
4564 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);
4566 if (g_vogl_trace_writer.is_opened())
4568 vogl_entrypoint_serializer &trace_serializer = pTLS_data->m_serializer;
4569 if (trace_serializer.is_in_begin())
4571 vogl_error_printf("%s: Attempting to flush final trace packet\n", VOGL_FUNCTION_NAME);
4573 trace_serializer.end();
4575 vogl_write_packet_to_trace(trace_serializer.get_packet());
4582 g_context_manager.unlock();
4584 scoped_mutex lock(g_vogl_trace_mutex);
4586 if (g_vogl_trace_writer.is_opened())
4588 dynamic_string filename(g_vogl_trace_writer.get_filename());
4590 vogl_flush_compilerinfo_to_trace_file();
4591 vogl_flush_machineinfo_to_trace_file();
4592 vogl_flush_backtrace_to_trace_file();
4594 if (!g_vogl_trace_writer.close())
4596 vogl_error_printf("%s: Failed closing trace file!\n", VOGL_FUNCTION_NAME);
4598 if (g_vogl_pCapture_status_callback)
4599 (*g_vogl_pCapture_status_callback)(NULL, g_vogl_pCapture_status_opaque);
4603 if (g_vogl_pCapture_status_callback)
4604 (*g_vogl_pCapture_status_callback)(filename.get_ptr(), g_vogl_pCapture_status_opaque);
4607 if (g_pJSON_node_pool)
4609 uint64_t total_bytes_freed = static_cast<uint64_t>(g_pJSON_node_pool->free_unused_blocks());
4610 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()));
4614 g_vogl_frames_remaining_to_capture = 0;
4616 g_vogl_pCapture_status_callback = NULL;
4617 g_vogl_pCapture_status_opaque = NULL;
4620 //----------------------------------------------------------------------------------------------------------------------
4621 static bool vogl_write_snapshot_to_trace(const char *pTrace_filename, const Display *dpy, GLXDrawable drawable, vogl_context *pVOGL_context)
4624 vogl_message_printf("%s: Snapshot begin\n", VOGL_FUNCTION_NAME);
4626 // pVOGL_context may be NULL here!
4628 vogl_unique_ptr<vogl_gl_state_snapshot> pSnapshot(vogl_snapshot_state(dpy, drawable, pVOGL_context));
4629 if (!pSnapshot.get())
4631 vogl_error_printf("%s: Failed snapshotting GL/GLX state!\n", VOGL_FUNCTION_NAME);
4638 pSnapshot->set_frame_index(0);
4640 if (!g_vogl_trace_writer.open(pTrace_filename, NULL, true, false))
4642 vogl_error_printf("%s: Failed creating trace file \"%s\"!\n", VOGL_FUNCTION_NAME, pTrace_filename);
4649 vogl_archive_blob_manager &trace_archive = *g_vogl_trace_writer.get_trace_archive();
4651 vogl_message_printf("%s: Serializing snapshot data to JSON document\n", VOGL_FUNCTION_NAME);
4653 // 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.
4655 if (!pSnapshot->serialize(*doc.get_root(), trace_archive, &g_vogl_process_gl_ctypes))
4657 vogl_error_printf("%s: Failed serializing GL state snapshot!\n", VOGL_FUNCTION_NAME);
4666 vogl_message_printf("%s: Serializing JSON document to UBJ\n", VOGL_FUNCTION_NAME);
4668 uint8_vec binary_snapshot_data;
4669 vogl::vector<char> snapshot_data;
4671 // TODO: This can take a lot of memory
4672 doc.binary_serialize(binary_snapshot_data);
4674 vogl_message_printf("%s: Compressing UBJ data and adding to trace archive\n", VOGL_FUNCTION_NAME);
4676 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));
4677 if (binary_snapshot_id.is_empty())
4679 vogl_error_printf("%s: Failed adding binary GL snapshot file to output blob manager!\n", VOGL_FUNCTION_NAME);
4686 binary_snapshot_data.clear();
4688 snapshot_data.clear();
4691 // TODO: This requires too much temp memory!
4692 doc.serialize(snapshot_data, true, 0, false);
4694 dynamic_string snapshot_id(trace_archive.add_buf_compute_unique_id(snapshot_data.get_ptr(), snapshot_data.size(), "state_snapshot", VOGL_TEXT_JSON_EXTENSION));
4695 if (snapshot_id.is_empty())
4697 vogl_error_printf("%s: Failed adding binary GL snapshot file to output blob manager!\n", VOGL_FUNCTION_NAME);
4698 g_vogl_trace_writer.deinit();
4703 key_value_map snapshot_key_value_map;
4704 snapshot_key_value_map.insert("command_type", "state_snapshot");
4705 snapshot_key_value_map.insert("binary_id", binary_snapshot_id);
4708 // TODO: This requires too much temp memory!
4709 snapshot_key_value_map.insert("id", snapshot_id);
4712 vogl_ctypes &trace_gl_ctypes = g_vogl_process_gl_ctypes;
4713 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)))
4717 vogl_error_printf("%s: Failed writing to trace file!\n", VOGL_FUNCTION_NAME);
4721 if (!vogl_write_glInternalTraceCommandRAD(g_vogl_trace_writer.get_stream(), &trace_gl_ctypes, cITCRDemarcation, 0, NULL))
4725 vogl_error_printf("%s: Failed writing to trace file!\n", VOGL_FUNCTION_NAME);
4731 if (g_pJSON_node_pool)
4733 uint64_t total_bytes_freed = static_cast<uint64_t>(g_pJSON_node_pool->free_unused_blocks());
4734 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()));
4737 vogl_message_printf("%s: Snapshot complete\n", VOGL_FUNCTION_NAME);
4742 //----------------------------------------------------------------------------------------------------------------------
4743 static void vogl_capture_status_callback_func(const char *pFilename, void *pOpaque)
4746 VOGL_ASSERT(pOpaque == (void *)1);
4747 vogl_message_printf("%s: Filename \"%s\", opaque: %p\n", VOGL_FUNCTION_NAME, pFilename ? pFilename : "<null>", pOpaque);
4750 //----------------------------------------------------------------------------------------------------------------------
4751 static bool vogl_check_for_trigger_file(const char *pBase_name, dynamic_string &filename)
4753 filename = pBase_name;
4754 if (!file_utils::does_file_exist(filename.get_ptr()))
4756 dynamic_string path_to_check(g_command_line_params.get_value_as_string_or_empty("vogl_tracepath"));
4757 if (path_to_check.is_empty())
4758 path_to_check = file_utils::get_pathname(g_command_line_params.get_value_as_string_or_empty("vogl_tracefile").get_ptr());
4760 if (path_to_check.is_empty())
4763 file_utils::combine_path(filename, path_to_check.get_ptr(), pBase_name);
4764 if (!file_utils::does_file_exist(filename.get_ptr()))
4771 //----------------------------------------------------------------------------------------------------------------------
4772 static void vogl_check_for_capture_stop_file()
4774 if (!vogl_is_capturing())
4777 dynamic_string stop_filename;
4778 if (!vogl_check_for_trigger_file(VOGL_STOP_CAPTURE_FILENAME, stop_filename))
4781 file_utils::delete_file(stop_filename.get_ptr());
4783 vogl_stop_capturing();
4786 //----------------------------------------------------------------------------------------------------------------------
4787 static void vogl_check_for_capture_trigger_file()
4790 scoped_mutex lock(g_vogl_trace_mutex);
4791 if ((g_vogl_frames_remaining_to_capture) || (g_vogl_trace_writer.is_opened()))
4795 dynamic_string trigger_filename;
4796 if (!vogl_check_for_trigger_file(VOGL_TRIGGER_CAPTURE_FILENAME, trigger_filename))
4801 // Lamely try to protected against racing - a better method is probably inotify: http://www.thegeekstuff.com/2010/04/inotify-c-program-example/
4805 file_utils::get_file_size(trigger_filename.get_ptr(), size);
4810 file_utils::get_file_size(trigger_filename.get_ptr(), size1);
4818 uint total_frames = 1;
4819 dynamic_string path;
4820 dynamic_string base_name;
4822 dynamic_string_array lines;
4823 if (!file_utils::read_text_file(trigger_filename.get_ptr(), lines, file_utils::cRTFTrim | file_utils::cRTFIgnoreEmptyLines))
4825 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());
4829 if (lines.size() >= 1)
4831 if (lines[0] == "all")
4832 total_frames = cUINT32_MAX;
4834 total_frames = string_to_uint(lines[0].get_ptr(), 1);
4836 if (lines.size() >= 2)
4840 if (lines.size() >= 3)
4841 base_name = lines[2];
4845 file_utils::delete_file(trigger_filename.get_ptr());
4847 bool success = vogl_capture_on_next_swap(total_frames, path.get_ptr(), base_name.get_ptr(), vogl_capture_status_callback_func, (void *)1);
4850 vogl_error_printf("%s: Failed enabling capture mode\n", VOGL_FUNCTION_NAME);
4852 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());
4855 //----------------------------------------------------------------------------------------------------------------------
4856 // vogl_tick_capture
4857 //----------------------------------------------------------------------------------------------------------------------
4858 static void vogl_tick_capture(const Display *dpy, GLXDrawable drawable, vogl_context *pVOGL_context)
4862 // pVOGL_context may be NULL here!
4864 vogl_check_for_capture_stop_file();
4865 vogl_check_for_capture_trigger_file();
4867 scoped_mutex lock(g_vogl_trace_mutex);
4869 if ((g_vogl_total_frames_to_capture) && (!g_vogl_frames_remaining_to_capture))
4871 g_vogl_frames_remaining_to_capture = g_vogl_total_frames_to_capture;
4872 g_vogl_total_frames_to_capture = 0;
4875 if (g_vogl_stop_capturing)
4877 g_vogl_stop_capturing = false;
4879 if (g_vogl_trace_writer.is_opened())
4887 if (!g_vogl_frames_remaining_to_capture)
4890 if (!g_vogl_trace_writer.is_opened())
4892 dynamic_string trace_path(g_command_line_params.get_value_as_string_or_empty("vogl_tracepath"));
4893 if (trace_path.is_empty())
4894 trace_path = "/tmp";
4895 if (!g_vogl_capture_path.is_empty())
4896 trace_path = g_vogl_capture_path;
4898 time_t t = time(NULL);
4899 struct tm ltm = *localtime(&t);
4901 dynamic_string trace_basename("capture");
4902 if (!g_vogl_capture_basename.is_empty())
4903 trace_basename = g_vogl_capture_basename;
4905 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);
4907 dynamic_string full_trace_filename;
4908 file_utils::combine_path(full_trace_filename, trace_path.get_ptr(), filename.get_ptr());
4910 if (g_vogl_frames_remaining_to_capture == cUINT32_MAX)
4911 vogl_message_printf("%s: Initiating capture of all remaining frames to file \"%s\"\n", VOGL_FUNCTION_NAME, full_trace_filename.get_ptr());
4913 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());
4915 if (!vogl_write_snapshot_to_trace(full_trace_filename.get_ptr(), dpy, drawable, pVOGL_context))
4917 file_utils::delete_file(full_trace_filename.get_ptr());
4918 vogl_error_printf("%s: Failed creating GL state snapshot, closing and deleting trace file\n", VOGL_FUNCTION_NAME);
4923 if (g_vogl_frames_remaining_to_capture != cUINT32_MAX)
4924 g_vogl_frames_remaining_to_capture--;
4926 // See if we should stop capturing.
4927 if (!g_vogl_frames_remaining_to_capture)
4935 //----------------------------------------------------------------------------------------------------------------------
4936 // vogl_glXSwapBuffersGLFuncProlog
4937 //----------------------------------------------------------------------------------------------------------------------
4938 static inline void vogl_glXSwapBuffersGLFuncProlog(const Display *dpy, GLXDrawable drawable, vogl_context *pVOGL_context, vogl_entrypoint_serializer &trace_serializer)
4940 // pVOGL_context may be NULL here!
4942 if (!GL_ENTRYPOINT(glXGetCurrentContext) || !GL_ENTRYPOINT(glXGetCurrentDisplay) ||
4943 !GL_ENTRYPOINT(glXGetCurrentDrawable) || !GL_ENTRYPOINT(glXGetCurrentReadDrawable))
4948 bool override_current_context = false;
4950 if ((!pVOGL_context) || ((pVOGL_context->get_display() != dpy) || (pVOGL_context->get_drawable() != drawable)))
4952 // 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.
4953 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);
4955 pVOGL_context = g_context_manager.find_context(dpy, drawable);
4959 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);
4962 else if (pVOGL_context->get_current_thread() != 0)
4964 vogl_error_printf("%s: The GL context which matches the provided display/drawable is already current on another thread!\n", VOGL_FUNCTION_NAME);
4968 override_current_context = true;
4971 GLXContext orig_context = 0;
4972 const Display *orig_dpy = NULL;
4973 GLXDrawable orig_drawable = 0;
4974 GLXDrawable orig_read_drawable = 0;
4975 if (override_current_context)
4977 orig_context = GL_ENTRYPOINT(glXGetCurrentContext)();
4978 orig_dpy = GL_ENTRYPOINT(glXGetCurrentDisplay)();
4979 orig_drawable = GL_ENTRYPOINT(glXGetCurrentDrawable)();
4980 orig_read_drawable = GL_ENTRYPOINT(glXGetCurrentReadDrawable)();
4985 GL_ENTRYPOINT(glXMakeCurrent)(pVOGL_context->get_display(), pVOGL_context->get_drawable(), pVOGL_context->get_context_handle());
4990 unsigned int width = 0, height = 0, border_width = 0, depth = 0;
4991 if ((dpy) && (XGetGeometry(const_cast<Display *>(dpy), drawable, &root, &x, &y, &width, &height, &border_width, &depth) != False))
4993 pVOGL_context->set_window_dimensions(width, height);
4995 vogl_tick_screen_capture(pVOGL_context);
4999 console::warning("%s: XGetGeometry() call failed!\n", VOGL_FUNCTION_NAME);
5002 if (trace_serializer.is_in_begin())
5004 trace_serializer.add_key_value(string_hash("win_width"), pVOGL_context->get_window_width());
5005 trace_serializer.add_key_value(string_hash("win_height"), pVOGL_context->get_window_height());
5008 if (g_dump_gl_calls_flag)
5010 vogl_log_printf("** Current window dimensions: %ix%i\n", pVOGL_context->get_window_width(), pVOGL_context->get_window_height());
5013 pVOGL_context->inc_frame_index();
5015 if ((override_current_context) && (orig_dpy))
5017 GL_ENTRYPOINT(glXMakeContextCurrent)(orig_dpy, orig_drawable, orig_read_drawable, orig_context);
5021 //----------------------------------------------------------------------------------------------------------------------
5022 #define DEF_FUNCTION_CUSTOM_HANDLER_glXSwapBuffers(exported, category, ret, ret_type_enum, num_params, name, args, params)
5023 static void vogl_glXSwapBuffers(const Display *dpy, GLXDrawable drawable)
5025 uint64_t begin_rdtsc = utils::RDTSC();
5027 if (g_dump_gl_calls_flag)
5029 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5032 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXSwapBuffers);
5033 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
5035 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);
5036 return GL_ENTRYPOINT(glXSwapBuffers)(dpy, drawable);
5039 // Use a local serializer because the call to glXSwapBuffer()'s will make GL calls if something like the Steam Overlay is active.
5040 vogl_entrypoint_serializer serializer;
5042 if (g_vogl_trace_writer.is_opened())
5044 serializer.begin(VOGL_ENTRYPOINT_glXSwapBuffers, g_context_manager.get_current());
5045 serializer.add_param(0, VOGL_CONST_DISPLAY_PTR, &dpy, sizeof(dpy));
5046 serializer.add_param(1, VOGL_GLXDRAWABLE, &drawable, sizeof(drawable));
5049 vogl_glXSwapBuffersGLFuncProlog(dpy, drawable, pTLS_data->m_pContext, serializer);
5051 uint64_t gl_begin_rdtsc = utils::RDTSC();
5053 // Call the driver directly, bypassing our GL/GLX wrappers which set m_calling_driver_entrypoint_id. The Steam Overlay may call us back!
5054 DIRECT_GL_ENTRYPOINT(glXSwapBuffers)(dpy, drawable);
5056 uint64_t gl_end_rdtsc = utils::RDTSC();
5058 if (g_vogl_trace_writer.is_opened())
5060 serializer.set_begin_rdtsc(begin_rdtsc);
5061 serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
5063 vogl_write_packet_to_trace(serializer.get_packet());
5066 vogl_tick_capture(dpy, drawable, pTLS_data->m_pContext);
5068 if (g_dump_gl_calls_flag)
5070 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));
5073 if (g_dump_gl_calls_flag)
5075 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5078 if (g_command_line_params.has_key("vogl_exit_after_x_frames") && (pTLS_data->m_pContext))
5080 uint64_t max_num_frames = g_command_line_params.get_value_as_uint64("vogl_exit_after_x_frames");
5081 uint64_t cur_num_frames = pTLS_data->m_pContext->get_frame_index();
5083 if (cur_num_frames >= max_num_frames)
5085 vogl_message_printf("Number of frames specified by --vogl_exit_after_x_frames param reached, forcing trace to close and calling exit()\n");
5095 //----------------------------------------------------------------------------------------------------------------------
5096 #define DEF_FUNCTION_CUSTOM_HANDLER_glXCreateContextAttribsARB(exported, category, ret, ret_type_enum, num_params, name, args, params)
5097 static GLXContext vogl_glXCreateContextAttribsARB(const Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list)
5099 uint64_t begin_rdtsc = utils::RDTSC();
5101 if (g_dump_gl_calls_flag)
5103 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5106 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXCreateContextAttribsARB);
5107 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
5109 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);
5110 return GL_ENTRYPOINT(glXCreateContextAttribsARB)(dpy, config, share_context, direct, attrib_list);
5113 vogl_context_attribs context_attribs;
5115 if (g_command_line_params.get_value_as_bool("vogl_force_debug_context"))
5117 vogl_warning_printf("%s: Forcing debug context\n", VOGL_FUNCTION_NAME);
5119 context_attribs.init(attrib_list);
5120 if (!context_attribs.has_key(GLX_CONTEXT_FLAGS_ARB))
5121 context_attribs.add_key(GLX_CONTEXT_FLAGS_ARB, 0);
5123 int context_flags_value_ofs = context_attribs.find_value_ofs(GLX_CONTEXT_FLAGS_ARB);
5124 VOGL_ASSERT(context_flags_value_ofs >= 0);
5125 if (context_flags_value_ofs >= 0)
5126 context_attribs[context_flags_value_ofs] |= GLX_CONTEXT_DEBUG_BIT_ARB;
5128 int context_major_version_ofs = context_attribs.find_value_ofs(GLX_CONTEXT_MAJOR_VERSION_ARB);
5129 int context_minor_version_ofs = context_attribs.find_value_ofs(GLX_CONTEXT_MINOR_VERSION_ARB);
5131 if (context_major_version_ofs < 0)
5133 // 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).
5135 else if (context_attribs[context_major_version_ofs] < 3)
5137 context_attribs[context_major_version_ofs] = 3;
5139 if (context_minor_version_ofs < 0)
5140 context_attribs.add_key(GLX_CONTEXT_MINOR_VERSION_ARB, 0);
5142 context_attribs[context_minor_version_ofs] = 0;
5144 vogl_warning_printf("%s: Forcing GL context version up to v3.0 due to debug context usage\n", VOGL_FUNCTION_NAME);
5147 attrib_list = context_attribs.get_vec().get_ptr();
5150 uint64_t gl_begin_rdtsc = utils::RDTSC();
5151 GLXContext result = GL_ENTRYPOINT(glXCreateContextAttribsARB)(dpy, config, share_context, direct, attrib_list);
5152 uint64_t gl_end_rdtsc = utils::RDTSC();
5154 if (g_dump_gl_calls_flag)
5156 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));
5159 if (g_vogl_trace_writer.is_opened())
5161 vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glXCreateContextAttribsARB, g_context_manager.get_current());
5162 serializer.set_begin_rdtsc(begin_rdtsc);
5163 serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
5164 serializer.add_param(0, VOGL_CONST_DISPLAY_PTR, &dpy, sizeof(dpy));
5165 serializer.add_param(1, VOGL_GLXFBCONFIG, &config, sizeof(config));
5166 serializer.add_param(2, VOGL_GLXCONTEXT, &share_context, sizeof(share_context));
5167 serializer.add_param(3, VOGL_BOOL, &direct, sizeof(direct));
5168 serializer.add_param(4, VOGL_CONST_INT_PTR, &attrib_list, sizeof(attrib_list));
5171 uint n = vogl_determine_attrib_list_array_size(attrib_list);
5172 serializer.add_array_client_memory(4, VOGL_INT, n, attrib_list, sizeof(int) * n);
5174 serializer.add_return_param(VOGL_GLXCONTEXT, &result, sizeof(result));
5176 vogl_write_packet_to_trace(serializer.get_packet());
5183 if (!g_app_uses_sharelists)
5184 vogl_message_printf("%s: sharelist usage detected\n", VOGL_FUNCTION_NAME);
5186 g_app_uses_sharelists = true;
5189 g_context_manager.lock();
5191 vogl_context *pVOGL_context = g_context_manager.create_context(result);
5192 pVOGL_context->set_display(dpy);
5193 pVOGL_context->set_fb_config(config);
5194 pVOGL_context->set_sharelist_handle(share_context);
5195 pVOGL_context->set_direct(direct);
5196 pVOGL_context->set_attrib_list(attrib_list);
5197 pVOGL_context->set_created_from_attribs(true);
5198 pVOGL_context->set_creation_func(VOGL_ENTRYPOINT_glXCreateContextAttribsARB);
5202 vogl_context *pShare_context = g_context_manager.lookup_vogl_context(share_context);
5204 if (!pShare_context)
5205 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));
5208 while (!pShare_context->is_root_context())
5209 pShare_context = pShare_context->get_shared_state();
5211 pVOGL_context->set_shared_context(pShare_context);
5213 pShare_context->add_ref();
5217 pVOGL_context->init();
5219 g_context_manager.unlock();
5222 if (g_dump_gl_calls_flag)
5224 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5230 //----------------------------------------------------------------------------------------------------------------------
5231 // vogl_get_fb_config_from_xvisual_info
5232 // Attempts to find the GLXFBConfig corresponding to a particular visual.
5233 // TODO: Test this more!
5234 //----------------------------------------------------------------------------------------------------------------------
5235 static GLXFBConfig *vogl_get_fb_config_from_xvisual_info(const Display *dpy, const XVisualInfo *vis)
5237 vogl_context_attribs attribs;
5239 #define GET_CONFIG(attrib) \
5243 GL_ENTRYPOINT(glXGetConfig)(dpy, vis, attrib, &val); \
5245 attribs.add_key(attrib, val); \
5249 GL_ENTRYPOINT(glXGetConfig)(dpy, vis, GLX_RGBA, &is_rgba);
5251 attribs.add_key(GLX_RENDER_TYPE, is_rgba ? GLX_RGBA_BIT : GLX_COLOR_INDEX_BIT);
5252 attribs.add_key(GLX_X_RENDERABLE, True);
5253 attribs.add_key(GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT);
5256 GET_CONFIG(GLX_BUFFER_SIZE);
5258 GET_CONFIG(GLX_LEVEL);
5260 GET_CONFIG(GLX_DOUBLEBUFFER);
5261 GET_CONFIG(GLX_STEREO);
5262 GET_CONFIG(GLX_AUX_BUFFERS);
5265 GET_CONFIG(GLX_RED_SIZE);
5266 GET_CONFIG(GLX_GREEN_SIZE);
5267 GET_CONFIG(GLX_BLUE_SIZE);
5268 GET_CONFIG(GLX_ALPHA_SIZE);
5270 GET_CONFIG(GLX_DEPTH_SIZE);
5271 GET_CONFIG(GLX_STENCIL_SIZE);
5273 GET_CONFIG(GLX_TRANSPARENT_INDEX_VALUE);
5274 GET_CONFIG(GLX_TRANSPARENT_RED_VALUE);
5275 GET_CONFIG(GLX_TRANSPARENT_GREEN_VALUE);
5276 GET_CONFIG(GLX_TRANSPARENT_BLUE_VALUE);
5277 GET_CONFIG(GLX_TRANSPARENT_ALPHA_VALUE);
5279 if (attribs.get_value_or_default(GLX_TRANSPARENT_INDEX_VALUE) || attribs.get_value_or_default(GLX_TRANSPARENT_RED_VALUE) ||
5280 attribs.get_value_or_default(GLX_TRANSPARENT_GREEN_VALUE) || attribs.get_value_or_default(GLX_TRANSPARENT_BLUE_VALUE) ||
5281 attribs.get_value_or_default(GLX_TRANSPARENT_ALPHA_VALUE))
5283 GET_CONFIG(GLX_TRANSPARENT_TYPE);
5288 for (uint i = 0; i < attribs.size(); i += 2)
5292 printf("%s 0x%x\n", g_gl_enums.find_glx_name(attribs[i]), attribs[i + 1]);
5296 int num_configs = 0;
5297 GLXFBConfig *pConfigs = GL_ENTRYPOINT(glXChooseFBConfig)(dpy, vis->screen, attribs.get_ptr(), &num_configs);
5298 return num_configs ? pConfigs : NULL;
5301 //----------------------------------------------------------------------------------------------------------------------
5302 #define DEF_FUNCTION_CUSTOM_HANDLER_glXCreateContext(exported, category, ret, ret_type_enum, num_params, name, args, params)
5303 static GLXContext vogl_glXCreateContext(const Display *dpy, const XVisualInfo *vis, GLXContext shareList, Bool direct)
5305 uint64_t begin_rdtsc = utils::RDTSC();
5307 if (g_dump_gl_calls_flag)
5309 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5312 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXCreateContext);
5313 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
5315 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);
5316 return GL_ENTRYPOINT(glXCreateContext)(dpy, vis, shareList, direct);
5319 if (g_command_line_params.get_value_as_bool("vogl_force_debug_context"))
5321 vogl_warning_printf("%s: Can't enable debug contexts via glXCreateContext(), forcing call to use glXCreateContextsAttribsARB() instead\n", VOGL_FUNCTION_NAME);
5323 GLXFBConfig *pConfig = vogl_get_fb_config_from_xvisual_info(dpy, vis);
5326 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);
5330 int empty_attrib_list[1] = { 0 };
5331 return vogl_glXCreateContextAttribsARB(dpy, pConfig[0], shareList, direct, empty_attrib_list);
5335 uint64_t gl_begin_rdtsc = utils::RDTSC();
5336 GLXContext result = GL_ENTRYPOINT(glXCreateContext)(dpy, vis, shareList, direct);
5337 uint64_t gl_end_rdtsc = utils::RDTSC();
5339 if (g_dump_gl_calls_flag)
5341 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));
5344 if (g_vogl_trace_writer.is_opened())
5346 vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glXCreateContext, g_context_manager.get_current());
5347 serializer.set_begin_rdtsc(begin_rdtsc);
5348 serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
5349 serializer.add_param(0, VOGL_CONST_DISPLAY_PTR, &dpy, sizeof(dpy));
5350 serializer.add_param(1, VOGL_CONST_XVISUALINFO_PTR, &vis, sizeof(vis));
5351 serializer.add_param(2, VOGL_GLXCONTEXT, &shareList, sizeof(shareList));
5352 serializer.add_param(3, VOGL_BOOL, &direct, sizeof(direct));
5353 serializer.add_return_param(VOGL_GLXCONTEXT, &result, sizeof(result));
5355 serializer.add_ref_client_memory(1, VOGL_XVISUALINFO, vis, sizeof(XVisualInfo));
5357 vogl_write_packet_to_trace(serializer.get_packet());
5364 if (!g_app_uses_sharelists)
5365 vogl_message_printf("%s: sharelist usage detected\n", VOGL_FUNCTION_NAME);
5367 g_app_uses_sharelists = true;
5370 g_context_manager.lock();
5372 vogl_context *pVOGL_context = g_context_manager.create_context(result);
5373 pVOGL_context->set_display(dpy);
5374 pVOGL_context->set_xvisual_info(vis);
5375 pVOGL_context->set_sharelist_handle(shareList);
5376 pVOGL_context->set_direct(direct);
5377 pVOGL_context->set_creation_func(VOGL_ENTRYPOINT_glXCreateContext);
5381 vogl_context *pShare_context = g_context_manager.lookup_vogl_context(shareList);
5383 if (!pShare_context)
5384 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));
5387 while (!pShare_context->is_root_context())
5388 pShare_context = pShare_context->get_shared_state();
5390 pVOGL_context->set_shared_context(pShare_context);
5392 pShare_context->add_ref();
5396 pVOGL_context->init();
5398 g_context_manager.unlock();
5401 if (g_dump_gl_calls_flag)
5403 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5409 //----------------------------------------------------------------------------------------------------------------------
5410 #define DEF_FUNCTION_CUSTOM_HANDLER_glXCreateNewContext(exported, category, ret, ret_type_enum, num_params, name, args, params)
5411 static GLXContext vogl_glXCreateNewContext(const Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct)
5413 if (render_type != GLX_RGBA_TYPE)
5415 vogl_error_printf("%s: Unsupported render type (%s)!\n", VOGL_FUNCTION_NAME, g_gl_enums.find_glx_name(render_type));
5418 if (g_command_line_params.get_value_as_bool("vogl_force_debug_context"))
5420 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);
5422 return vogl_glXCreateContextAttribsARB(dpy, config, share_list, direct, NULL);
5425 uint64_t begin_rdtsc = utils::RDTSC();
5427 if (g_dump_gl_calls_flag)
5429 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5432 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXCreateNewContext);
5433 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
5435 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);
5436 return GL_ENTRYPOINT(glXCreateNewContext)(dpy, config, render_type, share_list, direct);
5439 uint64_t gl_begin_rdtsc = utils::RDTSC();
5440 GLXContext result = GL_ENTRYPOINT(glXCreateNewContext)(dpy, config, render_type, share_list, direct);
5441 uint64_t gl_end_rdtsc = utils::RDTSC();
5443 if (g_dump_gl_calls_flag)
5445 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",
5446 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));
5449 if (g_vogl_trace_writer.is_opened())
5451 vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glXCreateNewContext, g_context_manager.get_current());
5452 serializer.set_begin_rdtsc(begin_rdtsc);
5453 serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
5454 serializer.add_param(0, VOGL_CONST_DISPLAY_PTR, &dpy, sizeof(dpy));
5455 serializer.add_param(1, VOGL_GLXFBCONFIG, &config, sizeof(config));
5456 serializer.add_param(2, VOGL_INT, &render_type, sizeof(render_type));
5457 serializer.add_param(3, VOGL_GLXCONTEXT, &share_list, sizeof(share_list));
5458 serializer.add_param(4, VOGL_BOOL, &direct, sizeof(direct));
5459 serializer.add_return_param(VOGL_GLXCONTEXT, &result, sizeof(result));
5461 vogl_write_packet_to_trace(serializer.get_packet());
5468 if (!g_app_uses_sharelists)
5469 vogl_message_printf("%s: sharelist usage detected\n", VOGL_FUNCTION_NAME);
5471 g_app_uses_sharelists = true;
5474 g_context_manager.lock();
5476 vogl_context *pVOGL_context = g_context_manager.create_context(result);
5477 pVOGL_context->set_display(dpy);
5478 pVOGL_context->set_fb_config(config);
5479 pVOGL_context->set_sharelist_handle(share_list);
5480 pVOGL_context->set_direct(direct);
5481 pVOGL_context->set_creation_func(VOGL_ENTRYPOINT_glXCreateNewContext);
5485 vogl_context *pShare_context = g_context_manager.lookup_vogl_context(share_list);
5487 if (!pShare_context)
5488 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));
5491 while (!pShare_context->is_root_context())
5492 pShare_context = pShare_context->get_shared_state();
5494 pVOGL_context->set_shared_context(pShare_context);
5496 pShare_context->add_ref();
5500 pVOGL_context->init();
5502 g_context_manager.unlock();
5505 if (g_dump_gl_calls_flag)
5507 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5513 //----------------------------------------------------------------------------------------------------------------------
5514 #define DEF_FUNCTION_CUSTOM_HANDLER_glXDestroyContext(exported, category, ret, ret_type_enum, num_params, name, args, params)
5515 static void vogl_glXDestroyContext(const Display *dpy, GLXContext context)
5517 uint64_t begin_rdtsc = utils::RDTSC();
5519 if (g_dump_gl_calls_flag)
5521 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5524 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXDestroyContext);
5525 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
5527 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);
5528 return GL_ENTRYPOINT(glXDestroyContext)(dpy, context);
5531 if (g_dump_gl_calls_flag)
5533 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));
5536 vogl_context *pContext = context ? g_context_manager.lookup_vogl_context(context) : NULL;
5538 vogl_error_printf("%s: glXDestroyContext() called on an unknown context handle 0x%" PRIX64 "!\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(context));
5539 else if (pContext->get_current_thread())
5540 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());
5544 pContext->on_destroy_prolog();
5547 uint64_t gl_begin_rdtsc = utils::RDTSC();
5548 GL_ENTRYPOINT(glXDestroyContext)(dpy, context);
5549 uint64_t gl_end_rdtsc = utils::RDTSC();
5551 if (g_vogl_trace_writer.is_opened())
5553 vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glXDestroyContext, g_context_manager.get_current());
5554 serializer.set_begin_rdtsc(begin_rdtsc);
5555 serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
5556 serializer.add_param(0, VOGL_CONST_DISPLAY_PTR, &dpy, sizeof(dpy));
5557 serializer.add_param(1, VOGL_GLXCONTEXT, &context, sizeof(context));
5559 vogl_write_packet_to_trace(serializer.get_packet());
5560 g_vogl_trace_writer.flush();
5565 g_context_manager.lock();
5567 VOGL_ASSERT(!pContext->get_deleted_flag());
5568 if (!pContext->get_deleted_flag())
5570 pContext->set_deleted_flag(true);
5572 if (pContext->is_share_context())
5574 VOGL_ASSERT(pContext->get_ref_count() == 1);
5577 int new_ref_count = pContext->del_ref();
5578 if (new_ref_count <= 0)
5580 if (pContext->is_share_context())
5582 vogl_context *pRoot_context = pContext->get_shared_state();
5584 pContext->set_shared_context(NULL);
5586 if (pRoot_context->del_ref() == 0)
5588 VOGL_ASSERT(pRoot_context->get_deleted_flag());
5590 bool status = g_context_manager.destroy_context(pRoot_context->get_context_handle());
5591 VOGL_ASSERT(status);
5592 VOGL_NOTE_UNUSED(status);
5596 bool status = g_context_manager.destroy_context(context);
5597 VOGL_ASSERT(status);
5598 VOGL_NOTE_UNUSED(status);
5602 g_context_manager.unlock();
5605 if (g_vogl_pLog_stream)
5607 // TODO: Ensure this is actually thread safe (does the gcc C runtime mutex this?)
5608 g_vogl_pLog_stream->flush();
5611 if (g_dump_gl_calls_flag)
5613 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5617 //----------------------------------------------------------------------------------------------------------------------
5618 #define DEF_FUNCTION_CUSTOM_HANDLER_glGetError(exported, category, ret, ret_type_enum, num_params, name, args, params)
5619 static GLenum vogl_glGetError()
5621 uint64_t begin_rdtsc = utils::RDTSC();
5623 if (g_dump_gl_calls_flag)
5625 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5628 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glGetError);
5629 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
5631 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);
5632 return GL_ENTRYPOINT(glGetError)();
5635 if (g_dump_gl_calls_flag)
5637 vogl_log_printf("** glGetError TID: 0x%" PRIX64 "\n", vogl_get_current_kernel_thread_id());
5640 vogl_context *pContext = pTLS_data->m_pContext;
5641 // 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).
5642 // 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).
5644 uint64_t gl_begin_rdtsc = utils::RDTSC();
5645 GLenum gl_err = GL_ENTRYPOINT(glGetError)();
5646 uint64_t gl_end_rdtsc = utils::RDTSC();
5648 if (g_vogl_trace_writer.is_opened())
5650 vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glGetError, g_context_manager.get_current());
5651 serializer.set_begin_rdtsc(begin_rdtsc);
5652 serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
5653 serializer.add_return_param(VOGL_GLENUM, &gl_err, sizeof(gl_err));
5655 if ((pContext) && (pContext->has_latched_gl_error()))
5657 // Record the latched error too, so the replayer knows what's going on.
5658 serializer.add_key_value("latched_gl_error", pContext->get_latched_gl_error());
5662 vogl_write_packet_to_trace(serializer.get_packet());
5663 g_vogl_trace_writer.flush();
5666 // 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.
5667 if (pContext && pContext->has_latched_gl_error())
5669 if (gl_err != GL_NO_ERROR)
5671 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());
5674 // 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.
5675 gl_err = pContext->get_latched_gl_error();
5677 pContext->clear_latched_gl_error();
5680 if (g_dump_gl_calls_flag)
5682 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5688 //----------------------------------------------------------------------------------------------------------------------
5689 // shader source code
5690 //----------------------------------------------------------------------------------------------------------------------
5691 #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);
5692 #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);
5693 static void vogl_serialize_shader_source(vogl_entrypoint_serializer &trace_serializer, GLsizei count, const GLcharARB *const *string, const GLint *length)
5695 if (g_dump_gl_shaders_flag)
5697 vogl_log_printf("Source source code, %i string(s):\n", count);
5698 for (GLsizei i = 0; i < count; i++)
5700 const char *pStr = (const char *)string[i];
5703 str_len = length[i];
5705 str_len = pStr ? (vogl_strlen(pStr) + 1) : 0;
5707 vogl_log_printf("\"");
5708 vogl_print_string(pStr, str_len);
5709 vogl_log_printf("\"\n");
5713 if (trace_serializer.is_in_begin())
5715 for (GLsizei i = 0; i < count; i++)
5717 const char *pStr = (const char *)string[i];
5720 str_len = length[i];
5722 str_len = pStr ? (vogl_strlen(pStr) + 1) : 0;
5724 if ((str_len) && (pStr))
5725 trace_serializer.add_key_value_blob(i, pStr, str_len);
5730 //----------------------------------------------------------------------------------------------------------------------
5731 // vogl_uses_client_side_arrays
5732 //----------------------------------------------------------------------------------------------------------------------
5733 static bool vogl_uses_client_side_arrays(vogl_context *pContext, bool indexed)
5735 if ((!pContext) || (!pContext->get_uses_client_side_arrays()) || (pContext->is_core_profile()))
5738 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
5739 VOGL_NOTE_UNUSED(gl_error_absorber);
5743 GLuint element_array_buffer = vogl_get_bound_gl_buffer(GL_ELEMENT_ARRAY_BUFFER);
5744 if (!element_array_buffer)
5748 bool used_old_style_gl_client_side_arrays = false;
5750 GLint prev_client_active_texture = 0;
5751 GL_ENTRYPOINT(glGetIntegerv)(GL_CLIENT_ACTIVE_TEXTURE, &prev_client_active_texture);
5753 const uint tex_coords = pContext->get_max_texture_coords();
5755 for (uint i = 0; i < VOGL_NUM_CLIENT_SIDE_ARRAY_DESCS; i++)
5757 const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[i];
5758 if (i == vogl_texcoord_pointer_array_id)
5760 for (uint tex_index = 0; tex_index < tex_coords; tex_index++)
5762 GL_ENTRYPOINT(glClientActiveTexture)(GL_TEXTURE0 + tex_index);
5764 GLboolean is_enabled = GL_ENTRYPOINT(glIsEnabled)(desc.m_is_enabled);
5769 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_binding, &binding);
5773 used_old_style_gl_client_side_arrays = true;
5777 if (used_old_style_gl_client_side_arrays)
5782 GLboolean is_enabled = GL_ENTRYPOINT(glIsEnabled)(desc.m_is_enabled);
5787 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_binding, &binding);
5791 used_old_style_gl_client_side_arrays = true;
5796 GL_ENTRYPOINT(glClientActiveTexture)(prev_client_active_texture);
5798 if (used_old_style_gl_client_side_arrays)
5801 uint64_t vertex_attrib_client_side_arrays = 0;
5802 VOGL_ASSUME(VOGL_MAX_SUPPORTED_GL_VERTEX_ATTRIBUTES <= sizeof(vertex_attrib_client_side_arrays) * 8);
5804 for (uint i = 0; i < pContext->get_max_vertex_attribs(); i++)
5806 GLint is_enabled = 0;
5807 GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &is_enabled);
5812 GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &cur_buf);
5822 //----------------------------------------------------------------------------------------------------------------------
5823 // vogl_serialize_client_side_arrays_helper
5824 //----------------------------------------------------------------------------------------------------------------------
5825 static void vogl_serialize_client_side_arrays_helper(
5826 vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, const char *pFunc,
5827 GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex, bool start_end_valid, bool indexed)
5829 VOGL_NOTE_UNUSED(mode);
5831 VOGL_NOTE_UNUSED(pFunc);
5833 if ((!pContext) || (pContext->is_core_profile()))
5838 vogl_error_printf("%s: end (%i) must be >= start (%i)\n", VOGL_FUNCTION_NAME, end, start);
5842 uint index_size = vogl_get_gl_type_size(type);
5845 vogl_error_printf("%s: Invalid type parameter 0x%08X\n", VOGL_FUNCTION_NAME, type);
5849 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
5850 VOGL_NOTE_UNUSED(gl_error_absorber);
5852 GLuint element_array_buffer = 0;
5855 element_array_buffer = vogl_get_bound_gl_buffer(GL_ELEMENT_ARRAY_BUFFER);
5856 if (!element_array_buffer)
5860 vogl_error_printf("%s: No bound element array buffer, and indices parameter is NULL\n", VOGL_FUNCTION_NAME);
5865 if (g_dump_gl_buffers_flag)
5867 vogl_log_printf("Client side index data: ");
5868 vogl_print_hex(indices, count * index_size, index_size);
5869 vogl_log_printf("\n");
5872 if (trace_serializer.is_in_begin())
5874 trace_serializer.add_key_value_blob(string_hash("indices"), indices, count * index_size);
5880 const gl_entrypoint_id_t cur_entrypoint = trace_serializer.get_cur_entrypoint();
5881 VOGL_NOTE_UNUSED(cur_entrypoint);
5883 // 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.
5885 bool used_old_style_gl_client_side_arrays = false;
5887 GLint prev_client_active_texture = 0;
5888 GL_ENTRYPOINT(glGetIntegerv)(GL_CLIENT_ACTIVE_TEXTURE, &prev_client_active_texture);
5890 const uint tex_coords = pContext->get_max_texture_coords();
5892 for (uint i = 0; i < VOGL_NUM_CLIENT_SIDE_ARRAY_DESCS; i++)
5894 const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[i];
5895 if (i == vogl_texcoord_pointer_array_id)
5897 for (uint tex_index = 0; tex_index < tex_coords; tex_index++)
5899 GL_ENTRYPOINT(glClientActiveTexture)(GL_TEXTURE0 + tex_index);
5901 GLboolean is_enabled = GL_ENTRYPOINT(glIsEnabled)(desc.m_is_enabled);
5906 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_binding, &binding);
5910 used_old_style_gl_client_side_arrays = true;
5914 if (used_old_style_gl_client_side_arrays)
5919 GLboolean is_enabled = GL_ENTRYPOINT(glIsEnabled)(desc.m_is_enabled);
5924 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_binding, &binding);
5928 used_old_style_gl_client_side_arrays = true;
5933 GL_ENTRYPOINT(glClientActiveTexture)(prev_client_active_texture);
5935 uint64_t vertex_attrib_client_side_arrays = 0;
5936 VOGL_ASSUME(VOGL_MAX_SUPPORTED_GL_VERTEX_ATTRIBUTES <= sizeof(vertex_attrib_client_side_arrays) * 8);
5938 for (uint i = 0; i < pContext->get_max_vertex_attribs(); i++)
5940 GLint is_enabled = 0;
5941 GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &is_enabled);
5946 GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &cur_buf);
5950 vertex_attrib_client_side_arrays |= (1ULL << i);
5953 if ((!used_old_style_gl_client_side_arrays) && (!vertex_attrib_client_side_arrays))
5958 if (!start_end_valid)
5960 uint total_index_data_size = count * index_size;
5962 // FIXME: Move index_data array to context state
5963 vogl::vector<uint8> index_data;
5964 const uint8 *pIndices_to_scan = static_cast<const uint8 *>(indices);
5966 if (element_array_buffer)
5968 index_data.resize(total_index_data_size);
5969 pIndices_to_scan = index_data.get_ptr();
5971 GL_ENTRYPOINT(glGetBufferSubData)(GL_ELEMENT_ARRAY_BUFFER, (GLintptr)indices, total_index_data_size, index_data.get_ptr());
5974 start = cUINT32_MAX;
5977 for (int i = 0; i < count; i++)
5981 if (type == GL_UNSIGNED_BYTE)
5982 v = pIndices_to_scan[i];
5983 else if (type == GL_UNSIGNED_SHORT)
5984 v = reinterpret_cast<const uint16 *>(pIndices_to_scan)[i];
5985 else if (type == GL_UNSIGNED_INT)
5986 v = reinterpret_cast<const uint32 *>(pIndices_to_scan)[i];
5992 start = math::minimum(start, v);
5993 end = math::maximum(end, v);
5997 if (trace_serializer.is_in_begin())
5999 trace_serializer.add_key_value(string_hash("start"), start);
6000 trace_serializer.add_key_value(string_hash("end"), end);
6004 if (used_old_style_gl_client_side_arrays)
6006 for (uint client_array_iter = 0; client_array_iter < VOGL_NUM_CLIENT_SIDE_ARRAY_DESCS; client_array_iter++)
6008 const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[client_array_iter];
6011 uint base_key_index = 0x1000 + client_array_iter;
6013 // Special case texcoord pointers, which are accessed via the client active texture.
6014 if (client_array_iter == vogl_texcoord_pointer_array_id)
6017 base_key_index = 0x2000;
6020 for (uint inner_iter = 0; inner_iter < n; inner_iter++)
6022 if (client_array_iter == vogl_texcoord_pointer_array_id)
6024 GL_ENTRYPOINT(glClientActiveTexture)(GL_TEXTURE0 + inner_iter);
6027 GLboolean is_enabled = GL_ENTRYPOINT(glIsEnabled)(desc.m_is_enabled);
6032 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_binding, &binding);
6037 GL_ENTRYPOINT(glGetPointerv)(desc.m_get_pointer, &ptr);
6041 GLint type = GL_BOOL;
6042 if (desc.m_get_type)
6044 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_type, &type);
6048 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_stride, &stride);
6051 if (desc.m_get_size)
6053 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_size, &size);
6056 uint type_size = vogl_get_gl_type_size(type);
6059 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);
6063 if ((desc.m_entrypoint == VOGL_ENTRYPOINT_glIndexPointer) || (desc.m_entrypoint == VOGL_ENTRYPOINT_glIndexPointerEXT) ||
6064 (desc.m_entrypoint == VOGL_ENTRYPOINT_glFogCoordPointer) || (desc.m_entrypoint == VOGL_ENTRYPOINT_glFogCoordPointerEXT) ||
6065 (desc.m_entrypoint == VOGL_ENTRYPOINT_glEdgeFlagPointer) || (desc.m_entrypoint == VOGL_ENTRYPOINT_glEdgeFlagPointerEXT))
6069 else if ((desc.m_entrypoint == VOGL_ENTRYPOINT_glNormalPointer) || (desc.m_entrypoint == VOGL_ENTRYPOINT_glNormalPointerEXT))
6073 else if ((size < 1) || (size > 4))
6075 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);
6080 stride = type_size * size;
6082 uint first_vertex_ofs = (start + basevertex) * stride;
6083 uint last_vertex_ofs = (end + basevertex) * stride;
6084 uint vertex_data_size = (last_vertex_ofs + stride) - first_vertex_ofs;
6086 if (g_dump_gl_buffers_flag)
6088 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);
6089 vogl_print_hex(static_cast<const uint8_t *>(ptr) + first_vertex_ofs, vertex_data_size, type_size);
6090 vogl_log_printf("\n");
6093 if (trace_serializer.is_in_begin())
6095 uint key_index = base_key_index + inner_iter;
6096 trace_serializer.add_key_value_blob(static_cast<uint16>(key_index), static_cast<const uint8_t *>(ptr) + first_vertex_ofs, vertex_data_size);
6100 } // client_array_iter
6102 GL_ENTRYPOINT(glClientActiveTexture)(prev_client_active_texture);
6103 } // used_old_style_gl_client_side_arrays
6105 if (vertex_attrib_client_side_arrays)
6107 for (uint i = 0; i < pContext->get_max_vertex_attribs(); i++)
6109 if ((vertex_attrib_client_side_arrays & (1ULL << i)) == 0)
6112 GLvoid *attrib_ptr = NULL;
6113 GL_ENTRYPOINT(glGetVertexAttribPointerv)(i, GL_VERTEX_ATTRIB_ARRAY_POINTER, &attrib_ptr);
6117 vogl_error_printf("%s: Enabled vertex attribute index %i has no vertex array buffer, and attribute pointer is NULL\n", VOGL_FUNCTION_NAME, i);
6121 GLint attrib_size = 0;
6122 GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_SIZE, &attrib_size);
6124 GLint attrib_type = 0;
6125 GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_TYPE, &attrib_type);
6127 GLint attrib_stride = 0;
6128 GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &attrib_stride);
6131 if ((attrib_size != GL_BGRA) && (attrib_size < 1) && (attrib_size > 4))
6133 vogl_error_printf("%s: Enabled vertex attribute index %i has invalid size 0x%0X\n", VOGL_FUNCTION_NAME, i, attrib_size);
6136 if ((attrib_size >= 1) && (attrib_size <= 4))
6137 num_comps = attrib_size;
6139 uint type_size = vogl_get_gl_type_size(attrib_type);
6142 vogl_error_printf("%s: Vertex attribute index %i has unsupported type 0x%0X\n", VOGL_FUNCTION_NAME, i, attrib_type);
6146 uint stride = attrib_stride ? attrib_stride : (type_size * num_comps);
6148 uint first_vertex_ofs = (start + basevertex) * stride;
6149 uint last_vertex_ofs = (end + basevertex) * stride;
6150 uint vertex_data_size = (last_vertex_ofs + stride) - first_vertex_ofs;
6152 if (g_dump_gl_buffers_flag)
6154 vogl_log_printf("Client side vertex data for attrib %i (comps: %i type_size: %i stride: %i):\n", i, num_comps, type_size, stride);
6156 vogl_print_hex(static_cast<const uint8_t *>(attrib_ptr) + first_vertex_ofs, vertex_data_size, type_size);
6158 vogl_log_printf("\n");
6161 if (trace_serializer.is_in_begin())
6163 // TODO: Also send down start/end/first_vertex_ofs for debugging/verification purposes
6164 trace_serializer.add_key_value_blob(static_cast<uint16>(i), static_cast<const uint8_t *>(attrib_ptr) + first_vertex_ofs, vertex_data_size);
6170 //----------------------------------------------------------------------------------------------------------------------
6171 // glDrawRangeElements, glDrawRangeElementsBaseVertex, glDrawRangeElementsEXT
6172 //----------------------------------------------------------------------------------------------------------------------
6173 #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);
6174 #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);
6175 #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);
6176 #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);
6177 #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);
6179 static inline void vogl_draw_range_elements_base_vertex_helper(
6180 vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, const char *pFunc,
6181 GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex, bool start_end_valid)
6183 if (trace_serializer.is_in_begin())
6185 vogl_serialize_client_side_arrays_helper(pContext, trace_serializer, pFunc,
6186 mode, start, end, count, type, indices, basevertex, start_end_valid, true);
6190 #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);
6191 #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);
6192 static void vogl_draw_arrays_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, const char *pFunc,
6193 GLenum mode, GLint first, GLsizei count)
6195 if (trace_serializer.is_in_begin())
6197 vogl_serialize_client_side_arrays_helper(pContext, trace_serializer, pFunc,
6198 mode, first, first + count - 1, count, GL_UNSIGNED_BYTE, NULL, 0, true, false);
6202 #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);
6203 #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);
6204 static void vogl_draw_arrays_instanced_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, const char *pFunc,
6205 GLenum mode, GLint first, GLsizei count, GLsizei primcount)
6207 VOGL_NOTE_UNUSED(primcount);
6208 if (trace_serializer.is_in_begin())
6210 vogl_serialize_client_side_arrays_helper(pContext, trace_serializer, pFunc,
6211 mode, first, first + count - 1, count, GL_UNSIGNED_BYTE, NULL, 0, true, false);
6215 #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);
6216 #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);
6217 static inline void vogl_multi_draw_arrays_helper(
6218 vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, const char *pFunc)
6220 if (trace_serializer.is_in_begin())
6222 if (vogl_uses_client_side_arrays(pContext, false))
6224 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);
6229 #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);
6230 #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);
6231 #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);
6232 static void vogl_multi_draw_elements_helper(
6233 vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, const char *pFunc)
6236 if (trace_serializer.is_in_begin())
6238 if (vogl_uses_client_side_arrays(pContext, true))
6240 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);
6245 //----------------------------------------------------------------------------------------------------------------------
6246 // String (extension manipulation)
6247 //----------------------------------------------------------------------------------------------------------------------
6248 #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);
6249 #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);
6250 static inline void vogl_get_string_helper(const char *pFunc_name, vogl_context *pVOGL_context, const GLubyte *&pResult, GLenum name, GLuint index)
6252 if (!g_disable_gl_program_binary_flag)
6255 if ((pVOGL_context) && (pResult) && (name == GL_EXTENSIONS))
6257 // Can't modify the driver's string directly, results in random crashes on my system. So we need to make a copy.
6258 char *pLoc = strstr((char *)pResult, "GL_ARB_get_program_binary");
6261 dynamic_string id(cVarArg, "%s_%x_%x", pFunc_name, name, index);
6263 dynamic_string &ext_str = pVOGL_context->get_extension_map()[id];
6264 ext_str.set((char *)pResult);
6266 int ofs = ext_str.find_left("GL_ARB_get_program_binary", true);
6269 ext_str.set_char(ofs + 3, 'X');
6270 ext_str.set_char(ofs + 4, 'X');
6271 ext_str.set_char(ofs + 5, 'X');
6272 vogl_warning_printf("%s: Disabled GL_ARB_get_program_binary by changing its name to GL_XXX_get_program_binary.\n", VOGL_FUNCTION_NAME);
6274 pResult = (const GLubyte *)ext_str.get_ptr();
6280 //----------------------------------------------------------------------------------------------------------------------
6281 // Buffer mapping, updating
6282 //----------------------------------------------------------------------------------------------------------------------
6285 // glMapNamedBufferEXT
6286 // glMapNamedBufferRangeEXT
6287 // glFlushMappedNamedBufferRangeEXT
6288 // glUnmapNamedBufferEXT
6289 // glGetNamedBufferSubDataEXT
6291 #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);
6292 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)
6294 VOGL_NOTE_UNUSED(trace_serializer);
6299 if (g_dump_gl_buffers_flag)
6301 vogl_log_printf("Buffer data (size: %" PRIu64 "):\n", static_cast<uint64_t>(size));
6302 vogl_print_hex(data, size, 1);
6303 vogl_log_printf("\n");
6306 gl_buffer_desc &buf_desc = pContext->get_or_create_buffer_desc(buffer);
6307 buf_desc.m_size = size;
6308 buf_desc.m_usage = usage;
6310 if (buf_desc.m_pMap)
6312 vogl_warning_printf("%s: Setting buffer's data on an already mapped buffer, buffer will get unmapped by GL\n", VOGL_FUNCTION_NAME);
6315 buf_desc.m_pMap = NULL;
6316 buf_desc.m_map_ofs = 0;
6317 buf_desc.m_map_size = 0;
6318 buf_desc.m_map_access = 0;
6319 buf_desc.m_map_range = 0;
6320 buf_desc.m_flushed_ranges.resize(0);
6323 #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);
6324 #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);
6325 static inline void vogl_buffer_data_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage)
6330 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6331 VOGL_NOTE_UNUSED(gl_error_absorber);
6333 GLuint buffer = vogl_get_bound_gl_buffer(target);
6336 vogl_error_printf("%s: No mapped buffer at target 0x%08X\n", VOGL_FUNCTION_NAME, target);
6340 vogl_named_buffer_data_ext_helper(pContext, trace_serializer, buffer, size, data, usage);
6343 #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);
6344 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)
6346 VOGL_NOTE_UNUSED(buffer);
6347 VOGL_NOTE_UNUSED(trace_serializer);
6348 VOGL_NOTE_UNUSED(pContext);
6350 if (g_dump_gl_buffers_flag)
6352 vogl_log_printf("Buffer sub data (offset: %" PRIu64 " size: %" PRIu64 "):\n", static_cast<uint64_t>(offset), static_cast<uint64_t>(size));
6353 vogl_print_hex(data, size, 1);
6354 vogl_log_printf("\n");
6358 #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);
6359 static inline void vogl_buffer_subdata_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data)
6364 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6365 VOGL_NOTE_UNUSED(gl_error_absorber);
6367 GLuint buffer = vogl_get_bound_gl_buffer(target);
6370 vogl_error_printf("%s: No mapped buffer at target 0x%08X\n", VOGL_FUNCTION_NAME, target);
6374 vogl_named_buffer_subdata_ext_helper(pContext, trace_serializer, buffer, offset, size, data);
6377 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glMapBuffer(exported, category, ret, ret_type_enum, num_params, name, args, params) \
6378 GLenum orig_access = access; \
6379 vogl_map_buffer_gl_prolog_helper(pContext, trace_serializer, target, access);
6380 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glMapBufferARB(exported, category, ret, ret_type_enum, num_params, name, args, params) \
6381 GLenum orig_access = access; \
6382 vogl_map_buffer_gl_prolog_helper(pContext, trace_serializer, target, access);
6383 static inline void vogl_map_buffer_gl_prolog_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLenum target, GLenum &access)
6385 VOGL_NOTE_UNUSED(target);
6386 VOGL_NOTE_UNUSED(pContext);
6388 if (trace_serializer.is_in_begin() || g_dump_gl_buffers_flag)
6390 if (access == GL_WRITE_ONLY)
6392 access = GL_READ_WRITE;
6397 #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);
6398 #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);
6399 static inline void vogl_map_buffer_gl_epilog_helper(vogl_context *pContext, GLenum target, GLenum access, GLvoid *pPtr)
6406 vogl_warning_printf("%s: Map failed!\n", VOGL_FUNCTION_NAME);
6410 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6411 VOGL_NOTE_UNUSED(gl_error_absorber);
6413 GLuint buffer = vogl_get_bound_gl_buffer(target);
6416 vogl_error_printf("%s: No mapped buffer at target 0x%08X\n", VOGL_FUNCTION_NAME, target);
6420 gl_buffer_desc &buf_desc = pContext->get_or_create_buffer_desc(buffer);
6421 if (buf_desc.m_pMap)
6423 vogl_warning_printf("%s: Buffer 0x%08X is already mapped!\n", VOGL_FUNCTION_NAME, buffer);
6427 // 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.
6428 GLint64 actual_buf_size = buf_desc.m_size;
6429 GL_ENTRYPOINT(glGetBufferParameteri64v)(target, GL_BUFFER_SIZE, &actual_buf_size);
6431 buf_desc.m_size = actual_buf_size;
6432 buf_desc.m_pMap = pPtr;
6433 buf_desc.m_map_ofs = 0;
6434 buf_desc.m_map_size = actual_buf_size;
6435 buf_desc.m_map_access = access;
6436 buf_desc.m_map_range = false;
6439 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glMapBufferRange(exported, category, ret, ret_type_enum, num_params, name, args, params) \
6440 GLbitfield orig_access = access; \
6441 vogl_map_buffer_range_gl_prolog_helper(pContext, trace_serializer, target, offset, length, access);
6442 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)
6444 VOGL_NOTE_UNUSED(length);
6445 VOGL_NOTE_UNUSED(offset);
6446 VOGL_NOTE_UNUSED(target);
6447 VOGL_NOTE_UNUSED(pContext);
6449 if (trace_serializer.is_in_begin() || g_dump_gl_buffers_flag)
6451 if (access & GL_MAP_WRITE_BIT)
6453 // They are going to write, so we need to be able to read the data.
6454 // TODO: Warn user that we're going to not invalidate, which is definitely going to slow the GL driver down with CPU/GPU syncs.
6455 access &= ~GL_MAP_INVALIDATE_RANGE_BIT;
6456 access &= ~GL_MAP_INVALIDATE_BUFFER_BIT;
6457 access &= ~GL_MAP_UNSYNCHRONIZED_BIT;
6458 access |= GL_MAP_READ_BIT;
6463 #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);
6464 static inline void vogl_map_buffer_range_gl_epilog_helper(vogl_context *pContext, GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield &access, GLvoid *pPtr)
6471 vogl_warning_printf("%s: Map failed!\n", VOGL_FUNCTION_NAME);
6475 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6476 VOGL_NOTE_UNUSED(gl_error_absorber);
6478 GLuint buffer = vogl_get_bound_gl_buffer(target);
6481 vogl_error_printf("%s: No mapped buffer at target 0x%08X\n", VOGL_FUNCTION_NAME, target);
6485 gl_buffer_desc &buf_desc = pContext->get_or_create_buffer_desc(buffer);
6486 if (buf_desc.m_pMap)
6488 vogl_error_printf("%s: Buffer 0x%08X is already mapped!\n", VOGL_FUNCTION_NAME, buffer);
6492 if (length > buf_desc.m_size)
6494 vogl_warning_printf("%s: passed in length parameter (%" PRIi64 ") is larger the buffer 0x%08X's recorded size (%" PRIi64 ")!\n",
6495 VOGL_FUNCTION_NAME, static_cast<int64_t>(length), buffer, buf_desc.m_size);
6497 GLint64 actual_buf_size = buf_desc.m_size;
6498 GL_ENTRYPOINT(glGetBufferParameteri64v)(target, GL_BUFFER_SIZE, &actual_buf_size);
6499 buf_desc.m_size = actual_buf_size;
6502 buf_desc.m_pMap = pPtr;
6503 buf_desc.m_map_ofs = offset;
6504 buf_desc.m_map_size = length;
6505 buf_desc.m_map_access = access;
6506 buf_desc.m_map_range = true;
6509 #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);
6510 #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);
6511 static inline void vogl_flush_mapped_buffer_range(vogl_context *pContext, GLenum target, GLintptr offset, GLsizeiptr length)
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 not currently mapped!\n", VOGL_FUNCTION_NAME, buffer);
6533 if ((offset + length) > buf_desc.m_map_size)
6535 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",
6536 VOGL_FUNCTION_NAME, static_cast<int64_t>(offset), static_cast<int64_t>(length), buffer, buf_desc.m_map_size);
6539 buf_desc.m_flushed_ranges.push_back(gl_buffer_desc::flushed_range(offset, length));
6542 #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);
6543 #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);
6544 static inline void vogl_unmap_buffer_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLenum target)
6549 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6550 VOGL_NOTE_UNUSED(gl_error_absorber);
6552 GLuint buffer = vogl_get_bound_gl_buffer(target);
6555 vogl_error_printf("%s: No mapped buffer at target 0x%08X\n", VOGL_FUNCTION_NAME, target);
6559 gl_buffer_desc &buf_desc = pContext->get_or_create_buffer_desc(buffer);
6560 if (!buf_desc.m_pMap)
6562 vogl_error_printf("%s: Buffer 0x%08X is not currently mapped!\n", VOGL_FUNCTION_NAME, buffer);
6566 bool writable_map = false;
6567 bool explicit_flush = false;
6568 if (buf_desc.m_map_range)
6570 writable_map = (buf_desc.m_map_access & GL_MAP_WRITE_BIT) != 0;
6571 explicit_flush = (buf_desc.m_map_access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0;
6575 writable_map = (buf_desc.m_map_access != GL_READ_ONLY);
6578 if (trace_serializer.is_in_begin())
6580 trace_serializer.add_key_value(string_hash("map_access"), buf_desc.m_map_access);
6581 trace_serializer.add_key_value(string_hash("map_range"), buf_desc.m_map_range);
6582 trace_serializer.add_key_value(string_hash("explicit_flush"), explicit_flush);
6583 trace_serializer.add_key_value(string_hash("writable_map"), writable_map);
6590 if (!buf_desc.m_flushed_ranges.size())
6592 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);
6595 if (g_dump_gl_buffers_flag)
6597 for (uint i = 0; i < buf_desc.m_flushed_ranges.size(); i++)
6599 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);
6600 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);
6601 vogl_log_printf("\n");
6605 if (trace_serializer.is_in_begin())
6607 trace_serializer.add_key_value(string_hash("flushed_ranges"), buf_desc.m_flushed_ranges.size());
6608 for (uint i = 0; i < buf_desc.m_flushed_ranges.size(); i++)
6610 int key_index = i * 4;
6611 trace_serializer.add_key_value(key_index, buf_desc.m_flushed_ranges[i].m_ofs);
6612 trace_serializer.add_key_value(key_index + 1, buf_desc.m_flushed_ranges[i].m_size);
6614 VOGL_ASSERT(buf_desc.m_flushed_ranges[i].m_size <= cUINT32_MAX);
6615 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));
6621 if (g_dump_gl_buffers_flag)
6623 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));
6624 vogl_print_hex(static_cast<const uint8_t *>(buf_desc.m_pMap), buf_desc.m_map_size, 1);
6625 vogl_log_printf("\n");
6628 if (trace_serializer.is_in_begin())
6630 trace_serializer.add_key_value(0, buf_desc.m_map_ofs);
6631 trace_serializer.add_key_value(1, buf_desc.m_map_size);
6633 VOGL_ASSERT(buf_desc.m_map_size <= cUINT32_MAX);
6634 trace_serializer.add_key_value_blob(2, static_cast<const uint8_t *>(buf_desc.m_pMap), static_cast<uint>(buf_desc.m_map_size));
6639 buf_desc.m_pMap = NULL;
6640 buf_desc.m_map_ofs = 0;
6641 buf_desc.m_map_size = 0;
6642 buf_desc.m_map_access = 0;
6643 buf_desc.m_flushed_ranges.resize(0);
6646 //----------------------------------------------------------------------------------------------------------------------
6647 // glCreateProgram/glCreateProgramARB function epilog
6648 //----------------------------------------------------------------------------------------------------------------------
6649 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glCreateProgram(e, c, rt, r, nu, ne, a, p) \
6651 vogl_create_program_helper(pContext, result);
6652 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glCreateProgramObjectARB(e, c, rt, r, nu, ne, a, p) \
6654 vogl_create_program_helper(pContext, result);
6655 static inline void vogl_create_program_helper(vogl_context *pContext, GLuint handle)
6657 VOGL_NOTE_UNUSED(pContext);
6658 VOGL_NOTE_UNUSED(handle);
6663 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6664 VOGL_NOTE_UNUSED(gl_error_absorber);
6666 // Ensure program bins are always retrievable
6667 GL_ENTRYPOINT(glProgramParameteri)(handle, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);
6672 //----------------------------------------------------------------------------------------------------------------------
6673 // glProgramParameteri GL prolog
6674 //----------------------------------------------------------------------------------------------------------------------
6675 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glProgramParameteri(e, c, rt, r, nu, ne, a, p) \
6677 vogl_program_parameteri_prolog(pContext, program, pname, value);
6678 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glProgramParameteriARB(e, c, rt, r, nu, ne, a, p) \
6680 vogl_program_parameteri_prolog(pContext, program, pname, value);
6681 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glProgramParameteriEXT(e, c, rt, r, nu, ne, a, p) \
6683 vogl_program_parameteri_prolog(pContext, program, pname, value);
6684 static void vogl_program_parameteri_prolog(vogl_context *pContext, GLuint program, GLenum pname, GLint &value)
6686 VOGL_NOTE_UNUSED(pContext);
6687 VOGL_NOTE_UNUSED(program);
6688 VOGL_NOTE_UNUSED(pname);
6689 VOGL_NOTE_UNUSED(value);
6692 if ((pname == GL_PROGRAM_BINARY_RETRIEVABLE_HINT) && (value == GL_FALSE))
6694 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);
6701 //----------------------------------------------------------------------------------------------------------------------
6702 // glBindAttribLocationARB/glBindAttribLocation function epilog
6703 //----------------------------------------------------------------------------------------------------------------------
6704 //#define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glBindAttribLocationARB(e, c, rt, r, nu, ne, a, p) if (pContext) pContext->bind_attrib_location(programObj, index, name);
6705 //#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));
6707 //----------------------------------------------------------------------------------------------------------------------
6708 // glDeleteProgramsARB/glDeleteProgram function epilog
6709 //----------------------------------------------------------------------------------------------------------------------
6710 //#define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDeleteProgramsARB(e, c, rt, r, nu, ne, a, p) if (pContext) pContext->delete_program_attrib_locations(n, programs);
6711 //#define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDeleteProgram(e, c, rt, r, nu, ne, a, p) if (pContext) pContext->delete_program_attrib_locations(1, &program);
6713 //----------------------------------------------------------------------------------------------------------------------
6714 // vogl_dump_program_outputs
6715 //----------------------------------------------------------------------------------------------------------------------
6716 static void vogl_dump_program_outputs(json_node &doc_root, vogl_context *pContext, GLuint program)
6718 if (pContext->get_context_info().supports_extension("GL_ARB_program_interface_query") &&
6719 GL_ENTRYPOINT(glGetProgramInterfaceiv) && GL_ENTRYPOINT(glGetProgramResourceName) && GL_ENTRYPOINT(glGetProgramResourceiv))
6721 GLint num_active_outputs = 0;
6722 GL_ENTRYPOINT(glGetProgramInterfaceiv)(program, GL_PROGRAM_OUTPUT, GL_ACTIVE_RESOURCES, &num_active_outputs);
6723 pContext->peek_and_drop_gl_error();
6725 doc_root.add_key_value("total_active_outputs", num_active_outputs);
6727 json_node &outputs_object = doc_root.add_array("active_outputs");
6728 for (int i = 0; i < num_active_outputs; i++)
6731 GLsizei name_len = 0;
6732 GL_ENTRYPOINT(glGetProgramResourceName)(program, GL_PROGRAM_OUTPUT, i, sizeof(name), &name_len, name);
6733 pContext->peek_and_drop_gl_error();
6735 const GLenum props_to_query[5] = { GL_LOCATION, GL_LOCATION_INDEX, GL_TYPE, GL_ARRAY_SIZE, GL_IS_PER_PATCH }; // TODO: GL_LOCATION_COMPONENT
6736 GLint props[5] = { 0, 0, 0, 0, 0 };
6737 GL_ENTRYPOINT(glGetProgramResourceiv)(program, GL_PROGRAM_OUTPUT, i, VOGL_ARRAY_SIZE(props_to_query), props_to_query, VOGL_ARRAY_SIZE(props), NULL, props);
6738 pContext->peek_and_drop_gl_error();
6740 json_node &output_node = outputs_object.add_object();
6741 output_node.add_key_value("index", i);
6742 output_node.add_key_value("name", reinterpret_cast<const char *>(name));
6743 output_node.add_key_value("location", props[0]);
6744 output_node.add_key_value("location_index", props[1]);
6745 output_node.add_key_value("type", props[2]);
6746 output_node.add_key_value("array_size", props[3]);
6747 output_node.add_key_value("is_per_patch", props[4]);
6748 //output_node.add_key_value("location_component", props[5]);
6753 //----------------------------------------------------------------------------------------------------------------------
6754 // glLinkProgramARB function epilog
6755 //----------------------------------------------------------------------------------------------------------------------
6756 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glLinkProgramARB(e, c, rt, r, nu, ne, a, p) vogl_link_program_arb(pContext, trace_serializer, programObj);
6757 static inline void vogl_link_program_arb(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLhandleARB programObj)
6762 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6763 VOGL_NOTE_UNUSED(gl_error_absorber);
6765 GLint link_status = 0;
6766 GL_ENTRYPOINT(glGetObjectParameterivARB)(programObj, GL_OBJECT_LINK_STATUS_ARB, &link_status);
6767 pContext->peek_and_drop_gl_error();
6769 if (trace_serializer.is_in_begin())
6772 json_node &doc_root = *doc.get_root();
6773 doc_root.add_key_value("program", programObj);
6774 doc_root.add_key_value("link_status", link_status);
6775 doc_root.add_key_value("func_id", VOGL_ENTRYPOINT_glLinkProgramARB);
6777 GLint active_attributes = 0;
6778 GL_ENTRYPOINT(glGetObjectParameterivARB)(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);
6779 pContext->peek_and_drop_gl_error();
6781 doc_root.add_key_value("total_active_attributes", active_attributes);
6783 if (active_attributes)
6785 json_node &attribs_object = doc_root.add_array("active_attribs");
6787 for (int i = 0; i < active_attributes; i++)
6791 GLcharARB name[256];
6793 GL_ENTRYPOINT(glGetActiveAttribARB)(programObj, i, sizeof(name), NULL, &size, &type, name);
6794 pContext->peek_and_drop_gl_error();
6796 if ((!name[0]) || ((name[0] == 'g') && (name[1] == 'l') && (name[2] == '_')))
6799 GLint location = GL_ENTRYPOINT(glGetAttribLocationARB)(programObj, name);
6800 pContext->peek_and_drop_gl_error();
6805 json_node &attrib_node = attribs_object.add_object();
6806 attrib_node.add_key_value("index", i);
6807 attrib_node.add_key_value("name", reinterpret_cast<const char *>(name));
6808 attrib_node.add_key_value("location", location);
6812 GLint active_uniforms = 0;
6813 GL_ENTRYPOINT(glGetObjectParameterivARB)(programObj, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &active_uniforms);
6814 pContext->peek_and_drop_gl_error();
6816 doc_root.add_key_value("total_active_uniforms", active_uniforms);
6818 if (active_uniforms)
6820 json_node &uniforms_object = doc_root.add_array("active_uniforms");
6822 for (int i = 0; i < active_uniforms; i++)
6827 GLcharARB name[256];
6829 GL_ENTRYPOINT(glGetActiveUniformARB)(programObj, i, sizeof(name), &length, &size, &type, name);
6830 pContext->peek_and_drop_gl_error();
6832 if ((!name[0]) || (!length) || ((name[0] == 'g') && (name[1] == 'l') && (name[2] == '_')))
6835 GLint location = GL_ENTRYPOINT(glGetUniformLocationARB)(programObj, name);
6836 pContext->peek_and_drop_gl_error();
6841 json_node &uniform_node = uniforms_object.add_object();
6842 uniform_node.add_key_value("index", i);
6843 uniform_node.add_key_value("name", reinterpret_cast<const char *>(name));
6844 uniform_node.add_key_value("location", location);
6845 uniform_node.add_key_value("size", size);
6846 uniform_node.add_key_value("type", type);
6850 vogl_dump_program_outputs(doc_root, pContext, programObj);
6852 trace_serializer.add_key_value_json_document("metadata", doc);
6857 if ((link_status) || (!pContext->has_linked_program_snapshot(programObj)))
6859 if (!pContext->add_linked_program_snapshot(programObj))
6860 vogl_error_printf("%s: Failed snapshotting program into link-time program shadow table, program 0x%X\n", VOGL_FUNCTION_NAME, programObj);
6865 //----------------------------------------------------------------------------------------------------------------------
6866 // glLinkProgram/glProgramBinary function epilog
6867 //----------------------------------------------------------------------------------------------------------------------
6868 #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);
6869 #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);
6870 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)
6875 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6876 VOGL_NOTE_UNUSED(gl_error_absorber);
6878 GLint link_status = 0;
6879 GL_ENTRYPOINT(glGetProgramiv)(program, GL_LINK_STATUS, &link_status);
6880 pContext->peek_and_drop_gl_error();
6882 if (trace_serializer.is_in_begin())
6885 json_node &doc_root = *doc.get_root();
6886 doc_root.add_key_value("program", program);
6887 doc_root.add_key_value("link_status", link_status);
6888 doc_root.add_key_value("func_id", static_cast<uint32>(id));
6890 // Active uniform blocks
6891 GLint active_uniform_blocks = 0;
6892 GL_ENTRYPOINT(glGetProgramiv)(program, GL_ACTIVE_UNIFORM_BLOCKS, &active_uniform_blocks);
6893 pContext->peek_and_drop_gl_error();
6895 doc_root.add_key_value("active_uniform_blocks", active_uniform_blocks);
6897 // Active attributes
6898 GLint active_attributes = 0;
6899 GL_ENTRYPOINT(glGetProgramiv)(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);
6900 pContext->peek_and_drop_gl_error();
6902 doc_root.add_key_value("total_active_attributes", active_attributes);
6904 if (active_attributes)
6906 json_node &attribs_object = doc_root.add_array("active_attribs");
6908 for (int i = 0; i < active_attributes; i++)
6914 GL_ENTRYPOINT(glGetActiveAttrib)(program, i, sizeof(name), NULL, &size, &type, name);
6915 pContext->peek_and_drop_gl_error();
6917 if ((!name[0]) || ((name[0] == 'g') && (name[1] == 'l') && (name[2] == '_')))
6920 GLint location = GL_ENTRYPOINT(glGetAttribLocation)(program, name);
6921 pContext->peek_and_drop_gl_error();
6926 json_node &attrib_node = attribs_object.add_object();
6927 attrib_node.add_key_value("index", i);
6928 attrib_node.add_key_value("name", reinterpret_cast<const char *>(name));
6929 attrib_node.add_key_value("location", location);
6934 GLint active_uniforms = 0;
6935 GL_ENTRYPOINT(glGetProgramiv)(program, GL_ACTIVE_UNIFORMS, &active_uniforms);
6936 doc_root.add_key_value("total_active_uniforms", active_uniforms);
6938 if (active_uniforms)
6940 json_node &uniforms_object = doc_root.add_array("active_uniforms");
6942 for (int i = 0; i < active_uniforms; i++)
6949 GL_ENTRYPOINT(glGetActiveUniform)(program, i, sizeof(name), &length, &size, &type, name);
6950 pContext->peek_and_drop_gl_error();
6952 if ((!name[0]) || (!length) || ((name[0] == 'g') && (name[1] == 'l') && (name[2] == '_')))
6955 GLint location = GL_ENTRYPOINT(glGetUniformLocation)(program, name);
6956 pContext->peek_and_drop_gl_error();
6961 json_node &uniform_node = uniforms_object.add_object();
6962 uniform_node.add_key_value("index", i);
6963 uniform_node.add_key_value("name", reinterpret_cast<const char *>(name));
6964 uniform_node.add_key_value("location", location);
6965 uniform_node.add_key_value("size", size);
6966 uniform_node.add_key_value("type", type);
6971 vogl_dump_program_outputs(doc_root, pContext, program);
6973 // Transform feedback
6974 GLint mode = GL_NONE;
6975 GL_ENTRYPOINT(glGetProgramiv)(program, GL_TRANSFORM_FEEDBACK_BUFFER_MODE, &mode);
6976 pContext->peek_and_drop_gl_error();
6978 doc_root.add_key_value("transform_feedback_mode", g_gl_enums.find_gl_name(mode));
6980 GLint num_varyings = 0;
6981 GL_ENTRYPOINT(glGetProgramiv)(program, GL_TRANSFORM_FEEDBACK_VARYINGS, &num_varyings);
6982 pContext->peek_and_drop_gl_error();
6984 doc_root.add_key_value("transform_feedback_num_varyings", num_varyings);
6988 json_node &transform_feedback_varyings = doc_root.add_array("transform_feedback_varyings");
6990 for (GLint i = 0; i < num_varyings; i++)
6993 GLsizei length = 0, size = 0;
6994 GLenum type = GL_NONE;
6996 GL_ENTRYPOINT(glGetTransformFeedbackVarying)(program, i, sizeof(name), &length, &size, &type, name);
6997 pContext->peek_and_drop_gl_error();
6999 json_node &uniform_node = transform_feedback_varyings.add_object();
7000 uniform_node.add_key_value("index", i);
7001 uniform_node.add_key_value("name", reinterpret_cast<const char *>(name));
7002 uniform_node.add_key_value("size", size);
7003 uniform_node.add_key_value("type", type);
7007 // Add JSON document to packet
7008 trace_serializer.add_key_value_json_document("metadata", doc);
7013 if ((link_status) || (!pContext->has_linked_program_snapshot(program)))
7015 if (id == VOGL_ENTRYPOINT_glProgramBinary)
7017 if (!pContext->add_linked_program_snapshot(program, binary_format, pBinary, binary_length))
7019 vogl_error_printf("%s: Failed snapshotting binary program into link-time program shadow table, program 0x%X\n", VOGL_FUNCTION_NAME, program);
7024 if (!pContext->add_linked_program_snapshot(program))
7026 vogl_error_printf("%s: Failed snapshotting program into link-time program shadow table, program 0x%X\n", VOGL_FUNCTION_NAME, program);
7033 #define DEF_FUNCTION_CUSTOM_FUNC_PROLOG_glProgramBinary(e, c, rt, r, nu, ne, a, p) vogl_glProgramBinary_prolog(program, binaryFormat, binary, length);
7034 static inline void vogl_glProgramBinary_prolog(GLuint program, GLenum binaryFormat, const void *&pBinary, GLsizei &length)
7036 VOGL_NOTE_UNUSED(binaryFormat);
7038 if (g_disable_gl_program_binary_flag)
7040 vogl_debug_printf("%s: Tracer is forcing a bogus program binary for program %d\n", VOGL_FUNCTION_NAME, program);
7042 // These will intentionally cause the program binary to not link, forcing the application to use shader strings instead of binaries.
7043 pBinary = &g_dummy_program;
7048 //----------------------------------------------------------------------------------------------------------------------
7049 // glTransformFeedbackVaryings func epilog
7050 //----------------------------------------------------------------------------------------------------------------------
7051 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glTransformFeedbackVaryings(e, c, rt, r, nu, ne, a, p) \
7053 vogl_transform_feedback_varyings(pContext, trace_serializer, count, varyings);
7054 static inline void vogl_transform_feedback_varyings(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLsizei count, GLchar *const *pVaryings)
7056 VOGL_NOTE_UNUSED(pContext);
7058 if ((!count) || (!pVaryings) || (!trace_serializer.is_in_begin()))
7061 dynamic_string varying;
7062 for (int i = 0; i < count; i++)
7066 varying = reinterpret_cast<const char *>(pVaryings[i]);
7068 trace_serializer.add_key_value(i, varying);
7072 //----------------------------------------------------------------------------------------------------------------------
7073 // ARB program shadowing
7074 //----------------------------------------------------------------------------------------------------------------------
7075 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenProgramsARB(e, c, rt, r, nu, ne, a, p) \
7077 pContext->peek_and_record_gl_error();
7078 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenProgramsARB(e, c, rt, r, nu, ne, a, p) \
7079 if (pContext && !pContext->peek_and_record_gl_error()) \
7080 pContext->gen_arb_programs(n, programs);
7082 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteProgramsARB(e, c, rt, r, nu, ne, a, p) \
7084 pContext->peek_and_record_gl_error();
7085 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteProgramsARB(e, c, rt, r, nu, ne, a, p) \
7086 if (pContext && !pContext->peek_and_record_gl_error()) \
7087 pContext->del_arb_programs(n, programs);
7089 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindProgramARB(e, c, rt, r, nu, ne, a, p) \
7091 pContext->peek_and_record_gl_error();
7092 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindProgramARB(e, c, rt, r, nu, ne, a, p) \
7093 if (pContext && !pContext->peek_and_record_gl_error()) \
7094 pContext->bind_arb_program(target, program);
7096 //----------------------------------------------------------------------------------------------------------------------
7097 // renderbuffer shadowing
7098 //----------------------------------------------------------------------------------------------------------------------
7099 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenRenderbuffers(e, c, rt, r, nu, ne, a, p) \
7101 pContext->peek_and_record_gl_error();
7102 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenRenderbuffers(e, c, rt, r, nu, ne, a, p) \
7103 if (pContext && !pContext->peek_and_record_gl_error()) \
7104 pContext->gen_render_buffers(n, renderbuffers);
7106 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenRenderbuffersEXT(e, c, rt, r, nu, ne, a, p) \
7108 pContext->peek_and_record_gl_error();
7109 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenRenderbuffersEXT(e, c, rt, r, nu, ne, a, p) \
7110 if (pContext && !pContext->peek_and_record_gl_error()) \
7111 pContext->gen_render_buffers(n, renderbuffers);
7113 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteRenderbuffers(e, c, rt, r, nu, ne, a, p) \
7115 pContext->peek_and_record_gl_error();
7116 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteRenderbuffers(e, c, rt, r, nu, ne, a, p) \
7117 if (pContext && !pContext->peek_and_record_gl_error()) \
7118 pContext->del_render_buffers(n, renderbuffers);
7120 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteRenderbuffersEXT(e, c, rt, r, nu, ne, a, p) \
7122 pContext->peek_and_record_gl_error();
7123 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteRenderbuffersEXT(e, c, rt, r, nu, ne, a, p) \
7124 if (pContext && !pContext->peek_and_record_gl_error()) \
7125 pContext->del_render_buffers(n, renderbuffers);
7126 //----------------------------------------------------------------------------------------------------------------------
7128 //----------------------------------------------------------------------------------------------------------------------
7129 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenBuffers(e, c, rt, r, nu, ne, a, p) \
7131 pContext->peek_and_record_gl_error();
7132 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenBuffers(e, c, rt, r, nu, ne, a, p) \
7133 if (pContext && !pContext->peek_and_record_gl_error()) \
7134 pContext->gen_buffers(n, buffers);
7136 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenBuffersARB(e, c, rt, r, nu, ne, a, p) \
7138 pContext->peek_and_record_gl_error();
7139 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenBuffersARB(e, c, rt, r, nu, ne, a, p) \
7140 if (pContext && !pContext->peek_and_record_gl_error()) \
7141 pContext->gen_buffers(n, buffers);
7143 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBuffer(e, c, rt, r, nu, ne, a, p) \
7145 pContext->peek_and_record_gl_error();
7146 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindBuffer(e, c, rt, r, nu, ne, a, p) \
7147 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7148 pContext->bind_buffer(target, buffer);
7150 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferBase(e, c, rt, r, nu, ne, a, p) \
7152 pContext->peek_and_record_gl_error();
7153 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindBufferBase(e, c, rt, r, nu, ne, a, p) \
7154 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7155 pContext->bind_buffer(target, buffer);
7157 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferBaseEXT(e, c, rt, r, nu, ne, a, p) \
7159 pContext->peek_and_record_gl_error();
7160 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindBufferBaseEXT(e, c, rt, r, nu, ne, a, p) \
7161 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7162 pContext->bind_buffer(target, buffer);
7164 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferBaseNV(e, c, rt, r, nu, ne, a, p) \
7166 pContext->peek_and_record_gl_error();
7167 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindBufferBaseNV(e, c, rt, r, nu, ne, a, p) \
7168 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7169 pContext->bind_buffer(target, buffer);
7171 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferRange(e, c, rt, r, nu, ne, a, p) \
7173 pContext->peek_and_record_gl_error();
7174 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindBufferRange(e, c, rt, r, nu, ne, a, p) \
7175 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7176 pContext->bind_buffer(target, buffer);
7178 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferRangeEXT(e, c, rt, r, nu, ne, a, p) \
7180 pContext->peek_and_record_gl_error();
7181 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindBufferRangeEXT(e, c, rt, r, nu, ne, a, p) \
7182 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7183 pContext->bind_buffer(target, buffer);
7185 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferRangeNV(e, c, rt, r, nu, ne, a, p) \
7187 pContext->peek_and_record_gl_error();
7188 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindBufferRangeNV(e, c, rt, r, nu, ne, a, p) \
7189 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7190 pContext->bind_buffer(target, buffer);
7192 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferARB(e, c, rt, r, nu, ne, a, p) \
7194 pContext->peek_and_record_gl_error();
7195 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindBufferARB(e, c, rt, r, nu, ne, a, p) \
7196 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7197 pContext->bind_buffer(target, buffer);
7199 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteBuffers(e, c, rt, r, nu, ne, a, p) \
7201 pContext->peek_and_record_gl_error();
7202 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteBuffers(e, c, rt, r, nu, ne, a, p) \
7203 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7204 pContext->delete_buffers(n, buffers);
7206 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteBuffersARB(e, c, rt, r, nu, ne, a, p) \
7208 pContext->peek_and_record_gl_error();
7209 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteBuffersARB(e, c, rt, r, nu, ne, a, p) \
7210 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7211 pContext->delete_buffers(n, buffers);
7213 //----------------------------------------------------------------------------------------------------------------------
7214 // Texture handle shadowing
7215 //----------------------------------------------------------------------------------------------------------------------
7216 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenTextures(e, c, rt, r, nu, ne, a, p) \
7218 pContext->peek_and_record_gl_error();
7219 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenTextures(e, c, rt, r, nu, ne, a, p) \
7220 if (pContext && !pContext->peek_and_record_gl_error()) \
7221 pContext->gen_textures(n, textures);
7223 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenTexturesEXT(e, c, rt, r, nu, ne, a, p) \
7225 pContext->peek_and_record_gl_error();
7226 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenTexturesEXT(e, c, rt, r, nu, ne, a, p) \
7227 if (pContext && !pContext->peek_and_record_gl_error()) \
7228 pContext->gen_textures(n, textures);
7230 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteTextures(e, c, rt, r, nu, ne, a, p) \
7232 pContext->peek_and_record_gl_error();
7233 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteTextures(e, c, rt, r, nu, ne, a, p) \
7234 if (pContext && !pContext->peek_and_record_gl_error()) \
7235 pContext->del_textures(n, textures);
7237 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteTexturesEXT(e, c, rt, r, nu, ne, a, p) \
7239 pContext->peek_and_record_gl_error();
7240 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteTexturesEXT(e, c, rt, r, nu, ne, a, p) \
7241 if (pContext && !pContext->peek_and_record_gl_error()) \
7242 pContext->del_textures(n, textures);
7244 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindTexture(e, c, rt, r, nu, ne, a, p) \
7246 pContext->peek_and_record_gl_error();
7247 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindTexture(e, c, rt, r, nu, ne, a, p) \
7248 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7249 pContext->bind_texture(target, texture);
7251 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindTextureEXT(e, c, rt, r, nu, ne, a, p) \
7253 pContext->peek_and_record_gl_error();
7254 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindTextureEXT(e, c, rt, r, nu, ne, a, p) \
7255 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7256 pContext->bind_texture(target, texture);
7258 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindMultiTextureEXT(e, c, rt, r, nu, ne, a, p) \
7260 pContext->peek_and_record_gl_error();
7261 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindMultiTextureEXT(e, c, rt, r, nu, ne, a, p) \
7262 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7263 pContext->bind_texture(target, texture);
7265 //----------------------------------------------------------------------------------------------------------------------
7266 // Framebuffer handle shadowing
7267 //----------------------------------------------------------------------------------------------------------------------
7268 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenFramebuffers(e, c, rt, r, nu, ne, a, p) \
7270 pContext->peek_and_record_gl_error();
7271 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenFramebuffers(e, c, rt, r, nu, ne, a, p) \
7272 if (pContext && !pContext->peek_and_record_gl_error()) \
7273 pContext->gen_framebuffers(n, framebuffers);
7275 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenFramebuffersEXT(e, c, rt, r, nu, ne, a, p) \
7277 pContext->peek_and_record_gl_error();
7278 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenFramebuffersEXT(e, c, rt, r, nu, ne, a, p) \
7279 if (pContext && !pContext->peek_and_record_gl_error()) \
7280 pContext->gen_framebuffers(n, framebuffers);
7282 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteFramebuffers(e, c, rt, r, nu, ne, a, p) \
7284 pContext->peek_and_record_gl_error();
7285 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteFramebuffers(e, c, rt, r, nu, ne, a, p) \
7286 if (pContext && !pContext->peek_and_record_gl_error()) \
7287 pContext->del_framebuffers(n, framebuffers);
7289 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteFramebuffersEXT(e, c, rt, r, nu, ne, a, p) \
7291 pContext->peek_and_record_gl_error();
7292 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteFramebuffersEXT(e, c, rt, r, nu, ne, a, p) \
7293 if (pContext && !pContext->peek_and_record_gl_error()) \
7294 pContext->del_framebuffers(n, framebuffers);
7296 //----------------------------------------------------------------------------------------------------------------------
7297 // VAO handle shadowing
7298 //----------------------------------------------------------------------------------------------------------------------
7299 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenVertexArrays(e, c, rt, r, nu, ne, a, p) \
7301 pContext->peek_and_record_gl_error();
7302 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenVertexArrays(e, c, rt, r, nu, ne, a, p) \
7303 if (pContext && !pContext->peek_and_record_gl_error()) \
7304 pContext->gen_vertexarrays(n, arrays);
7306 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteVertexArrays(e, c, rt, r, nu, ne, a, p) \
7308 pContext->peek_and_record_gl_error();
7309 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteVertexArrays(e, c, rt, r, nu, ne, a, p) \
7310 if (pContext && !pContext->peek_and_record_gl_error()) \
7311 pContext->del_vertexarrays(n, arrays);
7313 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindVertexArray(e, c, rt, r, nu, ne, a, p) \
7315 pContext->peek_and_record_gl_error();
7316 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindVertexArray(e, c, rt, r, nu, ne, a, p) \
7317 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7318 pContext->bind_vertexarray(array);
7320 //----------------------------------------------------------------------------------------------------------------------
7321 // Sync handle shadowing
7322 //----------------------------------------------------------------------------------------------------------------------
7323 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glFenceSync(e, c, rt, r, nu, ne, a, p) \
7325 pContext->peek_and_record_gl_error();
7326 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glFenceSync(e, c, rt, r, nu, ne, a, p) \
7327 if (pContext && !pContext->peek_and_record_gl_error()) \
7328 pContext->gen_sync(result);
7330 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteSync(e, c, rt, r, nu, ne, a, p) \
7332 pContext->peek_and_record_gl_error();
7333 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteSync(e, c, rt, r, nu, ne, a, p) \
7334 if (pContext && !pContext->peek_and_record_gl_error()) \
7335 pContext->del_sync(sync);
7337 //----------------------------------------------------------------------------------------------------------------------
7338 // Sampler object handle shadowing
7339 //----------------------------------------------------------------------------------------------------------------------
7340 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenSamplers(e, c, rt, r, nu, ne, a, p) \
7342 pContext->peek_and_record_gl_error();
7343 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenSamplers(e, c, rt, r, nu, ne, a, p) \
7344 if (pContext && !pContext->peek_and_record_gl_error()) \
7345 pContext->gen_samplers(count, samplers);
7347 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteSamplers(e, c, rt, r, nu, ne, a, p) \
7349 pContext->peek_and_record_gl_error();
7350 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteSamplers(e, c, rt, r, nu, ne, a, p) \
7351 if (pContext && !pContext->peek_and_record_gl_error()) \
7352 pContext->del_samplers(count, samplers);
7354 //----------------------------------------------------------------------------------------------------------------------
7355 // Query handle shadowing
7356 //----------------------------------------------------------------------------------------------------------------------
7357 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenQueries(e, c, rt, r, nu, ne, a, p) \
7359 pContext->peek_and_record_gl_error();
7360 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenQueries(e, c, rt, r, nu, ne, a, p) \
7361 if (pContext && !pContext->peek_and_record_gl_error()) \
7362 pContext->gen_queries(n, ids);
7364 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenQueriesARB(e, c, rt, r, nu, ne, a, p) \
7366 pContext->peek_and_record_gl_error();
7367 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenQueriesARB(e, c, rt, r, nu, ne, a, p) \
7368 if (pContext && !pContext->peek_and_record_gl_error()) \
7369 pContext->gen_queries(n, ids);
7371 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteQueries(e, c, rt, r, nu, ne, a, p) \
7373 pContext->peek_and_record_gl_error();
7374 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteQueries(e, c, rt, r, nu, ne, a, p) \
7375 if (pContext && !pContext->peek_and_record_gl_error()) \
7376 pContext->del_queries(n, ids);
7378 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteQueriesARB(e, c, rt, r, nu, ne, a, p) \
7380 pContext->peek_and_record_gl_error();
7381 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteQueriesARB(e, c, rt, r, nu, ne, a, p) \
7382 if (pContext && !pContext->peek_and_record_gl_error()) \
7383 pContext->del_queries(n, ids);
7385 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBeginQuery(e, c, rt, r, nu, ne, a, p) \
7387 pContext->peek_and_record_gl_error();
7388 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBeginQuery(e, c, rt, r, nu, ne, a, p) \
7389 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7390 pContext->begin_query(target, id);
7392 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBeginQueryARB(e, c, rt, r, nu, ne, a, p) \
7394 pContext->peek_and_record_gl_error();
7395 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBeginQueryARB(e, c, rt, r, nu, ne, a, p) \
7396 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7397 pContext->begin_query(target, id);
7399 //----------------------------------------------------------------------------------------------------------------------
7400 // Display list shadowing
7401 //----------------------------------------------------------------------------------------------------------------------
7402 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenLists(e, c, rt, r, nu, ne, a, p) \
7404 pContext->peek_and_record_gl_error();
7405 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenLists(e, c, rt, r, nu, ne, a, p) \
7406 if (pContext && !pContext->peek_and_record_gl_error()) \
7407 pContext->gen_lists(result, range);
7409 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteLists(e, c, rt, r, nu, ne, a, p) \
7411 pContext->peek_and_record_gl_error();
7412 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteLists(e, c, rt, r, nu, ne, a, p) \
7413 if (pContext && !pContext->peek_and_record_gl_error()) \
7414 pContext->del_lists(list, range);
7416 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glNewList(e, c, rt, r, nu, ne, a, p) \
7418 pContext->peek_and_record_gl_error();
7419 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glNewList(e, c, rt, r, nu, ne, a, p) \
7420 if (pContext && !pContext->peek_and_record_gl_error()) \
7421 pContext->new_list(list, mode);
7423 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glEndList(e, c, rt, r, nu, ne, a, p) \
7425 pContext->peek_and_record_gl_error();
7426 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glEndList(e, c, rt, r, nu, ne, a, p) \
7427 if (pContext && !pContext->peek_and_record_gl_error()) \
7428 pContext->end_list();
7430 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glXUseXFont(e, c, rt, r, nu, ne, a, p) \
7432 pContext->peek_and_record_gl_error();
7434 //----------------------------------------------------------------------------------------------------------------------
7435 // glBegin/glEnd shadowing
7436 //----------------------------------------------------------------------------------------------------------------------
7437 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBegin(e, c, rt, r, nu, ne, a, p) \
7439 pContext->peek_and_record_gl_error();
7440 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBegin(e, c, rt, r, nu, ne, a, p) \
7442 pContext->set_in_gl_begin(true);
7444 //#define DEF_FUNCTION_CUSTOM_GL_PROLOG_glEnd(e, c, rt, r, nu, ne, a, p)
7445 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glEnd(e, c, rt, r, nu, ne, a, p) \
7447 pContext->set_in_gl_begin(false);
7449 //----------------------------------------------------------------------------------------------------------------------
7450 // Program/shader shadowing
7451 //----------------------------------------------------------------------------------------------------------------------
7452 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glCreateProgram(e, c, rt, r, nu, ne, a, p) \
7454 result = pContext->handle_create_program(VOGL_ENTRYPOINT_##ne); \
7457 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glCreateProgramObjectARB(e, c, rt, r, nu, ne, a, p) \
7459 result = pContext->handle_create_program(VOGL_ENTRYPOINT_##ne); \
7463 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glCreateShader(e, c, rt, r, nu, ne, a, p) \
7465 result = pContext->handle_create_shader(VOGL_ENTRYPOINT_##ne, type); \
7468 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glCreateShaderObjectARB(e, c, rt, r, nu, ne, a, p) \
7470 result = pContext->handle_create_shader(VOGL_ENTRYPOINT_##ne, shaderType); \
7474 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glUseProgram(e, c, rt, r, nu, ne, a, p) \
7476 pContext->handle_use_program(VOGL_ENTRYPOINT_##ne, program);
7477 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glUseProgramObjectARB(e, c, rt, r, nu, ne, a, p) \
7479 pContext->handle_use_program(VOGL_ENTRYPOINT_##ne, programObj);
7481 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glDeleteShader(e, c, rt, r, nu, ne, a, p) \
7483 pContext->handle_del_shader(VOGL_ENTRYPOINT_##ne, shader);
7484 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glDeleteProgram(e, c, rt, r, nu, ne, a, p) \
7486 pContext->handle_del_program(VOGL_ENTRYPOINT_##ne, program);
7487 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glDeleteObjectARB(e, c, rt, r, nu, ne, a, p) \
7489 pContext->handle_del_object(VOGL_ENTRYPOINT_##ne, obj);
7491 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glDetachShader(e, c, rt, r, nu, ne, a, p) \
7493 pContext->handle_detach_shader(VOGL_ENTRYPOINT_##ne, program, shader);
7494 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glDetachObjectARB(e, c, rt, r, nu, ne, a, p) \
7496 pContext->handle_detach_shader(VOGL_ENTRYPOINT_##ne, containerObj, attachedObj);
7498 //----------------------------------------------------------------------------------------------------------------------
7499 // Client side array usage detection
7500 //----------------------------------------------------------------------------------------------------------------------
7501 #define VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE \
7502 if ((!g_disable_client_side_array_tracing) && (pContext) && (pointer)) \
7503 vogl_check_for_client_side_array_usage(pContext, pointer);
7504 static inline void vogl_check_for_client_side_array_usage(vogl_context *pContext, const void *pPointer)
7506 VOGL_NOTE_UNUSED(pPointer);
7508 if (pContext->get_uses_client_side_arrays() || pContext->is_core_profile())
7511 pContext->peek_and_record_gl_error();
7513 GLint cur_array_buf_binding = 0;
7514 GL_ENTRYPOINT(glGetIntegerv)(GL_ARRAY_BUFFER_BINDING, &cur_array_buf_binding);
7516 if (pContext->peek_and_drop_gl_error() == GL_NO_ERROR)
7518 if (!cur_array_buf_binding)
7520 pContext->set_uses_client_side_arrays(true);
7521 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);
7526 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7527 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glNormalPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7528 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glColorPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7529 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glIndexPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7530 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glTexCoordPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7531 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glEdgeFlagPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7532 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glFogCoordPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7533 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glSecondaryColorPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7534 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glInterleavedArrays(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7535 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7536 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glNormalPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7537 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glColorPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7538 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glIndexPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7539 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glTexCoordPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7540 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glEdgeFlagPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7541 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glFogCoordPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7542 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glSecondaryColorPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7543 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexAttribPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7544 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexAttribPointerARB(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7545 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexAttribPointerNV(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7546 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexAttribIPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7547 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexAttribIPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7548 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexAttribLPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7549 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexAttribLPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7551 //----------------------------------------------------------------------------------------------------------------------
7552 // glXUseXFont shadowing
7553 //----------------------------------------------------------------------------------------------------------------------
7554 #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);
7555 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)
7560 if (pContext->peek_and_record_gl_error())
7565 if (pContext->get_display())
7567 XFontStruct *pFont_struct = XQueryFont((Display *)pContext->get_display(), font);
7571 unsigned long value = 0;
7572 Bool result = XGetFontProperty(pFont_struct, XA_FONT, &value);
7575 pFont = (char *)XGetAtomName((Display *)pContext->get_display(), (Atom)value);
7576 if ((pFont) && (trace_serializer.is_in_begin()))
7578 trace_serializer.add_key_value("font_name", pFont);
7583 XFreeFontInfo(NULL, pFont_struct, 1);
7586 pContext->glx_font(pFont, first, count, list_base);
7589 //----------------------------------------------------------------------------------------------------------------------
7590 // vogl_display_list_bind_callback
7591 //----------------------------------------------------------------------------------------------------------------------
7592 static void vogl_display_list_bind_callback(vogl_namespace_t handle_namespace, GLenum target, GLuint handle, void *pOpaque)
7594 vogl_context *pContext = static_cast<vogl_context *>(pOpaque);
7596 // TODO: We don't whitelist anything but texture binds in display lists currently.
7597 switch (handle_namespace)
7599 case VOGL_NAMESPACE_TEXTURES:
7601 if ((handle) && (target != GL_NONE))
7602 pContext->bind_texture_conditionally(target, handle);
7607 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);
7613 //----------------------------------------------------------------------------------------------------------------------
7614 // glCallList shadowing
7615 //----------------------------------------------------------------------------------------------------------------------
7616 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glCallList(e, c, rt, r, nu, ne, a, p) \
7618 pContext->peek_and_record_gl_error();
7619 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glCallList(e, c, rt, r, nu, ne, a, p) \
7620 if (pContext && !pContext->peek_and_record_gl_error()) \
7621 vogl_gl_call_list_helper(pContext, list);
7622 static void vogl_gl_call_list_helper(vogl_context *pContext, GLuint list)
7627 pContext->parse_list_and_update_shadows(list, vogl_display_list_bind_callback, pContext);
7630 //----------------------------------------------------------------------------------------------------------------------
7631 // glCallLists shadowing
7632 //----------------------------------------------------------------------------------------------------------------------
7633 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glCallLists(e, c, rt, r, nu, ne, a, p) \
7635 pContext->peek_and_record_gl_error();
7636 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glCallLists(e, c, rt, r, nu, ne, a, p) \
7637 if (pContext && !pContext->peek_and_record_gl_error()) \
7638 vogl_gl_call_lists_helper(pContext, n, type, lists);
7639 static void vogl_gl_call_lists_helper(vogl_context *pContext, GLsizei n, GLenum type, const GLvoid *lists)
7644 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
7645 VOGL_NOTE_UNUSED(gl_error_absorber);
7647 pContext->parse_lists_and_update_shadows(n, type, lists, vogl_display_list_bind_callback, pContext);
7650 //----------------------------------------------------------------------------------------------------------------------
7651 // Ensure all entrypoints are fully serializable
7652 // This function MUST appear before #include "gl_glx_array_size_macros.inc", below
7653 //----------------------------------------------------------------------------------------------------------------------
7654 static void vogl_check_entrypoints()
7656 vogl_debug_printf("vogl_check_entrypoints: begin (specify --vogl_debug for more validation)\n");
7658 typedef vogl::hash_map<uint, dynamic_string> array_size_macro_hashmap;
7659 array_size_macro_hashmap defined_array_size_macros;
7660 array_size_macro_hashmap undefined_array_size_macros;
7662 #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);
7663 #define CUSTOM_FUNC_HANDLER_NOT_DEFINED(id)
7664 #include "gl_glx_custom_func_handler_validator.inc"
7665 #undef CUSTOM_FUNC_HANDLER_DEFINED
7666 #undef CUSTOM_FUNC_HANDLER_NOT_DEFINED
7668 #define VALIDATE_ARRAY_SIZE_MACRO_DEFINED(name, index) defined_array_size_macros.insert(index, #name);
7669 #define VALIDATE_ARRAY_SIZE_MACRO_NOT_DEFINED(name, index) undefined_array_size_macros.insert(index, #name);
7670 #include "gl_glx_array_size_macros_validator.inc"
7671 #undef VALIDATE_ARRAY_SIZE_MACRO_DEFINED
7672 #undef VALIDATE_ARRAY_SIZE_MACRO_NOT_DEFINED
7674 vogl::vector<uint> undefined_func_return_array_size_macros;
7676 #define CUSTOM_FUNC_RETURN_PARAM_ARRAY_SIZE_HANDLER_DEFINED(macro_name, func_name)
7677 #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;
7678 #include "gl_glx_custom_return_param_array_size_macro_validator.inc"
7679 #undef CUSTOM_FUNC_RETURN_PARAM_ARRAY_SIZE_HANDLER_DEFINED
7680 #undef CUSTOM_FUNC_RETURN_PARAM_ARRAY_SIZE_HANDLER_NOT_DEFINED
7682 if (vogl::check_for_command_line_param("--vogl_debug"))
7684 for (array_size_macro_hashmap::const_iterator it = undefined_array_size_macros.begin(); it != undefined_array_size_macros.end(); ++it)
7686 uint idx = it->first;
7687 const dynamic_string &name = it->second;
7688 VOGL_NOTE_UNUSED(name);
7690 gl_entrypoint_id_t func = static_cast<gl_entrypoint_id_t>(idx >> 16);
7691 uint param = idx & 0xFFFF;
7693 vogl_warning_printf("%s: Custom array size macro for func %u \"%s\" param %u has not been defined, this function cannot be traced\n",
7694 VOGL_FUNCTION_NAME, func, g_vogl_entrypoint_descs[func].m_pName, param);
7696 g_vogl_entrypoint_param_descs[func][param].m_custom_array_size_macro_is_missing = true;
7697 g_vogl_entrypoint_descs[func].m_custom_array_size_macro_is_missing = true;
7700 vogl_debug_printf("Undefined array size macros:\n");
7701 vogl_debug_printf("---\n");
7702 for (array_size_macro_hashmap::const_iterator it = undefined_array_size_macros.begin(); it != undefined_array_size_macros.end(); ++it)
7704 const dynamic_string &name = it->second;
7705 vogl_debug_printf("%s\n", name.get_ptr());
7707 vogl_debug_printf("---\n");
7709 vogl_debug_printf("Undefined return param array size macros:\n");
7710 vogl_debug_printf("---\n");
7711 for (uint i = 0; i < VOGL_NUM_ENTRYPOINTS; i++)
7713 vogl_ctype_t return_ctype = g_vogl_entrypoint_descs[i].m_return_ctype;
7715 if (return_ctype == VOGL_VOID)
7717 if (!g_vogl_process_gl_ctypes[return_ctype].m_is_pointer)
7719 //if (g_vogl_process_gl_ctypes[return_ctype].m_is_opaque_pointer)
7722 if (g_vogl_entrypoint_descs[i].m_custom_return_param_array_size_macro_is_missing)
7724 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);
7727 if (g_vogl_entrypoint_descs[i].m_whitelisted_for_displaylists)
7729 if (!g_vogl_entrypoint_descs[i].m_is_listable)
7731 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);
7735 vogl_debug_printf("---\n");
7737 vogl_debug_printf("Whitelisted funcs with undefined array size macros:\n");
7738 vogl_debug_printf("---\n");
7739 for (uint i = 0; i < VOGL_NUM_ENTRYPOINTS; i++)
7741 const gl_entrypoint_desc_t &desc = g_vogl_entrypoint_descs[i];
7742 if ((!desc.m_is_whitelisted) || (desc.m_has_custom_func_handler))
7745 if (desc.m_custom_array_size_macro_is_missing)
7746 vogl_debug_printf("%s\n", desc.m_pName);
7748 vogl_debug_printf("---\n");
7750 vogl_debug_printf("Whitelisted funcs with undefined return param array size macros:\n");
7751 vogl_debug_printf("---\n");
7752 for (uint i = 0; i < VOGL_NUM_ENTRYPOINTS; i++)
7754 const gl_entrypoint_desc_t &desc = g_vogl_entrypoint_descs[i];
7755 if (desc.m_is_whitelisted)
7758 vogl_ctype_t return_ctype = g_vogl_entrypoint_descs[i].m_return_ctype;
7760 if (return_ctype == VOGL_VOID)
7762 if (!g_vogl_process_gl_ctypes[return_ctype].m_is_pointer)
7764 if (g_vogl_process_gl_ctypes[return_ctype].m_is_opaque_pointer)
7767 if (g_vogl_entrypoint_descs[i].m_custom_return_param_array_size_macro_is_missing)
7769 vogl_debug_printf("%s\n", g_vogl_entrypoint_descs[i].m_pName);
7773 vogl_debug_printf("---\n");
7776 vogl_debug_printf("vogl_check_entrypoints: done\n");
7779 //----------------------------------------------------------------------------------------------------------------------
7780 // Include generated macros to define the internal entrypoint funcs
7781 //----------------------------------------------------------------------------------------------------------------------
7782 #include "gl_glx_array_size_macros.inc"
7783 #include "gl_glx_func_return_param_array_size_macros.inc"
7784 #include "gl_glx_func_defs.inc"
7786 #ifndef NO_PUBLIC_EXPORTS
7787 //----------------------------------------------------------------------------------------------------------------------
7788 // Declare exported gl/glx functions (each exported func immediately calls one of the internal vogl_* functions)
7789 //----------------------------------------------------------------------------------------------------------------------
7790 #define DEF_PROTO_EXPORTED(ret, name, args, params) \
7791 VOGL_API_EXPORT ret name args \
7793 return VOGL_GLUER(vogl_, name) params; \
7795 #define DEF_PROTO_EXPORTED_VOID(ret, name, args, params) \
7796 VOGL_API_EXPORT ret name args \
7798 VOGL_GLUER(vogl_, name) params; \
7800 #define DEF_PROTO_INTERNAL(ret, name, args, params)
7801 #define DEF_PROTO_INTERNAL_VOID(ret, name, args, params)
7802 #define DEF_FUNCTION_BEGIN(exported, category, ret, ret_type_enum, num_params, name, args, params) exported(ret, name, args, params)
7803 #define DEF_FUNCTION_BEGIN_VOID(exported, category, ret, ret_type_enum, num_params, name, args, params) exported(ret, name, args, params)
7804 #define DEF_FUNCTION_INIT(exported, category, ret, ret_type_enum, num_params, name, args, params)
7805 #define DEF_FUNCTION_INIT_VOID(exported, category, ret, ret_type_enum, num_params, name, args, params)
7806 #define DEF_FUNCTION_INPUT_VALUE_PARAM(idx, spectype, type, type_enum, param)
7807 #define DEF_FUNCTION_INPUT_REFERENCE_PARAM(idx, spectype, type, type_enum, param)
7808 #define DEF_FUNCTION_INPUT_ARRAY_PARAM(idx, spectype, type, type_enum, param, size)
7809 #define DEF_FUNCTION_OUTPUT_REFERENCE_PARAM(idx, spectype, type, type_enum, param)
7810 #define DEF_FUNCTION_OUTPUT_ARRAY_PARAM(idx, spectype, type, type_enum, param, size)
7811 #define DEF_FUNCTION_RETURN_PARAM(spectype, type, type_enum, size)
7812 #define DEF_FUNCTION_CALL_GL(exported, category, ret, ret_type_enum, num_params, name, args, params)
7813 #define DEF_FUNCTION_CALL_GL_VOID(exported, category, ret, ret_type_enum, num_params, name, args, params)
7814 #define DEF_FUNCTION_END(exported, category, ret, ret_type_enum, num_params, name, args, params)
7815 #define DEF_FUNCTION_END_VOID(exported, category, ret, ret_type_enum, num_params, name, args, params)
7816 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_GL_ENUM(pname) -1
7818 #include "gl_glx_array_size_macros.inc"
7819 #include "gl_glx_func_defs.inc"
7822 //----------------------------------------------------------------------------------------------------------------------
7823 // Define our exported gliGetProcAddressRAD function
7824 //----------------------------------------------------------------------------------------------------------------------
7825 VOGL_API_EXPORT __GLXextFuncPtr gliGetProcAddressRAD(const GLubyte *procName)
7827 if ((procName) && (!vogl_strcmp(reinterpret_cast<const char *>(procName), "gliGetProcAddressRAD")))
7828 return (__GLXextFuncPtr)gliGetProcAddressRAD;
7830 return vogl_glXGetProcAddressARB(procName);
7833 //----------------------------------------------------------------------------------------------------------------------
7834 // Determine addresses of our gl/glx wrapper functions
7835 //----------------------------------------------------------------------------------------------------------------------
7836 static void vogl_init_wrapper_func_ptrs()
7838 gl_entrypoint_desc_t *pDst = g_vogl_entrypoint_descs;
7840 #define DEF_PROTO(exported, category, ret, ret_type, num_params, name, args, params) \
7841 pDst->m_pWrapper_func = reinterpret_cast<vogl_void_func_ptr_t>(vogl_##name); \
7843 #define DEF_PROTO_VOID(exported, category, ret, ret_type, num_params, name, args, params) \
7844 pDst->m_pWrapper_func = reinterpret_cast<vogl_void_func_ptr_t>(vogl_##name); \
7846 #include "gl_glx_protos.inc"
7848 #undef DEF_PROTO_VOID
7851 //----------------------------------------------------------------------------------------------------------------------
7852 // vogl_direct_gl_func_prolog - This function is called before EVERY single GL/GLX function call we make.
7853 //----------------------------------------------------------------------------------------------------------------------
7854 static void vogl_direct_gl_func_prolog(gl_entrypoint_id_t entrypoint_id, void *pUser_data, void **ppStack_data)
7856 VOGL_NOTE_UNUSED(entrypoint_id);
7857 VOGL_NOTE_UNUSED(pUser_data);
7859 if (g_dump_gl_calls_flag)
7860 printf("** GLPROLOG %s\n", g_vogl_entrypoint_descs[entrypoint_id].m_pName);
7862 gl_entrypoint_id_t *pPrev_state = reinterpret_cast<gl_entrypoint_id_t *>(ppStack_data);
7863 *pPrev_state = VOGL_ENTRYPOINT_INVALID;
7865 vogl_thread_local_data *pTLS_data = vogl_get_or_create_thread_local_data();
7868 *pPrev_state = pTLS_data->m_calling_driver_entrypoint_id;
7869 pTLS_data->m_calling_driver_entrypoint_id = entrypoint_id;
7873 //----------------------------------------------------------------------------------------------------------------------
7874 // vogl_direct_gl_func_epilog - This function is called immediately after EVERY single GL/GLX function call we make.
7875 //----------------------------------------------------------------------------------------------------------------------
7876 static void vogl_direct_gl_func_epilog(gl_entrypoint_id_t entrypoint_id, void *pUser_data, void **ppStack_data)
7878 VOGL_NOTE_UNUSED(entrypoint_id);
7879 VOGL_NOTE_UNUSED(pUser_data);
7882 if (entrypoint_id == VOGL_ENTRYPOINT_glXMakeCurrent)
7884 // HACK HACK - crude test of the "calling driver entrypoint code"
7885 glXGetCurrentContext();
7889 if (g_dump_gl_calls_flag)
7890 printf("** GLEPILOG %s\n", g_vogl_entrypoint_descs[entrypoint_id].m_pName);
7892 gl_entrypoint_id_t *pPrev_state = reinterpret_cast<gl_entrypoint_id_t *>(ppStack_data);
7894 vogl_thread_local_data *pTLS_data = vogl_get_or_create_thread_local_data();
7897 pTLS_data->m_calling_driver_entrypoint_id = *pPrev_state;
7901 //----------------------------------------------------------------------------------------------------------------------
7903 // Note: Be VERY careful what you do in here! It's called very early during init (long before main, during c++ init)
7904 //----------------------------------------------------------------------------------------------------------------------
7905 void vogl_early_init()
7907 vogl_init_thread_local_data();
7909 vogl_set_direct_gl_func_prolog(vogl_direct_gl_func_prolog, NULL);
7910 vogl_set_direct_gl_func_epilog(vogl_direct_gl_func_epilog, NULL);
7912 vogl_init_wrapper_func_ptrs();
7914 vogl_check_entrypoints();