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;
347 struct mapped_buffer_desc
351 vogl_trace_ptr_value m_offset;
352 vogl_trace_ptr_value m_length;
360 VOGL_NO_COPY_OR_ASSIGNMENT_OP(context_state);
363 context_state(vogl_gl_replayer &replayer)
364 : m_replayer(replayer)
368 m_pShared_state = this;
372 m_last_call_counter = 0;
374 m_has_been_made_current = false;
375 m_inside_gl_begin = false;
378 m_replay_context = 0;
380 m_cur_replay_program = 0;
381 m_cur_trace_program = 0;
383 m_current_display_list_handle = -1;
384 m_current_display_list_mode = GL_NONE;
387 bool handle_context_made_current();
389 bool is_root_context() const
391 return m_pShared_state == this;
393 bool is_share_context() const
395 return m_pShared_state != this;
398 bool is_composing_display_list() const
400 return m_current_display_list_handle >= 0;
403 vogl_gl_replayer &m_replayer;
405 vogl_context_desc m_context_desc;
406 vogl_context_info m_context_info;
408 context_state *m_pShared_state;
412 uint64_t m_last_call_counter;
414 bool m_has_been_made_current;
415 bool m_inside_gl_begin;
417 vogl_trace_context_ptr_value m_trace_context;
418 GLXContext m_replay_context;
420 // maps trace to replay handles
421 gl_handle_hash_map m_framebuffers;
422 gl_handle_hash_map m_queries;
423 gl_handle_hash_map m_sampler_objects;
424 gl_handle_hash_map m_buffers;
425 gl_handle_hash_map m_buffer_targets; // maps trace handles to buffer targets
426 gl_handle_hash_map m_vertex_array_objects;
428 gl_handle_hash_map m_lists;
430 gl_sync_hash_map m_syncs;
432 // maps trace programs to glsl_program_state's
433 glsl_program_hash_map m_glsl_program_hash_map;
435 // maps replay query handles to the last active begin target
436 vogl_handle_hash_map m_query_targets;
438 gl_handle_hash_map m_arb_programs; // ARB_vertex_program/ARB_fragment_program, maps trace to replay handles
439 gl_handle_hash_map m_arb_program_targets; // maps trace programs to targets
441 GLuint m_cur_replay_program;
442 GLuint m_cur_trace_program;
444 vogl::vector<mapped_buffer_desc> m_mapped_buffers;
446 vogl::vector<GLfloat> m_feedback_buffer;
447 vogl::vector<GLuint> m_select_buffer;
449 vogl_capture_context_params m_shadow_state;
451 int m_current_display_list_handle;
452 GLenum m_current_display_list_mode;
455 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
456 context_hash_map m_contexts;
458 vogl_trace_context_ptr_value m_cur_trace_context;
459 GLXContext m_cur_replay_context;
460 context_state *m_pCur_context_state;
462 context_state *get_context_state()
464 return m_pCur_context_state;
466 context_state *get_shared_state()
468 return m_pCur_context_state->m_pShared_state;
473 VOGL_MAX_SUPPORTED_GL_VERTEX_ATTRIBUTES = 32,
474 VOGL_MAX_SUPPORTED_GL_TEXCOORD_ARRAYS = 32
477 uint8_vec m_client_side_vertex_attrib_data[VOGL_MAX_SUPPORTED_GL_VERTEX_ATTRIBUTES];
478 uint8_vec m_client_side_array_data[VOGL_NUM_CLIENT_SIDE_ARRAY_DESCS];
479 uint8_vec m_client_side_texcoord_data[VOGL_MAX_SUPPORTED_GL_TEXCOORD_ARRAYS];
481 uint8_vec m_screenshot_buffer;
483 vogl::vector<uint8> m_index_data;
485 uint64_t m_frame_draw_counter;
486 uint64_t m_frame_draw_counter_kill_threshold;
490 const vogl_blob_manager *m_pBlob_manager;
492 const vogl_gl_state_snapshot *m_pPending_snapshot;
493 bool m_delete_pending_snapshot_after_applying;
495 // TODO: Make a 1st class snapshot cache class
496 struct snapshot_cache_entry
498 snapshot_cache_entry()
503 dynamic_string m_name;
504 vogl_gl_state_snapshot *m_pSnapshot;
506 typedef vogl::vector<snapshot_cache_entry> snapshot_vec;
507 snapshot_vec m_snapshots;
509 void dump_packet_as_func_call(const vogl_trace_packet &trace_packet);
510 void dump_trace_gl_packet_debug_info(const vogl_trace_gl_entrypoint_packet &gl_packet);
512 status_t trigger_pending_window_resize(uint win_width, uint win_height);
513 void clear_pending_window_resize();
514 status_t process_frame_check_for_pending_window_resize();
516 void destroy_pending_snapshot();
518 // Returns *true* if any errors occurred.
519 bool check_gl_error_internal(bool quietly = false, const char *pFile = "", uint line = 0, const char *pFunc = "");
520 #define check_gl_error() (((m_flags &cGLReplayerBenchmarkMode) == 0) ? check_gl_error_internal(false, __FILE__, __LINE__, __PRETTY_FUNCTION__) : false)
521 #define check_gl_error_quietly() (((m_flags &cGLReplayerBenchmarkMode) == 0) ? check_gl_error_internal(true, __FILE__, __LINE__, __PRETTY_FUNCTION__) : false)
523 void destroy_contexts();
524 void clear_contexts();
526 // from=replay, to=trace
527 class replay_to_trace_handle_remapper : public vogl_handle_remapper
529 vogl_gl_replayer &m_replayer;
531 // TODO: This searches the entire hash map! Slow!
532 bool remap_replay_to_trace_handle(const gl_handle_hash_map &hash_map, GLuint &handle) const
534 VOGL_ASSERT(hash_map.search_table_for_value_get_count(handle) <= 1);
536 gl_handle_hash_map::const_iterator it(hash_map.search_table_for_value(handle));
537 if (it != hash_map.end())
539 VOGL_ASSERT(it->second == handle);
547 replay_to_trace_handle_remapper(vogl_gl_replayer &replayer)
548 : m_replayer(replayer)
552 virtual bool is_default_remapper() const
557 virtual uint64_t remap_handle(vogl_namespace_t handle_namespace, uint64_t replay_handle);
559 virtual bool is_valid_handle(vogl_namespace_t handle_namespace, uint64_t replay_handle);
561 virtual int32 remap_location(uint32 replay_program, int32 replay_location);
563 virtual vogl_trace_ptr_value remap_vertex_attrib_ptr(uint index, vogl_trace_ptr_value ptr_val)
565 VOGL_NOTE_UNUSED(index);
569 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)
571 VOGL_NOTE_UNUSED(id);
572 VOGL_NOTE_UNUSED(index);
576 virtual bool determine_from_object_target(vogl_namespace_t handle_namespace, uint64_t replay_handle, GLenum &target);
578 virtual bool determine_to_object_target(vogl_namespace_t handle_namespace, uint64_t trace_handle, GLenum &target);
581 replay_to_trace_handle_remapper m_replay_to_trace_remapper;
583 // from=trace, to=replay
584 class trace_to_replay_handle_remapper : public vogl_handle_remapper
586 vogl_gl_replayer &m_replayer;
589 // Note: This used to also take a vogl_gl_state_snapshot ref
590 trace_to_replay_handle_remapper(vogl_gl_replayer &replayer)
591 : m_replayer(replayer)
595 virtual bool is_default_remapper() const
600 virtual uint64_t remap_handle(vogl_namespace_t handle_namespace, uint64_t from_handle);
602 virtual bool is_valid_handle(vogl_namespace_t handle_namespace, uint64_t replay_handle);
604 virtual int32 remap_location(uint32 trace_program, int32 from_location);
606 virtual vogl_trace_ptr_value remap_vertex_attrib_ptr(uint index, vogl_trace_ptr_value ptr_val);
608 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);
610 virtual void declare_handle(vogl_namespace_t handle_namespace, uint64_t from_handle, uint64_t to_handle, GLenum target);
612 virtual void delete_handle_and_object(vogl_namespace_t handle_namespace, uint64_t from_handle, uint64_t to_handle);
614 virtual void declare_location(uint32 from_program_handle, uint32 to_program_handle, int32 from_location, int32 to_location);
616 virtual bool determine_from_object_target(vogl_namespace_t handle_namespace, uint64_t trace_handle, GLenum &target);
618 virtual bool determine_to_object_target(vogl_namespace_t handle_namespace, uint64_t replay_handle, GLenum &target);
621 inline bool gen_handle(gl_handle_hash_map &handle_hash_map, GLuint trace_handle, GLuint replay_handle)
627 VOGL_ASSERT(!replay_handle);
633 process_entrypoint_error("%s: Handle gen failed during replay, but succeeded during trace! Trace handle: %u\n", VOGL_METHOD_NAME, trace_handle);
638 gl_handle_hash_map::insert_result result(handle_hash_map.insert(trace_handle, replay_handle));
641 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);
643 gl_handle_hash_map::iterator it = result.first;
644 it->second = replay_handle;
651 template <typename T>
652 inline bool gen_handles(gl_handle_hash_map &handle_hash_map, GLsizei n, const GLuint *pTrace_ids, T gl_gen_function, GLuint *pReplay_handles)
656 for (GLsizei i = 0; i < n; i++)
659 pReplay_handles[i] = 0;
664 GLuint replay_id = 0;
665 gl_gen_function(1, &replay_id);
669 process_entrypoint_error("%s: GL handle gen call failed, but succeeded in the trace!\n", VOGL_METHOD_NAME);
674 pReplay_handles[i] = replay_id;
676 gl_handle_hash_map::insert_result result(handle_hash_map.insert(pTrace_ids[i], replay_id));
679 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]);
681 gl_handle_hash_map::iterator it = result.first;
682 it->second = replay_id;
689 template <typename T>
690 inline void delete_handles(gl_handle_hash_map &handle_hash_map, GLsizei trace_n, const GLuint *pTrace_ids, T gl_delete_function)
694 vogl::vector<GLuint> replay_ids;
695 replay_ids.reserve(trace_n);
697 for (int i = 0; i < trace_n; i++)
699 GLuint trace_id = pTrace_ids[i];
703 gl_handle_hash_map::const_iterator it(handle_hash_map.find(trace_id));
705 if (it != handle_hash_map.end())
707 replay_ids.push_back(it->second);
709 handle_hash_map.erase(pTrace_ids[i]);
713 replay_ids.push_back(trace_id);
715 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]);
719 if (replay_ids.size())
720 gl_delete_function(replay_ids.size(), replay_ids.get_ptr());
723 template <typename T>
724 inline void delete_handle(gl_handle_hash_map &handle_hash_map, GLuint trace_id, T gl_delete_function)
728 delete_handles(handle_hash_map, 1, &trace_id, gl_delete_function);
731 template <typename T>
732 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)
736 for (GLsizei i = 0; i < n; i++)
739 pReplay_handles[i] = 0;
744 GLuint replay_id = 0;
745 gl_gen_function(1, &replay_id);
749 process_entrypoint_error("%s: GL handle gen call failed, but succeeded in the trace!\n", VOGL_METHOD_NAME);
754 pReplay_handles[i] = replay_id;
756 if (!handle_tracker.insert(pTrace_ids[i], replay_id, def_target))
758 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]);
760 handle_tracker.erase(pTrace_ids[i]);
762 bool success = handle_tracker.insert(pTrace_ids[i], replay_id, def_target);
763 VOGL_ASSERT(success);
764 VOGL_NOTE_UNUSED(success);
771 inline bool gen_handle(vogl_handle_tracker &handle_tracker, const GLuint trace_id, GLuint replay_id, GLenum def_target)
777 VOGL_ASSERT(!replay_id);
781 if (!handle_tracker.insert(trace_id, replay_id, def_target))
783 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()));
785 handle_tracker.erase(trace_id);
787 bool success = handle_tracker.insert(trace_id, replay_id, def_target);
788 VOGL_ASSERT(success);
789 VOGL_NOTE_UNUSED(success);
795 template <typename T>
796 inline void delete_handles(vogl_handle_tracker &handle_tracker, GLsizei trace_n, const GLuint *pTrace_ids, T gl_delete_function)
800 vogl::growable_array<GLuint, 32> replay_ids;
801 replay_ids.reserve(trace_n);
803 for (int i = 0; i < trace_n; i++)
805 GLuint trace_id = pTrace_ids[i];
809 GLuint replay_id = trace_id;
810 if (!handle_tracker.map_handle_to_inv_handle(trace_id, replay_id))
811 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()));
813 handle_tracker.erase(trace_id);
815 replay_ids.push_back(replay_id);
818 if (replay_ids.size())
819 gl_delete_function(replay_ids.size(), replay_ids.get_ptr());
822 static void delete_program_helper(GLsizei n, const GLuint *pIDs)
826 for (GLsizei i = 0; i < n; i++)
827 GL_ENTRYPOINT(glDeleteProgram)(pIDs[i]);
830 static void delete_list_helper(GLsizei n, const GLuint *pIDs)
834 for (GLsizei i = 0; i < n; i++)
835 GL_ENTRYPOINT(glDeleteLists)(pIDs[i], 1);
838 // 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)
839 inline GLuint map_handle(gl_handle_hash_map &handle_hash_map, GLuint trace_handle, bool insert_if_not_found = false)
846 gl_handle_hash_map::const_iterator it = handle_hash_map.find(trace_handle);
847 if (it == handle_hash_map.end())
849 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);
851 if (insert_if_not_found)
852 handle_hash_map.insert(trace_handle, trace_handle);
860 inline bool map_handle(vogl_handle_tracker &handle_tracker, GLuint trace_handle, GLuint &replay_handle)
864 replay_handle = trace_handle;
869 if (!handle_tracker.map_handle_to_inv_handle(trace_handle, replay_handle))
871 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()));
878 inline GLuint map_handle(vogl_handle_tracker &handle_tracker, GLuint trace_handle, bool *pSuccess = NULL)
889 GLuint replay_handle = trace_handle;
890 if (!handle_tracker.map_handle_to_inv_handle(trace_handle, replay_handle))
894 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()));
895 return replay_handle;
900 return replay_handle;
903 inline context_state *get_trace_context_state(vogl_trace_context_ptr_value trace_context)
910 context_hash_map::iterator it = m_contexts.find(trace_context);
911 return (it == m_contexts.end()) ? NULL : it->second;
914 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);
916 GLXContext remap_context(vogl_trace_context_ptr_value trace_context);
918 bool destroy_context(vogl_trace_context_ptr_value trace_context);
920 // glVertexPointer, glNormalPointer, etc. client side data
921 bool set_client_side_array_data(const key_value_map &map, GLuint start, GLuint end, GLuint basevertex);
923 // glVertexAttrib client side data
924 bool set_client_side_vertex_attrib_array_data(const key_value_map &map, GLuint start, GLuint end, GLuint basevertex);
926 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);
928 GLint determine_uniform_replay_location(GLuint trace_program, GLint trace_location);
930 inline GLint determine_uniform_replay_location(GLint trace_location)
932 return determine_uniform_replay_location(m_pCur_context_state->m_cur_trace_program, trace_location);
935 template <uint N, class T, class F>
936 inline void set_uniformv_helper(F func)
940 GLint replay_location = determine_uniform_replay_location(m_pCur_gl_packet->get_param_value<GLint>(0));
942 GLsizei count = m_pCur_gl_packet->get_param_value<GLsizei>(1);
943 const T *pValues = m_pCur_gl_packet->get_param_client_memory<T>(2);
944 VOGL_ASSERT((uint)m_pCur_gl_packet->get_param_client_memory_data_size(2) == sizeof(T) * N * count);
946 func(replay_location, count, pValues);
949 template <uint C, uint R, class T, class F>
950 inline void set_uniform_matrixv_helper(F func)
954 GLint replay_location = determine_uniform_replay_location(m_pCur_gl_packet->get_param_value<GLint>(0));
956 GLsizei count = m_pCur_gl_packet->get_param_value<GLsizei>(1);
957 GLboolean transpose = m_pCur_gl_packet->get_param_value<GLboolean>(2);
958 const T *pValues = m_pCur_gl_packet->get_param_client_memory<T>(3);
959 VOGL_ASSERT((uint)m_pCur_gl_packet->get_param_client_memory_data_size(3) == sizeof(T) * C * R * count);
961 func(replay_location, count, transpose, pValues);
964 // glUniform* helpers
965 template <class T, class F>
966 inline void set_uniform_helper1(F func)
970 func(determine_uniform_replay_location(m_pCur_gl_packet->get_param_value<GLint>(0)), m_pCur_gl_packet->get_param_value<T>(1));
973 template <class T, class F>
974 inline void set_uniform_helper2(F func)
978 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));
981 template <class T, class F>
982 inline void set_uniform_helper3(F func)
986 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));
989 template <class T, class F>
990 inline void set_uniform_helper4(F func)
994 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));
997 // glSetProgramUniform* helpers
998 template <class T, class F>
999 inline void set_program_uniform_helper1(F func)
1003 GLuint trace_handle = m_pCur_gl_packet->get_param_value<GLuint>(0);
1004 GLuint replay_handle = map_handle(m_pCur_context_state->m_pShared_state->m_shadow_state.m_objs, trace_handle);
1005 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));
1008 template <class T, class F>
1009 inline void set_program_uniform_helper2(F func)
1013 GLuint trace_handle = m_pCur_gl_packet->get_param_value<GLuint>(0);
1014 GLuint replay_handle = map_handle(m_pCur_context_state->m_pShared_state->m_shadow_state.m_objs, trace_handle);
1015 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));
1018 template <class T, class F>
1019 inline void set_program_uniform_helper3(F func)
1023 GLuint trace_handle = m_pCur_gl_packet->get_param_value<GLuint>(0);
1024 GLuint replay_handle = map_handle(m_pCur_context_state->m_pShared_state->m_shadow_state.m_objs, trace_handle);
1025 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));
1028 template <class T, class F>
1029 inline void set_program_uniform_helper4(F func)
1033 GLuint trace_handle = m_pCur_gl_packet->get_param_value<GLuint>(0);
1034 GLuint replay_handle = map_handle(m_pCur_context_state->m_pShared_state->m_shadow_state.m_objs, trace_handle);
1035 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));
1038 template <uint C, uint R, class T, class F>
1039 inline void set_program_uniform_matrixv_helper(F func)
1043 GLuint trace_handle = m_pCur_gl_packet->get_param_value<GLuint>(0);
1044 GLuint replay_handle = map_handle(m_pCur_context_state->m_pShared_state->m_shadow_state.m_objs, trace_handle);
1046 GLint replay_location = determine_uniform_replay_location(trace_handle, m_pCur_gl_packet->get_param_value<GLint>(1));
1048 GLsizei count = m_pCur_gl_packet->get_param_value<GLsizei>(2);
1049 GLboolean transpose = m_pCur_gl_packet->get_param_value<GLboolean>(3);
1050 const T *pValues = m_pCur_gl_packet->get_param_client_memory<T>(4);
1051 VOGL_ASSERT((uint)m_pCur_gl_packet->get_param_client_memory_data_size(4) == sizeof(T) * C * R * count);
1053 func(replay_handle, replay_location, count, transpose, pValues);
1056 template <uint N, class T, class F>
1057 inline void set_program_uniformv_helper(F func)
1061 GLuint trace_handle = m_pCur_gl_packet->get_param_value<GLuint>(0);
1062 GLuint replay_handle = map_handle(m_pCur_context_state->m_pShared_state->m_shadow_state.m_objs, trace_handle);
1064 GLint replay_location = determine_uniform_replay_location(trace_handle, m_pCur_gl_packet->get_param_value<GLint>(1));
1066 GLsizei count = m_pCur_gl_packet->get_param_value<GLsizei>(2);
1067 const T *pValues = m_pCur_gl_packet->get_param_client_memory<T>(3);
1069 VOGL_ASSERT((uint)m_pCur_gl_packet->get_param_client_memory_data_size(3) == sizeof(T) * N * count);
1071 func(replay_handle, replay_location, count, pValues);
1074 static void delete_objects_arb(GLsizei n, const GLuint *pHandles)
1078 for (GLsizei i = 0; i < n; i++)
1079 GL_ENTRYPOINT(glDeleteObjectARB)(pHandles[i]);
1082 template <typename T, typename F>
1083 inline status_t get_vertex_attrib_helper(F entrypoint)
1085 if (benchmark_mode())
1090 GLint index = m_pCur_gl_packet->get_param_value<GLint>(0);
1091 GLenum pname = m_pCur_gl_packet->get_param_value<GLenum>(1);
1092 const T *pTrace_params = m_pCur_gl_packet->get_param_client_memory<const T>(2);
1093 uint num_trace_params = m_pCur_gl_packet->get_param_client_memory_data_size(2) / sizeof(T);
1095 int n = g_gl_enums.get_pname_count(pname);
1098 process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
1099 return cStatusSoftFailure;
1102 vogl::vector<T> params(n);
1103 entrypoint(index, pname, params.get_ptr());
1105 if (num_trace_params < static_cast<uint>(n))
1107 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);
1108 return cStatusSoftFailure;
1110 else if (!pTrace_params)
1112 process_entrypoint_error("%s: Trace has NULL params field, can't diff trace vs. replay's params\n", VOGL_METHOD_NAME);
1113 return cStatusSoftFailure;
1117 if (memcmp(pTrace_params, params.get_ptr(), n * sizeof(T)) != 0)
1119 process_entrypoint_error("%s: Replay's results differ from trace's\n", VOGL_METHOD_NAME);
1120 return cStatusSoftFailure;
1127 template <typename F>
1128 inline void vertex_array_helper(
1129 GLint size, GLenum type, GLsizei stride, vogl_trace_ptr_value trace_pointer,
1130 vogl_client_side_array_desc_id_t id, F func, uint8_vec &array_data)
1134 const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[id];
1135 VOGL_NOTE_UNUSED(desc);
1137 GLuint buffer = vogl_get_bound_gl_buffer(GL_ARRAY_BUFFER);
1139 GLvoid *pPtr = reinterpret_cast<GLvoid *>(trace_pointer);
1140 if ((!buffer) && (trace_pointer))
1142 // We've got a trace pointer to client side memory, but we don't have it until the actual draw.
1143 // So point this guy into one of our client size memory buffers that's hopefully large enough.
1144 if (!array_data.size())
1146 array_data.resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
1148 pPtr = array_data.get_ptr();
1151 func(size, type, stride, pPtr);
1154 template <typename F>
1155 inline void vertex_array_helper_count(
1156 GLint size, GLenum type, GLsizei stride, GLsizei count, vogl_trace_ptr_value trace_pointer,
1157 vogl_client_side_array_desc_id_t id, F func, uint8_vec &array_data)
1161 const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[id];
1162 VOGL_NOTE_UNUSED(desc);
1164 GLuint buffer = vogl_get_bound_gl_buffer(GL_ARRAY_BUFFER);
1166 GLvoid *pPtr = reinterpret_cast<GLvoid *>(trace_pointer);
1167 if ((!buffer) && (trace_pointer))
1169 // We've got a trace pointer to client side memory, but we don't have it until the actual draw.
1170 // So point this guy into one of our client size memory buffers that's hopefully large enough.
1171 if (!array_data.size())
1173 array_data.resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
1175 pPtr = array_data.get_ptr();
1178 func(size, type, stride, count, pPtr);
1181 template <typename F>
1182 inline void vertex_array_helper_no_size(
1183 GLenum type, GLsizei stride, vogl_trace_ptr_value trace_pointer,
1184 vogl_client_side_array_desc_id_t id, F func)
1188 const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[id];
1189 VOGL_NOTE_UNUSED(desc);
1191 GLuint buffer = vogl_get_bound_gl_buffer(GL_ARRAY_BUFFER);
1192 GLvoid *pPtr = reinterpret_cast<GLvoid *>(trace_pointer);
1193 if ((!buffer) && (trace_pointer))
1195 // We've got a trace pointer to client side memory, but we don't have it until the actual draw.
1196 // So point this guy into one of our client size memory buffers that's hopefully large enough.
1197 if (!m_client_side_array_data[id].size())
1199 m_client_side_array_data[id].resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
1201 pPtr = m_client_side_array_data[id].get_ptr();
1204 func(type, stride, pPtr);
1207 template <typename F>
1208 inline void vertex_array_helper_no_size_count(
1209 GLenum type, GLsizei stride, GLsizei count, vogl_trace_ptr_value trace_pointer,
1210 vogl_client_side_array_desc_id_t id, F func)
1214 const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[id];
1215 VOGL_NOTE_UNUSED(desc);
1217 GLuint buffer = vogl_get_bound_gl_buffer(GL_ARRAY_BUFFER);
1218 GLvoid *pPtr = reinterpret_cast<GLvoid *>(trace_pointer);
1219 if ((!buffer) && (trace_pointer))
1221 // We've got a trace pointer to client side memory, but we don't have it until the actual draw.
1222 // So point this guy into one of our client size memory buffers that's hopefully large enough.
1223 if (!m_client_side_array_data[id].size())
1225 m_client_side_array_data[id].resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
1227 pPtr = m_client_side_array_data[id].get_ptr();
1230 func(type, stride, count, pPtr);
1233 template <typename F>
1234 inline void vertex_array_helper_no_type_no_size(
1235 GLsizei stride, vogl_trace_ptr_value trace_pointer,
1236 vogl_client_side_array_desc_id_t id, F func)
1240 const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[id];
1241 VOGL_NOTE_UNUSED(desc);
1243 GLuint buffer = vogl_get_bound_gl_buffer(GL_ARRAY_BUFFER);
1244 GLvoid *pPtr = reinterpret_cast<GLvoid *>(trace_pointer);
1245 if ((!buffer) && (trace_pointer))
1247 // We've got a trace pointer to client side memory, but we don't have it until the actual draw.
1248 // So point this guy into one of our client size memory buffers that's hopefully large enough.
1249 if (!m_client_side_array_data[id].size())
1251 m_client_side_array_data[id].resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
1253 pPtr = m_client_side_array_data[id].get_ptr();
1259 template <typename F>
1260 inline void vertex_array_helper_no_type_no_size_count(
1261 GLsizei stride, GLsizei count, vogl_trace_ptr_value trace_pointer,
1262 vogl_client_side_array_desc_id_t id, F func)
1266 const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[id];
1267 VOGL_NOTE_UNUSED(desc);
1269 GLuint buffer = vogl_get_bound_gl_buffer(GL_ARRAY_BUFFER);
1270 GLvoid *pPtr = reinterpret_cast<GLvoid *>(trace_pointer);
1271 if ((!buffer) && (trace_pointer))
1273 // We've got a trace pointer to client side memory, but we don't have it until the actual draw.
1274 // So point this guy into one of our client size memory buffers that's hopefully large enough.
1275 if (!m_client_side_array_data[id].size())
1277 m_client_side_array_data[id].resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
1279 pPtr = m_client_side_array_data[id].get_ptr();
1282 func(stride, count, static_cast<const GLchar *>(pPtr));
1285 void process_entrypoint_print_summary_context(eConsoleMessageType msg_type);
1286 void print_detailed_context(eConsoleMessageType msg_type);
1287 void process_entrypoint_msg_print_detailed_context(eConsoleMessageType msg_type);
1288 void process_entrypoint_info(const char *pFmt, ...) VOGL_ATTRIBUTE_PRINTF(2, 3);
1289 void process_entrypoint_message(const char *pFmt, ...) VOGL_ATTRIBUTE_PRINTF(2, 3);
1290 void process_entrypoint_warning(const char *pFmt, ...) VOGL_ATTRIBUTE_PRINTF(2, 3);
1291 void process_entrypoint_error(const char *pFmt, ...) VOGL_ATTRIBUTE_PRINTF(2, 3);
1293 status_t switch_contexts(vogl_trace_context_ptr_value trace_context);
1295 // Loosely derived from http://www.altdevblogaday.com/2011/06/23/improving-opengl-error-messages/
1296 static void debug_callback_arb(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, GLvoid *pUser_param);
1298 bool is_extension_supported(const char *pExt);
1300 bool handle_context_made_current();
1302 void dump_context_attrib_list(const int *pAttrib_list, uint size);
1304 int find_attrib_key(const vogl::vector<int> &attrib_list, int key_to_find);
1306 status_t create_context_attribs(
1307 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,
1308 const int *pTrace_attrib_list, int trace_attrib_list_size, bool expecting_attribs);
1310 status_t process_pending_make_current();
1312 status_t process_internal_trace_command(const vogl_trace_gl_entrypoint_packet &gl_packet);
1314 void snapshot_backbuffer();
1316 bool check_program_binding_shadow();
1317 void handle_use_program(GLuint trace_handle, gl_entrypoint_id_t entrypoint_id);
1318 void handle_delete_program(GLuint trace_handle);
1319 void handle_delete_shader(GLuint trace_handle);
1320 void handle_detach_shader(gl_entrypoint_id_t entrypoint_id);
1321 void handle_link_program(gl_entrypoint_id_t entrypoint_id);
1323 static void display_list_bind_callback(vogl_namespace_t handle_namespace, GLenum target, GLuint handle, void *pOpaque);
1325 status_t restore_context(vogl_handle_remapper &trace_to_replay_remapper, const vogl_gl_state_snapshot &snapshot, const vogl_context_snapshot &context_snapshot);
1326 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);
1327 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);
1328 status_t restore_general_state(vogl_handle_remapper &trace_to_replay_remapper, const vogl_gl_state_snapshot &snapshot, const vogl_context_snapshot &context_snapshot);
1329 status_t update_context_shadows(vogl_handle_remapper &trace_to_replay_remapper, const vogl_gl_state_snapshot &snapshot, const vogl_context_snapshot &context_snapshot);
1330 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);
1331 bool determine_used_program_handles(const vogl_trace_packet_array &trim_packets, vogl_handle_hash_set &replay_program_handles);
1333 vogl_gl_replayer::status_t process_applying_pending_snapshot();
1334 bool validate_program_and_shader_handle_tables();
1335 bool validate_textures();
1337 void fill_replay_handle_hash_set(vogl_handle_hash_set &replay_handle_hash, const gl_handle_hash_map &trace_to_replay_hash);
1339 // write_trim_file_internal() may modify trim_packets
1340 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);
1342 bool dump_frontbuffer_to_file(const dynamic_string &filename);
1344 bool benchmark_mode() const
1346 return (m_flags & cGLReplayerBenchmarkMode) != 0;
1349 // DO NOT make these methods public
1350 status_t process_gl_entrypoint_packet(vogl_trace_packet& trace_packet);
1351 status_t process_gl_entrypoint_packet_internal(vogl_trace_packet &trace_packet);
1354 #endif // VOGL_GL_REPLAYER_H