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_gl_replayer.h
27 #ifndef VOGL_GL_REPLAYER_H
28 #define VOGL_GL_REPLAYER_H
30 #include "vogl_unique_ptr.h"
32 #include "vogl_common.h"
33 #include "vogl_trace_stream_types.h"
34 #include "vogl_trace_packet.h"
35 #include "vogl_trace_file_reader.h"
36 #include "vogl_context_info.h"
38 #include "vogl_replay_window.h"
39 #include "vogl_gl_state_snapshot.h"
40 #include "vogl_blob_manager.h"
42 // TODO: Make this a command line param
43 #define VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE (8U * 1024U * 1024U)
45 bool vogl_process_internal_trace_command_ctypes_packet(const key_value_map &kvm, const vogl_ctypes &ctypes);
47 //----------------------------------------------------------------------------------------------------------------------
48 // enum vogl_gl_replayer_flags
49 //----------------------------------------------------------------------------------------------------------------------
50 enum vogl_gl_replayer_flags
52 cGLReplayerSnapshotCaching = 0x00000001, // cache last X state snapshots
53 cGLReplayerBenchmarkMode = 0x00000002, // disable all glGetError()'s (*excluding* calls to glGetError in vogl_utils.cpp), disable all divergence checks
54 cGLReplayerVerboseMode = 0x00000004,
55 cGLReplayerForceDebugContexts = 0x00000008,
56 cGLReplayerDumpAllPackets = 0x00000010,
57 cGLReplayerDebugMode = 0x00000020,
58 cGLReplayerLockWindowDimensions = 0x00000040, // prevents replayer from ever changing the window dimensions (or waiting for the window to resize)
59 cGLReplayerLowLevelDebugMode = 0x00000080, // super low-level replayer debugging, slow
60 cGLReplayerDumpPacketBlobFilesOnError = 0x00000100,
61 cGLReplayerDumpShadersOnDraw = 0x00000200,
62 cGLReplayerDumpFramebufferOnDraws = 0x00000400,
63 cGLReplayerDumpPacketsOnError = 0x00000800,
64 cGLReplayerDumpScreenshots = 0x00001000,
65 cGLReplayerHashBackbuffer = 0x00002000,
66 cGLReplayerDumpBackbufferHashes = 0x00004000,
67 cGLReplayerSumHashing = 0x00008000
70 //----------------------------------------------------------------------------------------------------------------------
71 // class vogl_replayer
72 //----------------------------------------------------------------------------------------------------------------------
73 class vogl_gl_replayer
75 VOGL_NO_COPY_OR_ASSIGNMENT_OP(vogl_gl_replayer);
77 typedef vogl_trace_ptr_value vogl_trace_context_ptr_value;
78 typedef vogl_trace_ptr_value vogl_sync_ptr_value;
84 // The window must be opened before calling init().
85 bool init(uint flags, vogl_replay_window *pWindow, const vogl_trace_stream_start_of_file_packet &sof_packet, const vogl_blob_manager &blob_manager);
89 // Configuration: call after init().
91 void set_flags(uint flags)
95 uint get_flags() const
100 void set_swap_sleep_time(uint swap_sleep_time)
102 m_swap_sleep_time = swap_sleep_time;
104 uint get_swap_sleep_time() const
106 return m_swap_sleep_time;
109 const dynamic_string &get_dump_framebuffer_on_draw_prefix() const
111 return m_dump_framebuffer_on_draw_prefix;
113 void set_dump_framebuffer_on_draw_prefix(const dynamic_string &str)
115 m_dump_framebuffer_on_draw_prefix = str;
118 const dynamic_string &get_screenshot_prefix() const
120 return m_screenshot_prefix;
122 void set_screenshot_prefix(const dynamic_string &str)
124 m_screenshot_prefix = str;
127 const dynamic_string &get_backbuffer_hash_filename() const
129 return m_backbuffer_hash_filename;
131 void set_backbuffer_hash_filename(const dynamic_string &str)
133 m_backbuffer_hash_filename = str;
136 void set_dump_framebuffer_on_draw_frame_index(int64_t index)
138 m_dump_framebuffer_on_draw_frame_index = index;
140 int64_t get_dump_framebuffer_on_draw_frame_index() const
142 return m_dump_framebuffer_on_draw_frame_index;
145 void set_dump_framebuffer_on_draw_first_gl_call_index(int64_t index)
147 m_dump_framebuffer_on_draw_first_gl_call_index = index;
149 int64_t get_dump_framebuffer_on_draw_first_gl_call_index() const
151 return m_dump_framebuffer_on_draw_first_gl_call_index;
154 void set_dump_framebuffer_on_draw_last_gl_call_index(int64_t index)
156 m_dump_framebuffer_on_draw_last_gl_call_index = index;
158 int64_t get_dump_framebuffer_on_draw_last_gl_call_index() const
160 return m_dump_framebuffer_on_draw_last_gl_call_index;
163 bool is_valid() const
167 vogl_replay_window *get_window()
174 cStatusHardFailure = -3,
175 cStatusSoftFailure = -2,
183 // Call at the beginning of every frame to do internal housekeeping related to window resizing, which requires delaying all GL calls until the window system finishes resizing the window.
184 status_t process_pending_window_resize(bool *pApplied_snapshot = NULL);
186 // Processes the next packet in the trace file.
187 status_t process_next_packet(const vogl_trace_packet &gl_packet);
188 status_t process_next_packet(vogl_trace_file_reader &trace_reader);
190 // process_frame() calls process_next_packet() in a loop until the window must be resized, or until the next frame, or until the EOF or an error occurs.
191 status_t process_frame(vogl_trace_file_reader &trace_reader);
193 // Resets the replayer's state: kills all contexts, the pending snapshot, etc.
196 bool get_has_pending_window_resize() const
198 return m_pending_window_resize_width != 0;
200 uint get_pending_window_resize_width() const
202 return m_pending_window_resize_width;
204 uint get_pending_winow_resize_height() const
206 return m_pending_window_resize_height;
209 bool update_window_dimensions();
211 // Will cause a screenshot of the front buffer immediately before the next swap. This doesn't take the screenshot immediately because there may not be any active contents, depending on the state of replayer.
212 bool dump_frontbuffer_screenshot_before_next_swap(const dynamic_string &filename);
214 uint get_frame_index() const
216 return m_frame_index;
218 uint get_total_swaps() const
220 return m_total_swaps;
222 int64_t get_last_parsed_call_counter() const
224 return m_last_parsed_call_counter;
226 int64_t get_last_processed_call_counter() const
228 return m_last_processed_call_counter;
231 uint64_t get_frame_draw_counter() const
233 return m_frame_draw_counter;
236 bool get_at_frame_boundary() const
238 return m_at_frame_boundary;
241 // Caller must vogl_delete the snapshot.
242 vogl_gl_state_snapshot *snapshot_state(const vogl_trace_packet_array *pTrim_packets = NULL, bool optimize_snapshot = false);
244 status_t begin_applying_snapshot(const vogl_gl_state_snapshot *pSnapshot, bool delete_snapshot_after_applying);
245 const vogl_gl_state_snapshot *get_pending_apply_snapshot() const
247 return m_pPending_snapshot;
250 void set_frame_draw_counter_kill_threshold(uint64_t thresh)
252 m_frame_draw_counter_kill_threshold = thresh;
254 uint64_t get_frame_draw_counter_kill_threshold() const
256 return m_frame_draw_counter_kill_threshold;
259 const vogl_trace_stream_start_of_file_packet &get_sof_packet() const
264 // Will be updated after the ctypes packet is processed, otherwise it'll be invalid
265 const vogl_trace_packet &get_ctypes_packet() const
267 return m_ctypes_packet;
270 // Will be first updated at init(), then updated after the ctypes packet is processed
271 const vogl_ctypes &get_trace_gl_ctypes() const
273 return m_trace_gl_ctypes;
276 // If from_start_of_frame is true: Call at the very beginning of the frame to write a trim file containing trim_len frames.
277 // If from_start_of_frame is false: Call at any point to write a trim file starting at the current position with the current state.
278 enum write_trim_file_flags
280 cWriteTrimFileFromStartOfFrame = 1,
281 cWriteTrimFileOptimizeSnapshot = 2
284 bool write_trim_file(uint flags, const dynamic_string &trim_filename, uint trim_len, vogl_trace_file_reader &trace_reader, dynamic_string *pSnapshot_id = NULL);
287 status_t handle_ShaderSource(GLhandleARB trace_object,
289 const vogl_client_memory_array trace_strings_glchar_ptr_array,
290 const GLint *pTrace_lengths);
292 status_t post_draw_call();
294 bool dump_framebuffer(uint width, uint height, GLuint read_framebuffer, GLenum read_buffer, GLenum internal_format, uint orig_samples, GLuint replay_texture, GLuint replay_rbo);
295 void dump_current_framebuffer();
296 void dump_current_shaders();
299 uint m_swap_sleep_time;
300 dynamic_string m_dump_framebuffer_on_draw_prefix;
301 dynamic_string m_screenshot_prefix;
302 dynamic_string m_backbuffer_hash_filename;
303 int64_t m_dump_framebuffer_on_draw_frame_index;
304 int64_t m_dump_framebuffer_on_draw_first_gl_call_index;
305 int64_t m_dump_framebuffer_on_draw_last_gl_call_index;
307 dynamic_string m_dump_frontbuffer_filename;
309 vogl_trace_stream_start_of_file_packet m_sof_packet;
310 vogl_trace_packet m_ctypes_packet;
311 uint m_trace_pointer_size_in_bytes;
312 uint m_trace_pointer_size_in_uints;
314 vogl_ctypes m_trace_gl_ctypes;
316 // DO NOT refer to this packet while processing GL commands, use m_pCur_gl_packet.
317 vogl_trace_packet m_temp_gl_packet;
318 vogl_trace_packet m_temp2_gl_packet;
319 const vogl_trace_packet *m_pCur_gl_packet;
321 vogl_replay_window *m_pWindow;
323 vogl_trace_packet m_pending_make_current_packet;
325 uint m_pending_window_resize_width, m_pending_window_resize_height;
326 timer m_time_since_pending_window_resize;
327 uint m_pending_window_resize_attempt_counter;
331 int64_t m_last_parsed_call_counter;
332 int64_t m_last_processed_call_counter;
334 bool m_at_frame_boundary;
336 typedef vogl::hash_map<GLuint, GLuint> gl_handle_hash_map;
337 typedef vogl::hash_map<vogl_sync_ptr_value, GLsync, bit_hasher<vogl_sync_ptr_value> > gl_sync_hash_map;
339 typedef vogl::hash_map<GLint, GLint> uniform_location_hash_map;
340 struct glsl_program_state
342 // maps trace program locations to replay program locations
343 uniform_location_hash_map m_uniform_locations;
345 typedef vogl::hash_map<GLuint, glsl_program_state> glsl_program_hash_map;
349 VOGL_NO_COPY_OR_ASSIGNMENT_OP(context_state);
352 context_state(vogl_gl_replayer &replayer)
353 : m_replayer(replayer)
357 m_pShared_state = this;
361 m_last_call_counter = 0;
363 m_has_been_made_current = false;
364 m_inside_gl_begin = false;
367 m_replay_context = 0;
369 m_cur_replay_program = 0;
370 m_cur_trace_program = 0;
372 m_current_display_list_handle = -1;
373 m_current_display_list_mode = GL_NONE;
376 bool handle_context_made_current();
378 bool is_root_context() const
380 return m_pShared_state == this;
382 bool is_share_context() const
384 return m_pShared_state != this;
387 bool is_composing_display_list() const
389 return m_current_display_list_handle >= 0;
392 vogl_gl_replayer &m_replayer;
394 vogl_context_desc m_context_desc;
395 vogl_context_info m_context_info;
397 context_state *m_pShared_state;
401 uint64_t m_last_call_counter;
403 bool m_has_been_made_current;
404 bool m_inside_gl_begin;
406 vogl_trace_context_ptr_value m_trace_context;
407 GLXContext m_replay_context;
409 // maps trace to replay handles
410 gl_handle_hash_map m_framebuffers;
411 gl_handle_hash_map m_queries;
412 gl_handle_hash_map m_sampler_objects;
413 gl_handle_hash_map m_buffers;
414 gl_handle_hash_map m_buffer_targets; // maps trace handles to buffer targets
415 gl_handle_hash_map m_vertex_array_objects;
417 gl_handle_hash_map m_lists;
419 gl_sync_hash_map m_syncs;
421 // maps trace programs to glsl_program_state's
422 glsl_program_hash_map m_glsl_program_hash_map;
424 // maps replay query handles to the last active begin target
425 vogl_handle_hash_map m_query_targets;
427 gl_handle_hash_map m_arb_programs; // ARB_vertex_program/ARB_fragment_program, maps trace to replay handles
428 gl_handle_hash_map m_arb_program_targets; // maps trace programs to targets
430 GLuint m_cur_replay_program;
431 GLuint m_cur_trace_program;
433 vogl::vector<GLfloat> m_feedback_buffer;
434 vogl::vector<GLuint> m_select_buffer;
436 vogl_capture_context_params m_shadow_state;
438 int m_current_display_list_handle;
439 GLenum m_current_display_list_mode;
442 typedef vogl::hash_map<vogl_trace_context_ptr_value, context_state *, bit_hasher<vogl_trace_context_ptr_value> > context_hash_map; // maps trace to replay contexts
443 context_hash_map m_contexts;
445 vogl_trace_context_ptr_value m_cur_trace_context;
446 GLXContext m_cur_replay_context;
447 context_state *m_pCur_context_state;
449 context_state *get_context_state()
451 return m_pCur_context_state;
453 context_state *get_shared_state()
455 return m_pCur_context_state->m_pShared_state;
460 VOGL_MAX_SUPPORTED_GL_VERTEX_ATTRIBUTES = 32,
461 VOGL_MAX_SUPPORTED_GL_TEXCOORD_ARRAYS = 32
464 uint8_vec m_client_side_vertex_attrib_data[VOGL_MAX_SUPPORTED_GL_VERTEX_ATTRIBUTES];
465 uint8_vec m_client_side_array_data[VOGL_NUM_CLIENT_SIDE_ARRAY_DESCS];
466 uint8_vec m_client_side_texcoord_data[VOGL_MAX_SUPPORTED_GL_TEXCOORD_ARRAYS];
468 uint8_vec m_screenshot_buffer;
470 vogl::vector<uint8> m_index_data;
472 uint64_t m_frame_draw_counter;
473 uint64_t m_frame_draw_counter_kill_threshold;
477 const vogl_blob_manager *m_pBlob_manager;
479 const vogl_gl_state_snapshot *m_pPending_snapshot;
480 bool m_delete_pending_snapshot_after_applying;
482 // TODO: Make a 1st class snapshot cache class
483 struct snapshot_cache_entry
485 snapshot_cache_entry()
490 dynamic_string m_name;
491 vogl_gl_state_snapshot *m_pSnapshot;
493 typedef vogl::vector<snapshot_cache_entry> snapshot_vec;
494 snapshot_vec m_snapshots;
496 void dump_packet_as_func_call(const vogl_trace_packet &trace_packet);
497 void dump_trace_gl_packet_debug_info(const vogl_trace_gl_entrypoint_packet &gl_packet);
499 status_t trigger_pending_window_resize(uint win_width, uint win_height);
500 void clear_pending_window_resize();
501 status_t process_frame_check_for_pending_window_resize();
503 void destroy_pending_snapshot();
505 // Returns *true* if any errors occurred.
506 bool check_gl_error_internal(bool quietly = false, const char *pFile = "", uint line = 0, const char *pFunc = "");
507 #define check_gl_error() (((m_flags &cGLReplayerBenchmarkMode) == 0) ? check_gl_error_internal(false, __FILE__, __LINE__, __PRETTY_FUNCTION__) : false)
508 #define check_gl_error_quietly() (((m_flags &cGLReplayerBenchmarkMode) == 0) ? check_gl_error_internal(true, __FILE__, __LINE__, __PRETTY_FUNCTION__) : false)
510 void destroy_contexts();
511 void clear_contexts();
513 // from=replay, to=trace
514 class replay_to_trace_handle_remapper : public vogl_handle_remapper
516 vogl_gl_replayer &m_replayer;
518 // TODO: This searches the entire hash map! Slow!
519 bool remap_replay_to_trace_handle(const gl_handle_hash_map &hash_map, GLuint &handle) const
521 VOGL_ASSERT(hash_map.search_table_for_value_get_count(handle) <= 1);
523 gl_handle_hash_map::const_iterator it(hash_map.search_table_for_value(handle));
524 if (it != hash_map.end())
526 VOGL_ASSERT(it->second == handle);
534 replay_to_trace_handle_remapper(vogl_gl_replayer &replayer)
535 : m_replayer(replayer)
539 virtual bool is_default_remapper() const
544 virtual uint64_t remap_handle(vogl_namespace_t handle_namespace, uint64_t replay_handle);
546 virtual bool is_valid_handle(vogl_namespace_t handle_namespace, uint64_t replay_handle);
548 virtual int32 remap_location(uint32 replay_program, int32 replay_location);
550 virtual vogl_trace_ptr_value remap_vertex_attrib_ptr(uint index, vogl_trace_ptr_value ptr_val)
552 VOGL_NOTE_UNUSED(index);
556 virtual vogl_trace_ptr_value remap_vertex_array_ptr(vogl_client_side_array_desc_id_t id, uint index, vogl_trace_ptr_value ptr_val)
558 VOGL_NOTE_UNUSED(id);
559 VOGL_NOTE_UNUSED(index);
563 virtual bool determine_from_object_target(vogl_namespace_t handle_namespace, uint64_t replay_handle, GLenum &target);
565 virtual bool determine_to_object_target(vogl_namespace_t handle_namespace, uint64_t trace_handle, GLenum &target);
568 replay_to_trace_handle_remapper m_replay_to_trace_remapper;
570 // from=trace, to=replay
571 class trace_to_replay_handle_remapper : public vogl_handle_remapper
573 vogl_gl_replayer &m_replayer;
576 // Note: This used to also take a vogl_gl_state_snapshot ref
577 trace_to_replay_handle_remapper(vogl_gl_replayer &replayer)
578 : m_replayer(replayer)
582 virtual bool is_default_remapper() const
587 virtual uint64_t remap_handle(vogl_namespace_t handle_namespace, uint64_t from_handle);
589 virtual bool is_valid_handle(vogl_namespace_t handle_namespace, uint64_t replay_handle);
591 virtual int32 remap_location(uint32 trace_program, int32 from_location);
593 virtual vogl_trace_ptr_value remap_vertex_attrib_ptr(uint index, vogl_trace_ptr_value ptr_val);
595 virtual vogl_trace_ptr_value remap_vertex_array_ptr(vogl_client_side_array_desc_id_t id, uint index, vogl_trace_ptr_value ptr_val);
597 virtual void declare_handle(vogl_namespace_t handle_namespace, uint64_t from_handle, uint64_t to_handle, GLenum target);
599 virtual void delete_handle_and_object(vogl_namespace_t handle_namespace, uint64_t from_handle, uint64_t to_handle);
601 virtual void declare_location(uint32 from_program_handle, uint32 to_program_handle, int32 from_location, int32 to_location);
603 virtual bool determine_from_object_target(vogl_namespace_t handle_namespace, uint64_t trace_handle, GLenum &target);
605 virtual bool determine_to_object_target(vogl_namespace_t handle_namespace, uint64_t replay_handle, GLenum &target);
608 inline bool gen_handle(gl_handle_hash_map &handle_hash_map, GLuint trace_handle, GLuint replay_handle)
614 VOGL_ASSERT(!replay_handle);
620 process_entrypoint_error("%s: Handle gen failed during replay, but succeeded during trace! Trace handle: %u\n", VOGL_METHOD_NAME, trace_handle);
625 gl_handle_hash_map::insert_result result(handle_hash_map.insert(trace_handle, replay_handle));
628 process_entrypoint_error("%s: Replacing genned GL handle %u trace handle %u in handle hash map (this indicates a handle shadowing error)\n", VOGL_METHOD_NAME, replay_handle, trace_handle);
630 gl_handle_hash_map::iterator it = result.first;
631 it->second = replay_handle;
638 template <typename T>
639 inline bool gen_handles(gl_handle_hash_map &handle_hash_map, GLsizei n, const GLuint *pTrace_ids, T gl_gen_function, GLuint *pReplay_handles)
643 for (GLsizei i = 0; i < n; i++)
646 pReplay_handles[i] = 0;
651 GLuint replay_id = 0;
652 gl_gen_function(1, &replay_id);
656 process_entrypoint_error("%s: GL handle gen call failed, but succeeded in the trace!\n", VOGL_METHOD_NAME);
661 pReplay_handles[i] = replay_id;
663 gl_handle_hash_map::insert_result result(handle_hash_map.insert(pTrace_ids[i], replay_id));
666 process_entrypoint_error("%s: TODO: Replacing genned GL handle %u trace handle %u in handle hash map (this indicates a handle shadowing error)\n", VOGL_METHOD_NAME, replay_id, pTrace_ids[i]);
668 gl_handle_hash_map::iterator it = result.first;
669 it->second = replay_id;
676 template <typename T>
677 inline void delete_handles(gl_handle_hash_map &handle_hash_map, GLsizei trace_n, const GLuint *pTrace_ids, T gl_delete_function)
681 vogl::vector<GLuint> replay_ids;
682 replay_ids.reserve(trace_n);
684 for (int i = 0; i < trace_n; i++)
686 GLuint trace_id = pTrace_ids[i];
690 gl_handle_hash_map::const_iterator it(handle_hash_map.find(trace_id));
692 if (it != handle_hash_map.end())
694 replay_ids.push_back(it->second);
696 handle_hash_map.erase(pTrace_ids[i]);
700 replay_ids.push_back(trace_id);
702 process_entrypoint_warning("%s: Couldn't map trace GL handle %u to replay GL handle, using trace handle instead\n", VOGL_METHOD_NAME, pTrace_ids[i]);
706 if (replay_ids.size())
707 gl_delete_function(replay_ids.size(), replay_ids.get_ptr());
710 template <typename T>
711 inline void delete_handle(gl_handle_hash_map &handle_hash_map, GLuint trace_id, T gl_delete_function)
715 delete_handles(handle_hash_map, 1, &trace_id, gl_delete_function);
718 template <typename T>
719 inline bool gen_handles(vogl_handle_tracker &handle_tracker, GLsizei n, const GLuint *pTrace_ids, T gl_gen_function, GLuint *pReplay_handles, GLenum def_target)
723 for (GLsizei i = 0; i < n; i++)
726 pReplay_handles[i] = 0;
731 GLuint replay_id = 0;
732 gl_gen_function(1, &replay_id);
736 process_entrypoint_error("%s: GL handle gen call failed, but succeeded in the trace!\n", VOGL_METHOD_NAME);
741 pReplay_handles[i] = replay_id;
743 if (!handle_tracker.insert(pTrace_ids[i], replay_id, def_target))
745 process_entrypoint_error("%s: Replacing genned GL handle %u trace handle %u in handle hash map (this indicates a handle shadowing error)\n", VOGL_METHOD_NAME, replay_id, pTrace_ids[i]);
747 handle_tracker.erase(pTrace_ids[i]);
749 bool success = handle_tracker.insert(pTrace_ids[i], replay_id, def_target);
750 VOGL_ASSERT(success);
751 VOGL_NOTE_UNUSED(success);
758 inline bool gen_handle(vogl_handle_tracker &handle_tracker, const GLuint trace_id, GLuint replay_id, GLenum def_target)
764 VOGL_ASSERT(!replay_id);
768 if (!handle_tracker.insert(trace_id, replay_id, def_target))
770 process_entrypoint_error("%s: Replacing genned GL handle %u trace handle %u in handle hash map, namespace %s (this indicates a handle shadowing error)\n", VOGL_METHOD_NAME, replay_id, trace_id, vogl_get_namespace_name(handle_tracker.get_namespace()));
772 handle_tracker.erase(trace_id);
774 bool success = handle_tracker.insert(trace_id, replay_id, def_target);
775 VOGL_ASSERT(success);
776 VOGL_NOTE_UNUSED(success);
782 template <typename T>
783 inline void delete_handles(vogl_handle_tracker &handle_tracker, GLsizei trace_n, const GLuint *pTrace_ids, T gl_delete_function)
787 vogl::growable_array<GLuint, 32> replay_ids;
788 replay_ids.reserve(trace_n);
790 for (int i = 0; i < trace_n; i++)
792 GLuint trace_id = pTrace_ids[i];
796 GLuint replay_id = trace_id;
797 if (!handle_tracker.map_handle_to_inv_handle(trace_id, replay_id))
798 process_entrypoint_warning("%s: Couldn't map trace GL handle %u to replay GL handle, using trace handle instead, namespace %s\n", VOGL_METHOD_NAME, pTrace_ids[i], vogl_get_namespace_name(handle_tracker.get_namespace()));
800 handle_tracker.erase(trace_id);
802 replay_ids.push_back(replay_id);
805 if (replay_ids.size())
806 gl_delete_function(replay_ids.size(), replay_ids.get_ptr());
809 static void delete_program_helper(GLsizei n, const GLuint *pIDs)
813 for (GLsizei i = 0; i < n; i++)
814 GL_ENTRYPOINT(glDeleteProgram)(pIDs[i]);
817 static void delete_list_helper(GLsizei n, const GLuint *pIDs)
821 for (GLsizei i = 0; i < n; i++)
822 GL_ENTRYPOINT(glDeleteLists)(pIDs[i], 1);
825 // TODO: Closely examine each object type and set insert_if_not_found to true for the ones that don't really need to be genned (textures is already done)
826 inline GLuint map_handle(gl_handle_hash_map &handle_hash_map, GLuint trace_handle, bool insert_if_not_found = false)
833 gl_handle_hash_map::const_iterator it = handle_hash_map.find(trace_handle);
834 if (it == handle_hash_map.end())
836 process_entrypoint_warning("%s: Couldn't map trace GL handle %u to GL handle, using trace handle instead (handle may not have been genned)\n", VOGL_METHOD_NAME, trace_handle);
838 if (insert_if_not_found)
839 handle_hash_map.insert(trace_handle, trace_handle);
847 inline bool map_handle(vogl_handle_tracker &handle_tracker, GLuint trace_handle, GLuint &replay_handle)
851 replay_handle = trace_handle;
856 if (!handle_tracker.map_handle_to_inv_handle(trace_handle, replay_handle))
858 process_entrypoint_warning("%s: Couldn't map trace GL handle %u to GL handle, using trace handle instead (handle may not have been genned), namespace: %s\n", VOGL_METHOD_NAME, trace_handle, vogl_get_namespace_name(handle_tracker.get_namespace()));
865 inline GLuint map_handle(vogl_handle_tracker &handle_tracker, GLuint trace_handle, bool *pSuccess = NULL)
876 GLuint replay_handle = trace_handle;
877 if (!handle_tracker.map_handle_to_inv_handle(trace_handle, replay_handle))
881 process_entrypoint_warning("%s: Couldn't map trace GL handle %u to GL handle, using trace handle instead (handle may not have been genned), namespace: %s\n", VOGL_METHOD_NAME, trace_handle, vogl_get_namespace_name(handle_tracker.get_namespace()));
882 return replay_handle;
887 return replay_handle;
890 inline context_state *get_trace_context_state(vogl_trace_context_ptr_value trace_context)
897 context_hash_map::iterator it = m_contexts.find(trace_context);
898 return (it == m_contexts.end()) ? NULL : it->second;
901 context_state *define_new_context(vogl_trace_context_ptr_value trace_context, GLXContext replay_context, vogl_trace_context_ptr_value trace_share_context, GLboolean direct, gl_entrypoint_id_t creation_func, const int *pAttrib_list, uint attrib_list_size);
903 GLXContext remap_context(vogl_trace_context_ptr_value trace_context);
905 bool destroy_context(vogl_trace_context_ptr_value trace_context);
907 // glVertexPointer, glNormalPointer, etc. client side data
908 bool set_client_side_array_data(const key_value_map &map, GLuint start, GLuint end, GLuint basevertex);
910 // glVertexAttrib client side data
911 bool set_client_side_vertex_attrib_array_data(const key_value_map &map, GLuint start, GLuint end, GLuint basevertex);
913 bool draw_elements_client_side_array_setup(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, vogl_trace_ptr_value trace_indices_ptr_value, const GLvoid *&pIndices, GLint basevertex, bool has_valid_start_end, bool indexed);
915 GLint determine_uniform_replay_location(GLuint trace_program, GLint trace_location);
917 inline GLint determine_uniform_replay_location(GLint trace_location)
919 return determine_uniform_replay_location(m_pCur_context_state->m_cur_trace_program, trace_location);
922 template <uint N, class T, class F>
923 inline void set_uniformv_helper(F func)
927 GLint replay_location = determine_uniform_replay_location(m_pCur_gl_packet->get_param_value<GLint>(0));
929 GLsizei count = m_pCur_gl_packet->get_param_value<GLsizei>(1);
930 const T *pValues = m_pCur_gl_packet->get_param_client_memory<T>(2);
931 VOGL_ASSERT((uint)m_pCur_gl_packet->get_param_client_memory_data_size(2) == sizeof(T) * N * count);
933 func(replay_location, count, pValues);
936 template <uint C, uint R, class T, class F>
937 inline void set_uniform_matrixv_helper(F func)
941 GLint replay_location = determine_uniform_replay_location(m_pCur_gl_packet->get_param_value<GLint>(0));
943 GLsizei count = m_pCur_gl_packet->get_param_value<GLsizei>(1);
944 GLboolean transpose = m_pCur_gl_packet->get_param_value<GLboolean>(2);
945 const T *pValues = m_pCur_gl_packet->get_param_client_memory<T>(3);
946 VOGL_ASSERT((uint)m_pCur_gl_packet->get_param_client_memory_data_size(3) == sizeof(T) * C * R * count);
948 func(replay_location, count, transpose, pValues);
951 // glUniform* helpers
952 template <class T, class F>
953 inline void set_uniform_helper1(F func)
957 func(determine_uniform_replay_location(m_pCur_gl_packet->get_param_value<GLint>(0)), m_pCur_gl_packet->get_param_value<T>(1));
960 template <class T, class F>
961 inline void set_uniform_helper2(F func)
965 func(determine_uniform_replay_location(m_pCur_gl_packet->get_param_value<GLint>(0)), m_pCur_gl_packet->get_param_value<T>(1), m_pCur_gl_packet->get_param_value<T>(2));
968 template <class T, class F>
969 inline void set_uniform_helper3(F func)
973 func(determine_uniform_replay_location(m_pCur_gl_packet->get_param_value<GLint>(0)), m_pCur_gl_packet->get_param_value<T>(1), m_pCur_gl_packet->get_param_value<T>(2), m_pCur_gl_packet->get_param_value<T>(3));
976 template <class T, class F>
977 inline void set_uniform_helper4(F func)
981 func(determine_uniform_replay_location(m_pCur_gl_packet->get_param_value<GLint>(0)), m_pCur_gl_packet->get_param_value<T>(1), m_pCur_gl_packet->get_param_value<T>(2), m_pCur_gl_packet->get_param_value<T>(3), m_pCur_gl_packet->get_param_value<T>(4));
984 // glSetProgramUniform* helpers
985 template <class T, class F>
986 inline void set_program_uniform_helper1(F func)
990 GLuint trace_handle = m_pCur_gl_packet->get_param_value<GLuint>(0);
991 GLuint replay_handle = map_handle(m_pCur_context_state->m_pShared_state->m_shadow_state.m_objs, trace_handle);
992 func(replay_handle, determine_uniform_replay_location(trace_handle, m_pCur_gl_packet->get_param_value<GLint>(1)), m_pCur_gl_packet->get_param_value<T>(2));
995 template <class T, class F>
996 inline void set_program_uniform_helper2(F func)
1000 GLuint trace_handle = m_pCur_gl_packet->get_param_value<GLuint>(0);
1001 GLuint replay_handle = map_handle(m_pCur_context_state->m_pShared_state->m_shadow_state.m_objs, trace_handle);
1002 func(replay_handle, determine_uniform_replay_location(trace_handle, m_pCur_gl_packet->get_param_value<GLint>(1)), m_pCur_gl_packet->get_param_value<T>(2), m_pCur_gl_packet->get_param_value<T>(3));
1005 template <class T, class F>
1006 inline void set_program_uniform_helper3(F func)
1010 GLuint trace_handle = m_pCur_gl_packet->get_param_value<GLuint>(0);
1011 GLuint replay_handle = map_handle(m_pCur_context_state->m_pShared_state->m_shadow_state.m_objs, trace_handle);
1012 func(replay_handle, determine_uniform_replay_location(trace_handle, m_pCur_gl_packet->get_param_value<GLint>(1)), m_pCur_gl_packet->get_param_value<T>(2), m_pCur_gl_packet->get_param_value<T>(3), m_pCur_gl_packet->get_param_value<T>(4));
1015 template <class T, class F>
1016 inline void set_program_uniform_helper4(F func)
1020 GLuint trace_handle = m_pCur_gl_packet->get_param_value<GLuint>(0);
1021 GLuint replay_handle = map_handle(m_pCur_context_state->m_pShared_state->m_shadow_state.m_objs, trace_handle);
1022 func(replay_handle, determine_uniform_replay_location(trace_handle, m_pCur_gl_packet->get_param_value<GLint>(1)), m_pCur_gl_packet->get_param_value<T>(2), m_pCur_gl_packet->get_param_value<T>(3), m_pCur_gl_packet->get_param_value<T>(4), m_pCur_gl_packet->get_param_value<T>(5));
1025 template <uint C, uint R, class T, class F>
1026 inline void set_program_uniform_matrixv_helper(F func)
1030 GLuint trace_handle = m_pCur_gl_packet->get_param_value<GLuint>(0);
1031 GLuint replay_handle = map_handle(m_pCur_context_state->m_pShared_state->m_shadow_state.m_objs, trace_handle);
1033 GLint replay_location = determine_uniform_replay_location(trace_handle, m_pCur_gl_packet->get_param_value<GLint>(1));
1035 GLsizei count = m_pCur_gl_packet->get_param_value<GLsizei>(2);
1036 GLboolean transpose = m_pCur_gl_packet->get_param_value<GLboolean>(3);
1037 const T *pValues = m_pCur_gl_packet->get_param_client_memory<T>(4);
1038 VOGL_ASSERT((uint)m_pCur_gl_packet->get_param_client_memory_data_size(4) == sizeof(T) * C * R * count);
1040 func(replay_handle, replay_location, count, transpose, pValues);
1043 template <uint N, class T, class F>
1044 inline void set_program_uniformv_helper(F func)
1048 GLuint trace_handle = m_pCur_gl_packet->get_param_value<GLuint>(0);
1049 GLuint replay_handle = map_handle(m_pCur_context_state->m_pShared_state->m_shadow_state.m_objs, trace_handle);
1051 GLint replay_location = determine_uniform_replay_location(trace_handle, m_pCur_gl_packet->get_param_value<GLint>(1));
1053 GLsizei count = m_pCur_gl_packet->get_param_value<GLsizei>(2);
1054 const T *pValues = m_pCur_gl_packet->get_param_client_memory<T>(3);
1056 VOGL_ASSERT((uint)m_pCur_gl_packet->get_param_client_memory_data_size(3) == sizeof(T) * N * count);
1058 func(replay_handle, replay_location, count, pValues);
1061 static void delete_objects_arb(GLsizei n, const GLuint *pHandles)
1065 for (GLsizei i = 0; i < n; i++)
1066 GL_ENTRYPOINT(glDeleteObjectARB)(pHandles[i]);
1069 template <typename T, typename F>
1070 inline status_t get_vertex_attrib_helper(F entrypoint)
1072 if (benchmark_mode())
1077 GLint index = m_pCur_gl_packet->get_param_value<GLint>(0);
1078 GLenum pname = m_pCur_gl_packet->get_param_value<GLenum>(1);
1079 const T *pTrace_params = m_pCur_gl_packet->get_param_client_memory<const T>(2);
1080 uint num_trace_params = m_pCur_gl_packet->get_param_client_memory_data_size(2) / sizeof(T);
1082 int n = g_gl_enums.get_pname_count(pname);
1085 process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
1086 return cStatusSoftFailure;
1089 vogl::vector<T> params(n);
1090 entrypoint(index, pname, params.get_ptr());
1092 if (num_trace_params < static_cast<uint>(n))
1094 process_entrypoint_error("%s: Was expecting at least %u params for GL pname 0x%08X, but only got %u params in the trace\n", VOGL_METHOD_NAME, n, pname, num_trace_params);
1095 return cStatusSoftFailure;
1097 else if (!pTrace_params)
1099 process_entrypoint_error("%s: Trace has NULL params field, can't diff trace vs. replay's params\n", VOGL_METHOD_NAME);
1100 return cStatusSoftFailure;
1104 if (memcmp(pTrace_params, params.get_ptr(), n * sizeof(T)) != 0)
1106 process_entrypoint_error("%s: Replay's results differ from trace's\n", VOGL_METHOD_NAME);
1107 return cStatusSoftFailure;
1114 template <typename F>
1115 inline void vertex_array_helper(
1116 GLint size, GLenum type, GLsizei stride, vogl_trace_ptr_value trace_pointer,
1117 vogl_client_side_array_desc_id_t id, F func, uint8_vec &array_data)
1121 const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[id];
1122 VOGL_NOTE_UNUSED(desc);
1124 GLuint buffer = vogl_get_bound_gl_buffer(GL_ARRAY_BUFFER);
1126 GLvoid *pPtr = reinterpret_cast<GLvoid *>(trace_pointer);
1127 if ((!buffer) && (trace_pointer))
1129 // We've got a trace pointer to client side memory, but we don't have it until the actual draw.
1130 // So point this guy into one of our client size memory buffers that's hopefully large enough.
1131 if (!array_data.size())
1133 array_data.resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
1135 pPtr = array_data.get_ptr();
1138 func(size, type, stride, pPtr);
1141 template <typename F>
1142 inline void vertex_array_helper_count(
1143 GLint size, GLenum type, GLsizei stride, GLsizei count, vogl_trace_ptr_value trace_pointer,
1144 vogl_client_side_array_desc_id_t id, F func, uint8_vec &array_data)
1148 const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[id];
1149 VOGL_NOTE_UNUSED(desc);
1151 GLuint buffer = vogl_get_bound_gl_buffer(GL_ARRAY_BUFFER);
1153 GLvoid *pPtr = reinterpret_cast<GLvoid *>(trace_pointer);
1154 if ((!buffer) && (trace_pointer))
1156 // We've got a trace pointer to client side memory, but we don't have it until the actual draw.
1157 // So point this guy into one of our client size memory buffers that's hopefully large enough.
1158 if (!array_data.size())
1160 array_data.resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
1162 pPtr = array_data.get_ptr();
1165 func(size, type, stride, count, pPtr);
1168 template <typename F>
1169 inline void vertex_array_helper_no_size(
1170 GLenum type, GLsizei stride, vogl_trace_ptr_value trace_pointer,
1171 vogl_client_side_array_desc_id_t id, F func)
1175 const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[id];
1176 VOGL_NOTE_UNUSED(desc);
1178 GLuint buffer = vogl_get_bound_gl_buffer(GL_ARRAY_BUFFER);
1179 GLvoid *pPtr = reinterpret_cast<GLvoid *>(trace_pointer);
1180 if ((!buffer) && (trace_pointer))
1182 // We've got a trace pointer to client side memory, but we don't have it until the actual draw.
1183 // So point this guy into one of our client size memory buffers that's hopefully large enough.
1184 if (!m_client_side_array_data[id].size())
1186 m_client_side_array_data[id].resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
1188 pPtr = m_client_side_array_data[id].get_ptr();
1191 func(type, stride, pPtr);
1194 template <typename F>
1195 inline void vertex_array_helper_no_size_count(
1196 GLenum type, GLsizei stride, GLsizei count, vogl_trace_ptr_value trace_pointer,
1197 vogl_client_side_array_desc_id_t id, F func)
1201 const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[id];
1202 VOGL_NOTE_UNUSED(desc);
1204 GLuint buffer = vogl_get_bound_gl_buffer(GL_ARRAY_BUFFER);
1205 GLvoid *pPtr = reinterpret_cast<GLvoid *>(trace_pointer);
1206 if ((!buffer) && (trace_pointer))
1208 // We've got a trace pointer to client side memory, but we don't have it until the actual draw.
1209 // So point this guy into one of our client size memory buffers that's hopefully large enough.
1210 if (!m_client_side_array_data[id].size())
1212 m_client_side_array_data[id].resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
1214 pPtr = m_client_side_array_data[id].get_ptr();
1217 func(type, stride, count, pPtr);
1220 template <typename F>
1221 inline void vertex_array_helper_no_type_no_size(
1222 GLsizei stride, vogl_trace_ptr_value trace_pointer,
1223 vogl_client_side_array_desc_id_t id, F func)
1227 const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[id];
1228 VOGL_NOTE_UNUSED(desc);
1230 GLuint buffer = vogl_get_bound_gl_buffer(GL_ARRAY_BUFFER);
1231 GLvoid *pPtr = reinterpret_cast<GLvoid *>(trace_pointer);
1232 if ((!buffer) && (trace_pointer))
1234 // We've got a trace pointer to client side memory, but we don't have it until the actual draw.
1235 // So point this guy into one of our client size memory buffers that's hopefully large enough.
1236 if (!m_client_side_array_data[id].size())
1238 m_client_side_array_data[id].resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
1240 pPtr = m_client_side_array_data[id].get_ptr();
1246 template <typename F>
1247 inline void vertex_array_helper_no_type_no_size_count(
1248 GLsizei stride, GLsizei count, vogl_trace_ptr_value trace_pointer,
1249 vogl_client_side_array_desc_id_t id, F func)
1253 const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[id];
1254 VOGL_NOTE_UNUSED(desc);
1256 GLuint buffer = vogl_get_bound_gl_buffer(GL_ARRAY_BUFFER);
1257 GLvoid *pPtr = reinterpret_cast<GLvoid *>(trace_pointer);
1258 if ((!buffer) && (trace_pointer))
1260 // We've got a trace pointer to client side memory, but we don't have it until the actual draw.
1261 // So point this guy into one of our client size memory buffers that's hopefully large enough.
1262 if (!m_client_side_array_data[id].size())
1264 m_client_side_array_data[id].resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
1266 pPtr = m_client_side_array_data[id].get_ptr();
1269 func(stride, count, static_cast<const GLchar *>(pPtr));
1272 void process_entrypoint_print_summary_context(eConsoleMessageType msg_type);
1273 void print_detailed_context(eConsoleMessageType msg_type);
1274 void process_entrypoint_msg_print_detailed_context(eConsoleMessageType msg_type);
1275 void process_entrypoint_info(const char *pFmt, ...) VOGL_ATTRIBUTE_PRINTF(2, 3);
1276 void process_entrypoint_message(const char *pFmt, ...) VOGL_ATTRIBUTE_PRINTF(2, 3);
1277 void process_entrypoint_warning(const char *pFmt, ...) VOGL_ATTRIBUTE_PRINTF(2, 3);
1278 void process_entrypoint_error(const char *pFmt, ...) VOGL_ATTRIBUTE_PRINTF(2, 3);
1280 status_t switch_contexts(vogl_trace_context_ptr_value trace_context);
1282 // Loosely derived from http://www.altdevblogaday.com/2011/06/23/improving-opengl-error-messages/
1283 static void debug_callback_arb(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, GLvoid *pUser_param);
1284 static void debug_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, GLvoid *pUser_param);
1286 bool is_extension_supported(const char *pExt);
1288 bool handle_context_made_current();
1290 void dump_context_attrib_list(const int *pAttrib_list, uint size);
1292 int find_attrib_key(const vogl::vector<int> &attrib_list, int key_to_find);
1294 status_t create_context_attribs(
1295 vogl_trace_context_ptr_value trace_context, Display *dpy, GLXFBConfig config, vogl_trace_context_ptr_value trace_share_context, GLXContext replay_share_context, Bool direct,
1296 const int *pTrace_attrib_list, int trace_attrib_list_size, bool expecting_attribs);
1298 status_t process_pending_make_current();
1300 status_t process_internal_trace_command(const vogl_trace_gl_entrypoint_packet &gl_packet);
1302 void snapshot_backbuffer();
1304 bool check_program_binding_shadow();
1305 void handle_use_program(GLuint trace_handle, gl_entrypoint_id_t entrypoint_id);
1306 void handle_delete_program(GLuint trace_handle);
1307 void handle_delete_shader(GLuint trace_handle);
1308 void handle_detach_shader(gl_entrypoint_id_t entrypoint_id);
1309 void handle_link_program(gl_entrypoint_id_t entrypoint_id);
1311 static void display_list_bind_callback(vogl_namespace_t handle_namespace, GLenum target, GLuint handle, void *pOpaque);
1313 status_t restore_context(vogl_handle_remapper &trace_to_replay_remapper, const vogl_gl_state_snapshot &snapshot, const vogl_context_snapshot &context_snapshot);
1314 status_t restore_objects(vogl_handle_remapper &trace_to_replay_remapper, const vogl_gl_state_snapshot &snapshot, const vogl_context_snapshot &context_state, vogl_gl_object_state_type state_type, vogl_const_gl_object_state_ptr_vec &objects_to_delete);
1315 vogl_gl_replayer::status_t restore_display_lists(vogl_handle_remapper &trace_to_replay_remapper, const vogl_gl_state_snapshot &snapshot, const vogl_context_snapshot &context_snapshot);
1316 status_t restore_general_state(vogl_handle_remapper &trace_to_replay_remapper, const vogl_gl_state_snapshot &snapshot, const vogl_context_snapshot &context_snapshot);
1317 status_t update_context_shadows(vogl_handle_remapper &trace_to_replay_remapper, const vogl_gl_state_snapshot &snapshot, const vogl_context_snapshot &context_snapshot);
1318 void handle_marked_for_deleted_objects(vogl_const_gl_object_state_ptr_vec &objects_to_delete, trace_to_replay_handle_remapper &trace_to_replay_remapper);
1319 bool determine_used_program_handles(const vogl_trace_packet_array &trim_packets, vogl_handle_hash_set &replay_program_handles);
1321 vogl_gl_replayer::status_t process_applying_pending_snapshot();
1322 bool validate_program_and_shader_handle_tables();
1323 bool validate_textures();
1325 void fill_replay_handle_hash_set(vogl_handle_hash_set &replay_handle_hash, const gl_handle_hash_map &trace_to_replay_hash);
1327 // write_trim_file_internal() may modify trim_packets
1328 bool write_trim_file_internal(vogl_trace_packet_array &trim_packets, const dynamic_string &trim_filename, vogl_trace_file_reader &trace_reader, bool optimize_snapshot, dynamic_string *pSnapshot_id);
1330 bool dump_frontbuffer_to_file(const dynamic_string &filename);
1332 bool benchmark_mode() const
1334 return (m_flags & cGLReplayerBenchmarkMode) != 0;
1337 // DO NOT make these methods public
1338 status_t process_gl_entrypoint_packet(vogl_trace_packet& trace_packet);
1339 status_t process_gl_entrypoint_packet_internal(vogl_trace_packet &trace_packet);
1342 #endif // VOGL_GL_REPLAYER_H