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 // TODO: For glTexImage3DEXT, glTexSubImage1DEXT, etc. - should these check the currently bound GL_PIXEL_UNPACK_BUFFER?
3084 //----------------------------------------------------------------------------------------------------------------------
3085 size_t vogl_calc_set_tex_image_serialize_size(vogl_context *pContext, GLenum format, GLenum type, GLsizei width, GLsizei height, GLsizei depth)
3089 if (vogl_get_bound_gl_buffer(GL_PIXEL_UNPACK_BUFFER))
3093 return vogl_get_image_size(format, type, width, height, depth);
3096 size_t vogl_calc_get_tex_image_serialize_size(vogl_context *pContext, GLenum format, GLenum type, GLsizei width, GLsizei height, GLsizei depth)
3100 if (vogl_get_bound_gl_buffer(GL_PIXEL_PACK_BUFFER))
3104 return vogl_get_image_size(format, type, width, height, depth);
3107 size_t vogl_calc_get_tex_target_serialize_size(vogl_context *pContext, GLenum target, GLint level, GLenum format, GLenum type)
3111 if (vogl_get_bound_gl_buffer(GL_PIXEL_PACK_BUFFER))
3115 return vogl_get_tex_target_image_size(target, level, format, type);
3118 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexImage1D_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, 1, 1)
3119 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexImage2D_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, 1)
3120 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexImage3D_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, depth)
3121 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexImage3DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, depth)
3123 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexSubImage1D_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, 1, 1)
3124 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexSubImage1DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, 1, 1)
3126 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexSubImage2D_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, 1)
3127 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexSubImage2DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, 1)
3129 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexSubImage3D_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, depth)
3130 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTexSubImage3DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, depth)
3132 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTextureImage3DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, depth)
3133 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTextureImage2DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, 1)
3134 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTextureImage1DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, 1, 1)
3136 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTextureSubImage3DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, depth)
3137 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTextureSubImage2DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, 1)
3138 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glTextureSubImage1DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, 1, 1)
3140 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glMultiTexImage3DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, depth)
3141 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glMultiTexImage2DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, 1)
3142 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glMultiTexImage1DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, 1, 1)
3144 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glMultiTexSubImage3DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, depth)
3145 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glMultiTexSubImage2DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, 1)
3146 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glMultiTexSubImage1DEXT_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, 1, 1)
3148 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glDrawPixels_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, 1)
3149 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glConvolutionFilter1D_image(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, 1, 1)
3150 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glConvolutionFilter2D_image(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, height, 1)
3152 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glColorTable_table(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, 1, 1)
3153 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glColorSubTable_data(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, count, 1, 1)
3155 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glBitmap_size(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, GL_COLOR_INDEX, GL_BITMAP, width, height, 1)
3156 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glPolygonStipple_mask(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, GL_COLOR_INDEX, GL_BITMAP, 32, 32, 1)
3158 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetTexImage_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_get_tex_target_serialize_size(pContext, target, level, format, type)
3160 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glStringMarkerGREMEDY_string(e, c, rt, r, nu, ne, a, p) ((string) ? (!(len) ? (strlen(static_cast<const char *>(string)) + 1) : (len)) : 0)
3162 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glViewportArrayv_v(e, c, rt, r, nu, ne, a, p) (4 * (count))
3163 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glScissorArrayv_v(e, c, rt, r, nu, ne, a, p) (4 * (count))
3164 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glDepthRangeArrayv_v(e, c, rt, r, nu, ne, a, p) (2 * (count))
3166 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetActiveAttrib_name(e, c, rt, r, nu, ne, a, p) ((name) ? (strlen((const char *)(name)) + 1) : -1)
3167 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetActiveAttribARB_name(e, c, rt, r, nu, ne, a, p) ((name) ? (strlen((const char *)(name)) + 1) : -1)
3169 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glReadPixels_pixels(e, c, rt, r, nu, ne, a, p) vogl_calc_get_tex_image_serialize_size(pContext, format, type, width, height, 1)
3171 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glBindFragDataLocationIndexed_name(e, c, rt, r, nu, ne, a, p) (name ? (strlen((const char *)(name)) + 1) : -1)
3172 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glBindFragDataLocation_name(e, c, rt, r, nu, ne, a, p) (name ? (strlen((const char *)(name)) + 1) : -1)
3173 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glBindFragDataLocationEXT_name(e, c, rt, r, nu, ne, a, p) (name ? (strlen((const char *)(name)) + 1) : -1)
3175 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glBitmap_bitmap(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, GL_COLOR_INDEX, GL_BITMAP, width, height, 1)
3177 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetActiveUniform_name(e, c, rt, r, nu, ne, a, p) ((name) ? ((length) ? (*(length) + 1) : (bufSize)) : -1)
3179 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetAttachedShaders_obj(e, c, rt, r, nu, ne, a, p) ((obj) ? ((count) ? *(count) : (maxCount)) : -1)
3181 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetProgramInfoLog_infoLog(e, c, rt, r, nu, ne, a, p) ((infoLog) ? ((length) ? (*length + 1) : (bufSize)) : -1)
3183 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetShaderSource_source(e, c, rt, r, nu, ne, a, p) ((source) ? ((length) ? (*(length) + 1) : (bufSize)) : -1)
3185 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glCallLists_lists(e, c, rt, r, nu, ne, a, p) (vogl_get_gl_type_size(type) * (n))
3187 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetDebugMessageLogARB_messageLog(e, c, rt, r, nu, ne, a, p) vogl_compute_message_log_size_in_bytes(count, lengths)
3188 static GLsizei vogl_compute_message_log_size_in_bytes(GLuint count, const GLsizei *lengths)
3192 GLsizei total_length = 0;
3193 for (uint i = 0; i < count; i++)
3194 total_length += lengths[i];
3195 return total_length;
3198 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glSeparableFilter2D_row(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, width, 1, 1)
3199 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glSeparableFilter2D_column(e, c, rt, r, nu, ne, a, p) vogl_calc_set_tex_image_serialize_size(pContext, format, type, height, 1, 1)
3201 // TODO - These are all gets, so they aren't completely necessary for proper replaying because they have no side effects (except for possibly glError's).
3202 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetUniformfv_params(e, c, rt, r, nu, ne, a, p) -1
3203 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetUniformiv_params(e, c, rt, r, nu, ne, a, p) -1
3204 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetPolygonStipple_mask(e, c, rt, r, nu, ne, a, p) -1
3205 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetMapdv_v(e, c, rt, r, nu, ne, a, p) -1
3206 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetMapfv_v(e, c, rt, r, nu, ne, a, p) -1
3207 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetMapiv_v(e, c, rt, r, nu, ne, a, p) -1
3208 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetColorTable_table(e, c, rt, r, nu, ne, a, p) -1
3209 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetConvolutionFilter_image(e, c, rt, r, nu, ne, a, p) -1
3210 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetSeparableFilter_row(e, c, rt, r, nu, ne, a, p) -1
3211 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetSeparableFilter_column(e, c, rt, r, nu, ne, a, p) -1
3212 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetSeparableFilter_span(e, c, rt, r, nu, ne, a, p) -1
3213 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetHistogram_values(e, c, rt, r, nu, ne, a, p) -1
3214 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetMinmax_values(e, c, rt, r, nu, ne, a, p) -1
3215 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetCompressedTexImage_img(e, c, rt, r, nu, ne, a, p) -1
3217 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glClearBufferfv_value(e, c, rt, r, nu, ne, a, p) vogl_get_clearbuffer_array_size(buffer)
3218 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glClearBufferuiv_value(e, c, rt, r, nu, ne, a, p) vogl_get_clearbuffer_array_size(buffer)
3219 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glClearBufferiv_value(e, c, rt, r, nu, ne, a, p) vogl_get_clearbuffer_array_size(buffer)
3220 static int vogl_get_clearbuffer_array_size(GLenum buffer)
3222 if ((buffer == GL_DEPTH) || (buffer == GL_STENCIL))
3224 else if (utils::is_in_set<GLenum, GLenum>(buffer, GL_COLOR, GL_FRONT, GL_BACK, GL_LEFT, GL_RIGHT, GL_FRONT_AND_BACK))
3227 vogl_warning_printf("%s: Invalid value for buffer parameter passed to glClearBufferfv: 0x%04X\n", VOGL_FUNCTION_NAME, buffer);
3245 //----------------------------------------------------------------------------------------------------------------------
3246 // Custom return parameter array size helper macros
3247 //----------------------------------------------------------------------------------------------------------------------
3248 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXGetFBConfigs(dpy, screen, nelements) (nelements ? *nelements : 1)
3249 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXChooseFBConfig(dpy, screen, attrib_list, nelements) (nelements ? *nelements : 1)
3250 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXChooseVisual(dpy, screen, nelements) 1
3251 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXGetVisualFromFBConfig(dpy, config) 1
3252 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXGetCurrentDisplay() 1
3253 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXGetCurrentDisplayEXT() 1
3254 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXEnumerateVideoCaptureDevicesNV(dpy, screen, nelements) (nelements ? *nelements : 1)
3255 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXEnumerateVideoDevicesNV(dpy, screen, nelements) (nelements ? *nelements : 1)
3257 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetString(name) (result ? (strlen(reinterpret_cast<const char *>(result)) + 1) : 0)
3258 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glGetStringi(name, idx) (result ? (strlen(reinterpret_cast<const char *>(result)) + 1) : 0)
3259 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXGetClientString(dpy, name) (result ? (strlen(reinterpret_cast<const char *>(result)) + 1) : 0)
3260 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXQueryExtensionsString(dpy, name) (result ? (strlen(reinterpret_cast<const char *>(result)) + 1) : 0)
3261 #define DEF_FUNCTION_RETURN_PARAM_COMPUTE_ARRAY_SIZE_FUNC_glXQueryServerString(dpy, screen, name) (result ? (strlen(reinterpret_cast<const char *>(result)) + 1) : 0)
3263 //----------------------------------------------------------------------------------------------------------------------
3264 static void vogl_print_hex(const void *p, uint64_t size, uint64_t type_size)
3268 vogl_log_printf("<null>\n");
3272 const uint8_t *ptr = reinterpret_cast<const uint8_t *>(p);
3273 if ((type_size == 2) && (!(size & 1)))
3276 vogl_log_printf("[ ");
3277 for (uint64_t i = 0; i < size; i += 2)
3280 vogl_log_printf(", ");
3281 vogl_log_printf("0x%04X", *reinterpret_cast<const uint16_t *>(ptr + i));
3284 vogl_log_printf("\n");
3286 vogl_log_printf(" ]");
3288 else if ((type_size == 4) && (!(size & 3)))
3291 vogl_log_printf("[ ");
3292 for (uint64_t i = 0; i < size; i += 4)
3295 vogl_log_printf(", ");
3296 vogl_log_printf("0x%08X", *reinterpret_cast<const uint32_t *>(ptr + i));
3299 vogl_log_printf("\n");
3301 vogl_log_printf(" ]");
3303 else if ((type_size == 8) && (!(size & 7)))
3306 vogl_log_printf("[ ");
3307 for (uint64_t i = 0; i < size; i += 8)
3310 vogl_log_printf(", ");
3311 vogl_log_printf("0x%" PRIX64, *reinterpret_cast<const uint64_t *>(ptr + i));
3314 vogl_log_printf("\n");
3316 vogl_log_printf(" ]");
3322 vogl_log_printf("\n");
3324 vogl_log_printf("[ ");
3325 for (uint64_t i = 0; i < size; i++)
3328 vogl_log_printf(", ");
3329 vogl_log_printf("%02X", ptr[i]);
3331 if ((++c & 63) == 63)
3332 vogl_log_printf("\n");
3334 vogl_log_printf(" ]");
3338 //----------------------------------------------------------------------------------------------------------------------
3339 static void vogl_print_string(const char *pStr, uint64_t total_size)
3341 for (uint64_t i = 0; i < total_size; i++)
3343 uint8_t c = reinterpret_cast<const uint8_t *>(pStr)[i];
3345 vogl_log_printf("\n");
3348 if ((c < 32) || (c > 127))
3350 vogl_log_printf("%c", c);
3353 if ((i & 511) == 511)
3354 vogl_log_printf(" \\\n");
3358 //----------------------------------------------------------------------------------------------------------------------
3359 template <typename T>
3360 static inline void vogl_dump_value_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pDesc, uint param_index, const char *pParam_name, const char *pType, vogl_ctype_t type, const T &val)
3362 VOGL_NOTE_UNUSED(pContext);
3364 int size = sizeof(T);
3366 if (g_vogl_process_gl_ctypes[type].m_size != size)
3367 vogl_error_printf("%s: size mismatch on ctype %u\n", VOGL_FUNCTION_NAME, type);
3369 if (serializer.is_in_begin())
3371 serializer.add_param(param_index, type, &val, sizeof(val));
3374 if (g_dump_gl_calls_flag)
3376 vogl_log_printf("%s: %s %s, ctype: %s, size: %i: ", pDesc, pType, pParam_name, g_vogl_process_gl_ctypes[type].m_pName, size);
3378 if (Loki::TypeTraits<T>::isPointer)
3380 vogl_log_printf("OPAQUE POINTER TYPE");
3384 vogl_log_printf("OPAQUE TYPE");
3388 vogl_print_hex(&val, size, size);
3390 if (((type == VOGL_GLFLOAT) || (type == VOGL_GLCLAMPF)) && (size == sizeof(float)))
3392 float flt_val = *reinterpret_cast<const float *>(&val);
3393 vogl_log_printf(" %f", flt_val);
3395 else if (((type == VOGL_GLDOUBLE) || (type == VOGL_GLCLAMPD)) && (size == sizeof(double)))
3397 double dbl_val = *reinterpret_cast<const double *>(&val);
3398 vogl_log_printf(" %f", dbl_val);
3400 else if ((type == VOGL_GLENUM) && (size == sizeof(int)))
3402 GLenum enum_val = *reinterpret_cast<const GLenum *>(&val);
3403 const char *pName = g_gl_enums.find_name(enum_val);
3405 vogl_log_printf(" %s", pName);
3409 vogl_log_printf("\n");
3413 //----------------------------------------------------------------------------------------------------------------------
3414 template <typename T>
3415 static inline void vogl_dump_ptr_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pDesc, uint param_index, const char *pParam_name, const char *pType, vogl_ctype_t type, const T &val)
3417 VOGL_NOTE_UNUSED(pContext);
3419 VOGL_ASSUME(Loki::TypeTraits<T>::isPointer);
3420 int size = sizeof(T);
3422 if (g_vogl_process_gl_ctypes[type].m_size != size)
3423 vogl_error_printf("%s: size mismatch on ctype %u\n", VOGL_FUNCTION_NAME, type);
3425 if (serializer.is_in_begin())
3427 serializer.add_param(param_index, type, &val, sizeof(val));
3430 if (g_dump_gl_calls_flag)
3432 vogl_log_printf("%s: %s %s, ctype: %s, size: %i, ptr: 0x%" PRIX64 "\n", pDesc, pType, pParam_name, g_vogl_process_gl_ctypes[type].m_pName, size, cast_val_to_uint64(val));
3436 //----------------------------------------------------------------------------------------------------------------------
3438 static inline void vogl_dump_ref_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pDesc, uint param_index, const char *pParam_name, const char *pType, vogl_ctype_t type, const T *pObj)
3440 VOGL_NOTE_UNUSED(pContext);
3442 if (g_vogl_process_gl_ctypes[type].m_size != sizeof(const T *))
3443 vogl_error_printf("%s: size mismatch on ctype %u\n", VOGL_FUNCTION_NAME, type);
3445 int obj_size = gl_ctype_sizeof<T>::size;
3447 vogl_ctype_t pointee_type = g_vogl_process_gl_ctypes[type].m_pointee_ctype;
3448 if (pointee_type == VOGL_INVALID_CTYPE)
3450 vogl_error_printf("%s: Type %u doesn't have a pointee ctype\n", VOGL_FUNCTION_NAME, type);
3454 if (g_vogl_process_gl_ctypes[pointee_type].m_size != obj_size)
3455 vogl_error_printf("%s: size mismatch on pointee ctype %u\n", VOGL_FUNCTION_NAME, type);
3457 if (serializer.is_in_begin())
3459 serializer.add_param(param_index, type, &pObj, sizeof(pObj));
3461 if ((pObj) && (obj_size > 0))
3463 serializer.add_ref_client_memory(param_index, pointee_type, pObj, obj_size);
3467 if (g_dump_gl_calls_flag)
3469 vogl_log_printf("%s: %s %s, ptr: 0x%" PRIX64 ", ctype: %s, pointee_ctype: %s, pointee_size: %i: ", pDesc, pType, pParam_name, cast_val_to_uint64(pObj), g_vogl_process_gl_ctypes[type].m_pName, g_vogl_process_gl_ctypes[pointee_type].m_pName, obj_size);
3472 vogl_log_printf("NULL");
3474 else if (obj_size <= 0)
3476 vogl_log_printf("OPAQUE TYPE");
3480 vogl_print_hex(pObj, obj_size, obj_size);
3483 vogl_log_printf("\n");
3487 //----------------------------------------------------------------------------------------------------------------------
3489 static inline void vogl_dump_array_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pDesc, uint param_index, const char *pParam_name, const char *pType, vogl_ctype_t type, const T *pArray, int64_t size)
3491 VOGL_NOTE_UNUSED(pContext);
3493 int64_t obj_size = gl_ctype_sizeof<T>::size;
3494 int64_t total_size = obj_size * math::maximum<int64_t>(size, 0);
3496 vogl_ctype_t pointee_type = g_vogl_process_gl_ctypes[type].m_pointee_ctype;
3497 if (((type == VOGL_CONST_VOID_PTR) || (type == VOGL_CONST_GLVOID_PTR) || (type == VOGL_GLVOID_PTR)) && (size > 0))
3504 if (pointee_type == VOGL_INVALID_CTYPE)
3506 vogl_error_printf("%s: Type %u doesn't have a pointee ctype\n", VOGL_FUNCTION_NAME, type);
3510 if (g_vogl_process_gl_ctypes[pointee_type].m_size != obj_size)
3511 vogl_error_printf("%s: Size mismatch on ctype %u\n", VOGL_FUNCTION_NAME, type);
3514 bool pointee_is_ptr = g_vogl_process_gl_ctypes[pointee_type].m_is_pointer;
3516 if (serializer.is_in_begin())
3518 serializer.add_param(param_index, type, &pArray, sizeof(pArray));
3520 if ((pArray) && (size > 0) && (obj_size > 0))
3522 serializer.add_array_client_memory(param_index, pointee_type, size, pArray, total_size);
3526 if (g_dump_gl_calls_flag)
3528 vogl_log_printf("%s: %s %s, ptr: 0x%" PRIX64 ", ctype: %s, pointee_ctype: %s, size: %" PRIi64 ", pointee_size: %" PRIi64 ", total size: %" PRIi64 ": ", pDesc, pType, pParam_name, cast_val_to_uint64(pArray), g_vogl_process_gl_ctypes[type].m_pName, g_vogl_process_gl_ctypes[pointee_type].m_pName,
3529 size, obj_size, total_size);
3532 vogl_log_printf("NULL");
3536 vogl_log_printf("UNKNOWN SIZE");
3538 else if (obj_size <= 0)
3540 vogl_log_printf("OPAQUE TYPE");
3546 vogl_log_printf("POINTEE IS POINTER: \n");
3549 vogl_print_hex(pArray, total_size, obj_size);
3551 switch (pointee_type)
3556 case VOGL_GLCHARARB:
3558 vogl_log_printf("\nAs string: \"");
3559 vogl_print_string(*(const char **)&pArray, total_size);
3560 vogl_log_printf("\"");
3570 vogl_log_printf("\n");
3574 //----------------------------------------------------------------------------------------------------------------------
3575 // Return parameters
3576 //----------------------------------------------------------------------------------------------------------------------
3578 static inline void vogl_dump_return_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pType, vogl_ctype_t type, int64_t size, const T &val)
3580 VOGL_NOTE_UNUSED(size);
3582 VOGL_ASSUME(!Loki::TypeTraits<T>::isPointer);
3584 vogl_dump_value_param(pContext, serializer, "RETURN_VALUE", VOGL_RETURN_PARAM_INDEX, "result", pType, type, val);
3587 static inline void vogl_dump_return_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pType, vogl_ctype_t type, int64_t size, unsigned char *pPtr)
3589 VOGL_NOTE_UNUSED(size);
3591 size_t array_size = pPtr ? (strlen(reinterpret_cast<const char *>(pPtr)) + 1) : 0;
3592 vogl_dump_array_param(pContext, serializer, "RETURN_UCHAR_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr, array_size);
3595 static inline void vogl_dump_return_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pType, vogl_ctype_t type, int64_t size, const GLubyte *pPtr)
3597 VOGL_NOTE_UNUSED(size);
3599 size_t array_size = pPtr ? (strlen(reinterpret_cast<const char *>(pPtr)) + 1) : 0;
3600 vogl_dump_array_param(pContext, serializer, "RETURN_GLUBYTE_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr, array_size);
3603 static inline void vogl_dump_return_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pType, vogl_ctype_t type, int64_t size, void *pPtr)
3605 VOGL_NOTE_UNUSED(size);
3608 vogl_dump_ptr_param(pContext, serializer, "RETURN_VOID_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr);
3611 static inline void vogl_dump_return_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pType, vogl_ctype_t type, int64_t size, unsigned int *pPtr)
3613 vogl_dump_array_param(pContext, serializer, "RETURN_UINT_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr, size);
3616 static inline void vogl_dump_return_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pType, vogl_ctype_t type, int64_t size, long unsigned int *pPtr)
3618 vogl_dump_array_param(pContext, serializer, "RETUURN_LUINT_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr, size);
3621 static inline void vogl_dump_return_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pType, vogl_ctype_t type, int64_t size, XVisualInfo *pPtr)
3623 VOGL_NOTE_UNUSED(size);
3625 vogl_dump_ref_param(pContext, serializer, "RETURN_XVISUALINFO_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr);
3628 static inline void vogl_dump_return_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pType, vogl_ctype_t type, int64_t size, GLXFBConfig *pPtr)
3630 VOGL_NOTE_UNUSED(size);
3632 vogl_dump_ref_param(pContext, serializer, "RETURN_GLXFBCONFIG_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr);
3635 static inline void vogl_dump_return_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pType, vogl_ctype_t type, int64_t size, GLXContext pPtr)
3637 VOGL_NOTE_UNUSED(size);
3640 vogl_dump_ptr_param(pContext, serializer, "RETURN_GLXCONTEXT", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr);
3643 static inline void vogl_dump_return_param(vogl_context *pContext, vogl_entrypoint_serializer &serializer, const char *pType, vogl_ctype_t type, int64_t size, _XDisplay *pPtr)
3645 VOGL_NOTE_UNUSED(size);
3648 vogl_dump_ptr_param(pContext, serializer, "RETURN_XDISPLAY_PTR", VOGL_RETURN_PARAM_INDEX, "result", pType, type, pPtr);
3651 //----------------------------------------------------------------------------------------------------------------------
3652 // vogl_should_serialize_call
3653 //----------------------------------------------------------------------------------------------------------------------
3654 static inline bool vogl_should_serialize_call(gl_entrypoint_id_t func, vogl_context *pContext)
3656 bool is_in_display_list = pContext && pContext->is_composing_display_list();
3657 bool is_listable = g_vogl_entrypoint_descs[func].m_is_listable;
3658 bool is_whitelisted = g_vogl_entrypoint_descs[func].m_whitelisted_for_displaylists;
3660 if ((is_in_display_list) && (is_listable) && (!is_whitelisted))
3662 vogl_error_printf("%s: Called GL func %s is not currently supported in display lists! The replay will diverge.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[func].m_pName);
3665 // When we're writing a trace we ALWAYS want to serialize, even if the func is not listable (so we can at least process the trace, etc.)
3666 if (g_vogl_trace_writer.is_opened())
3669 return is_in_display_list && is_whitelisted;
3672 //----------------------------------------------------------------------------------------------------------------------
3673 // vogl_write_packet_to_trace
3674 //----------------------------------------------------------------------------------------------------------------------
3675 static inline void vogl_write_packet_to_trace(vogl_trace_packet &packet)
3677 if (!g_vogl_trace_writer.is_opened())
3680 scoped_mutex lock(g_vogl_trace_mutex);
3682 // The trace got closed on another thread while we where serializing - this is OK I guess.
3683 // This can happen when control+c is pressed.
3684 if (g_vogl_trace_writer.is_opened())
3686 bool success = g_vogl_trace_writer.write_packet(packet);
3690 if ((g_flush_files_after_each_call) ||
3691 ((g_flush_files_after_each_swap) && (packet.get_entrypoint_id() == VOGL_ENTRYPOINT_glXSwapBuffers)))
3693 g_vogl_trace_writer.flush();
3695 if (g_vogl_pLog_stream)
3696 g_vogl_pLog_stream->flush();
3701 vogl_error_printf("%s: Failed writing to trace file! Exiting app.\n", VOGL_FUNCTION_NAME);
3703 // TODO: Add common termination handler func, or just stop writing to the trace? or call abort()
3709 //----------------------------------------------------------------------------------------------------------------------
3710 // Declare gl/glx internal wrapper functions, all start with "vogl_" (so we can safely get the address of our internal
3711 // wrappers, avoiding global symbol naming conflicts that I started to see on test apps when I started building with -fPIC)
3712 //----------------------------------------------------------------------------------------------------------------------
3714 #define DEF_PROTO_EXPORTED(ret, name, args, params) \
3715 static ret VOGL_GLUER(vogl_, name) args \
3717 if (vogl_func_is_nulled(VOGL_ENTRYPOINT_##name)) \
3722 #define DEF_PROTO_EXPORTED_VOID(ret, name, args, params) \
3723 static ret VOGL_GLUER(vogl_, name) args \
3725 if (vogl_func_is_nulled(VOGL_ENTRYPOINT_##name)) \
3727 #define DEF_PROTO_INTERNAL(ret, name, args, params) \
3728 static ret VOGL_GLUER(vogl_, name) args \
3730 if (vogl_func_is_nulled(VOGL_ENTRYPOINT_##name)) \
3735 #define DEF_PROTO_INTERNAL_VOID(ret, name, args, params) \
3736 static ret VOGL_GLUER(vogl_, name) args \
3738 if (vogl_func_is_nulled(VOGL_ENTRYPOINT_##name)) \
3741 #define DEF_FUNCTION_BEGIN(exported, category, ret, ret_type_enum, num_params, name, args, params) exported(ret, name, args, params)
3742 #define DEF_FUNCTION_BEGIN_VOID(exported, category, ret, ret_type_enum, num_params, name, args, params) exported(ret, name, args, params)
3744 // TODO: When serialization is off, the array size determination code is still active (which could involve useless GL calls and in the worst case could trigger errors when/if this code is buggy).
3745 // A completely different code path through the wrapper should be used.
3747 // func init (after the optional custom function prolog)
3748 #define VOGL_MASTER_FUNCTION_PROLOG(name, params) \
3749 if (g_dump_gl_calls_flag) \
3751 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "" PRIX64 "\n", #name, vogl_get_current_kernel_thread_id()); \
3753 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_##name); \
3754 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID) \
3756 vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName); \
3757 return g_vogl_actual_gl_entrypoints.m_##name params; \
3759 vogl_context *pContext = pTLS_data->m_pContext; \
3760 vogl_entrypoint_serializer &trace_serializer = pTLS_data->m_serializer; \
3761 if (vogl_should_serialize_call(VOGL_ENTRYPOINT_##name, pContext)) \
3763 if (!trace_serializer.begin(VOGL_ENTRYPOINT_##name, pContext)) \
3765 vogl_warning_printf("%s: Reentrant wrapper call detected!\n", VOGL_FUNCTION_NAME); \
3766 return g_vogl_actual_gl_entrypoints.m_##name params; \
3770 #define VOGL_MASTER_FUNCTION_PROLOG_VOID(name, params) \
3771 if (g_dump_gl_calls_flag) \
3773 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", #name, vogl_get_current_kernel_thread_id()); \
3775 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_##name); \
3776 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID) \
3778 vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName); \
3779 g_vogl_actual_gl_entrypoints.m_##name params; \
3782 vogl_context *pContext = pTLS_data->m_pContext; \
3783 vogl_entrypoint_serializer &trace_serializer = pTLS_data->m_serializer; \
3784 if (vogl_should_serialize_call(VOGL_ENTRYPOINT_##name, pContext)) \
3786 if (!trace_serializer.begin(VOGL_ENTRYPOINT_##name, pContext)) \
3788 vogl_warning_printf("%s: Reentrant wrapper call detected!\n", VOGL_FUNCTION_NAME); \
3789 g_vogl_actual_gl_entrypoints.m_##name params; \
3794 #define DEF_FUNCTION_INIT(exported, category, ret, ret_type_enum, num_params, name, args, params) VOGL_MASTER_FUNCTION_PROLOG(name, params)
3795 #define DEF_FUNCTION_INIT_VOID(exported, category, ret, ret_type_enum, num_params, name, args, params) VOGL_MASTER_FUNCTION_PROLOG_VOID(name, params)
3798 #define DEF_FUNCTION_INPUT_VALUE_PARAM(idx, spectype, type, type_enum, param) vogl_dump_value_param(pContext, trace_serializer, "INPUT_VALUE", idx, #param, #type, type_enum, param);
3799 #define DEF_FUNCTION_INPUT_REFERENCE_PARAM(idx, spectype, type, type_enum, param) vogl_dump_ref_param(pContext, trace_serializer, "INPUT_REF", idx, #param, #type, type_enum, param);
3800 #define DEF_FUNCTION_INPUT_ARRAY_PARAM(idx, spectype, type, type_enum, param, size) vogl_dump_array_param(pContext, trace_serializer, "INPUT_ARRAY", idx, #param, #type, type_enum, param, size);
3802 #define DEF_FUNCTION_OUTPUT_REFERENCE_PARAM(idx, spectype, type, type_enum, param) vogl_dump_ref_param(pContext, trace_serializer, "OUTPUT_REF", idx, #param, #type, type_enum, param);
3803 #define DEF_FUNCTION_OUTPUT_ARRAY_PARAM(idx, spectype, type, type_enum, param, size) vogl_dump_array_param(pContext, trace_serializer, "OUTPUT_ARRAY", idx, #param, #type, type_enum, param, size);
3805 #define DEF_FUNCTION_RETURN_PARAM(spectype, type, type_enum, size) vogl_dump_return_param(pContext, trace_serializer, #type, type_enum, size, result);
3807 #define DEF_FUNCTION_CALL_GL(exported, category, ret, ret_type_enum, num_params, name, args, params) \
3808 if (trace_serializer.is_in_begin()) \
3809 trace_serializer.set_gl_begin_rdtsc(utils::RDTSC()); \
3810 result = g_vogl_actual_gl_entrypoints.m_##name params; \
3811 if (trace_serializer.is_in_begin()) \
3812 trace_serializer.set_gl_end_rdtsc(utils::RDTSC());
3814 #define DEF_FUNCTION_CALL_GL_VOID(exported, category, ret, ret_type_enum, num_params, name, args, params) \
3815 if (trace_serializer.is_in_begin()) \
3816 trace_serializer.set_gl_begin_rdtsc(utils::RDTSC()); \
3817 g_vogl_actual_gl_entrypoints.m_##name params; \
3818 if (trace_serializer.is_in_begin()) \
3819 trace_serializer.set_gl_end_rdtsc(utils::RDTSC());
3821 // Be careful modifying these END macros. They must be compatible with the logic in the glXSwapBuffers GL end prolog!
3822 // func end (after the optional custom function epilog)
3823 #define DEF_FUNCTION_END(exported, category, ret, ret_type_enum, num_params, name, args, params) \
3824 if (g_dump_gl_calls_flag) \
3826 vogl_message_printf("** END %s res=%s 0x%" PRIX64 "\n", #name, #ret, cast_val_to_uint64(result)); \
3828 if (trace_serializer.is_in_begin()) \
3830 trace_serializer.end(); \
3831 vogl_write_packet_to_trace(trace_serializer.get_packet()); \
3833 pContext->add_packet_to_current_display_list(VOGL_ENTRYPOINT_##name, trace_serializer.get_packet()); \
3838 #define DEF_FUNCTION_END_VOID(exported, category, ret, ret_type_enum, num_params, name, args, params) \
3839 if (g_dump_gl_calls_flag) \
3841 vogl_message_printf("** END %s\n", #name); \
3843 if (trace_serializer.is_in_begin()) \
3845 trace_serializer.end(); \
3846 vogl_write_packet_to_trace(trace_serializer.get_packet()); \
3848 pContext->add_packet_to_current_display_list(VOGL_ENTRYPOINT_##name, trace_serializer.get_packet()); \
3852 //----------------------------------------------------------------------------------------------------------------------
3853 // gl/glx override functions
3854 //----------------------------------------------------------------------------------------------------------------------
3855 static __GLXextFuncPtr vogl_get_proc_address_helper(const GLubyte *procName)
3860 if (g_dump_gl_calls_flag)
3862 vogl_printf("glXGetProcAddress: \"%s\"\n", procName);
3865 if (!GL_ENTRYPOINT(glXGetProcAddress))
3868 // FIXME: We need to make this per-context on OSX (under Linux it doesn't matter, because all GL funcs are statically exported anyway as symbols by the SO)
3869 __GLXextFuncPtr pActual_entrypoint = GL_ENTRYPOINT(glXGetProcAddress)(procName);
3870 if (!pActual_entrypoint)
3873 for (uint i = 0; i < VOGL_NUM_ENTRYPOINTS; ++i)
3875 if (vogl_strcmp(reinterpret_cast<const char *>(procName), g_vogl_entrypoint_descs[i].m_pName) == 0)
3877 if (g_vogl_entrypoint_descs[i].m_pWrapper_func)
3879 if (!g_vogl_entrypoint_descs[i].m_is_whitelisted)
3881 // TODO: Only print this message once
3882 vogl_warning_printf("%s: App has queried the address of non-whitelisted GL func %s (this will only be a problem if this func. is actually called, and will reported during tracing and at exit)\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[i].m_pName);
3885 return reinterpret_cast<__GLXextFuncPtr>(g_vogl_entrypoint_descs[i].m_pWrapper_func);
3892 return pActual_entrypoint;
3895 //----------------------------------------------------------------------------------------------------------------------
3896 // Custom function handler implementations
3897 //----------------------------------------------------------------------------------------------------------------------
3898 #define DEF_FUNCTION_CUSTOM_HANDLER_glInternalTraceCommandRAD(exported, category, ret, ret_type_enum, num_params, name, args, params)
3899 static void vogl_glInternalTraceCommandRAD(GLuint cmd, GLuint size, const GLubyte *data)
3901 if (g_dump_gl_calls_flag)
3903 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
3906 if (g_vogl_trace_writer.is_opened())
3908 vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glInternalTraceCommandRAD, NULL);
3910 uint64_t cur_rdtsc = utils::RDTSC();
3911 serializer.set_gl_begin_end_rdtsc(cur_rdtsc, cur_rdtsc + 1);
3913 serializer.add_param(0, VOGL_GLUINT, &cmd, sizeof(cmd));
3914 serializer.add_param(1, VOGL_GLUINT, &size, sizeof(size));
3915 serializer.add_param(2, VOGL_CONST_GLUBYTE_PTR, &data, sizeof(data));
3919 case cITCRDemarcation:
3923 case cITCRKeyValueMap:
3925 if ((size == sizeof(key_value_map)) && (data))
3927 // Directly jam in the key value map, so it properly serializes as readable JSON.
3928 serializer.get_key_value_map() = *reinterpret_cast<const key_value_map *>(data);
3932 vogl_error_printf("%s: data pointer is NULL, or invalid key_value_map size %u\n", VOGL_FUNCTION_NAME, size);
3939 vogl_error_printf("%s: Unknown trace command type %u\n", VOGL_FUNCTION_NAME, cmd);
3946 vogl_write_packet_to_trace(serializer.get_packet());
3949 if (g_dump_gl_calls_flag)
3951 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
3955 //----------------------------------------------------------------------------------------------------------------------
3956 // TODO: Merge this with vogl_glXGetProcAddressARB to avoid duplicated code
3957 #define DEF_FUNCTION_CUSTOM_HANDLER_glXGetProcAddress(exported, category, ret, ret_type_enum, num_params, name, args, params)
3958 static __GLXextFuncPtr vogl_glXGetProcAddress(const GLubyte *procName)
3960 uint64_t begin_rdtsc = utils::RDTSC();
3962 if (g_dump_gl_calls_flag)
3964 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
3967 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXGetProcAddress);
3968 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
3970 vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName);
3971 return GL_ENTRYPOINT(glXGetProcAddress)(procName);
3974 uint64_t gl_begin_rdtsc = utils::RDTSC();
3975 __GLXextFuncPtr ptr = vogl_get_proc_address_helper(procName);
3976 uint64_t gl_end_rdtsc = utils::RDTSC();
3978 if (g_vogl_trace_writer.is_opened())
3980 vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glXGetProcAddress, g_context_manager.get_current());
3981 serializer.set_begin_rdtsc(begin_rdtsc);
3982 serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
3983 serializer.add_param(0, VOGL_CONST_GLUBYTE_PTR, &procName, sizeof(procName));
3986 size_t len = strlen(reinterpret_cast<const char *>(procName)) + 1;
3987 serializer.add_array_client_memory(0, VOGL_GLUBYTE, len, procName, len);
3989 serializer.add_return_param(VOGL_GLXEXTFUNCPTR, &ptr, sizeof(ptr));
3991 vogl_write_packet_to_trace(serializer.get_packet());
3994 if (g_dump_gl_calls_flag)
3996 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
4002 //----------------------------------------------------------------------------------------------------------------------
4003 #define DEF_FUNCTION_CUSTOM_HANDLER_glXGetProcAddressARB(exported, category, ret, ret_type_enum, num_params, name, args, params)
4004 static __GLXextFuncPtr vogl_glXGetProcAddressARB(const GLubyte *procName)
4006 uint64_t begin_rdtsc = utils::RDTSC();
4008 if (g_dump_gl_calls_flag)
4010 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
4013 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXGetProcAddressARB);
4014 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
4016 vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName);
4017 return GL_ENTRYPOINT(glXGetProcAddressARB)(procName);
4020 uint64_t gl_begin_rdtsc = utils::RDTSC();
4021 __GLXextFuncPtr ptr = vogl_get_proc_address_helper(procName);
4022 uint64_t gl_end_rdtsc = utils::RDTSC();
4024 if (g_vogl_trace_writer.is_opened())
4026 vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glXGetProcAddressARB, g_context_manager.get_current());
4027 serializer.set_begin_rdtsc(begin_rdtsc);
4028 serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
4029 serializer.add_param(0, VOGL_CONST_GLUBYTE_PTR, &procName, sizeof(procName));
4032 size_t len = strlen(reinterpret_cast<const char *>(procName)) + 1;
4033 serializer.add_array_client_memory(0, VOGL_GLUBYTE, len, procName, len);
4035 serializer.add_return_param(VOGL_GLXEXTFUNCPTR, &ptr, sizeof(ptr));
4037 vogl_write_packet_to_trace(serializer.get_packet());
4040 if (g_dump_gl_calls_flag)
4042 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
4048 //----------------------------------------------------------------------------------------------------------------------
4049 static void vogl_add_make_current_key_value_fields(const Display *dpy, GLXDrawable drawable, Bool result, vogl_context *pVOGL_context, vogl_entrypoint_serializer &serializer)
4051 if ((result) && (pVOGL_context))
4053 vogl_scoped_gl_error_absorber gl_error_absorber(pVOGL_context);
4054 VOGL_NOTE_UNUSED(gl_error_absorber);
4056 GLint cur_viewport[4];
4057 GL_ENTRYPOINT(glGetIntegerv)(GL_VIEWPORT, cur_viewport);
4059 serializer.add_key_value(string_hash("viewport_x"), cur_viewport[0]);
4060 serializer.add_key_value(string_hash("viewport_y"), cur_viewport[1]);
4061 serializer.add_key_value(string_hash("viewport_width"), cur_viewport[2]);
4062 serializer.add_key_value(string_hash("viewport_height"), cur_viewport[3]);
4065 if ((pVOGL_context) && (pVOGL_context->get_window_width() < 0))
4067 if ((dpy) && (drawable) && (result))
4071 unsigned int width, height, border_width, depth;
4072 if (XGetGeometry(const_cast<Display *>(dpy), drawable, &root, &x, &y, &width, &height, &border_width, &depth) != False)
4074 pVOGL_context->set_window_dimensions(width, height);
4076 serializer.add_key_value(string_hash("win_width"), width);
4077 serializer.add_key_value(string_hash("win_height"), height);
4079 if (g_dump_gl_calls_flag)
4081 vogl_log_printf("** Current window dimensions: %ix%i\n", width, height);
4089 //----------------------------------------------------------------------------------------------------------------------
4090 // HACK HACK - for NS2 experiment in AMD
4091 #define DEF_FUNCTION_CUSTOM_HANDLER_glTexStorage2D(exported, category, ret, ret_type_enum, num_params, name, args, params)
4092 static void vogl_glTexStorage2D( GLenum target,
4094 GLenum internalformat,
4098 GL_ENTRYPOINT(glTexParameteri)(target, GL_TEXTURE_BASE_LEVEL, 0);
4099 GL_ENTRYPOINT(glTexParameteri)(target, GL_TEXTURE_MAX_LEVEL, levels - 1);
4101 if (target == GL_TEXTURE_2D)
4103 for (uint i = 0; i < levels; i++)
4105 uint w = math::maximum<uint>(width >> i, 1);
4106 uint h = math::maximum<uint>(height >> i, 1);
4107 vogl::vector<uint8> pixels(w * h * 4);
4108 GL_ENTRYPOINT(glTexImage2D)(GL_TEXTURE_2D, i, internalformat, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, pixels.get_ptr());
4114 //----------------------------------------------------------------------------------------------------------------------
4115 #define DEF_FUNCTION_CUSTOM_HANDLER_glXMakeCurrent(exported, category, ret, ret_type_enum, num_params, name, args, params)
4116 static Bool vogl_glXMakeCurrent(const Display *dpy, GLXDrawable drawable, GLXContext context)
4118 uint64_t begin_rdtsc = utils::RDTSC();
4120 if (g_dump_gl_calls_flag)
4122 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
4125 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXMakeCurrent);
4126 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
4128 vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName);
4129 return GL_ENTRYPOINT(glXMakeCurrent)(dpy, drawable, context);
4132 if (g_dump_gl_calls_flag)
4134 vogl_log_printf("** glXMakeCurrent TID: 0x%" PRIX64 " dpy: 0x%" PRIX64 " drawable: 0x%" PRIX64 " context: 0x%" PRIX64 "\n", vogl_get_current_kernel_thread_id(), cast_val_to_uint64(dpy), cast_val_to_uint64(drawable), cast_val_to_uint64(context));
4137 vogl_context *pCur_context = g_context_manager.get_current();
4139 vogl_context *pNew_context = context ? g_context_manager.lookup_vogl_context(context) : NULL;
4140 if ((context) && (!pNew_context))
4142 vogl_error_printf("%s: Unknown context handle 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(context));
4147 if (pCur_context != pNew_context)
4148 pCur_context->on_release_current_prolog();
4150 vogl_warning_printf("%s: Context 0x%" PRIX64 " is already current (redundant call)\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(context));
4153 uint64_t gl_begin_rdtsc = utils::RDTSC();
4154 Bool result = GL_ENTRYPOINT(glXMakeCurrent)(dpy, drawable, context);
4155 uint64_t gl_end_rdtsc = utils::RDTSC();
4157 if ((result) && (pCur_context != pNew_context))
4160 g_context_manager.release_current();
4164 vogl_context *p = g_context_manager.make_current(context);
4165 VOGL_ASSERT(p == pNew_context);
4166 VOGL_NOTE_UNUSED(p);
4168 pNew_context->set_display(dpy);
4169 pNew_context->set_drawable(drawable);
4170 pNew_context->set_read_drawable(drawable);
4174 if (g_dump_gl_calls_flag)
4176 vogl_log_printf("** glXMakeCurrent result: %i\n", result);
4179 if (g_vogl_trace_writer.is_opened())
4181 vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glXMakeCurrent, pCur_context);
4182 serializer.set_begin_rdtsc(begin_rdtsc);
4183 serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
4184 serializer.add_param(0, VOGL_CONST_DISPLAY_PTR, &dpy, sizeof(dpy));
4185 serializer.add_param(1, VOGL_GLXDRAWABLE, &drawable, sizeof(drawable));
4186 serializer.add_param(2, VOGL_GLXCONTEXT, &context, sizeof(context));
4187 serializer.add_return_param(VOGL_BOOL, &result, sizeof(result));
4189 vogl_add_make_current_key_value_fields(dpy, drawable, result, pNew_context, serializer);
4192 vogl_write_packet_to_trace(serializer.get_packet());
4195 if (g_dump_gl_calls_flag)
4197 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
4200 static bool s_added_atexit = false;
4201 if (!s_added_atexit)
4203 // atexit routines are called in the reverse order in which they were registered. We would like
4204 // our vogl_atexit() routine to be called before anything else (Ie C++ destructors, etc.) So we
4205 // put atexit at the end of vogl_global_init() and another at the end of glXMakeCurrent.
4206 atexit(vogl_atexit);
4207 s_added_atexit = true;
4213 //----------------------------------------------------------------------------------------------------------------------
4214 #define DEF_FUNCTION_CUSTOM_HANDLER_glXMakeContextCurrent(exported, category, ret, ret_type_enum, num_params, name, args, params)
4215 static Bool vogl_glXMakeContextCurrent(const Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext context)
4217 uint64_t begin_rdtsc = utils::RDTSC();
4219 if (g_dump_gl_calls_flag)
4221 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
4224 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXMakeContextCurrent);
4225 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
4227 vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName);
4228 return GL_ENTRYPOINT(glXMakeContextCurrent)(dpy, draw, read, context);
4231 if (g_dump_gl_calls_flag)
4233 vogl_log_printf("** glXMakeContextCurrent TID: 0x%" PRIX64 " dpy: 0x%" PRIX64 " draw: 0x%" PRIX64 " read: 0x%" PRIX64 " context: 0x%" PRIX64 "\n", vogl_get_current_kernel_thread_id(), cast_val_to_uint64(dpy), cast_val_to_uint64(draw), cast_val_to_uint64(read), cast_val_to_uint64(context));
4236 vogl_context *pCur_context = g_context_manager.get_current();
4238 vogl_context *pNew_context = context ? g_context_manager.lookup_vogl_context(context) : NULL;
4239 if ((context) && (!pNew_context))
4241 vogl_error_printf("%s: Unknown coontext handle 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(context));
4246 if (pCur_context != pNew_context)
4247 pCur_context->on_release_current_prolog();
4249 vogl_warning_printf("%s: Context 0x%" PRIX64 " is already current (redundant call)\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(context));
4252 uint64_t gl_begin_rdtsc = utils::RDTSC();
4253 Bool result = GL_ENTRYPOINT(glXMakeContextCurrent)(dpy, draw, read, context);
4254 uint64_t gl_end_rdtsc = utils::RDTSC();
4256 if ((result) && (pCur_context != pNew_context))
4259 g_context_manager.release_current();
4263 vogl_context *p = g_context_manager.make_current(context);
4264 VOGL_ASSERT(p == pNew_context);
4265 VOGL_NOTE_UNUSED(p);
4267 pNew_context->set_display(dpy);
4268 pNew_context->set_drawable(draw);
4269 pNew_context->set_read_drawable(read);
4273 if (g_dump_gl_calls_flag)
4275 vogl_log_printf("** glXMakeCurrent result: %i\n", result);
4278 if (g_vogl_trace_writer.is_opened())
4280 vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glXMakeContextCurrent, pCur_context);
4281 serializer.set_begin_rdtsc(begin_rdtsc);
4282 serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
4283 serializer.add_param(0, VOGL_CONST_DISPLAY_PTR, &dpy, sizeof(dpy));
4284 serializer.add_param(1, VOGL_GLXDRAWABLE, &draw, sizeof(draw));
4285 serializer.add_param(2, VOGL_GLXDRAWABLE, &read, sizeof(read));
4286 serializer.add_param(3, VOGL_GLXCONTEXT, &context, sizeof(context));
4287 serializer.add_return_param(VOGL_BOOL, &result, sizeof(result));
4289 vogl_add_make_current_key_value_fields(dpy, draw, result, pNew_context, serializer);
4292 vogl_write_packet_to_trace(serializer.get_packet());
4295 if (g_dump_gl_calls_flag)
4297 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
4303 //----------------------------------------------------------------------------------------------------------------------
4304 static bool vogl_screen_capture_callback(uint width, uint height, uint pitch, size_t size, GLenum pixel_format, GLenum pixel_type, const void *pImage, void *pOpaque, uint64_t frame_index)
4306 vogl_context *pContext = static_cast<vogl_context *>(pOpaque);
4308 if ((!pContext) || (!width) || (!height))
4314 if ((pixel_format != GL_RGB) || (pixel_type != GL_UNSIGNED_BYTE) || (pitch != width * 3))
4320 if (g_command_line_params.get_value_as_bool("vogl_dump_png_screenshots"))
4322 size_t png_size = 0;
4323 void *pPNG_data = tdefl_write_image_to_png_file_in_memory_ex(pImage, width, height, 3, &png_size, 1, true);
4325 dynamic_string screenshot_filename(cVarArg, "%s__%08" PRIx64 "_%08" PRIu64 ".png", g_command_line_params.get_value_as_string("vogl_screenshot_prefix", 0, "screenshot").get_ptr(), cast_val_to_uint64(pContext->get_context_handle()), cast_val_to_uint64(frame_index));
4326 if (!file_utils::write_buf_to_file(screenshot_filename.get_ptr(), pPNG_data, png_size))
4328 console::error("Failed writing PNG screenshot to file %s\n", screenshot_filename.get_ptr());
4333 else if (g_command_line_params.get_value_as_bool("vogl_dump_jpeg_screenshots"))
4335 int jpeg_quality = g_command_line_params.get_value_as_int("vogl_jpeg_quality", 0, 80, 1, 100);
4337 long unsigned int jpeg_size = 0;
4338 unsigned char *pJPEG_data = NULL;
4340 tjhandle _jpegCompressor = tjInitCompress();
4342 int status = tjCompress2(_jpegCompressor, (unsigned char *)pImage, width, pitch, height, TJPF_RGB,
4343 &pJPEG_data, &jpeg_size, TJSAMP_422, jpeg_quality,
4344 TJFLAG_FASTDCT | TJFLAG_BOTTOMUP);
4346 tjDestroy(_jpegCompressor);
4350 dynamic_string screenshot_filename(cVarArg, "%s_%08" PRIx64 "_%08" PRIu64 ".jpg",
4351 g_command_line_params.get_value_as_string("vogl_screenshot_prefix", 0, "screenshot").get_ptr(),
4352 cast_val_to_uint64(pContext->get_context_handle()),
4353 cast_val_to_uint64(frame_index));
4354 if (!file_utils::write_buf_to_file(screenshot_filename.get_ptr(), pJPEG_data, jpeg_size))
4356 console::error("Failed writing JPEG screenshot to file %s\n", screenshot_filename.get_ptr());
4363 if (g_command_line_params.get_value_as_bool("vogl_dump_backbuffer_hashes") || g_command_line_params.get_value_as_bool("vogl_hash_backbuffer"))
4365 uint64_t backbuffer_crc64;
4367 if (g_command_line_params.get_value_as_bool("vogl_sum_hashing"))
4369 backbuffer_crc64 = calc_sum64(static_cast<const uint8 *>(pImage), size);
4373 backbuffer_crc64 = calc_crc64(CRC64_INIT, static_cast<const uint8 *>(pImage), size);
4376 console::printf("Frame %" PRIu64 " hash: 0x%016" PRIX64 "\n", cast_val_to_uint64(frame_index), backbuffer_crc64);
4378 dynamic_string backbuffer_hash_file;
4379 if (g_command_line_params.get_value_as_string(backbuffer_hash_file, "vogl_dump_backbuffer_hashes"))
4381 FILE *pFile = vogl_fopen(backbuffer_hash_file.get_ptr(), "a");
4383 console::error("Failed writing to backbuffer hash file %s\n", backbuffer_hash_file.get_ptr());
4386 vogl_fprintf(pFile, "0x%016" PRIX64 "\n", backbuffer_crc64);
4394 //----------------------------------------------------------------------------------------------------------------------
4395 static void vogl_tick_screen_capture(vogl_context *pVOGL_context)
4400 uint width = pVOGL_context->get_window_width();
4401 uint height = pVOGL_context->get_window_height();
4402 if ((!width) || (!height))
4405 bool grab_backbuffer = g_command_line_params.get_value_as_bool("vogl_dump_backbuffer_hashes") || g_command_line_params.get_value_as_bool("vogl_hash_backbuffer") ||
4406 g_command_line_params.get_value_as_bool("vogl_dump_jpeg_screenshots") || g_command_line_params.get_value_as_bool("vogl_dump_png_screenshots");
4407 if (!grab_backbuffer)
4410 vogl_scoped_gl_error_absorber gl_error_absorber(pVOGL_context);
4411 VOGL_NOTE_UNUSED(gl_error_absorber);
4413 if (!pVOGL_context->get_framebuffer_capturer().is_initialized())
4415 if (!pVOGL_context->get_framebuffer_capturer().init(2, vogl_screen_capture_callback, pVOGL_context, GL_RGB, GL_UNSIGNED_BYTE))
4417 vogl_error_printf("%s: Failed initializing context's vogl_framebuffer_capturer!\n", VOGL_FUNCTION_NAME);
4422 if (!pVOGL_context->get_framebuffer_capturer().capture(width, height, 0, GL_BACK, pVOGL_context->get_frame_index()))
4424 vogl_error_printf("%s: vogl_framebuffer_capturer::capture() failed!\n", VOGL_FUNCTION_NAME);
4429 //----------------------------------------------------------------------------------------------------------------------
4430 static vogl_gl_state_snapshot *vogl_snapshot_state(const Display *dpy, GLXDrawable drawable, vogl_context *pCur_context)
4432 VOGL_NOTE_UNUSED(dpy);
4433 VOGL_NOTE_UNUSED(drawable);
4435 // pCur_context may be NULL!
4437 if (!GL_ENTRYPOINT(glXGetCurrentContext) || !GL_ENTRYPOINT(glXGetCurrentDisplay) ||
4438 !GL_ENTRYPOINT(glXGetCurrentDrawable) || !GL_ENTRYPOINT(glXGetCurrentReadDrawable))
4441 timed_scope ts(VOGL_FUNCTION_NAME);
4443 g_context_manager.lock();
4445 if (vogl_check_gl_error())
4446 vogl_error_printf("%s: A GL error occured sometime before this function was called\n", VOGL_FUNCTION_NAME);
4448 const Display *orig_dpy = GL_ENTRYPOINT(glXGetCurrentDisplay)();
4449 GLXDrawable orig_drawable = GL_ENTRYPOINT(glXGetCurrentDrawable)();
4450 GLXDrawable orig_read_drawable = GL_ENTRYPOINT(glXGetCurrentReadDrawable)();
4451 GLXContext orig_context = GL_ENTRYPOINT(glXGetCurrentContext)();
4456 vogl_check_gl_error();
4458 vogl_gl_state_snapshot *pSnapshot = vogl_new(vogl_gl_state_snapshot);
4460 const glxcontext_map &contexts = g_context_manager.get_context_map();
4462 // TODO: Find a better way of determining which window dimensions to use.
4463 // No context is current, let's just find the biggest window.
4465 uint win_height = 0;
4468 win_width = pCur_context->get_window_width();
4469 win_height = pCur_context->get_window_height();
4473 glxcontext_map::const_iterator it;
4474 for (it = contexts.begin(); it != contexts.end(); ++it)
4476 vogl_context *pVOGL_context = it->second;
4477 if ((pVOGL_context->get_window_width() > (int)win_width) || (pVOGL_context->get_window_height() > (int)win_height))
4479 win_width = pVOGL_context->get_window_width();
4480 win_height = pVOGL_context->get_window_height();
4485 vogl_message_printf("%s: Beginning capture: width %u, height %u\n", VOGL_FUNCTION_NAME, win_width, win_height);
4487 if (!pSnapshot->begin_capture(win_width, win_height, pCur_context ? (uint64_t)pCur_context->get_context_handle() : 0, 0, g_vogl_trace_writer.get_cur_gl_call_counter(), true))
4489 vogl_error_printf("%s: Failed beginning capture\n", VOGL_FUNCTION_NAME);
4491 vogl_delete(pSnapshot);
4494 g_context_manager.unlock();
4499 vogl_printf("%s: Capturing %u context(s)\n", VOGL_FUNCTION_NAME, contexts.size());
4501 glxcontext_map::const_iterator it;
4502 for (it = contexts.begin(); it != contexts.end(); ++it)
4504 GLXContext glx_context = it->first;
4505 vogl_context *pVOGL_context = it->second;
4507 if (pVOGL_context->get_deleted_flag())
4509 vogl_error_printf("%s: Context 0x%" PRIX64 " has been deleted but is the root of a sharelist group - this scenario is not yet supported for state snapshotting.\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(glx_context));
4513 if (pVOGL_context->get_has_been_made_current())
4515 if (!GL_ENTRYPOINT(glXMakeCurrent)(pVOGL_context->get_display(), pVOGL_context->get_drawable(), glx_context))
4517 vogl_error_printf("%s: Failed switching to trace context 0x%" PRIX64 ". (This context may be current on another thread.) Capture failed!\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(glx_context));
4521 if (pVOGL_context->get_total_mapped_buffers())
4523 vogl_error_printf("%s: Trace context 0x%" PRIX64 " has %u buffer(s) mapped across a call to glXSwapBuffers(), which is not currently supported!\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(glx_context), pVOGL_context->get_total_mapped_buffers());
4527 if (pVOGL_context->is_composing_display_list())
4529 vogl_error_printf("%s: Trace context 0x%" PRIX64 " is currently composing a display list across a call to glXSwapBuffers()!\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(glx_context));
4533 if (pVOGL_context->get_in_gl_begin())
4535 vogl_error_printf("%s: Trace context 0x%" PRIX64 " is currently in a glBegin() across a call to glXSwapBuffers(), which is not supported!\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(glx_context));
4540 vogl_capture_context_params &capture_context_params = pVOGL_context->get_capture_context_params();
4542 if (!pSnapshot->capture_context(pVOGL_context->get_context_desc(), pVOGL_context->get_context_info(), pVOGL_context->get_handle_remapper(), capture_context_params))
4544 vogl_error_printf("%s: Failed capturing trace context 0x%" PRIX64 ", capture failed\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(glx_context));
4549 if ((it == contexts.end()) && (pSnapshot->end_capture()))
4551 vogl_printf("%s: Capture succeeded\n", VOGL_FUNCTION_NAME);
4555 vogl_printf("%s: Capture failed\n", VOGL_FUNCTION_NAME);
4557 vogl_delete(pSnapshot);
4563 GL_ENTRYPOINT(glXMakeContextCurrent)(orig_dpy, orig_drawable, orig_read_drawable, orig_context);
4566 vogl_check_gl_error();
4568 g_context_manager.unlock();
4573 //----------------------------------------------------------------------------------------------------------------------
4575 // Important: This could be called at signal time!
4576 //----------------------------------------------------------------------------------------------------------------------
4577 static void vogl_end_capture(bool inside_signal_handler)
4581 VOGL_NOTE_UNUSED(inside_signal_handler);
4583 vogl_debug_printf("%s\n", VOGL_FUNCTION_NAME);
4585 g_context_manager.lock();
4587 vogl_context *pVOGL_context = g_context_manager.get_current();
4591 pVOGL_context->get_framebuffer_capturer().flush();
4593 if (inside_signal_handler)
4595 vogl_thread_local_data *pTLS_data = vogl_get_thread_local_data();
4596 if ((pTLS_data) && (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID))
4598 vogl_error_printf("%s: Signal handler called while the tracer was calling OpenGL in func %s!\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName);
4600 if (g_vogl_trace_writer.is_opened())
4602 vogl_entrypoint_serializer &trace_serializer = pTLS_data->m_serializer;
4603 if (trace_serializer.is_in_begin())
4605 vogl_error_printf("%s: Attempting to flush final trace packet\n", VOGL_FUNCTION_NAME);
4607 trace_serializer.end();
4609 vogl_write_packet_to_trace(trace_serializer.get_packet());
4616 g_context_manager.unlock();
4618 scoped_mutex lock(g_vogl_trace_mutex);
4620 if (g_vogl_trace_writer.is_opened())
4622 dynamic_string filename(g_vogl_trace_writer.get_filename());
4624 vogl_flush_compilerinfo_to_trace_file();
4625 vogl_flush_machineinfo_to_trace_file();
4626 vogl_flush_backtrace_to_trace_file();
4628 if (!g_vogl_trace_writer.close())
4630 vogl_error_printf("%s: Failed closing trace file!\n", VOGL_FUNCTION_NAME);
4632 if (g_vogl_pCapture_status_callback)
4633 (*g_vogl_pCapture_status_callback)(NULL, g_vogl_pCapture_status_opaque);
4637 if (g_vogl_pCapture_status_callback)
4638 (*g_vogl_pCapture_status_callback)(filename.get_ptr(), g_vogl_pCapture_status_opaque);
4641 if (g_pJSON_node_pool)
4643 uint64_t total_bytes_freed = static_cast<uint64_t>(g_pJSON_node_pool->free_unused_blocks());
4644 vogl_debug_printf("%s: Freed %" PRIu64 " bytes from the JSON object pool (%" PRIu64 " bytes remaining)\n", VOGL_FUNCTION_NAME, total_bytes_freed, static_cast<uint64_t>(g_pJSON_node_pool->get_total_heap_bytes()));
4648 g_vogl_frames_remaining_to_capture = 0;
4650 g_vogl_pCapture_status_callback = NULL;
4651 g_vogl_pCapture_status_opaque = NULL;
4654 //----------------------------------------------------------------------------------------------------------------------
4655 static bool vogl_write_snapshot_to_trace(const char *pTrace_filename, const Display *dpy, GLXDrawable drawable, vogl_context *pVOGL_context)
4658 vogl_message_printf("%s: Snapshot begin\n", VOGL_FUNCTION_NAME);
4660 // pVOGL_context may be NULL here!
4662 vogl_unique_ptr<vogl_gl_state_snapshot> pSnapshot(vogl_snapshot_state(dpy, drawable, pVOGL_context));
4663 if (!pSnapshot.get())
4665 vogl_error_printf("%s: Failed snapshotting GL/GLX state!\n", VOGL_FUNCTION_NAME);
4672 pSnapshot->set_frame_index(0);
4674 if (!g_vogl_trace_writer.open(pTrace_filename, NULL, true, false))
4676 vogl_error_printf("%s: Failed creating trace file \"%s\"!\n", VOGL_FUNCTION_NAME, pTrace_filename);
4683 vogl_archive_blob_manager &trace_archive = *g_vogl_trace_writer.get_trace_archive();
4685 vogl_message_printf("%s: Serializing snapshot data to JSON document\n", VOGL_FUNCTION_NAME);
4687 // TODO: This can take a lot of memory, probably better off to split the snapshot into separate smaller binary json or whatever files stored directly in the archive.
4689 if (!pSnapshot->serialize(*doc.get_root(), trace_archive, &g_vogl_process_gl_ctypes))
4691 vogl_error_printf("%s: Failed serializing GL state snapshot!\n", VOGL_FUNCTION_NAME);
4700 vogl_message_printf("%s: Serializing JSON document to UBJ\n", VOGL_FUNCTION_NAME);
4702 uint8_vec binary_snapshot_data;
4703 vogl::vector<char> snapshot_data;
4705 // TODO: This can take a lot of memory
4706 doc.binary_serialize(binary_snapshot_data);
4708 vogl_message_printf("%s: Compressing UBJ data and adding to trace archive\n", VOGL_FUNCTION_NAME);
4710 dynamic_string binary_snapshot_id(trace_archive.add_buf_compute_unique_id(binary_snapshot_data.get_ptr(), binary_snapshot_data.size(), "binary_state_snapshot", VOGL_BINARY_JSON_EXTENSION));
4711 if (binary_snapshot_id.is_empty())
4713 vogl_error_printf("%s: Failed adding binary GL snapshot file to output blob manager!\n", VOGL_FUNCTION_NAME);
4720 binary_snapshot_data.clear();
4722 snapshot_data.clear();
4725 // TODO: This requires too much temp memory!
4726 doc.serialize(snapshot_data, true, 0, false);
4728 dynamic_string snapshot_id(trace_archive.add_buf_compute_unique_id(snapshot_data.get_ptr(), snapshot_data.size(), "state_snapshot", VOGL_TEXT_JSON_EXTENSION));
4729 if (snapshot_id.is_empty())
4731 vogl_error_printf("%s: Failed adding binary GL snapshot file to output blob manager!\n", VOGL_FUNCTION_NAME);
4732 g_vogl_trace_writer.deinit();
4737 key_value_map snapshot_key_value_map;
4738 snapshot_key_value_map.insert("command_type", "state_snapshot");
4739 snapshot_key_value_map.insert("binary_id", binary_snapshot_id);
4742 // TODO: This requires too much temp memory!
4743 snapshot_key_value_map.insert("id", snapshot_id);
4746 vogl_ctypes &trace_gl_ctypes = g_vogl_process_gl_ctypes;
4747 if (!vogl_write_glInternalTraceCommandRAD(g_vogl_trace_writer.get_stream(), &trace_gl_ctypes, cITCRKeyValueMap, sizeof(snapshot_key_value_map), reinterpret_cast<const GLubyte *>(&snapshot_key_value_map)))
4751 vogl_error_printf("%s: Failed writing to trace file!\n", VOGL_FUNCTION_NAME);
4755 if (!vogl_write_glInternalTraceCommandRAD(g_vogl_trace_writer.get_stream(), &trace_gl_ctypes, cITCRDemarcation, 0, NULL))
4759 vogl_error_printf("%s: Failed writing to trace file!\n", VOGL_FUNCTION_NAME);
4765 if (g_pJSON_node_pool)
4767 uint64_t total_bytes_freed = static_cast<uint64_t>(g_pJSON_node_pool->free_unused_blocks());
4768 vogl_debug_printf("%s: Freed %" PRIu64 " bytes from the JSON object pool (%" PRIu64 " bytes remaining)\n", VOGL_FUNCTION_NAME, total_bytes_freed, static_cast<uint64_t>(g_pJSON_node_pool->get_total_heap_bytes()));
4771 vogl_message_printf("%s: Snapshot complete\n", VOGL_FUNCTION_NAME);
4776 //----------------------------------------------------------------------------------------------------------------------
4777 static void vogl_capture_status_callback_func(const char *pFilename, void *pOpaque)
4780 VOGL_ASSERT(pOpaque == (void *)1);
4781 vogl_message_printf("%s: Filename \"%s\", opaque: %p\n", VOGL_FUNCTION_NAME, pFilename ? pFilename : "<null>", pOpaque);
4784 //----------------------------------------------------------------------------------------------------------------------
4785 static bool vogl_check_for_trigger_file(const char *pBase_name, dynamic_string &filename)
4787 filename = pBase_name;
4788 if (!file_utils::does_file_exist(filename.get_ptr()))
4790 dynamic_string path_to_check(g_command_line_params.get_value_as_string_or_empty("vogl_tracepath"));
4791 if (path_to_check.is_empty())
4792 path_to_check = file_utils::get_pathname(g_command_line_params.get_value_as_string_or_empty("vogl_tracefile").get_ptr());
4794 if (path_to_check.is_empty())
4797 file_utils::combine_path(filename, path_to_check.get_ptr(), pBase_name);
4798 if (!file_utils::does_file_exist(filename.get_ptr()))
4805 //----------------------------------------------------------------------------------------------------------------------
4806 static void vogl_check_for_capture_stop_file()
4808 if (!vogl_is_capturing())
4811 dynamic_string stop_filename;
4812 if (!vogl_check_for_trigger_file(VOGL_STOP_CAPTURE_FILENAME, stop_filename))
4815 file_utils::delete_file(stop_filename.get_ptr());
4817 vogl_stop_capturing();
4820 //----------------------------------------------------------------------------------------------------------------------
4821 static void vogl_check_for_capture_trigger_file()
4824 scoped_mutex lock(g_vogl_trace_mutex);
4825 if ((g_vogl_frames_remaining_to_capture) || (g_vogl_trace_writer.is_opened()))
4829 dynamic_string trigger_filename;
4830 if (!vogl_check_for_trigger_file(VOGL_TRIGGER_CAPTURE_FILENAME, trigger_filename))
4835 // Lamely try to protected against racing - a better method is probably inotify: http://www.thegeekstuff.com/2010/04/inotify-c-program-example/
4839 file_utils::get_file_size(trigger_filename.get_ptr(), size);
4844 file_utils::get_file_size(trigger_filename.get_ptr(), size1);
4852 uint total_frames = 1;
4853 dynamic_string path;
4854 dynamic_string base_name;
4856 dynamic_string_array lines;
4857 if (!file_utils::read_text_file(trigger_filename.get_ptr(), lines, file_utils::cRTFTrim | file_utils::cRTFIgnoreEmptyLines))
4859 vogl_error_printf("%s: Failed reading from trigger file \"%s\", using default parameters to trigger a capture.\n", VOGL_FUNCTION_NAME, trigger_filename.get_ptr());
4863 if (lines.size() >= 1)
4865 if (lines[0] == "all")
4866 total_frames = cUINT32_MAX;
4868 total_frames = string_to_uint(lines[0].get_ptr(), 1);
4870 if (lines.size() >= 2)
4874 if (lines.size() >= 3)
4875 base_name = lines[2];
4879 file_utils::delete_file(trigger_filename.get_ptr());
4881 bool success = vogl_capture_on_next_swap(total_frames, path.get_ptr(), base_name.get_ptr(), vogl_capture_status_callback_func, (void *)1);
4884 vogl_error_printf("%s: Failed enabling capture mode\n", VOGL_FUNCTION_NAME);
4886 vogl_message_printf("%s: Successfully enabled capture mode, will capture up to %u frame(s), override path \"%s\", override base_name \"%s\"\n", VOGL_FUNCTION_NAME, total_frames, path.get_ptr(), base_name.get_ptr());
4889 //----------------------------------------------------------------------------------------------------------------------
4890 // vogl_tick_capture
4891 //----------------------------------------------------------------------------------------------------------------------
4892 static void vogl_tick_capture(const Display *dpy, GLXDrawable drawable, vogl_context *pVOGL_context)
4896 // pVOGL_context may be NULL here!
4898 vogl_check_for_capture_stop_file();
4899 vogl_check_for_capture_trigger_file();
4901 scoped_mutex lock(g_vogl_trace_mutex);
4903 if ((g_vogl_total_frames_to_capture) && (!g_vogl_frames_remaining_to_capture))
4905 g_vogl_frames_remaining_to_capture = g_vogl_total_frames_to_capture;
4906 g_vogl_total_frames_to_capture = 0;
4909 if (g_vogl_stop_capturing)
4911 g_vogl_stop_capturing = false;
4913 if (g_vogl_trace_writer.is_opened())
4921 if (!g_vogl_frames_remaining_to_capture)
4924 if (!g_vogl_trace_writer.is_opened())
4926 dynamic_string trace_path(g_command_line_params.get_value_as_string_or_empty("vogl_tracepath"));
4927 if (trace_path.is_empty())
4928 trace_path = "/tmp";
4929 if (!g_vogl_capture_path.is_empty())
4930 trace_path = g_vogl_capture_path;
4932 time_t t = time(NULL);
4933 struct tm ltm = *localtime(&t);
4935 dynamic_string trace_basename("capture");
4936 if (!g_vogl_capture_basename.is_empty())
4937 trace_basename = g_vogl_capture_basename;
4939 dynamic_string filename(cVarArg, "%s_%04d_%02d_%02d_%02d_%02d_%02d.bin", trace_basename.get_ptr(), ltm.tm_year + 1900, ltm.tm_mon + 1, ltm.tm_mday, ltm.tm_hour, ltm.tm_min, ltm.tm_sec);
4941 dynamic_string full_trace_filename;
4942 file_utils::combine_path(full_trace_filename, trace_path.get_ptr(), filename.get_ptr());
4944 if (g_vogl_frames_remaining_to_capture == cUINT32_MAX)
4945 vogl_message_printf("%s: Initiating capture of all remaining frames to file \"%s\"\n", VOGL_FUNCTION_NAME, full_trace_filename.get_ptr());
4947 vogl_message_printf("%s: Initiating capture of up to %u frame(s) to file \"%s\"\n", VOGL_FUNCTION_NAME, g_vogl_frames_remaining_to_capture, full_trace_filename.get_ptr());
4949 if (!vogl_write_snapshot_to_trace(full_trace_filename.get_ptr(), dpy, drawable, pVOGL_context))
4951 file_utils::delete_file(full_trace_filename.get_ptr());
4952 vogl_error_printf("%s: Failed creating GL state snapshot, closing and deleting trace file\n", VOGL_FUNCTION_NAME);
4957 if (g_vogl_frames_remaining_to_capture != cUINT32_MAX)
4958 g_vogl_frames_remaining_to_capture--;
4960 // See if we should stop capturing.
4961 if (!g_vogl_frames_remaining_to_capture)
4969 //----------------------------------------------------------------------------------------------------------------------
4970 // vogl_glXSwapBuffersGLFuncProlog
4971 //----------------------------------------------------------------------------------------------------------------------
4972 static inline void vogl_glXSwapBuffersGLFuncProlog(const Display *dpy, GLXDrawable drawable, vogl_context *pVOGL_context, vogl_entrypoint_serializer &trace_serializer)
4974 // pVOGL_context may be NULL here!
4976 if (!GL_ENTRYPOINT(glXGetCurrentContext) || !GL_ENTRYPOINT(glXGetCurrentDisplay) ||
4977 !GL_ENTRYPOINT(glXGetCurrentDrawable) || !GL_ENTRYPOINT(glXGetCurrentReadDrawable))
4982 bool override_current_context = false;
4984 if ((!pVOGL_context) || ((pVOGL_context->get_display() != dpy) || (pVOGL_context->get_drawable() != drawable)))
4986 // NVidia/AMD closed source don't seem to care if a context is current when glXSwapBuffer()'s is called. But Mesa doesn't like it.
4987 vogl_warning_printf_once("%s: No context is current, or the current context's display/drawable don't match the provided display/drawable. Will try to find the first context which matches the provided params, but this may not work reliably.\n", VOGL_FUNCTION_NAME);
4989 pVOGL_context = g_context_manager.find_context(dpy, drawable);
4993 vogl_error_printf("%s: Unable to determine which GL context is associated with the indicated drawable/display! Will not be able to take a screen capture, or record context related information to the trace!\n", VOGL_FUNCTION_NAME);
4996 else if (pVOGL_context->get_current_thread() != 0)
4998 vogl_error_printf("%s: The GL context which matches the provided display/drawable is already current on another thread!\n", VOGL_FUNCTION_NAME);
5002 override_current_context = true;
5005 GLXContext orig_context = 0;
5006 const Display *orig_dpy = NULL;
5007 GLXDrawable orig_drawable = 0;
5008 GLXDrawable orig_read_drawable = 0;
5009 if (override_current_context)
5011 orig_context = GL_ENTRYPOINT(glXGetCurrentContext)();
5012 orig_dpy = GL_ENTRYPOINT(glXGetCurrentDisplay)();
5013 orig_drawable = GL_ENTRYPOINT(glXGetCurrentDrawable)();
5014 orig_read_drawable = GL_ENTRYPOINT(glXGetCurrentReadDrawable)();
5019 GL_ENTRYPOINT(glXMakeCurrent)(pVOGL_context->get_display(), pVOGL_context->get_drawable(), pVOGL_context->get_context_handle());
5024 unsigned int width = 0, height = 0, border_width = 0, depth = 0;
5025 if ((dpy) && (XGetGeometry(const_cast<Display *>(dpy), drawable, &root, &x, &y, &width, &height, &border_width, &depth) != False))
5027 pVOGL_context->set_window_dimensions(width, height);
5029 vogl_tick_screen_capture(pVOGL_context);
5033 console::warning("%s: XGetGeometry() call failed!\n", VOGL_FUNCTION_NAME);
5036 if (trace_serializer.is_in_begin())
5038 trace_serializer.add_key_value(string_hash("win_width"), pVOGL_context->get_window_width());
5039 trace_serializer.add_key_value(string_hash("win_height"), pVOGL_context->get_window_height());
5042 if (g_dump_gl_calls_flag)
5044 vogl_log_printf("** Current window dimensions: %ix%i\n", pVOGL_context->get_window_width(), pVOGL_context->get_window_height());
5047 pVOGL_context->inc_frame_index();
5049 if ((override_current_context) && (orig_dpy))
5051 GL_ENTRYPOINT(glXMakeContextCurrent)(orig_dpy, orig_drawable, orig_read_drawable, orig_context);
5055 //----------------------------------------------------------------------------------------------------------------------
5056 #define DEF_FUNCTION_CUSTOM_HANDLER_glXSwapBuffers(exported, category, ret, ret_type_enum, num_params, name, args, params)
5057 static void vogl_glXSwapBuffers(const Display *dpy, GLXDrawable drawable)
5059 uint64_t begin_rdtsc = utils::RDTSC();
5061 if (g_dump_gl_calls_flag)
5063 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5066 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXSwapBuffers);
5067 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
5069 vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName);
5070 return GL_ENTRYPOINT(glXSwapBuffers)(dpy, drawable);
5073 // Use a local serializer because the call to glXSwapBuffer()'s will make GL calls if something like the Steam Overlay is active.
5074 vogl_entrypoint_serializer serializer;
5076 if (g_vogl_trace_writer.is_opened())
5078 serializer.begin(VOGL_ENTRYPOINT_glXSwapBuffers, g_context_manager.get_current());
5079 serializer.add_param(0, VOGL_CONST_DISPLAY_PTR, &dpy, sizeof(dpy));
5080 serializer.add_param(1, VOGL_GLXDRAWABLE, &drawable, sizeof(drawable));
5083 vogl_glXSwapBuffersGLFuncProlog(dpy, drawable, pTLS_data->m_pContext, serializer);
5085 uint64_t gl_begin_rdtsc = utils::RDTSC();
5087 // Call the driver directly, bypassing our GL/GLX wrappers which set m_calling_driver_entrypoint_id. The Steam Overlay may call us back!
5088 DIRECT_GL_ENTRYPOINT(glXSwapBuffers)(dpy, drawable);
5090 uint64_t gl_end_rdtsc = utils::RDTSC();
5092 if (g_vogl_trace_writer.is_opened())
5094 serializer.set_begin_rdtsc(begin_rdtsc);
5095 serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
5097 vogl_write_packet_to_trace(serializer.get_packet());
5100 vogl_tick_capture(dpy, drawable, pTLS_data->m_pContext);
5102 if (g_dump_gl_calls_flag)
5104 vogl_log_printf("** glXSwapBuffers TID: 0x%" PRIX64 " Display: 0x%" PRIX64 " drawable: 0x%" PRIX64 "\n", vogl_get_current_kernel_thread_id(), cast_val_to_uint64(dpy), cast_val_to_uint64(drawable));
5107 if (g_dump_gl_calls_flag)
5109 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5112 if (g_command_line_params.has_key("vogl_exit_after_x_frames") && (pTLS_data->m_pContext))
5114 uint64_t max_num_frames = g_command_line_params.get_value_as_uint64("vogl_exit_after_x_frames");
5115 uint64_t cur_num_frames = pTLS_data->m_pContext->get_frame_index();
5117 if (cur_num_frames >= max_num_frames)
5119 vogl_message_printf("Number of frames specified by --vogl_exit_after_x_frames param reached, forcing trace to close and calling exit()\n");
5129 //----------------------------------------------------------------------------------------------------------------------
5130 #define DEF_FUNCTION_CUSTOM_HANDLER_glXCreateContextAttribsARB(exported, category, ret, ret_type_enum, num_params, name, args, params)
5131 static GLXContext vogl_glXCreateContextAttribsARB(const Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list)
5133 uint64_t begin_rdtsc = utils::RDTSC();
5135 if (g_dump_gl_calls_flag)
5137 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5140 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXCreateContextAttribsARB);
5141 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
5143 vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName);
5144 return GL_ENTRYPOINT(glXCreateContextAttribsARB)(dpy, config, share_context, direct, attrib_list);
5147 vogl_context_attribs context_attribs;
5149 if (g_command_line_params.get_value_as_bool("vogl_force_debug_context"))
5151 vogl_warning_printf("%s: Forcing debug context\n", VOGL_FUNCTION_NAME);
5153 context_attribs.init(attrib_list);
5154 if (!context_attribs.has_key(GLX_CONTEXT_FLAGS_ARB))
5155 context_attribs.add_key(GLX_CONTEXT_FLAGS_ARB, 0);
5157 int context_flags_value_ofs = context_attribs.find_value_ofs(GLX_CONTEXT_FLAGS_ARB);
5158 VOGL_ASSERT(context_flags_value_ofs >= 0);
5159 if (context_flags_value_ofs >= 0)
5160 context_attribs[context_flags_value_ofs] |= GLX_CONTEXT_DEBUG_BIT_ARB;
5162 int context_major_version_ofs = context_attribs.find_value_ofs(GLX_CONTEXT_MAJOR_VERSION_ARB);
5163 int context_minor_version_ofs = context_attribs.find_value_ofs(GLX_CONTEXT_MINOR_VERSION_ARB);
5165 if (context_major_version_ofs < 0)
5167 // Don't slam up if they haven't requested a specific GL version, the driver will give us the most recent version that is backwards compatible with 1.0 (i.e. 4.3 for NVidia's current dirver).
5169 else if (context_attribs[context_major_version_ofs] < 3)
5171 context_attribs[context_major_version_ofs] = 3;
5173 if (context_minor_version_ofs < 0)
5174 context_attribs.add_key(GLX_CONTEXT_MINOR_VERSION_ARB, 0);
5176 context_attribs[context_minor_version_ofs] = 0;
5178 vogl_warning_printf("%s: Forcing GL context version up to v3.0 due to debug context usage\n", VOGL_FUNCTION_NAME);
5181 attrib_list = context_attribs.get_vec().get_ptr();
5184 uint64_t gl_begin_rdtsc = utils::RDTSC();
5185 GLXContext result = GL_ENTRYPOINT(glXCreateContextAttribsARB)(dpy, config, share_context, direct, attrib_list);
5186 uint64_t gl_end_rdtsc = utils::RDTSC();
5188 if (g_dump_gl_calls_flag)
5190 vogl_log_printf("** glXCreateContextAttribsARB TID: 0x%" PRIX64 " Display: 0x%" PRIX64 " config: 0x%" PRIX64 " share_context: 0x%" PRIX64 " direct %i attrib_list: 0x%" PRIX64 ", result: 0x%" PRIX64 "\n", vogl_get_current_kernel_thread_id(), cast_val_to_uint64(dpy), cast_val_to_uint64(config), cast_val_to_uint64(share_context), (int)direct, cast_val_to_uint64(attrib_list), cast_val_to_uint64(result));
5193 if (g_vogl_trace_writer.is_opened())
5195 vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glXCreateContextAttribsARB, g_context_manager.get_current());
5196 serializer.set_begin_rdtsc(begin_rdtsc);
5197 serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
5198 serializer.add_param(0, VOGL_CONST_DISPLAY_PTR, &dpy, sizeof(dpy));
5199 serializer.add_param(1, VOGL_GLXFBCONFIG, &config, sizeof(config));
5200 serializer.add_param(2, VOGL_GLXCONTEXT, &share_context, sizeof(share_context));
5201 serializer.add_param(3, VOGL_BOOL, &direct, sizeof(direct));
5202 serializer.add_param(4, VOGL_CONST_INT_PTR, &attrib_list, sizeof(attrib_list));
5205 uint n = vogl_determine_attrib_list_array_size(attrib_list);
5206 serializer.add_array_client_memory(4, VOGL_INT, n, attrib_list, sizeof(int) * n);
5208 serializer.add_return_param(VOGL_GLXCONTEXT, &result, sizeof(result));
5210 vogl_write_packet_to_trace(serializer.get_packet());
5217 if (!g_app_uses_sharelists)
5218 vogl_message_printf("%s: sharelist usage detected\n", VOGL_FUNCTION_NAME);
5220 g_app_uses_sharelists = true;
5223 g_context_manager.lock();
5225 vogl_context *pVOGL_context = g_context_manager.create_context(result);
5226 pVOGL_context->set_display(dpy);
5227 pVOGL_context->set_fb_config(config);
5228 pVOGL_context->set_sharelist_handle(share_context);
5229 pVOGL_context->set_direct(direct);
5230 pVOGL_context->set_attrib_list(attrib_list);
5231 pVOGL_context->set_created_from_attribs(true);
5232 pVOGL_context->set_creation_func(VOGL_ENTRYPOINT_glXCreateContextAttribsARB);
5236 vogl_context *pShare_context = g_context_manager.lookup_vogl_context(share_context);
5238 if (!pShare_context)
5239 vogl_error_printf("%s: Failed finding share context 0x%" PRIx64 " in context manager's hashmap! This handle is probably invalid.\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(share_context));
5242 while (!pShare_context->is_root_context())
5243 pShare_context = pShare_context->get_shared_state();
5245 pVOGL_context->set_shared_context(pShare_context);
5247 pShare_context->add_ref();
5251 pVOGL_context->init();
5253 g_context_manager.unlock();
5256 if (g_dump_gl_calls_flag)
5258 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5264 //----------------------------------------------------------------------------------------------------------------------
5265 // vogl_get_fb_config_from_xvisual_info
5266 // Attempts to find the GLXFBConfig corresponding to a particular visual.
5267 // TODO: Test this more!
5268 //----------------------------------------------------------------------------------------------------------------------
5269 static GLXFBConfig *vogl_get_fb_config_from_xvisual_info(const Display *dpy, const XVisualInfo *vis)
5271 vogl_context_attribs attribs;
5273 #define GET_CONFIG(attrib) \
5277 GL_ENTRYPOINT(glXGetConfig)(dpy, vis, attrib, &val); \
5279 attribs.add_key(attrib, val); \
5283 GL_ENTRYPOINT(glXGetConfig)(dpy, vis, GLX_RGBA, &is_rgba);
5285 attribs.add_key(GLX_RENDER_TYPE, is_rgba ? GLX_RGBA_BIT : GLX_COLOR_INDEX_BIT);
5286 attribs.add_key(GLX_X_RENDERABLE, True);
5287 attribs.add_key(GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT);
5290 GET_CONFIG(GLX_BUFFER_SIZE);
5292 GET_CONFIG(GLX_LEVEL);
5294 GET_CONFIG(GLX_DOUBLEBUFFER);
5295 GET_CONFIG(GLX_STEREO);
5296 GET_CONFIG(GLX_AUX_BUFFERS);
5299 GET_CONFIG(GLX_RED_SIZE);
5300 GET_CONFIG(GLX_GREEN_SIZE);
5301 GET_CONFIG(GLX_BLUE_SIZE);
5302 GET_CONFIG(GLX_ALPHA_SIZE);
5304 GET_CONFIG(GLX_DEPTH_SIZE);
5305 GET_CONFIG(GLX_STENCIL_SIZE);
5307 GET_CONFIG(GLX_TRANSPARENT_INDEX_VALUE);
5308 GET_CONFIG(GLX_TRANSPARENT_RED_VALUE);
5309 GET_CONFIG(GLX_TRANSPARENT_GREEN_VALUE);
5310 GET_CONFIG(GLX_TRANSPARENT_BLUE_VALUE);
5311 GET_CONFIG(GLX_TRANSPARENT_ALPHA_VALUE);
5313 if (attribs.get_value_or_default(GLX_TRANSPARENT_INDEX_VALUE) || attribs.get_value_or_default(GLX_TRANSPARENT_RED_VALUE) ||
5314 attribs.get_value_or_default(GLX_TRANSPARENT_GREEN_VALUE) || attribs.get_value_or_default(GLX_TRANSPARENT_BLUE_VALUE) ||
5315 attribs.get_value_or_default(GLX_TRANSPARENT_ALPHA_VALUE))
5317 GET_CONFIG(GLX_TRANSPARENT_TYPE);
5322 for (uint i = 0; i < attribs.size(); i += 2)
5326 printf("%s 0x%x\n", g_gl_enums.find_glx_name(attribs[i]), attribs[i + 1]);
5330 int num_configs = 0;
5331 GLXFBConfig *pConfigs = GL_ENTRYPOINT(glXChooseFBConfig)(dpy, vis->screen, attribs.get_ptr(), &num_configs);
5332 return num_configs ? pConfigs : NULL;
5335 //----------------------------------------------------------------------------------------------------------------------
5336 #define DEF_FUNCTION_CUSTOM_HANDLER_glXCreateContext(exported, category, ret, ret_type_enum, num_params, name, args, params)
5337 static GLXContext vogl_glXCreateContext(const Display *dpy, const XVisualInfo *vis, GLXContext shareList, Bool direct)
5339 uint64_t begin_rdtsc = utils::RDTSC();
5341 if (g_dump_gl_calls_flag)
5343 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5346 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXCreateContext);
5347 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
5349 vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName);
5350 return GL_ENTRYPOINT(glXCreateContext)(dpy, vis, shareList, direct);
5353 if (g_command_line_params.get_value_as_bool("vogl_force_debug_context"))
5355 vogl_warning_printf("%s: Can't enable debug contexts via glXCreateContext(), forcing call to use glXCreateContextsAttribsARB() instead\n", VOGL_FUNCTION_NAME);
5357 GLXFBConfig *pConfig = vogl_get_fb_config_from_xvisual_info(dpy, vis);
5360 vogl_error_printf("%s: Can't enable debug contexts: Unable to find the FB config that matches the passed in XVisualInfo!\n", VOGL_FUNCTION_NAME);
5364 int empty_attrib_list[1] = { 0 };
5365 return vogl_glXCreateContextAttribsARB(dpy, pConfig[0], shareList, direct, empty_attrib_list);
5369 uint64_t gl_begin_rdtsc = utils::RDTSC();
5370 GLXContext result = GL_ENTRYPOINT(glXCreateContext)(dpy, vis, shareList, direct);
5371 uint64_t gl_end_rdtsc = utils::RDTSC();
5373 if (g_dump_gl_calls_flag)
5375 vogl_log_printf("** glXCreateContext TID: 0x%" PRIX64 " dpy: 0x%" PRIX64 " vis: 0x%" PRIX64 " shareList: 0x%" PRIX64 " direct %i, result: 0x%" PRIX64 "\n", vogl_get_current_kernel_thread_id(), cast_val_to_uint64(dpy), cast_val_to_uint64(vis), cast_val_to_uint64(shareList), (int)direct, cast_val_to_uint64(result));
5378 if (g_vogl_trace_writer.is_opened())
5380 vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glXCreateContext, g_context_manager.get_current());
5381 serializer.set_begin_rdtsc(begin_rdtsc);
5382 serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
5383 serializer.add_param(0, VOGL_CONST_DISPLAY_PTR, &dpy, sizeof(dpy));
5384 serializer.add_param(1, VOGL_CONST_XVISUALINFO_PTR, &vis, sizeof(vis));
5385 serializer.add_param(2, VOGL_GLXCONTEXT, &shareList, sizeof(shareList));
5386 serializer.add_param(3, VOGL_BOOL, &direct, sizeof(direct));
5387 serializer.add_return_param(VOGL_GLXCONTEXT, &result, sizeof(result));
5389 serializer.add_ref_client_memory(1, VOGL_XVISUALINFO, vis, sizeof(XVisualInfo));
5391 vogl_write_packet_to_trace(serializer.get_packet());
5398 if (!g_app_uses_sharelists)
5399 vogl_message_printf("%s: sharelist usage detected\n", VOGL_FUNCTION_NAME);
5401 g_app_uses_sharelists = true;
5404 g_context_manager.lock();
5406 vogl_context *pVOGL_context = g_context_manager.create_context(result);
5407 pVOGL_context->set_display(dpy);
5408 pVOGL_context->set_xvisual_info(vis);
5409 pVOGL_context->set_sharelist_handle(shareList);
5410 pVOGL_context->set_direct(direct);
5411 pVOGL_context->set_creation_func(VOGL_ENTRYPOINT_glXCreateContext);
5415 vogl_context *pShare_context = g_context_manager.lookup_vogl_context(shareList);
5417 if (!pShare_context)
5418 vogl_error_printf("%s: Failed finding share context 0x%" PRIx64 " in context manager's hashmap! This handle is probably invalid.\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(shareList));
5421 while (!pShare_context->is_root_context())
5422 pShare_context = pShare_context->get_shared_state();
5424 pVOGL_context->set_shared_context(pShare_context);
5426 pShare_context->add_ref();
5430 pVOGL_context->init();
5432 g_context_manager.unlock();
5435 if (g_dump_gl_calls_flag)
5437 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5443 //----------------------------------------------------------------------------------------------------------------------
5444 #define DEF_FUNCTION_CUSTOM_HANDLER_glXCreateNewContext(exported, category, ret, ret_type_enum, num_params, name, args, params)
5445 static GLXContext vogl_glXCreateNewContext(const Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct)
5447 if (render_type != GLX_RGBA_TYPE)
5449 vogl_error_printf("%s: Unsupported render type (%s)!\n", VOGL_FUNCTION_NAME, g_gl_enums.find_glx_name(render_type));
5452 if (g_command_line_params.get_value_as_bool("vogl_force_debug_context"))
5454 vogl_warning_printf("%s: Redirecting call from glxCreateNewContext() to glxCreateContextAttribsARB because --vogl_force_debug_context was specified. Note this may fail if glXCreateWindow() was called.\n", VOGL_FUNCTION_NAME);
5456 return vogl_glXCreateContextAttribsARB(dpy, config, share_list, direct, NULL);
5459 uint64_t begin_rdtsc = utils::RDTSC();
5461 if (g_dump_gl_calls_flag)
5463 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5466 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXCreateNewContext);
5467 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
5469 vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName);
5470 return GL_ENTRYPOINT(glXCreateNewContext)(dpy, config, render_type, share_list, direct);
5473 uint64_t gl_begin_rdtsc = utils::RDTSC();
5474 GLXContext result = GL_ENTRYPOINT(glXCreateNewContext)(dpy, config, render_type, share_list, direct);
5475 uint64_t gl_end_rdtsc = utils::RDTSC();
5477 if (g_dump_gl_calls_flag)
5479 vogl_log_printf("** glXCreateNewContext TID: 0x%" PRIX64 " dpy: 0x%" PRIX64 " config: 0x%" PRIX64 " render_type: %i shareList: 0x%" PRIX64 " direct %i, result: 0x%" PRIX64 "\n",
5480 vogl_get_current_kernel_thread_id(), cast_val_to_uint64(dpy), cast_val_to_uint64(config), render_type, cast_val_to_uint64(share_list), static_cast<int>(direct), cast_val_to_uint64(result));
5483 if (g_vogl_trace_writer.is_opened())
5485 vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glXCreateNewContext, g_context_manager.get_current());
5486 serializer.set_begin_rdtsc(begin_rdtsc);
5487 serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
5488 serializer.add_param(0, VOGL_CONST_DISPLAY_PTR, &dpy, sizeof(dpy));
5489 serializer.add_param(1, VOGL_GLXFBCONFIG, &config, sizeof(config));
5490 serializer.add_param(2, VOGL_INT, &render_type, sizeof(render_type));
5491 serializer.add_param(3, VOGL_GLXCONTEXT, &share_list, sizeof(share_list));
5492 serializer.add_param(4, VOGL_BOOL, &direct, sizeof(direct));
5493 serializer.add_return_param(VOGL_GLXCONTEXT, &result, sizeof(result));
5495 vogl_write_packet_to_trace(serializer.get_packet());
5502 if (!g_app_uses_sharelists)
5503 vogl_message_printf("%s: sharelist usage detected\n", VOGL_FUNCTION_NAME);
5505 g_app_uses_sharelists = true;
5508 g_context_manager.lock();
5510 vogl_context *pVOGL_context = g_context_manager.create_context(result);
5511 pVOGL_context->set_display(dpy);
5512 pVOGL_context->set_fb_config(config);
5513 pVOGL_context->set_sharelist_handle(share_list);
5514 pVOGL_context->set_direct(direct);
5515 pVOGL_context->set_creation_func(VOGL_ENTRYPOINT_glXCreateNewContext);
5519 vogl_context *pShare_context = g_context_manager.lookup_vogl_context(share_list);
5521 if (!pShare_context)
5522 vogl_error_printf("%s: Failed finding share context 0x%" PRIx64 " in context manager's hashmap! This handle is probably invalid.\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(share_list));
5525 while (!pShare_context->is_root_context())
5526 pShare_context = pShare_context->get_shared_state();
5528 pVOGL_context->set_shared_context(pShare_context);
5530 pShare_context->add_ref();
5534 pVOGL_context->init();
5536 g_context_manager.unlock();
5539 if (g_dump_gl_calls_flag)
5541 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5547 //----------------------------------------------------------------------------------------------------------------------
5548 #define DEF_FUNCTION_CUSTOM_HANDLER_glXDestroyContext(exported, category, ret, ret_type_enum, num_params, name, args, params)
5549 static void vogl_glXDestroyContext(const Display *dpy, GLXContext context)
5551 uint64_t begin_rdtsc = utils::RDTSC();
5553 if (g_dump_gl_calls_flag)
5555 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5558 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glXDestroyContext);
5559 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
5561 vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName);
5562 return GL_ENTRYPOINT(glXDestroyContext)(dpy, context);
5565 if (g_dump_gl_calls_flag)
5567 vogl_log_printf("** glXDestroyContext TID: 0x%" PRIX64 " Display: 0x%" PRIX64 " context: 0x%" PRIX64 "\n", vogl_get_current_kernel_thread_id(), cast_val_to_uint64(dpy), cast_val_to_uint64(context));
5570 vogl_context *pContext = context ? g_context_manager.lookup_vogl_context(context) : NULL;
5572 vogl_error_printf("%s: glXDestroyContext() called on an unknown context handle 0x%" PRIX64 "!\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(context));
5573 else if (pContext->get_current_thread())
5574 vogl_error_printf("%s: glXDestroyContext() called on a handle 0x%" PRIX64 " that is still current on thread 0x%" PRIX64 "! This may cause the asynchronous framebuffer capturing system to miss frames!\n", VOGL_FUNCTION_NAME, cast_val_to_uint64(context), pContext->get_current_thread());
5578 pContext->on_destroy_prolog();
5581 uint64_t gl_begin_rdtsc = utils::RDTSC();
5582 GL_ENTRYPOINT(glXDestroyContext)(dpy, context);
5583 uint64_t gl_end_rdtsc = utils::RDTSC();
5585 if (g_vogl_trace_writer.is_opened())
5587 vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glXDestroyContext, g_context_manager.get_current());
5588 serializer.set_begin_rdtsc(begin_rdtsc);
5589 serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
5590 serializer.add_param(0, VOGL_CONST_DISPLAY_PTR, &dpy, sizeof(dpy));
5591 serializer.add_param(1, VOGL_GLXCONTEXT, &context, sizeof(context));
5593 vogl_write_packet_to_trace(serializer.get_packet());
5594 g_vogl_trace_writer.flush();
5599 g_context_manager.lock();
5601 VOGL_ASSERT(!pContext->get_deleted_flag());
5602 if (!pContext->get_deleted_flag())
5604 pContext->set_deleted_flag(true);
5606 if (pContext->is_share_context())
5608 VOGL_ASSERT(pContext->get_ref_count() == 1);
5611 int new_ref_count = pContext->del_ref();
5612 if (new_ref_count <= 0)
5614 if (pContext->is_share_context())
5616 vogl_context *pRoot_context = pContext->get_shared_state();
5618 pContext->set_shared_context(NULL);
5620 if (pRoot_context->del_ref() == 0)
5622 VOGL_ASSERT(pRoot_context->get_deleted_flag());
5624 bool status = g_context_manager.destroy_context(pRoot_context->get_context_handle());
5625 VOGL_ASSERT(status);
5626 VOGL_NOTE_UNUSED(status);
5630 bool status = g_context_manager.destroy_context(context);
5631 VOGL_ASSERT(status);
5632 VOGL_NOTE_UNUSED(status);
5636 g_context_manager.unlock();
5639 if (g_vogl_pLog_stream)
5641 // TODO: Ensure this is actually thread safe (does the gcc C runtime mutex this?)
5642 g_vogl_pLog_stream->flush();
5645 if (g_dump_gl_calls_flag)
5647 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5651 //----------------------------------------------------------------------------------------------------------------------
5652 #define DEF_FUNCTION_CUSTOM_HANDLER_glGetError(exported, category, ret, ret_type_enum, num_params, name, args, params)
5653 static GLenum vogl_glGetError()
5655 uint64_t begin_rdtsc = utils::RDTSC();
5657 if (g_dump_gl_calls_flag)
5659 vogl_message_printf("** BEGIN %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5662 vogl_thread_local_data *pTLS_data = vogl_entrypoint_prolog(VOGL_ENTRYPOINT_glGetError);
5663 if (pTLS_data->m_calling_driver_entrypoint_id != VOGL_ENTRYPOINT_INVALID)
5665 vogl_warning_printf("%s: GL call detected while libvogltrace was itself making a GL call to func %s! This call will not be traced.\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[pTLS_data->m_calling_driver_entrypoint_id].m_pName);
5666 return GL_ENTRYPOINT(glGetError)();
5669 if (g_dump_gl_calls_flag)
5671 vogl_log_printf("** glGetError TID: 0x%" PRIX64 "\n", vogl_get_current_kernel_thread_id());
5674 vogl_context *pContext = pTLS_data->m_pContext;
5675 // pContext may be NULL here if the user has called glGetError() incorrectly, we've already printed the error message, but we're still going to call the driver (which will probably just immediately return).
5676 // Also, even if we have a latched error for this context, we MUST call glGetError() to guarantee there are no current errors on the context (to preserve the original behavior if the tracer wasn't present).
5678 uint64_t gl_begin_rdtsc = utils::RDTSC();
5679 GLenum gl_err = GL_ENTRYPOINT(glGetError)();
5680 uint64_t gl_end_rdtsc = utils::RDTSC();
5682 if (g_vogl_trace_writer.is_opened())
5684 vogl_entrypoint_serializer serializer(VOGL_ENTRYPOINT_glGetError, g_context_manager.get_current());
5685 serializer.set_begin_rdtsc(begin_rdtsc);
5686 serializer.set_gl_begin_end_rdtsc(gl_begin_rdtsc, gl_end_rdtsc);
5687 serializer.add_return_param(VOGL_GLENUM, &gl_err, sizeof(gl_err));
5689 if ((pContext) && (pContext->has_latched_gl_error()))
5691 // Record the latched error too, so the replayer knows what's going on.
5692 serializer.add_key_value("latched_gl_error", pContext->get_latched_gl_error());
5696 vogl_write_packet_to_trace(serializer.get_packet());
5697 g_vogl_trace_writer.flush();
5700 // See if our context's shadow has a latched GL error recorded by the tracer in an earlier call. If so, it must override this GL error.
5701 if (pContext && pContext->has_latched_gl_error())
5703 if (gl_err != GL_NO_ERROR)
5705 vogl_warning_printf("%s: glGetError() called with a GL error latched on the context by the tracer. Current error is 0x%04X, latched error is 0x%04X. Note the queued error will suppress the current error.\n", VOGL_FUNCTION_NAME, gl_err, pContext->get_latched_gl_error());
5708 // We're going to replace the current GL error with our previously latched error, which *would have* masked this error if the tracer wasn't present.
5709 gl_err = pContext->get_latched_gl_error();
5711 pContext->clear_latched_gl_error();
5714 if (g_dump_gl_calls_flag)
5716 vogl_message_printf("** END %s 0x%" PRIX64 "\n", VOGL_FUNCTION_NAME, vogl_get_current_kernel_thread_id());
5722 //----------------------------------------------------------------------------------------------------------------------
5723 // shader source code
5724 //----------------------------------------------------------------------------------------------------------------------
5725 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glShaderSourceARB(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_serialize_shader_source(trace_serializer, count, string, length);
5726 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glShaderSource(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_serialize_shader_source(trace_serializer, count, (const GLcharARB *const *)string, length);
5727 static void vogl_serialize_shader_source(vogl_entrypoint_serializer &trace_serializer, GLsizei count, const GLcharARB *const *string, const GLint *length)
5729 if (g_dump_gl_shaders_flag)
5731 vogl_log_printf("Source source code, %i string(s):\n", count);
5732 for (GLsizei i = 0; i < count; i++)
5734 const char *pStr = (const char *)string[i];
5737 str_len = length[i];
5739 str_len = pStr ? (vogl_strlen(pStr) + 1) : 0;
5741 vogl_log_printf("\"");
5742 vogl_print_string(pStr, str_len);
5743 vogl_log_printf("\"\n");
5747 if (trace_serializer.is_in_begin())
5749 for (GLsizei i = 0; i < count; i++)
5751 const char *pStr = (const char *)string[i];
5754 str_len = length[i];
5756 str_len = pStr ? (vogl_strlen(pStr) + 1) : 0;
5758 if ((str_len) && (pStr))
5759 trace_serializer.add_key_value_blob(i, pStr, str_len);
5764 //----------------------------------------------------------------------------------------------------------------------
5765 // vogl_uses_client_side_arrays
5766 //----------------------------------------------------------------------------------------------------------------------
5767 static bool vogl_uses_client_side_arrays(vogl_context *pContext, bool indexed)
5769 if ((!pContext) || (!pContext->get_uses_client_side_arrays()) || (pContext->is_core_profile()))
5772 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
5773 VOGL_NOTE_UNUSED(gl_error_absorber);
5777 GLuint element_array_buffer = vogl_get_bound_gl_buffer(GL_ELEMENT_ARRAY_BUFFER);
5778 if (!element_array_buffer)
5782 bool used_old_style_gl_client_side_arrays = false;
5784 GLint prev_client_active_texture = 0;
5785 GL_ENTRYPOINT(glGetIntegerv)(GL_CLIENT_ACTIVE_TEXTURE, &prev_client_active_texture);
5787 const uint tex_coords = pContext->get_max_texture_coords();
5789 for (uint i = 0; i < VOGL_NUM_CLIENT_SIDE_ARRAY_DESCS; i++)
5791 const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[i];
5792 if (i == vogl_texcoord_pointer_array_id)
5794 for (uint tex_index = 0; tex_index < tex_coords; tex_index++)
5796 GL_ENTRYPOINT(glClientActiveTexture)(GL_TEXTURE0 + tex_index);
5798 GLboolean is_enabled = GL_ENTRYPOINT(glIsEnabled)(desc.m_is_enabled);
5803 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_binding, &binding);
5807 used_old_style_gl_client_side_arrays = true;
5811 if (used_old_style_gl_client_side_arrays)
5816 GLboolean is_enabled = GL_ENTRYPOINT(glIsEnabled)(desc.m_is_enabled);
5821 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_binding, &binding);
5825 used_old_style_gl_client_side_arrays = true;
5830 GL_ENTRYPOINT(glClientActiveTexture)(prev_client_active_texture);
5832 if (used_old_style_gl_client_side_arrays)
5835 uint64_t vertex_attrib_client_side_arrays = 0;
5836 VOGL_ASSUME(VOGL_MAX_SUPPORTED_GL_VERTEX_ATTRIBUTES <= sizeof(vertex_attrib_client_side_arrays) * 8);
5838 for (uint i = 0; i < pContext->get_max_vertex_attribs(); i++)
5840 GLint is_enabled = 0;
5841 GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &is_enabled);
5846 GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &cur_buf);
5856 //----------------------------------------------------------------------------------------------------------------------
5857 // vogl_serialize_client_side_arrays_helper
5858 //----------------------------------------------------------------------------------------------------------------------
5859 static void vogl_serialize_client_side_arrays_helper(
5860 vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, const char *pFunc,
5861 GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex, bool start_end_valid, bool indexed)
5863 VOGL_NOTE_UNUSED(mode);
5865 VOGL_NOTE_UNUSED(pFunc);
5867 if ((!pContext) || (pContext->is_core_profile()))
5872 vogl_error_printf("%s: end (%i) must be >= start (%i)\n", VOGL_FUNCTION_NAME, end, start);
5876 uint index_size = vogl_get_gl_type_size(type);
5879 vogl_error_printf("%s: Invalid type parameter 0x%08X\n", VOGL_FUNCTION_NAME, type);
5883 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
5884 VOGL_NOTE_UNUSED(gl_error_absorber);
5886 GLuint element_array_buffer = 0;
5889 element_array_buffer = vogl_get_bound_gl_buffer(GL_ELEMENT_ARRAY_BUFFER);
5890 if (!element_array_buffer)
5894 vogl_error_printf("%s: No bound element array buffer, and indices parameter is NULL\n", VOGL_FUNCTION_NAME);
5899 if (g_dump_gl_buffers_flag)
5901 vogl_log_printf("Client side index data: ");
5902 vogl_print_hex(indices, count * index_size, index_size);
5903 vogl_log_printf("\n");
5906 if (trace_serializer.is_in_begin())
5908 trace_serializer.add_key_value_blob(string_hash("indices"), indices, count * index_size);
5914 const gl_entrypoint_id_t cur_entrypoint = trace_serializer.get_cur_entrypoint();
5915 VOGL_NOTE_UNUSED(cur_entrypoint);
5917 // TODO: Have the glSet*Pointer()'s funcs set a flag when the client uses this old shit, so we can avoid checking for it on apps that don't.
5919 bool used_old_style_gl_client_side_arrays = false;
5921 GLint prev_client_active_texture = 0;
5922 GL_ENTRYPOINT(glGetIntegerv)(GL_CLIENT_ACTIVE_TEXTURE, &prev_client_active_texture);
5924 const uint tex_coords = pContext->get_max_texture_coords();
5926 for (uint i = 0; i < VOGL_NUM_CLIENT_SIDE_ARRAY_DESCS; i++)
5928 const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[i];
5929 if (i == vogl_texcoord_pointer_array_id)
5931 for (uint tex_index = 0; tex_index < tex_coords; tex_index++)
5933 GL_ENTRYPOINT(glClientActiveTexture)(GL_TEXTURE0 + tex_index);
5935 GLboolean is_enabled = GL_ENTRYPOINT(glIsEnabled)(desc.m_is_enabled);
5940 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_binding, &binding);
5944 used_old_style_gl_client_side_arrays = true;
5948 if (used_old_style_gl_client_side_arrays)
5953 GLboolean is_enabled = GL_ENTRYPOINT(glIsEnabled)(desc.m_is_enabled);
5958 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_binding, &binding);
5962 used_old_style_gl_client_side_arrays = true;
5967 GL_ENTRYPOINT(glClientActiveTexture)(prev_client_active_texture);
5969 uint64_t vertex_attrib_client_side_arrays = 0;
5970 VOGL_ASSUME(VOGL_MAX_SUPPORTED_GL_VERTEX_ATTRIBUTES <= sizeof(vertex_attrib_client_side_arrays) * 8);
5972 for (uint i = 0; i < pContext->get_max_vertex_attribs(); i++)
5974 GLint is_enabled = 0;
5975 GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &is_enabled);
5980 GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &cur_buf);
5984 vertex_attrib_client_side_arrays |= (1ULL << i);
5987 if ((!used_old_style_gl_client_side_arrays) && (!vertex_attrib_client_side_arrays))
5992 if (!start_end_valid)
5994 uint total_index_data_size = count * index_size;
5996 // FIXME: Move index_data array to context state
5997 vogl::vector<uint8> index_data;
5998 const uint8 *pIndices_to_scan = static_cast<const uint8 *>(indices);
6000 if (element_array_buffer)
6002 index_data.resize(total_index_data_size);
6003 pIndices_to_scan = index_data.get_ptr();
6005 GL_ENTRYPOINT(glGetBufferSubData)(GL_ELEMENT_ARRAY_BUFFER, (GLintptr)indices, total_index_data_size, index_data.get_ptr());
6008 start = cUINT32_MAX;
6011 for (int i = 0; i < count; i++)
6015 if (type == GL_UNSIGNED_BYTE)
6016 v = pIndices_to_scan[i];
6017 else if (type == GL_UNSIGNED_SHORT)
6018 v = reinterpret_cast<const uint16 *>(pIndices_to_scan)[i];
6019 else if (type == GL_UNSIGNED_INT)
6020 v = reinterpret_cast<const uint32 *>(pIndices_to_scan)[i];
6026 start = math::minimum(start, v);
6027 end = math::maximum(end, v);
6031 if (trace_serializer.is_in_begin())
6033 trace_serializer.add_key_value(string_hash("start"), start);
6034 trace_serializer.add_key_value(string_hash("end"), end);
6038 if (used_old_style_gl_client_side_arrays)
6040 for (uint client_array_iter = 0; client_array_iter < VOGL_NUM_CLIENT_SIDE_ARRAY_DESCS; client_array_iter++)
6042 const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[client_array_iter];
6045 uint base_key_index = 0x1000 + client_array_iter;
6047 // Special case texcoord pointers, which are accessed via the client active texture.
6048 if (client_array_iter == vogl_texcoord_pointer_array_id)
6051 base_key_index = 0x2000;
6054 for (uint inner_iter = 0; inner_iter < n; inner_iter++)
6056 if (client_array_iter == vogl_texcoord_pointer_array_id)
6058 GL_ENTRYPOINT(glClientActiveTexture)(GL_TEXTURE0 + inner_iter);
6061 GLboolean is_enabled = GL_ENTRYPOINT(glIsEnabled)(desc.m_is_enabled);
6066 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_binding, &binding);
6071 GL_ENTRYPOINT(glGetPointerv)(desc.m_get_pointer, &ptr);
6075 GLint type = GL_BOOL;
6076 if (desc.m_get_type)
6078 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_type, &type);
6082 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_stride, &stride);
6085 if (desc.m_get_size)
6087 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_size, &size);
6090 uint type_size = vogl_get_gl_type_size(type);
6093 vogl_error_printf("%s: Can't determine type size of enabled client side array set by func %s\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[desc.m_entrypoint].m_pName);
6097 if ((desc.m_entrypoint == VOGL_ENTRYPOINT_glIndexPointer) || (desc.m_entrypoint == VOGL_ENTRYPOINT_glIndexPointerEXT) ||
6098 (desc.m_entrypoint == VOGL_ENTRYPOINT_glFogCoordPointer) || (desc.m_entrypoint == VOGL_ENTRYPOINT_glFogCoordPointerEXT) ||
6099 (desc.m_entrypoint == VOGL_ENTRYPOINT_glEdgeFlagPointer) || (desc.m_entrypoint == VOGL_ENTRYPOINT_glEdgeFlagPointerEXT))
6103 else if ((desc.m_entrypoint == VOGL_ENTRYPOINT_glNormalPointer) || (desc.m_entrypoint == VOGL_ENTRYPOINT_glNormalPointerEXT))
6107 else if ((size < 1) || (size > 4))
6109 vogl_error_printf("%s: Size of client side array set by func %s must be between 1 and 4\n", VOGL_FUNCTION_NAME, g_vogl_entrypoint_descs[desc.m_entrypoint].m_pName);
6114 stride = type_size * size;
6116 uint first_vertex_ofs = (start + basevertex) * stride;
6117 uint last_vertex_ofs = (end + basevertex) * stride;
6118 uint vertex_data_size = (last_vertex_ofs + stride) - first_vertex_ofs;
6120 if (g_dump_gl_buffers_flag)
6122 vogl_log_printf("Client side vertex data from %s index %u (comps: %i type_size: %i stride: %i):\n", g_vogl_entrypoint_descs[desc.m_entrypoint].m_pName, inner_iter, size, type_size, stride);
6123 vogl_print_hex(static_cast<const uint8_t *>(ptr) + first_vertex_ofs, vertex_data_size, type_size);
6124 vogl_log_printf("\n");
6127 if (trace_serializer.is_in_begin())
6129 uint key_index = base_key_index + inner_iter;
6130 trace_serializer.add_key_value_blob(static_cast<uint16>(key_index), static_cast<const uint8_t *>(ptr) + first_vertex_ofs, vertex_data_size);
6134 } // client_array_iter
6136 GL_ENTRYPOINT(glClientActiveTexture)(prev_client_active_texture);
6137 } // used_old_style_gl_client_side_arrays
6139 if (vertex_attrib_client_side_arrays)
6141 for (uint i = 0; i < pContext->get_max_vertex_attribs(); i++)
6143 if ((vertex_attrib_client_side_arrays & (1ULL << i)) == 0)
6146 GLvoid *attrib_ptr = NULL;
6147 GL_ENTRYPOINT(glGetVertexAttribPointerv)(i, GL_VERTEX_ATTRIB_ARRAY_POINTER, &attrib_ptr);
6151 vogl_error_printf("%s: Enabled vertex attribute index %i has no vertex array buffer, and attribute pointer is NULL\n", VOGL_FUNCTION_NAME, i);
6155 GLint attrib_size = 0;
6156 GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_SIZE, &attrib_size);
6158 GLint attrib_type = 0;
6159 GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_TYPE, &attrib_type);
6161 GLint attrib_stride = 0;
6162 GL_ENTRYPOINT(glGetVertexAttribiv)(i, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &attrib_stride);
6165 if ((attrib_size != GL_BGRA) && (attrib_size < 1) && (attrib_size > 4))
6167 vogl_error_printf("%s: Enabled vertex attribute index %i has invalid size 0x%0X\n", VOGL_FUNCTION_NAME, i, attrib_size);
6170 if ((attrib_size >= 1) && (attrib_size <= 4))
6171 num_comps = attrib_size;
6173 uint type_size = vogl_get_gl_type_size(attrib_type);
6176 vogl_error_printf("%s: Vertex attribute index %i has unsupported type 0x%0X\n", VOGL_FUNCTION_NAME, i, attrib_type);
6180 uint stride = attrib_stride ? attrib_stride : (type_size * num_comps);
6182 uint first_vertex_ofs = (start + basevertex) * stride;
6183 uint last_vertex_ofs = (end + basevertex) * stride;
6184 uint vertex_data_size = (last_vertex_ofs + stride) - first_vertex_ofs;
6186 if (g_dump_gl_buffers_flag)
6188 vogl_log_printf("Client side vertex data for attrib %i (comps: %i type_size: %i stride: %i):\n", i, num_comps, type_size, stride);
6190 vogl_print_hex(static_cast<const uint8_t *>(attrib_ptr) + first_vertex_ofs, vertex_data_size, type_size);
6192 vogl_log_printf("\n");
6195 if (trace_serializer.is_in_begin())
6197 // TODO: Also send down start/end/first_vertex_ofs for debugging/verification purposes
6198 trace_serializer.add_key_value_blob(static_cast<uint16>(i), static_cast<const uint8_t *>(attrib_ptr) + first_vertex_ofs, vertex_data_size);
6204 //----------------------------------------------------------------------------------------------------------------------
6205 // glDrawRangeElements, glDrawRangeElementsBaseVertex, glDrawRangeElementsEXT
6206 //----------------------------------------------------------------------------------------------------------------------
6207 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDrawRangeElementsBaseVertex(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_draw_range_elements_base_vertex_helper(pContext, trace_serializer, #name, mode, start, end, count, type, indices, 0, true);
6208 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDrawRangeElements(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_draw_range_elements_base_vertex_helper(pContext, trace_serializer, #name, mode, start, end, count, type, indices, 0, true);
6209 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDrawRangeElementsEXT(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_draw_range_elements_base_vertex_helper(pContext, trace_serializer, #name, mode, start, end, count, type, indices, 0, true);
6210 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDrawElements(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_draw_range_elements_base_vertex_helper(pContext, trace_serializer, #name, mode, 0, 0, count, type, indices, 0, false);
6211 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDrawElementsInstanced(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_draw_range_elements_base_vertex_helper(pContext, trace_serializer, #name, mode, 0, 0, count, type, indices, 0, false);
6213 static inline void vogl_draw_range_elements_base_vertex_helper(
6214 vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, const char *pFunc,
6215 GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex, bool start_end_valid)
6217 if (trace_serializer.is_in_begin())
6219 vogl_serialize_client_side_arrays_helper(pContext, trace_serializer, pFunc,
6220 mode, start, end, count, type, indices, basevertex, start_end_valid, true);
6224 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDrawArrays(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_draw_arrays_helper(pContext, trace_serializer, #name, mode, first, count);
6225 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDrawArraysEXT(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_draw_arrays_helper(pContext, trace_serializer, #name, mode, first, count);
6226 static void vogl_draw_arrays_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, const char *pFunc,
6227 GLenum mode, GLint first, GLsizei count)
6229 if (trace_serializer.is_in_begin())
6231 vogl_serialize_client_side_arrays_helper(pContext, trace_serializer, pFunc,
6232 mode, first, first + count - 1, count, GL_UNSIGNED_BYTE, NULL, 0, true, false);
6236 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDrawArraysInstanced(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_draw_arrays_instanced_helper(pContext, trace_serializer, #name, mode, first, count, instancecount);
6237 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDrawArraysInstancedEXT(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_draw_arrays_instanced_helper(pContext, trace_serializer, #name, mode, start, count, primcount);
6238 static void vogl_draw_arrays_instanced_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, const char *pFunc,
6239 GLenum mode, GLint first, GLsizei count, GLsizei primcount)
6241 VOGL_NOTE_UNUSED(primcount);
6242 if (trace_serializer.is_in_begin())
6244 vogl_serialize_client_side_arrays_helper(pContext, trace_serializer, pFunc,
6245 mode, first, first + count - 1, count, GL_UNSIGNED_BYTE, NULL, 0, true, false);
6249 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glMultiDrawArrays(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_multi_draw_arrays_helper(pContext, trace_serializer, #name);
6250 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glMultiDrawArraysEXT(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_multi_draw_arrays_helper(pContext, trace_serializer, #name);
6251 static inline void vogl_multi_draw_arrays_helper(
6252 vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, const char *pFunc)
6254 if (trace_serializer.is_in_begin())
6256 if (vogl_uses_client_side_arrays(pContext, false))
6258 vogl_warning_printf("%s: Function \"%s\" uses client side arrays, which is not currently supported. This call will not replay properly.\n", VOGL_FUNCTION_NAME, pFunc);
6263 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glMultiDrawElements(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_multi_draw_elements_helper(pContext, trace_serializer, #name);
6264 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glMultiDrawElementsEXT(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_multi_draw_elements_helper(pContext, trace_serializer, #name);
6265 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glMultiDrawElementsBaseVertex(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_multi_draw_elements_helper(pContext, trace_serializer, #name);
6266 static void vogl_multi_draw_elements_helper(
6267 vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, const char *pFunc)
6269 if (trace_serializer.is_in_begin())
6271 if (vogl_uses_client_side_arrays(pContext, true))
6273 vogl_warning_printf("%s: Function \"%s\" uses client side arrays, which is not currently supported. This call will not replay properly.\n", VOGL_FUNCTION_NAME, pFunc);
6278 //----------------------------------------------------------------------------------------------------------------------
6279 // String (extension manipulation)
6280 //----------------------------------------------------------------------------------------------------------------------
6281 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGetString(exported, category, ret, ret_type_enum, num_params, func_name, args, params) vogl_get_string_helper(#func_name, pContext, result, name, 0);
6282 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGetStringi(exported, category, ret, ret_type_enum, num_params, func_name, args, params) vogl_get_string_helper(#func_name, pContext, result, name, index);
6283 static inline void vogl_get_string_helper(const char *pFunc_name, vogl_context *pVOGL_context, const GLubyte *&pResult, GLenum name, GLuint index)
6285 if (!g_disable_gl_program_binary_flag)
6288 if ((pVOGL_context) && (pResult) && (name == GL_EXTENSIONS))
6290 // Can't modify the driver's string directly, results in random crashes on my system. So we need to make a copy.
6291 char *pLoc = strstr((char *)pResult, "GL_ARB_get_program_binary");
6294 dynamic_string id(cVarArg, "%s_%x_%x", pFunc_name, name, index);
6296 dynamic_string &ext_str = pVOGL_context->get_extension_map()[id];
6297 ext_str.set((char *)pResult);
6299 int ofs = ext_str.find_left("GL_ARB_get_program_binary", true);
6302 ext_str.set_char(ofs + 3, 'X');
6303 ext_str.set_char(ofs + 4, 'X');
6304 ext_str.set_char(ofs + 5, 'X');
6305 vogl_warning_printf("%s: Disabled GL_ARB_get_program_binary by changing its name to GL_XXX_get_program_binary.\n", VOGL_FUNCTION_NAME);
6307 pResult = (const GLubyte *)ext_str.get_ptr();
6313 //----------------------------------------------------------------------------------------------------------------------
6314 // Buffer mapping, updating
6315 //----------------------------------------------------------------------------------------------------------------------
6318 // glMapNamedBufferEXT
6319 // glMapNamedBufferRangeEXT
6320 // glFlushMappedNamedBufferRangeEXT
6321 // glUnmapNamedBufferEXT
6322 // glGetNamedBufferSubDataEXT
6324 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glNamedBufferDataEXT(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_named_buffer_data_ext_helper(pContext, trace_serializer, buffer, size, data, usage);
6325 static inline void vogl_named_buffer_data_ext_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLuint buffer, GLsizeiptr size, const GLvoid *data, GLenum usage)
6327 VOGL_NOTE_UNUSED(trace_serializer);
6332 if (g_dump_gl_buffers_flag)
6334 vogl_log_printf("Buffer data (size: %" PRIu64 "):\n", static_cast<uint64_t>(size));
6335 vogl_print_hex(data, size, 1);
6336 vogl_log_printf("\n");
6339 gl_buffer_desc &buf_desc = pContext->get_or_create_buffer_desc(buffer);
6340 buf_desc.m_size = size;
6341 buf_desc.m_usage = usage;
6343 if (buf_desc.m_pMap)
6345 vogl_warning_printf("%s: Setting buffer's data on an already mapped buffer, buffer will get unmapped by GL\n", VOGL_FUNCTION_NAME);
6348 buf_desc.m_pMap = NULL;
6349 buf_desc.m_map_ofs = 0;
6350 buf_desc.m_map_size = 0;
6351 buf_desc.m_map_access = 0;
6352 buf_desc.m_map_range = 0;
6353 buf_desc.m_flushed_ranges.resize(0);
6356 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glBufferData(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_buffer_data_helper(pContext, trace_serializer, target, size, data, usage);
6357 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glBufferDataARB(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_buffer_data_helper(pContext, trace_serializer, target, size, data, usage);
6358 static inline void vogl_buffer_data_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage)
6363 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6364 VOGL_NOTE_UNUSED(gl_error_absorber);
6366 GLuint buffer = vogl_get_bound_gl_buffer(target);
6369 vogl_error_printf("%s: No mapped buffer at target 0x%08X\n", VOGL_FUNCTION_NAME, target);
6373 vogl_named_buffer_data_ext_helper(pContext, trace_serializer, buffer, size, data, usage);
6376 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glNamedBufferSubDataEXT(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_named_buffer_subdata_ext_helper(pContext, trace_serializer, buffer, offset, size, data);
6377 static inline void vogl_named_buffer_subdata_ext_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLuint buffer, GLintptr offset, GLsizeiptr size, const GLvoid *data)
6379 VOGL_NOTE_UNUSED(buffer);
6380 VOGL_NOTE_UNUSED(trace_serializer);
6381 VOGL_NOTE_UNUSED(pContext);
6383 if (g_dump_gl_buffers_flag)
6385 vogl_log_printf("Buffer sub data (offset: %" PRIu64 " size: %" PRIu64 "):\n", static_cast<uint64_t>(offset), static_cast<uint64_t>(size));
6386 vogl_print_hex(data, size, 1);
6387 vogl_log_printf("\n");
6391 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glBufferSubData(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_buffer_subdata_helper(pContext, trace_serializer, target, offset, size, data);
6392 static inline void vogl_buffer_subdata_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data)
6397 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6398 VOGL_NOTE_UNUSED(gl_error_absorber);
6400 GLuint buffer = vogl_get_bound_gl_buffer(target);
6403 vogl_error_printf("%s: No mapped buffer at target 0x%08X\n", VOGL_FUNCTION_NAME, target);
6407 vogl_named_buffer_subdata_ext_helper(pContext, trace_serializer, buffer, offset, size, data);
6410 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glMapBuffer(exported, category, ret, ret_type_enum, num_params, name, args, params) \
6411 GLenum orig_access = access; \
6412 vogl_map_buffer_gl_prolog_helper(pContext, trace_serializer, target, access);
6413 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glMapBufferARB(exported, category, ret, ret_type_enum, num_params, name, args, params) \
6414 GLenum orig_access = access; \
6415 vogl_map_buffer_gl_prolog_helper(pContext, trace_serializer, target, access);
6416 static inline void vogl_map_buffer_gl_prolog_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLenum target, GLenum &access)
6418 VOGL_NOTE_UNUSED(target);
6419 VOGL_NOTE_UNUSED(pContext);
6421 if (trace_serializer.is_in_begin() || g_dump_gl_buffers_flag)
6423 if (access == GL_WRITE_ONLY)
6425 access = GL_READ_WRITE;
6430 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glMapBuffer(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_map_buffer_gl_epilog_helper(pContext, target, orig_access, result);
6431 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glMapBufferARB(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_map_buffer_gl_epilog_helper(pContext, target, orig_access, result);
6432 static inline void vogl_map_buffer_gl_epilog_helper(vogl_context *pContext, GLenum target, GLenum access, GLvoid *pPtr)
6439 vogl_warning_printf("%s: Map failed!\n", VOGL_FUNCTION_NAME);
6443 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6444 VOGL_NOTE_UNUSED(gl_error_absorber);
6446 GLuint buffer = vogl_get_bound_gl_buffer(target);
6449 vogl_error_printf("%s: No mapped buffer at target 0x%08X\n", VOGL_FUNCTION_NAME, target);
6453 gl_buffer_desc &buf_desc = pContext->get_or_create_buffer_desc(buffer);
6454 if (buf_desc.m_pMap)
6456 vogl_warning_printf("%s: Buffer 0x%08X is already mapped!\n", VOGL_FUNCTION_NAME, buffer);
6460 // We need to sync with the underlying GL here to retreive the actual, true size of the mapped buffer in case an error occurred earlier and we didn't actually record the true size of the buffer.
6461 GLint64 actual_buf_size = buf_desc.m_size;
6462 GL_ENTRYPOINT(glGetBufferParameteri64v)(target, GL_BUFFER_SIZE, &actual_buf_size);
6464 buf_desc.m_size = actual_buf_size;
6465 buf_desc.m_pMap = pPtr;
6466 buf_desc.m_map_ofs = 0;
6467 buf_desc.m_map_size = actual_buf_size;
6468 buf_desc.m_map_access = access;
6469 buf_desc.m_map_range = false;
6472 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glMapBufferRange(exported, category, ret, ret_type_enum, num_params, name, args, params) \
6473 GLbitfield orig_access = access; \
6474 vogl_map_buffer_range_gl_prolog_helper(pContext, trace_serializer, target, offset, length, access);
6475 static inline void vogl_map_buffer_range_gl_prolog_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield &access)
6477 VOGL_NOTE_UNUSED(length);
6478 VOGL_NOTE_UNUSED(offset);
6479 VOGL_NOTE_UNUSED(target);
6480 VOGL_NOTE_UNUSED(pContext);
6482 if (trace_serializer.is_in_begin() || g_dump_gl_buffers_flag)
6484 if (access & GL_MAP_WRITE_BIT)
6486 // They are going to write, so we need to be able to read the data.
6487 // TODO: Warn user that we're going to not invalidate, which is definitely going to slow the GL driver down with CPU/GPU syncs.
6488 access &= ~GL_MAP_INVALIDATE_RANGE_BIT;
6489 access &= ~GL_MAP_INVALIDATE_BUFFER_BIT;
6490 access &= ~GL_MAP_UNSYNCHRONIZED_BIT;
6491 access |= GL_MAP_READ_BIT;
6496 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glMapBufferRange(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_map_buffer_range_gl_epilog_helper(pContext, target, offset, length, orig_access, result);
6497 static inline void vogl_map_buffer_range_gl_epilog_helper(vogl_context *pContext, GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield &access, GLvoid *pPtr)
6504 vogl_warning_printf("%s: Map failed!\n", VOGL_FUNCTION_NAME);
6508 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6509 VOGL_NOTE_UNUSED(gl_error_absorber);
6511 GLuint buffer = vogl_get_bound_gl_buffer(target);
6514 vogl_error_printf("%s: No mapped buffer at target 0x%08X\n", VOGL_FUNCTION_NAME, target);
6518 gl_buffer_desc &buf_desc = pContext->get_or_create_buffer_desc(buffer);
6519 if (buf_desc.m_pMap)
6521 vogl_error_printf("%s: Buffer 0x%08X is already mapped!\n", VOGL_FUNCTION_NAME, buffer);
6525 if (length > buf_desc.m_size)
6527 vogl_warning_printf("%s: passed in length parameter (%" PRIi64 ") is larger the buffer 0x%08X's recorded size (%" PRIi64 ")!\n",
6528 VOGL_FUNCTION_NAME, static_cast<int64_t>(length), buffer, buf_desc.m_size);
6530 GLint64 actual_buf_size = buf_desc.m_size;
6531 GL_ENTRYPOINT(glGetBufferParameteri64v)(target, GL_BUFFER_SIZE, &actual_buf_size);
6532 buf_desc.m_size = actual_buf_size;
6535 buf_desc.m_pMap = pPtr;
6536 buf_desc.m_map_ofs = offset;
6537 buf_desc.m_map_size = length;
6538 buf_desc.m_map_access = access;
6539 buf_desc.m_map_range = true;
6542 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glFlushMappedBufferRange(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_flush_mapped_buffer_range(pContext, target, offset, length);
6543 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glFlushMappedBufferRangeAPPLE(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_flush_mapped_buffer_range(pContext, target, offset, size);
6544 static inline void vogl_flush_mapped_buffer_range(vogl_context *pContext, GLenum target, GLintptr offset, GLsizeiptr length)
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 if ((offset + length) > buf_desc.m_map_size)
6568 vogl_warning_printf("%s: passed in offset (%" PRIi64 ") and/or length (%" PRIi64 ") parameters are out of range vs. buffer 0x%08X's recorded map size (%" PRIi64 ")!\n",
6569 VOGL_FUNCTION_NAME, static_cast<int64_t>(offset), static_cast<int64_t>(length), buffer, buf_desc.m_map_size);
6572 buf_desc.m_flushed_ranges.push_back(gl_buffer_desc::flushed_range(offset, length));
6575 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glUnmapBuffer(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_unmap_buffer_helper(pContext, trace_serializer, target);
6576 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glUnmapBufferARB(exported, category, ret, ret_type_enum, num_params, name, args, params) vogl_unmap_buffer_helper(pContext, trace_serializer, target);
6577 static inline void vogl_unmap_buffer_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLenum target)
6582 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6583 VOGL_NOTE_UNUSED(gl_error_absorber);
6585 GLuint buffer = vogl_get_bound_gl_buffer(target);
6588 vogl_error_printf("%s: No mapped buffer at target 0x%08X\n", VOGL_FUNCTION_NAME, target);
6592 gl_buffer_desc &buf_desc = pContext->get_or_create_buffer_desc(buffer);
6593 if (!buf_desc.m_pMap)
6595 vogl_error_printf("%s: Buffer 0x%08X is not currently mapped!\n", VOGL_FUNCTION_NAME, buffer);
6599 bool writable_map = false;
6600 bool explicit_flush = false;
6601 if (buf_desc.m_map_range)
6603 writable_map = (buf_desc.m_map_access & GL_MAP_WRITE_BIT) != 0;
6604 explicit_flush = (buf_desc.m_map_access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0;
6608 writable_map = (buf_desc.m_map_access != GL_READ_ONLY);
6611 if (trace_serializer.is_in_begin())
6613 trace_serializer.add_key_value(string_hash("map_access"), buf_desc.m_map_access);
6614 trace_serializer.add_key_value(string_hash("map_range"), buf_desc.m_map_range);
6615 trace_serializer.add_key_value(string_hash("explicit_flush"), explicit_flush);
6616 trace_serializer.add_key_value(string_hash("writable_map"), writable_map);
6623 if (!buf_desc.m_flushed_ranges.size())
6625 vogl_warning_printf("%s: Mapped buffer at target 0x%08X was mapped with GL_MAP_FLUSH_EXPLICIT_BIT, but no ranges where actually flushed\n", VOGL_FUNCTION_NAME, target);
6628 if (g_dump_gl_buffers_flag)
6630 for (uint i = 0; i < buf_desc.m_flushed_ranges.size(); i++)
6632 vogl_log_printf("Flushed buffer data (ofs: %" PRIu64 " size: %" PRIu64 "):\n", buf_desc.m_flushed_ranges[i].m_ofs, buf_desc.m_flushed_ranges[i].m_size);
6633 vogl_print_hex(static_cast<const uint8_t *>(buf_desc.m_pMap) + buf_desc.m_flushed_ranges[i].m_ofs, buf_desc.m_flushed_ranges[i].m_size, 1);
6634 vogl_log_printf("\n");
6638 if (trace_serializer.is_in_begin())
6640 trace_serializer.add_key_value(string_hash("flushed_ranges"), buf_desc.m_flushed_ranges.size());
6641 for (uint i = 0; i < buf_desc.m_flushed_ranges.size(); i++)
6643 int key_index = i * 4;
6644 trace_serializer.add_key_value(key_index, buf_desc.m_flushed_ranges[i].m_ofs);
6645 trace_serializer.add_key_value(key_index + 1, buf_desc.m_flushed_ranges[i].m_size);
6647 VOGL_ASSERT(buf_desc.m_flushed_ranges[i].m_size <= cUINT32_MAX);
6648 trace_serializer.add_key_value_blob(key_index + 2, static_cast<const uint8_t *>(buf_desc.m_pMap) + buf_desc.m_flushed_ranges[i].m_ofs, static_cast<uint>(buf_desc.m_flushed_ranges[i].m_size));
6654 if (g_dump_gl_buffers_flag)
6656 vogl_log_printf("Flushed buffer data (ofs: %" PRIu64 " size: %" PRIu64 "):\n", cast_val_to_uint64(buf_desc.m_map_ofs), cast_val_to_uint64(buf_desc.m_map_size));
6657 vogl_print_hex(static_cast<const uint8_t *>(buf_desc.m_pMap), buf_desc.m_map_size, 1);
6658 vogl_log_printf("\n");
6661 if (trace_serializer.is_in_begin())
6663 trace_serializer.add_key_value(0, buf_desc.m_map_ofs);
6664 trace_serializer.add_key_value(1, buf_desc.m_map_size);
6666 VOGL_ASSERT(buf_desc.m_map_size <= cUINT32_MAX);
6667 trace_serializer.add_key_value_blob(2, static_cast<const uint8_t *>(buf_desc.m_pMap), static_cast<uint>(buf_desc.m_map_size));
6672 buf_desc.m_pMap = NULL;
6673 buf_desc.m_map_ofs = 0;
6674 buf_desc.m_map_size = 0;
6675 buf_desc.m_map_access = 0;
6676 buf_desc.m_flushed_ranges.resize(0);
6679 //----------------------------------------------------------------------------------------------------------------------
6680 // glCreateProgram/glCreateProgramARB function epilog
6681 //----------------------------------------------------------------------------------------------------------------------
6682 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glCreateProgram(e, c, rt, r, nu, ne, a, p) \
6684 vogl_create_program_helper(pContext, result);
6685 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glCreateProgramObjectARB(e, c, rt, r, nu, ne, a, p) \
6687 vogl_create_program_helper(pContext, result);
6688 static inline void vogl_create_program_helper(vogl_context *pContext, GLuint handle)
6690 VOGL_NOTE_UNUSED(pContext);
6691 VOGL_NOTE_UNUSED(handle);
6696 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6697 VOGL_NOTE_UNUSED(gl_error_absorber);
6699 // Ensure program bins are always retrievable
6700 GL_ENTRYPOINT(glProgramParameteri)(handle, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);
6705 //----------------------------------------------------------------------------------------------------------------------
6706 // glProgramParameteri GL prolog
6707 //----------------------------------------------------------------------------------------------------------------------
6708 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glProgramParameteri(e, c, rt, r, nu, ne, a, p) \
6710 vogl_program_parameteri_prolog(pContext, program, pname, value);
6711 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glProgramParameteriARB(e, c, rt, r, nu, ne, a, p) \
6713 vogl_program_parameteri_prolog(pContext, program, pname, value);
6714 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glProgramParameteriEXT(e, c, rt, r, nu, ne, a, p) \
6716 vogl_program_parameteri_prolog(pContext, program, pname, value);
6717 static void vogl_program_parameteri_prolog(vogl_context *pContext, GLuint program, GLenum pname, GLint &value)
6719 VOGL_NOTE_UNUSED(pContext);
6720 VOGL_NOTE_UNUSED(program);
6721 VOGL_NOTE_UNUSED(pname);
6722 VOGL_NOTE_UNUSED(value);
6725 if ((pname == GL_PROGRAM_BINARY_RETRIEVABLE_HINT) && (value == GL_FALSE))
6727 vogl_warning_printf("%s: Client is trying to set program %u's GL_PROGRAM_BINARY_RETRIEVABLE_HINT to GL_FALSE, the tracer is overriding this to GL_TRUE\n", VOGL_FUNCTION_NAME, program);
6734 //----------------------------------------------------------------------------------------------------------------------
6735 // glBindAttribLocationARB/glBindAttribLocation function epilog
6736 //----------------------------------------------------------------------------------------------------------------------
6737 //#define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glBindAttribLocationARB(e, c, rt, r, nu, ne, a, p) if (pContext) pContext->bind_attrib_location(programObj, index, name);
6738 //#define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glBindAttribLocation(e, c, rt, r, nu, ne, a, p) if (pContext) pContext->bind_attrib_location(program, index, reinterpret_cast<const char *>(name));
6740 //----------------------------------------------------------------------------------------------------------------------
6741 // glDeleteProgramsARB/glDeleteProgram function epilog
6742 //----------------------------------------------------------------------------------------------------------------------
6743 //#define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDeleteProgramsARB(e, c, rt, r, nu, ne, a, p) if (pContext) pContext->delete_program_attrib_locations(n, programs);
6744 //#define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glDeleteProgram(e, c, rt, r, nu, ne, a, p) if (pContext) pContext->delete_program_attrib_locations(1, &program);
6746 //----------------------------------------------------------------------------------------------------------------------
6747 // vogl_dump_program_outputs
6748 //----------------------------------------------------------------------------------------------------------------------
6749 static void vogl_dump_program_outputs(json_node &doc_root, vogl_context *pContext, GLuint program)
6751 if (pContext->get_context_info().supports_extension("GL_ARB_program_interface_query") &&
6752 GL_ENTRYPOINT(glGetProgramInterfaceiv) && GL_ENTRYPOINT(glGetProgramResourceName) && GL_ENTRYPOINT(glGetProgramResourceiv))
6754 GLint num_active_outputs = 0;
6755 GL_ENTRYPOINT(glGetProgramInterfaceiv)(program, GL_PROGRAM_OUTPUT, GL_ACTIVE_RESOURCES, &num_active_outputs);
6756 pContext->peek_and_drop_gl_error();
6758 doc_root.add_key_value("total_active_outputs", num_active_outputs);
6760 json_node &outputs_object = doc_root.add_array("active_outputs");
6761 for (int i = 0; i < num_active_outputs; i++)
6764 GLsizei name_len = 0;
6765 GL_ENTRYPOINT(glGetProgramResourceName)(program, GL_PROGRAM_OUTPUT, i, sizeof(name), &name_len, name);
6766 pContext->peek_and_drop_gl_error();
6768 const GLenum props_to_query[5] = { GL_LOCATION, GL_LOCATION_INDEX, GL_TYPE, GL_ARRAY_SIZE, GL_IS_PER_PATCH }; // TODO: GL_LOCATION_COMPONENT
6769 GLint props[5] = { 0, 0, 0, 0, 0 };
6770 GL_ENTRYPOINT(glGetProgramResourceiv)(program, GL_PROGRAM_OUTPUT, i, VOGL_ARRAY_SIZE(props_to_query), props_to_query, VOGL_ARRAY_SIZE(props), NULL, props);
6771 pContext->peek_and_drop_gl_error();
6773 json_node &output_node = outputs_object.add_object();
6774 output_node.add_key_value("index", i);
6775 output_node.add_key_value("name", reinterpret_cast<const char *>(name));
6776 output_node.add_key_value("location", props[0]);
6777 output_node.add_key_value("location_index", props[1]);
6778 output_node.add_key_value("type", props[2]);
6779 output_node.add_key_value("array_size", props[3]);
6780 output_node.add_key_value("is_per_patch", props[4]);
6781 //output_node.add_key_value("location_component", props[5]);
6786 //----------------------------------------------------------------------------------------------------------------------
6787 // glLinkProgramARB function epilog
6788 //----------------------------------------------------------------------------------------------------------------------
6789 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glLinkProgramARB(e, c, rt, r, nu, ne, a, p) vogl_link_program_arb(pContext, trace_serializer, programObj);
6790 static inline void vogl_link_program_arb(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLhandleARB programObj)
6795 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6796 VOGL_NOTE_UNUSED(gl_error_absorber);
6798 GLint link_status = 0;
6799 GL_ENTRYPOINT(glGetObjectParameterivARB)(programObj, GL_OBJECT_LINK_STATUS_ARB, &link_status);
6800 pContext->peek_and_drop_gl_error();
6802 if (trace_serializer.is_in_begin())
6805 json_node &doc_root = *doc.get_root();
6806 doc_root.add_key_value("program", programObj);
6807 doc_root.add_key_value("link_status", link_status);
6808 doc_root.add_key_value("func_id", VOGL_ENTRYPOINT_glLinkProgramARB);
6810 GLint active_attributes = 0;
6811 GL_ENTRYPOINT(glGetObjectParameterivARB)(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);
6812 pContext->peek_and_drop_gl_error();
6814 doc_root.add_key_value("total_active_attributes", active_attributes);
6816 if (active_attributes)
6818 json_node &attribs_object = doc_root.add_array("active_attribs");
6820 for (int i = 0; i < active_attributes; i++)
6824 GLcharARB name[256];
6826 GL_ENTRYPOINT(glGetActiveAttribARB)(programObj, i, sizeof(name), NULL, &size, &type, name);
6827 pContext->peek_and_drop_gl_error();
6829 if ((!name[0]) || ((name[0] == 'g') && (name[1] == 'l') && (name[2] == '_')))
6832 GLint location = GL_ENTRYPOINT(glGetAttribLocationARB)(programObj, name);
6833 pContext->peek_and_drop_gl_error();
6838 json_node &attrib_node = attribs_object.add_object();
6839 attrib_node.add_key_value("index", i);
6840 attrib_node.add_key_value("name", reinterpret_cast<const char *>(name));
6841 attrib_node.add_key_value("location", location);
6845 GLint active_uniforms = 0;
6846 GL_ENTRYPOINT(glGetObjectParameterivARB)(programObj, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &active_uniforms);
6847 pContext->peek_and_drop_gl_error();
6849 doc_root.add_key_value("total_active_uniforms", active_uniforms);
6851 if (active_uniforms)
6853 json_node &uniforms_object = doc_root.add_array("active_uniforms");
6855 for (int i = 0; i < active_uniforms; i++)
6860 GLcharARB name[256];
6862 GL_ENTRYPOINT(glGetActiveUniformARB)(programObj, i, sizeof(name), &length, &size, &type, name);
6863 pContext->peek_and_drop_gl_error();
6865 if ((!name[0]) || (!length) || ((name[0] == 'g') && (name[1] == 'l') && (name[2] == '_')))
6868 GLint location = GL_ENTRYPOINT(glGetUniformLocationARB)(programObj, name);
6869 pContext->peek_and_drop_gl_error();
6874 json_node &uniform_node = uniforms_object.add_object();
6875 uniform_node.add_key_value("index", i);
6876 uniform_node.add_key_value("name", reinterpret_cast<const char *>(name));
6877 uniform_node.add_key_value("location", location);
6878 uniform_node.add_key_value("size", size);
6879 uniform_node.add_key_value("type", type);
6883 vogl_dump_program_outputs(doc_root, pContext, programObj);
6885 trace_serializer.add_key_value_json_document("metadata", doc);
6890 if ((link_status) || (!pContext->has_linked_program_snapshot(programObj)))
6892 if (!pContext->add_linked_program_snapshot(programObj))
6893 vogl_error_printf("%s: Failed snapshotting program into link-time program shadow table, program 0x%X\n", VOGL_FUNCTION_NAME, programObj);
6898 //----------------------------------------------------------------------------------------------------------------------
6899 // glLinkProgram/glProgramBinary function epilog
6900 //----------------------------------------------------------------------------------------------------------------------
6901 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glLinkProgram(e, c, rt, r, nu, ne, a, p) vogl_link_program_epilog_helper(pContext, trace_serializer, program, VOGL_ENTRYPOINT_##ne, GL_NONE, NULL, 0);
6902 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glProgramBinary(e, c, rt, r, nu, ne, a, p) vogl_link_program_epilog_helper(pContext, trace_serializer, program, VOGL_ENTRYPOINT_##ne, binaryFormat, binary, length);
6903 static inline void vogl_link_program_epilog_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLuint program, gl_entrypoint_id_t id, GLenum binary_format, const GLvoid *pBinary, GLsizei binary_length)
6908 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
6909 VOGL_NOTE_UNUSED(gl_error_absorber);
6911 GLint link_status = 0;
6912 GL_ENTRYPOINT(glGetProgramiv)(program, GL_LINK_STATUS, &link_status);
6913 pContext->peek_and_drop_gl_error();
6915 if (trace_serializer.is_in_begin())
6918 json_node &doc_root = *doc.get_root();
6919 doc_root.add_key_value("program", program);
6920 doc_root.add_key_value("link_status", link_status);
6921 doc_root.add_key_value("func_id", static_cast<uint32>(id));
6923 // Active uniform blocks
6924 GLint active_uniform_blocks = 0;
6925 GL_ENTRYPOINT(glGetProgramiv)(program, GL_ACTIVE_UNIFORM_BLOCKS, &active_uniform_blocks);
6926 pContext->peek_and_drop_gl_error();
6928 doc_root.add_key_value("active_uniform_blocks", active_uniform_blocks);
6930 // Active attributes
6931 GLint active_attributes = 0;
6932 GL_ENTRYPOINT(glGetProgramiv)(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);
6933 pContext->peek_and_drop_gl_error();
6935 doc_root.add_key_value("total_active_attributes", active_attributes);
6937 if (active_attributes)
6939 json_node &attribs_object = doc_root.add_array("active_attribs");
6941 for (int i = 0; i < active_attributes; i++)
6947 GL_ENTRYPOINT(glGetActiveAttrib)(program, i, sizeof(name), NULL, &size, &type, name);
6948 pContext->peek_and_drop_gl_error();
6950 if ((!name[0]) || ((name[0] == 'g') && (name[1] == 'l') && (name[2] == '_')))
6953 GLint location = GL_ENTRYPOINT(glGetAttribLocation)(program, name);
6954 pContext->peek_and_drop_gl_error();
6959 json_node &attrib_node = attribs_object.add_object();
6960 attrib_node.add_key_value("index", i);
6961 attrib_node.add_key_value("name", reinterpret_cast<const char *>(name));
6962 attrib_node.add_key_value("location", location);
6967 GLint active_uniforms = 0;
6968 GL_ENTRYPOINT(glGetProgramiv)(program, GL_ACTIVE_UNIFORMS, &active_uniforms);
6969 doc_root.add_key_value("total_active_uniforms", active_uniforms);
6971 if (active_uniforms)
6973 json_node &uniforms_object = doc_root.add_array("active_uniforms");
6975 for (int i = 0; i < active_uniforms; i++)
6982 GL_ENTRYPOINT(glGetActiveUniform)(program, i, sizeof(name), &length, &size, &type, name);
6983 pContext->peek_and_drop_gl_error();
6985 if ((!name[0]) || (!length) || ((name[0] == 'g') && (name[1] == 'l') && (name[2] == '_')))
6988 GLint location = GL_ENTRYPOINT(glGetUniformLocation)(program, name);
6989 pContext->peek_and_drop_gl_error();
6994 json_node &uniform_node = uniforms_object.add_object();
6995 uniform_node.add_key_value("index", i);
6996 uniform_node.add_key_value("name", reinterpret_cast<const char *>(name));
6997 uniform_node.add_key_value("location", location);
6998 uniform_node.add_key_value("size", size);
6999 uniform_node.add_key_value("type", type);
7004 vogl_dump_program_outputs(doc_root, pContext, program);
7006 // Transform feedback
7007 GLint mode = GL_NONE;
7008 GL_ENTRYPOINT(glGetProgramiv)(program, GL_TRANSFORM_FEEDBACK_BUFFER_MODE, &mode);
7009 pContext->peek_and_drop_gl_error();
7011 doc_root.add_key_value("transform_feedback_mode", g_gl_enums.find_gl_name(mode));
7013 GLint num_varyings = 0;
7014 GL_ENTRYPOINT(glGetProgramiv)(program, GL_TRANSFORM_FEEDBACK_VARYINGS, &num_varyings);
7015 pContext->peek_and_drop_gl_error();
7017 doc_root.add_key_value("transform_feedback_num_varyings", num_varyings);
7021 json_node &transform_feedback_varyings = doc_root.add_array("transform_feedback_varyings");
7023 for (GLint i = 0; i < num_varyings; i++)
7026 GLsizei length = 0, size = 0;
7027 GLenum type = GL_NONE;
7029 GL_ENTRYPOINT(glGetTransformFeedbackVarying)(program, i, sizeof(name), &length, &size, &type, name);
7030 pContext->peek_and_drop_gl_error();
7032 json_node &uniform_node = transform_feedback_varyings.add_object();
7033 uniform_node.add_key_value("index", i);
7034 uniform_node.add_key_value("name", reinterpret_cast<const char *>(name));
7035 uniform_node.add_key_value("size", size);
7036 uniform_node.add_key_value("type", type);
7040 // Add JSON document to packet
7041 trace_serializer.add_key_value_json_document("metadata", doc);
7046 if ((link_status) || (!pContext->has_linked_program_snapshot(program)))
7048 if (id == VOGL_ENTRYPOINT_glProgramBinary)
7050 if (!pContext->add_linked_program_snapshot(program, binary_format, pBinary, binary_length))
7052 vogl_error_printf("%s: Failed snapshotting binary program into link-time program shadow table, program 0x%X\n", VOGL_FUNCTION_NAME, program);
7057 if (!pContext->add_linked_program_snapshot(program))
7059 vogl_error_printf("%s: Failed snapshotting program into link-time program shadow table, program 0x%X\n", VOGL_FUNCTION_NAME, program);
7066 #define DEF_FUNCTION_CUSTOM_FUNC_PROLOG_glProgramBinary(e, c, rt, r, nu, ne, a, p) vogl_glProgramBinary_prolog(program, binaryFormat, binary, length);
7067 static inline void vogl_glProgramBinary_prolog(GLuint program, GLenum binaryFormat, const void *&pBinary, GLsizei &length)
7069 VOGL_NOTE_UNUSED(binaryFormat);
7071 if (g_disable_gl_program_binary_flag)
7073 vogl_debug_printf("%s: Tracer is forcing a bogus program binary for program %d\n", VOGL_FUNCTION_NAME, program);
7075 // These will intentionally cause the program binary to not link, forcing the application to use shader strings instead of binaries.
7076 pBinary = &g_dummy_program;
7081 //----------------------------------------------------------------------------------------------------------------------
7082 // glTransformFeedbackVaryings func epilog
7083 //----------------------------------------------------------------------------------------------------------------------
7084 #define DEF_FUNCTION_CUSTOM_FUNC_EPILOG_glTransformFeedbackVaryings(e, c, rt, r, nu, ne, a, p) \
7086 vogl_transform_feedback_varyings(pContext, trace_serializer, count, varyings);
7087 static inline void vogl_transform_feedback_varyings(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, GLsizei count, GLchar *const *pVaryings)
7089 VOGL_NOTE_UNUSED(pContext);
7091 if ((!count) || (!pVaryings) || (!trace_serializer.is_in_begin()))
7094 dynamic_string varying;
7095 for (int i = 0; i < count; i++)
7099 varying = reinterpret_cast<const char *>(pVaryings[i]);
7101 trace_serializer.add_key_value(i, varying);
7105 //----------------------------------------------------------------------------------------------------------------------
7106 // ARB program shadowing
7107 //----------------------------------------------------------------------------------------------------------------------
7108 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenProgramsARB(e, c, rt, r, nu, ne, a, p) \
7110 pContext->peek_and_record_gl_error();
7111 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenProgramsARB(e, c, rt, r, nu, ne, a, p) \
7112 if (pContext && !pContext->peek_and_record_gl_error()) \
7113 pContext->gen_arb_programs(n, programs);
7115 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteProgramsARB(e, c, rt, r, nu, ne, a, p) \
7117 pContext->peek_and_record_gl_error();
7118 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteProgramsARB(e, c, rt, r, nu, ne, a, p) \
7119 if (pContext && !pContext->peek_and_record_gl_error()) \
7120 pContext->del_arb_programs(n, programs);
7122 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindProgramARB(e, c, rt, r, nu, ne, a, p) \
7124 pContext->peek_and_record_gl_error();
7125 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindProgramARB(e, c, rt, r, nu, ne, a, p) \
7126 if (pContext && !pContext->peek_and_record_gl_error()) \
7127 pContext->bind_arb_program(target, program);
7129 //----------------------------------------------------------------------------------------------------------------------
7130 // renderbuffer shadowing
7131 //----------------------------------------------------------------------------------------------------------------------
7132 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenRenderbuffers(e, c, rt, r, nu, ne, a, p) \
7134 pContext->peek_and_record_gl_error();
7135 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenRenderbuffers(e, c, rt, r, nu, ne, a, p) \
7136 if (pContext && !pContext->peek_and_record_gl_error()) \
7137 pContext->gen_render_buffers(n, renderbuffers);
7139 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenRenderbuffersEXT(e, c, rt, r, nu, ne, a, p) \
7141 pContext->peek_and_record_gl_error();
7142 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenRenderbuffersEXT(e, c, rt, r, nu, ne, a, p) \
7143 if (pContext && !pContext->peek_and_record_gl_error()) \
7144 pContext->gen_render_buffers(n, renderbuffers);
7146 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteRenderbuffers(e, c, rt, r, nu, ne, a, p) \
7148 pContext->peek_and_record_gl_error();
7149 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteRenderbuffers(e, c, rt, r, nu, ne, a, p) \
7150 if (pContext && !pContext->peek_and_record_gl_error()) \
7151 pContext->del_render_buffers(n, renderbuffers);
7153 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteRenderbuffersEXT(e, c, rt, r, nu, ne, a, p) \
7155 pContext->peek_and_record_gl_error();
7156 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteRenderbuffersEXT(e, c, rt, r, nu, ne, a, p) \
7157 if (pContext && !pContext->peek_and_record_gl_error()) \
7158 pContext->del_render_buffers(n, renderbuffers);
7159 //----------------------------------------------------------------------------------------------------------------------
7161 //----------------------------------------------------------------------------------------------------------------------
7162 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenBuffers(e, c, rt, r, nu, ne, a, p) \
7164 pContext->peek_and_record_gl_error();
7165 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenBuffers(e, c, rt, r, nu, ne, a, p) \
7166 if (pContext && !pContext->peek_and_record_gl_error()) \
7167 pContext->gen_buffers(n, buffers);
7169 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenBuffersARB(e, c, rt, r, nu, ne, a, p) \
7171 pContext->peek_and_record_gl_error();
7172 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenBuffersARB(e, c, rt, r, nu, ne, a, p) \
7173 if (pContext && !pContext->peek_and_record_gl_error()) \
7174 pContext->gen_buffers(n, buffers);
7176 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBuffer(e, c, rt, r, nu, ne, a, p) \
7178 pContext->peek_and_record_gl_error();
7179 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindBuffer(e, c, rt, r, nu, ne, a, p) \
7180 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7181 pContext->bind_buffer(target, buffer);
7183 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferBase(e, c, rt, r, nu, ne, a, p) \
7185 pContext->peek_and_record_gl_error();
7186 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindBufferBase(e, c, rt, r, nu, ne, a, p) \
7187 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7188 pContext->bind_buffer(target, buffer);
7190 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferBaseEXT(e, c, rt, r, nu, ne, a, p) \
7192 pContext->peek_and_record_gl_error();
7193 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindBufferBaseEXT(e, c, rt, r, nu, ne, a, p) \
7194 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7195 pContext->bind_buffer(target, buffer);
7197 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferBaseNV(e, c, rt, r, nu, ne, a, p) \
7199 pContext->peek_and_record_gl_error();
7200 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindBufferBaseNV(e, c, rt, r, nu, ne, a, p) \
7201 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7202 pContext->bind_buffer(target, buffer);
7204 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferRange(e, c, rt, r, nu, ne, a, p) \
7206 pContext->peek_and_record_gl_error();
7207 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindBufferRange(e, c, rt, r, nu, ne, a, p) \
7208 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7209 pContext->bind_buffer(target, buffer);
7211 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferRangeEXT(e, c, rt, r, nu, ne, a, p) \
7213 pContext->peek_and_record_gl_error();
7214 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindBufferRangeEXT(e, c, rt, r, nu, ne, a, p) \
7215 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7216 pContext->bind_buffer(target, buffer);
7218 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferRangeNV(e, c, rt, r, nu, ne, a, p) \
7220 pContext->peek_and_record_gl_error();
7221 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindBufferRangeNV(e, c, rt, r, nu, ne, a, p) \
7222 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7223 pContext->bind_buffer(target, buffer);
7225 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindBufferARB(e, c, rt, r, nu, ne, a, p) \
7227 pContext->peek_and_record_gl_error();
7228 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindBufferARB(e, c, rt, r, nu, ne, a, p) \
7229 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7230 pContext->bind_buffer(target, buffer);
7232 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteBuffers(e, c, rt, r, nu, ne, a, p) \
7234 pContext->peek_and_record_gl_error();
7235 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteBuffers(e, c, rt, r, nu, ne, a, p) \
7236 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7237 pContext->delete_buffers(n, buffers);
7239 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteBuffersARB(e, c, rt, r, nu, ne, a, p) \
7241 pContext->peek_and_record_gl_error();
7242 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteBuffersARB(e, c, rt, r, nu, ne, a, p) \
7243 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7244 pContext->delete_buffers(n, buffers);
7246 //----------------------------------------------------------------------------------------------------------------------
7247 // Texture handle shadowing
7248 //----------------------------------------------------------------------------------------------------------------------
7249 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenTextures(e, c, rt, r, nu, ne, a, p) \
7251 pContext->peek_and_record_gl_error();
7252 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenTextures(e, c, rt, r, nu, ne, a, p) \
7253 if (pContext && !pContext->peek_and_record_gl_error()) \
7254 pContext->gen_textures(n, textures);
7256 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenTexturesEXT(e, c, rt, r, nu, ne, a, p) \
7258 pContext->peek_and_record_gl_error();
7259 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenTexturesEXT(e, c, rt, r, nu, ne, a, p) \
7260 if (pContext && !pContext->peek_and_record_gl_error()) \
7261 pContext->gen_textures(n, textures);
7263 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteTextures(e, c, rt, r, nu, ne, a, p) \
7265 pContext->peek_and_record_gl_error();
7266 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteTextures(e, c, rt, r, nu, ne, a, p) \
7267 if (pContext && !pContext->peek_and_record_gl_error()) \
7268 pContext->del_textures(n, textures);
7270 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteTexturesEXT(e, c, rt, r, nu, ne, a, p) \
7272 pContext->peek_and_record_gl_error();
7273 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteTexturesEXT(e, c, rt, r, nu, ne, a, p) \
7274 if (pContext && !pContext->peek_and_record_gl_error()) \
7275 pContext->del_textures(n, textures);
7277 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindTexture(e, c, rt, r, nu, ne, a, p) \
7279 pContext->peek_and_record_gl_error();
7280 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindTexture(e, c, rt, r, nu, ne, a, p) \
7281 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7282 pContext->bind_texture(target, texture);
7284 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindTextureEXT(e, c, rt, r, nu, ne, a, p) \
7286 pContext->peek_and_record_gl_error();
7287 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindTextureEXT(e, c, rt, r, nu, ne, a, p) \
7288 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7289 pContext->bind_texture(target, texture);
7291 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindMultiTextureEXT(e, c, rt, r, nu, ne, a, p) \
7293 pContext->peek_and_record_gl_error();
7294 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindMultiTextureEXT(e, c, rt, r, nu, ne, a, p) \
7295 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7296 pContext->bind_texture(target, texture);
7298 //----------------------------------------------------------------------------------------------------------------------
7299 // Framebuffer handle shadowing
7300 //----------------------------------------------------------------------------------------------------------------------
7301 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenFramebuffers(e, c, rt, r, nu, ne, a, p) \
7303 pContext->peek_and_record_gl_error();
7304 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenFramebuffers(e, c, rt, r, nu, ne, a, p) \
7305 if (pContext && !pContext->peek_and_record_gl_error()) \
7306 pContext->gen_framebuffers(n, framebuffers);
7308 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenFramebuffersEXT(e, c, rt, r, nu, ne, a, p) \
7310 pContext->peek_and_record_gl_error();
7311 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenFramebuffersEXT(e, c, rt, r, nu, ne, a, p) \
7312 if (pContext && !pContext->peek_and_record_gl_error()) \
7313 pContext->gen_framebuffers(n, framebuffers);
7315 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteFramebuffers(e, c, rt, r, nu, ne, a, p) \
7317 pContext->peek_and_record_gl_error();
7318 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteFramebuffers(e, c, rt, r, nu, ne, a, p) \
7319 if (pContext && !pContext->peek_and_record_gl_error()) \
7320 pContext->del_framebuffers(n, framebuffers);
7322 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteFramebuffersEXT(e, c, rt, r, nu, ne, a, p) \
7324 pContext->peek_and_record_gl_error();
7325 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteFramebuffersEXT(e, c, rt, r, nu, ne, a, p) \
7326 if (pContext && !pContext->peek_and_record_gl_error()) \
7327 pContext->del_framebuffers(n, framebuffers);
7329 //----------------------------------------------------------------------------------------------------------------------
7330 // VAO handle shadowing
7331 //----------------------------------------------------------------------------------------------------------------------
7332 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenVertexArrays(e, c, rt, r, nu, ne, a, p) \
7334 pContext->peek_and_record_gl_error();
7335 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenVertexArrays(e, c, rt, r, nu, ne, a, p) \
7336 if (pContext && !pContext->peek_and_record_gl_error()) \
7337 pContext->gen_vertexarrays(n, arrays);
7339 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteVertexArrays(e, c, rt, r, nu, ne, a, p) \
7341 pContext->peek_and_record_gl_error();
7342 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteVertexArrays(e, c, rt, r, nu, ne, a, p) \
7343 if (pContext && !pContext->peek_and_record_gl_error()) \
7344 pContext->del_vertexarrays(n, arrays);
7346 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBindVertexArray(e, c, rt, r, nu, ne, a, p) \
7348 pContext->peek_and_record_gl_error();
7349 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBindVertexArray(e, c, rt, r, nu, ne, a, p) \
7350 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7351 pContext->bind_vertexarray(array);
7353 //----------------------------------------------------------------------------------------------------------------------
7354 // Sync handle shadowing
7355 //----------------------------------------------------------------------------------------------------------------------
7356 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glFenceSync(e, c, rt, r, nu, ne, a, p) \
7358 pContext->peek_and_record_gl_error();
7359 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glFenceSync(e, c, rt, r, nu, ne, a, p) \
7360 if (pContext && !pContext->peek_and_record_gl_error()) \
7361 pContext->gen_sync(result);
7363 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteSync(e, c, rt, r, nu, ne, a, p) \
7365 pContext->peek_and_record_gl_error();
7366 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteSync(e, c, rt, r, nu, ne, a, p) \
7367 if (pContext && !pContext->peek_and_record_gl_error()) \
7368 pContext->del_sync(sync);
7370 //----------------------------------------------------------------------------------------------------------------------
7371 // Sampler object handle shadowing
7372 //----------------------------------------------------------------------------------------------------------------------
7373 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenSamplers(e, c, rt, r, nu, ne, a, p) \
7375 pContext->peek_and_record_gl_error();
7376 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenSamplers(e, c, rt, r, nu, ne, a, p) \
7377 if (pContext && !pContext->peek_and_record_gl_error()) \
7378 pContext->gen_samplers(count, samplers);
7380 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteSamplers(e, c, rt, r, nu, ne, a, p) \
7382 pContext->peek_and_record_gl_error();
7383 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteSamplers(e, c, rt, r, nu, ne, a, p) \
7384 if (pContext && !pContext->peek_and_record_gl_error()) \
7385 pContext->del_samplers(count, samplers);
7387 //----------------------------------------------------------------------------------------------------------------------
7388 // Query handle shadowing
7389 //----------------------------------------------------------------------------------------------------------------------
7390 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenQueries(e, c, rt, r, nu, ne, a, p) \
7392 pContext->peek_and_record_gl_error();
7393 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenQueries(e, c, rt, r, nu, ne, a, p) \
7394 if (pContext && !pContext->peek_and_record_gl_error()) \
7395 pContext->gen_queries(n, ids);
7397 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenQueriesARB(e, c, rt, r, nu, ne, a, p) \
7399 pContext->peek_and_record_gl_error();
7400 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenQueriesARB(e, c, rt, r, nu, ne, a, p) \
7401 if (pContext && !pContext->peek_and_record_gl_error()) \
7402 pContext->gen_queries(n, ids);
7404 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteQueries(e, c, rt, r, nu, ne, a, p) \
7406 pContext->peek_and_record_gl_error();
7407 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteQueries(e, c, rt, r, nu, ne, a, p) \
7408 if (pContext && !pContext->peek_and_record_gl_error()) \
7409 pContext->del_queries(n, ids);
7411 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteQueriesARB(e, c, rt, r, nu, ne, a, p) \
7413 pContext->peek_and_record_gl_error();
7414 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteQueriesARB(e, c, rt, r, nu, ne, a, p) \
7415 if (pContext && !pContext->peek_and_record_gl_error()) \
7416 pContext->del_queries(n, ids);
7418 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBeginQuery(e, c, rt, r, nu, ne, a, p) \
7420 pContext->peek_and_record_gl_error();
7421 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBeginQuery(e, c, rt, r, nu, ne, a, p) \
7422 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7423 pContext->begin_query(target, id);
7425 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBeginQueryARB(e, c, rt, r, nu, ne, a, p) \
7427 pContext->peek_and_record_gl_error();
7428 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBeginQueryARB(e, c, rt, r, nu, ne, a, p) \
7429 if (pContext && !pContext->peek_and_record_gl_error() && (pContext->get_current_display_list_mode() != GL_COMPILE)) \
7430 pContext->begin_query(target, id);
7432 //----------------------------------------------------------------------------------------------------------------------
7433 // Display list shadowing
7434 //----------------------------------------------------------------------------------------------------------------------
7435 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glGenLists(e, c, rt, r, nu, ne, a, p) \
7437 pContext->peek_and_record_gl_error();
7438 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glGenLists(e, c, rt, r, nu, ne, a, p) \
7439 if (pContext && !pContext->peek_and_record_gl_error()) \
7440 pContext->gen_lists(result, range);
7442 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glDeleteLists(e, c, rt, r, nu, ne, a, p) \
7444 pContext->peek_and_record_gl_error();
7445 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glDeleteLists(e, c, rt, r, nu, ne, a, p) \
7446 if (pContext && !pContext->peek_and_record_gl_error()) \
7447 pContext->del_lists(list, range);
7449 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glNewList(e, c, rt, r, nu, ne, a, p) \
7451 pContext->peek_and_record_gl_error();
7452 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glNewList(e, c, rt, r, nu, ne, a, p) \
7453 if (pContext && !pContext->peek_and_record_gl_error()) \
7454 pContext->new_list(list, mode);
7456 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glEndList(e, c, rt, r, nu, ne, a, p) \
7458 pContext->peek_and_record_gl_error();
7459 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glEndList(e, c, rt, r, nu, ne, a, p) \
7460 if (pContext && !pContext->peek_and_record_gl_error()) \
7461 pContext->end_list();
7463 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glXUseXFont(e, c, rt, r, nu, ne, a, p) \
7465 pContext->peek_and_record_gl_error();
7467 //----------------------------------------------------------------------------------------------------------------------
7468 // glBegin/glEnd shadowing
7469 //----------------------------------------------------------------------------------------------------------------------
7470 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glBegin(e, c, rt, r, nu, ne, a, p) \
7472 pContext->peek_and_record_gl_error();
7473 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glBegin(e, c, rt, r, nu, ne, a, p) \
7475 pContext->set_in_gl_begin(true);
7477 //#define DEF_FUNCTION_CUSTOM_GL_PROLOG_glEnd(e, c, rt, r, nu, ne, a, p)
7478 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glEnd(e, c, rt, r, nu, ne, a, p) \
7480 pContext->set_in_gl_begin(false);
7482 //----------------------------------------------------------------------------------------------------------------------
7483 // Program/shader shadowing
7484 //----------------------------------------------------------------------------------------------------------------------
7485 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glCreateProgram(e, c, rt, r, nu, ne, a, p) \
7487 result = pContext->handle_create_program(VOGL_ENTRYPOINT_##ne); \
7490 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glCreateProgramObjectARB(e, c, rt, r, nu, ne, a, p) \
7492 result = pContext->handle_create_program(VOGL_ENTRYPOINT_##ne); \
7496 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glCreateShader(e, c, rt, r, nu, ne, a, p) \
7498 result = pContext->handle_create_shader(VOGL_ENTRYPOINT_##ne, type); \
7501 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glCreateShaderObjectARB(e, c, rt, r, nu, ne, a, p) \
7503 result = pContext->handle_create_shader(VOGL_ENTRYPOINT_##ne, shaderType); \
7507 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glUseProgram(e, c, rt, r, nu, ne, a, p) \
7509 pContext->handle_use_program(VOGL_ENTRYPOINT_##ne, program);
7510 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glUseProgramObjectARB(e, c, rt, r, nu, ne, a, p) \
7512 pContext->handle_use_program(VOGL_ENTRYPOINT_##ne, programObj);
7514 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glDeleteShader(e, c, rt, r, nu, ne, a, p) \
7516 pContext->handle_del_shader(VOGL_ENTRYPOINT_##ne, shader);
7517 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glDeleteProgram(e, c, rt, r, nu, ne, a, p) \
7519 pContext->handle_del_program(VOGL_ENTRYPOINT_##ne, program);
7520 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glDeleteObjectARB(e, c, rt, r, nu, ne, a, p) \
7522 pContext->handle_del_object(VOGL_ENTRYPOINT_##ne, obj);
7524 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glDetachShader(e, c, rt, r, nu, ne, a, p) \
7526 pContext->handle_detach_shader(VOGL_ENTRYPOINT_##ne, program, shader);
7527 #define DEF_FUNCTION_CUSTOM_GL_CALLER_glDetachObjectARB(e, c, rt, r, nu, ne, a, p) \
7529 pContext->handle_detach_shader(VOGL_ENTRYPOINT_##ne, containerObj, attachedObj);
7531 //----------------------------------------------------------------------------------------------------------------------
7532 // Client side array usage detection
7533 //----------------------------------------------------------------------------------------------------------------------
7534 #define VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE \
7535 if ((!g_disable_client_side_array_tracing) && (pContext) && (pointer)) \
7536 vogl_check_for_client_side_array_usage(pContext, pointer);
7537 static inline void vogl_check_for_client_side_array_usage(vogl_context *pContext, const void *pPointer)
7539 VOGL_NOTE_UNUSED(pPointer);
7541 if (pContext->get_uses_client_side_arrays() || pContext->is_core_profile())
7544 pContext->peek_and_record_gl_error();
7546 GLint cur_array_buf_binding = 0;
7547 GL_ENTRYPOINT(glGetIntegerv)(GL_ARRAY_BUFFER_BINDING, &cur_array_buf_binding);
7549 if (pContext->peek_and_drop_gl_error() == GL_NO_ERROR)
7551 if (!cur_array_buf_binding)
7553 pContext->set_uses_client_side_arrays(true);
7554 vogl_warning_printf("%s: Client side array usage has been detected, this will negatively impact tracing performance, use --vogl_disable_client_side_array_tracing to disable\n", VOGL_FUNCTION_NAME);
7559 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7560 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glNormalPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7561 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glColorPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7562 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glIndexPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7563 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glTexCoordPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7564 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glEdgeFlagPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7565 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glFogCoordPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7566 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glSecondaryColorPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7567 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glInterleavedArrays(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7568 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7569 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glNormalPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7570 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glColorPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7571 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glIndexPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7572 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glTexCoordPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7573 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glEdgeFlagPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7574 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glFogCoordPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7575 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glSecondaryColorPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7576 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexAttribPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7577 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexAttribPointerARB(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7578 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexAttribPointerNV(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7579 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexAttribIPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7580 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexAttribIPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7581 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexAttribLPointer(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7582 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glVertexAttribLPointerEXT(e, c, rt, r, nu, ne, a, p) VOGL_CHECK_FOR_CLIENT_SIDE_ARRAY_USAGE
7584 //----------------------------------------------------------------------------------------------------------------------
7585 // glXUseXFont shadowing
7586 //----------------------------------------------------------------------------------------------------------------------
7587 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glXUseXFont(e, c, rt, r, nu, ne, a, p) vogl_glx_use_xfont_epilog_helper(pContext, trace_serializer, font, first, count, list_base);
7588 static void vogl_glx_use_xfont_epilog_helper(vogl_context *pContext, vogl_entrypoint_serializer &trace_serializer, Font font, int first, int count, int list_base)
7593 if (pContext->peek_and_record_gl_error())
7598 if (pContext->get_display())
7600 XFontStruct *pFont_struct = XQueryFont((Display *)pContext->get_display(), font);
7604 unsigned long value = 0;
7605 Bool result = XGetFontProperty(pFont_struct, XA_FONT, &value);
7608 pFont = (char *)XGetAtomName((Display *)pContext->get_display(), (Atom)value);
7609 if ((pFont) && (trace_serializer.is_in_begin()))
7611 trace_serializer.add_key_value("font_name", pFont);
7616 XFreeFontInfo(NULL, pFont_struct, 1);
7619 pContext->glx_font(pFont, first, count, list_base);
7622 //----------------------------------------------------------------------------------------------------------------------
7623 // vogl_display_list_bind_callback
7624 //----------------------------------------------------------------------------------------------------------------------
7625 static void vogl_display_list_bind_callback(vogl_namespace_t handle_namespace, GLenum target, GLuint handle, void *pOpaque)
7627 vogl_context *pContext = static_cast<vogl_context *>(pOpaque);
7629 // TODO: We don't whitelist anything but texture binds in display lists currently.
7630 switch (handle_namespace)
7632 case VOGL_NAMESPACE_TEXTURES:
7634 if ((handle) && (target != GL_NONE))
7635 pContext->bind_texture_conditionally(target, handle);
7640 vogl_warning_printf("%s: TODO: Unsupported bind in display list, namespace %s target %s handle %u\n", VOGL_FUNCTION_NAME, vogl_get_namespace_name(handle_namespace), g_gl_enums.find_gl_name(target), handle);
7646 //----------------------------------------------------------------------------------------------------------------------
7647 // glCallList shadowing
7648 //----------------------------------------------------------------------------------------------------------------------
7649 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glCallList(e, c, rt, r, nu, ne, a, p) \
7651 pContext->peek_and_record_gl_error();
7652 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glCallList(e, c, rt, r, nu, ne, a, p) \
7653 if (pContext && !pContext->peek_and_record_gl_error()) \
7654 vogl_gl_call_list_helper(pContext, list);
7655 static void vogl_gl_call_list_helper(vogl_context *pContext, GLuint list)
7660 pContext->parse_list_and_update_shadows(list, vogl_display_list_bind_callback, pContext);
7663 //----------------------------------------------------------------------------------------------------------------------
7664 // glCallLists shadowing
7665 //----------------------------------------------------------------------------------------------------------------------
7666 #define DEF_FUNCTION_CUSTOM_GL_PROLOG_glCallLists(e, c, rt, r, nu, ne, a, p) \
7668 pContext->peek_and_record_gl_error();
7669 #define DEF_FUNCTION_CUSTOM_GL_EPILOG_glCallLists(e, c, rt, r, nu, ne, a, p) \
7670 if (pContext && !pContext->peek_and_record_gl_error()) \
7671 vogl_gl_call_lists_helper(pContext, n, type, lists);
7672 static void vogl_gl_call_lists_helper(vogl_context *pContext, GLsizei n, GLenum type, const GLvoid *lists)
7677 vogl_scoped_gl_error_absorber gl_error_absorber(pContext);
7678 VOGL_NOTE_UNUSED(gl_error_absorber);
7680 pContext->parse_lists_and_update_shadows(n, type, lists, vogl_display_list_bind_callback, pContext);
7683 //----------------------------------------------------------------------------------------------------------------------
7684 // Ensure all entrypoints are fully serializable
7685 // This function MUST appear before #include "gl_glx_array_size_macros.inc", below
7686 //----------------------------------------------------------------------------------------------------------------------
7687 static void vogl_check_entrypoints()
7689 vogl_debug_printf("vogl_check_entrypoints: begin (specify --vogl_debug for more validation)\n");
7691 typedef vogl::hash_map<uint, dynamic_string> array_size_macro_hashmap;
7692 array_size_macro_hashmap defined_array_size_macros;
7693 array_size_macro_hashmap undefined_array_size_macros;
7695 #define CUSTOM_FUNC_HANDLER_DEFINED(id) g_vogl_entrypoint_descs[id].m_has_custom_func_handler = true; //printf("%u %s\n", id, g_vogl_entrypoint_descs[id].m_pName);
7696 #define CUSTOM_FUNC_HANDLER_NOT_DEFINED(id)
7697 #include "gl_glx_custom_func_handler_validator.inc"
7698 #undef CUSTOM_FUNC_HANDLER_DEFINED
7699 #undef CUSTOM_FUNC_HANDLER_NOT_DEFINED
7701 #define VALIDATE_ARRAY_SIZE_MACRO_DEFINED(name, index) defined_array_size_macros.insert(index, #name);
7702 #define VALIDATE_ARRAY_SIZE_MACRO_NOT_DEFINED(name, index) undefined_array_size_macros.insert(index, #name);
7703 #include "gl_glx_array_size_macros_validator.inc"
7704 #undef VALIDATE_ARRAY_SIZE_MACRO_DEFINED
7705 #undef VALIDATE_ARRAY_SIZE_MACRO_NOT_DEFINED
7707 vogl::vector<uint> undefined_func_return_array_size_macros;
7709 #define CUSTOM_FUNC_RETURN_PARAM_ARRAY_SIZE_HANDLER_DEFINED(macro_name, func_name)
7710 #define CUSTOM_FUNC_RETURN_PARAM_ARRAY_SIZE_HANDLER_NOT_DEFINED(macro_name, func_name) g_vogl_entrypoint_descs[VOGL_ENTRYPOINT_##func_name].m_custom_return_param_array_size_macro_is_missing = true;
7711 #include "gl_glx_custom_return_param_array_size_macro_validator.inc"
7712 #undef CUSTOM_FUNC_RETURN_PARAM_ARRAY_SIZE_HANDLER_DEFINED
7713 #undef CUSTOM_FUNC_RETURN_PARAM_ARRAY_SIZE_HANDLER_NOT_DEFINED
7715 if (vogl::check_for_command_line_param("--vogl_debug"))
7717 for (array_size_macro_hashmap::const_iterator it = undefined_array_size_macros.begin(); it != undefined_array_size_macros.end(); ++it)
7719 uint idx = it->first;
7720 const dynamic_string &name = it->second;
7721 VOGL_NOTE_UNUSED(name);
7723 gl_entrypoint_id_t func = static_cast<gl_entrypoint_id_t>(idx >> 16);
7724 uint param = idx & 0xFFFF;
7726 vogl_warning_printf("%s: Custom array size macro for func %u \"%s\" param %u has not been defined, this function cannot be traced\n",
7727 VOGL_FUNCTION_NAME, func, g_vogl_entrypoint_descs[func].m_pName, param);
7729 g_vogl_entrypoint_param_descs[func][param].m_custom_array_size_macro_is_missing = true;
7730 g_vogl_entrypoint_descs[func].m_custom_array_size_macro_is_missing = true;
7733 vogl_debug_printf("Undefined array size macros:\n");
7734 vogl_debug_printf("---\n");
7735 for (array_size_macro_hashmap::const_iterator it = undefined_array_size_macros.begin(); it != undefined_array_size_macros.end(); ++it)
7737 const dynamic_string &name = it->second;
7738 vogl_debug_printf("%s\n", name.get_ptr());
7740 vogl_debug_printf("---\n");
7742 vogl_debug_printf("Undefined return param array size macros:\n");
7743 vogl_debug_printf("---\n");
7744 for (uint i = 0; i < VOGL_NUM_ENTRYPOINTS; i++)
7746 vogl_ctype_t return_ctype = g_vogl_entrypoint_descs[i].m_return_ctype;
7748 if (return_ctype == VOGL_VOID)
7750 if (!g_vogl_process_gl_ctypes[return_ctype].m_is_pointer)
7752 //if (g_vogl_process_gl_ctypes[return_ctype].m_is_opaque_pointer)
7755 if (g_vogl_entrypoint_descs[i].m_custom_return_param_array_size_macro_is_missing)
7757 vogl_debug_printf("%s, opaque_ptr: %u\n", g_vogl_entrypoint_descs[i].m_pName, g_vogl_process_gl_ctypes[return_ctype].m_is_opaque_pointer);
7760 if (g_vogl_entrypoint_descs[i].m_whitelisted_for_displaylists)
7762 if (!g_vogl_entrypoint_descs[i].m_is_listable)
7764 vogl_debug_printf("Function %s is marked as whitelistable in display lists, but is not a listable function!\n", g_vogl_entrypoint_descs[i].m_pName);
7768 vogl_debug_printf("---\n");
7770 vogl_debug_printf("Whitelisted funcs with undefined array size macros:\n");
7771 vogl_debug_printf("---\n");
7772 for (uint i = 0; i < VOGL_NUM_ENTRYPOINTS; i++)
7774 const gl_entrypoint_desc_t &desc = g_vogl_entrypoint_descs[i];
7775 if ((!desc.m_is_whitelisted) || (desc.m_has_custom_func_handler))
7778 if (desc.m_custom_array_size_macro_is_missing)
7779 vogl_debug_printf("%s\n", desc.m_pName);
7781 vogl_debug_printf("---\n");
7783 vogl_debug_printf("Whitelisted funcs with undefined return param array size macros:\n");
7784 vogl_debug_printf("---\n");
7785 for (uint i = 0; i < VOGL_NUM_ENTRYPOINTS; i++)
7787 const gl_entrypoint_desc_t &desc = g_vogl_entrypoint_descs[i];
7788 if (desc.m_is_whitelisted)
7791 vogl_ctype_t return_ctype = g_vogl_entrypoint_descs[i].m_return_ctype;
7793 if (return_ctype == VOGL_VOID)
7795 if (!g_vogl_process_gl_ctypes[return_ctype].m_is_pointer)
7797 if (g_vogl_process_gl_ctypes[return_ctype].m_is_opaque_pointer)
7800 if (g_vogl_entrypoint_descs[i].m_custom_return_param_array_size_macro_is_missing)
7802 vogl_debug_printf("%s\n", g_vogl_entrypoint_descs[i].m_pName);
7806 vogl_debug_printf("---\n");
7809 vogl_debug_printf("vogl_check_entrypoints: done\n");
7812 //----------------------------------------------------------------------------------------------------------------------
7813 // Include generated macros to define the internal entrypoint funcs
7814 //----------------------------------------------------------------------------------------------------------------------
7815 #include "gl_glx_array_size_macros.inc"
7816 #include "gl_glx_func_return_param_array_size_macros.inc"
7817 #include "gl_glx_func_defs.inc"
7819 #ifndef NO_PUBLIC_EXPORTS
7820 //----------------------------------------------------------------------------------------------------------------------
7821 // Declare exported gl/glx functions (each exported func immediately calls one of the internal vogl_* functions)
7822 //----------------------------------------------------------------------------------------------------------------------
7823 #define DEF_PROTO_EXPORTED(ret, name, args, params) \
7824 VOGL_API_EXPORT ret name args \
7826 return VOGL_GLUER(vogl_, name) params; \
7828 #define DEF_PROTO_EXPORTED_VOID(ret, name, args, params) \
7829 VOGL_API_EXPORT ret name args \
7831 VOGL_GLUER(vogl_, name) params; \
7833 #define DEF_PROTO_INTERNAL(ret, name, args, params)
7834 #define DEF_PROTO_INTERNAL_VOID(ret, name, args, params)
7835 #define DEF_FUNCTION_BEGIN(exported, category, ret, ret_type_enum, num_params, name, args, params) exported(ret, name, args, params)
7836 #define DEF_FUNCTION_BEGIN_VOID(exported, category, ret, ret_type_enum, num_params, name, args, params) exported(ret, name, args, params)
7837 #define DEF_FUNCTION_INIT(exported, category, ret, ret_type_enum, num_params, name, args, params)
7838 #define DEF_FUNCTION_INIT_VOID(exported, category, ret, ret_type_enum, num_params, name, args, params)
7839 #define DEF_FUNCTION_INPUT_VALUE_PARAM(idx, spectype, type, type_enum, param)
7840 #define DEF_FUNCTION_INPUT_REFERENCE_PARAM(idx, spectype, type, type_enum, param)
7841 #define DEF_FUNCTION_INPUT_ARRAY_PARAM(idx, spectype, type, type_enum, param, size)
7842 #define DEF_FUNCTION_OUTPUT_REFERENCE_PARAM(idx, spectype, type, type_enum, param)
7843 #define DEF_FUNCTION_OUTPUT_ARRAY_PARAM(idx, spectype, type, type_enum, param, size)
7844 #define DEF_FUNCTION_RETURN_PARAM(spectype, type, type_enum, size)
7845 #define DEF_FUNCTION_CALL_GL(exported, category, ret, ret_type_enum, num_params, name, args, params)
7846 #define DEF_FUNCTION_CALL_GL_VOID(exported, category, ret, ret_type_enum, num_params, name, args, params)
7847 #define DEF_FUNCTION_END(exported, category, ret, ret_type_enum, num_params, name, args, params)
7848 #define DEF_FUNCTION_END_VOID(exported, category, ret, ret_type_enum, num_params, name, args, params)
7849 #define DEF_FUNCTION_PARAM_COMPUTE_ARRAY_SIZE_GL_ENUM(pname) -1
7851 #include "gl_glx_array_size_macros.inc"
7852 #include "gl_glx_func_defs.inc"
7855 //----------------------------------------------------------------------------------------------------------------------
7856 // Define our exported gliGetProcAddressRAD function
7857 //----------------------------------------------------------------------------------------------------------------------
7858 VOGL_API_EXPORT __GLXextFuncPtr gliGetProcAddressRAD(const GLubyte *procName)
7860 if ((procName) && (!vogl_strcmp(reinterpret_cast<const char *>(procName), "gliGetProcAddressRAD")))
7861 return (__GLXextFuncPtr)gliGetProcAddressRAD;
7863 return vogl_glXGetProcAddressARB(procName);
7866 //----------------------------------------------------------------------------------------------------------------------
7867 // Determine addresses of our gl/glx wrapper functions
7868 //----------------------------------------------------------------------------------------------------------------------
7869 static void vogl_init_wrapper_func_ptrs()
7871 gl_entrypoint_desc_t *pDst = g_vogl_entrypoint_descs;
7873 #define DEF_PROTO(exported, category, ret, ret_type, num_params, name, args, params) \
7874 pDst->m_pWrapper_func = reinterpret_cast<vogl_void_func_ptr_t>(vogl_##name); \
7876 #define DEF_PROTO_VOID(exported, category, ret, ret_type, num_params, name, args, params) \
7877 pDst->m_pWrapper_func = reinterpret_cast<vogl_void_func_ptr_t>(vogl_##name); \
7879 #include "gl_glx_protos.inc"
7881 #undef DEF_PROTO_VOID
7884 //----------------------------------------------------------------------------------------------------------------------
7885 // vogl_direct_gl_func_prolog - This function is called before EVERY single GL/GLX function call we make.
7886 //----------------------------------------------------------------------------------------------------------------------
7887 static void vogl_direct_gl_func_prolog(gl_entrypoint_id_t entrypoint_id, void *pUser_data, void **ppStack_data)
7889 VOGL_NOTE_UNUSED(entrypoint_id);
7890 VOGL_NOTE_UNUSED(pUser_data);
7892 if (g_dump_gl_calls_flag)
7893 printf("** GLPROLOG %s\n", g_vogl_entrypoint_descs[entrypoint_id].m_pName);
7895 gl_entrypoint_id_t *pPrev_state = reinterpret_cast<gl_entrypoint_id_t *>(ppStack_data);
7896 *pPrev_state = VOGL_ENTRYPOINT_INVALID;
7898 vogl_thread_local_data *pTLS_data = vogl_get_or_create_thread_local_data();
7901 *pPrev_state = pTLS_data->m_calling_driver_entrypoint_id;
7902 pTLS_data->m_calling_driver_entrypoint_id = entrypoint_id;
7906 //----------------------------------------------------------------------------------------------------------------------
7907 // vogl_direct_gl_func_epilog - This function is called immediately after EVERY single GL/GLX function call we make.
7908 //----------------------------------------------------------------------------------------------------------------------
7909 static void vogl_direct_gl_func_epilog(gl_entrypoint_id_t entrypoint_id, void *pUser_data, void **ppStack_data)
7911 VOGL_NOTE_UNUSED(entrypoint_id);
7912 VOGL_NOTE_UNUSED(pUser_data);
7915 if (entrypoint_id == VOGL_ENTRYPOINT_glXMakeCurrent)
7917 // HACK HACK - crude test of the "calling driver entrypoint code"
7918 glXGetCurrentContext();
7922 if (g_dump_gl_calls_flag)
7923 printf("** GLEPILOG %s\n", g_vogl_entrypoint_descs[entrypoint_id].m_pName);
7925 gl_entrypoint_id_t *pPrev_state = reinterpret_cast<gl_entrypoint_id_t *>(ppStack_data);
7927 vogl_thread_local_data *pTLS_data = vogl_get_or_create_thread_local_data();
7930 pTLS_data->m_calling_driver_entrypoint_id = *pPrev_state;
7934 //----------------------------------------------------------------------------------------------------------------------
7936 // Note: Be VERY careful what you do in here! It's called very early during init (long before main, during c++ init)
7937 //----------------------------------------------------------------------------------------------------------------------
7938 void vogl_early_init()
7940 vogl_init_thread_local_data();
7942 vogl_set_direct_gl_func_prolog(vogl_direct_gl_func_prolog, NULL);
7943 vogl_set_direct_gl_func_epilog(vogl_direct_gl_func_epilog, NULL);
7945 vogl_init_wrapper_func_ptrs();
7947 vogl_check_entrypoints();