]> git.cworth.org Git - vogl/blob - src/voglcommon/vogl_gl_replayer.h
- Initial support for KHR_debug API's in tracer/replayer
[vogl] / src / voglcommon / vogl_gl_replayer.h
1 /**************************************************************************
2  *
3  * Copyright 2013-2014 RAD Game Tools and Valve Software
4  * All Rights Reserved.
5  *
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:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
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
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26 // File: vogl_gl_replayer.h
27 #ifndef VOGL_GL_REPLAYER_H
28 #define VOGL_GL_REPLAYER_H
29
30 #include "vogl_unique_ptr.h"
31
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"
37
38 #include "vogl_replay_window.h"
39 #include "vogl_gl_state_snapshot.h"
40 #include "vogl_blob_manager.h"
41
42 // TODO: Make this a command line param
43 #define VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE (8U * 1024U * 1024U)
44
45 bool vogl_process_internal_trace_command_ctypes_packet(const key_value_map &kvm, const vogl_ctypes &ctypes);
46
47 //----------------------------------------------------------------------------------------------------------------------
48 // enum vogl_gl_replayer_flags
49 //----------------------------------------------------------------------------------------------------------------------
50 enum vogl_gl_replayer_flags
51 {
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
68 };
69
70 //----------------------------------------------------------------------------------------------------------------------
71 // class vogl_replayer
72 //----------------------------------------------------------------------------------------------------------------------
73 class vogl_gl_replayer
74 {
75     VOGL_NO_COPY_OR_ASSIGNMENT_OP(vogl_gl_replayer);
76
77     typedef vogl_trace_ptr_value vogl_trace_context_ptr_value;
78     typedef vogl_trace_ptr_value vogl_sync_ptr_value;
79
80 public:
81     vogl_gl_replayer();
82     ~vogl_gl_replayer();
83
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);
86
87     void deinit();
88
89     // Configuration: call after init().
90
91     void set_flags(uint flags)
92     {
93         m_flags = flags;
94     }
95     uint get_flags() const
96     {
97         return m_flags;
98     }
99
100     void set_swap_sleep_time(uint swap_sleep_time)
101     {
102         m_swap_sleep_time = swap_sleep_time;
103     }
104     uint get_swap_sleep_time() const
105     {
106         return m_swap_sleep_time;
107     }
108
109     const dynamic_string &get_dump_framebuffer_on_draw_prefix() const
110     {
111         return m_dump_framebuffer_on_draw_prefix;
112     }
113     void set_dump_framebuffer_on_draw_prefix(const dynamic_string &str)
114     {
115         m_dump_framebuffer_on_draw_prefix = str;
116     }
117
118     const dynamic_string &get_screenshot_prefix() const
119     {
120         return m_screenshot_prefix;
121     }
122     void set_screenshot_prefix(const dynamic_string &str)
123     {
124         m_screenshot_prefix = str;
125     }
126
127     const dynamic_string &get_backbuffer_hash_filename() const
128     {
129         return m_backbuffer_hash_filename;
130     }
131     void set_backbuffer_hash_filename(const dynamic_string &str)
132     {
133         m_backbuffer_hash_filename = str;
134     }
135
136     void set_dump_framebuffer_on_draw_frame_index(int64_t index)
137     {
138         m_dump_framebuffer_on_draw_frame_index = index;
139     }
140     int64_t get_dump_framebuffer_on_draw_frame_index() const
141     {
142         return m_dump_framebuffer_on_draw_frame_index;
143     }
144
145     void set_dump_framebuffer_on_draw_first_gl_call_index(int64_t index)
146     {
147         m_dump_framebuffer_on_draw_first_gl_call_index = index;
148     }
149     int64_t get_dump_framebuffer_on_draw_first_gl_call_index() const
150     {
151         return m_dump_framebuffer_on_draw_first_gl_call_index;
152     }
153
154     void set_dump_framebuffer_on_draw_last_gl_call_index(int64_t index)
155     {
156         m_dump_framebuffer_on_draw_last_gl_call_index = index;
157     }
158     int64_t get_dump_framebuffer_on_draw_last_gl_call_index() const
159     {
160         return m_dump_framebuffer_on_draw_last_gl_call_index;
161     }
162
163     bool is_valid() const
164     {
165         return m_is_valid;
166     }
167     vogl_replay_window *get_window()
168     {
169         return m_pWindow;
170     }
171
172     enum status_t
173     {
174         cStatusHardFailure = -3,
175         cStatusSoftFailure = -2,
176         cStatusGLError = -1,
177         cStatusOK = 0,
178         cStatusNextFrame,
179         cStatusResizeWindow,
180         cStatusAtEOF
181     };
182
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);
185
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);
189
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);
192
193     // Resets the replayer's state: kills all contexts, the pending snapshot, etc.
194     void reset_state();
195
196     bool get_has_pending_window_resize() const
197     {
198         return m_pending_window_resize_width != 0;
199     }
200     uint get_pending_window_resize_width() const
201     {
202         return m_pending_window_resize_width;
203     }
204     uint get_pending_winow_resize_height() const
205     {
206         return m_pending_window_resize_height;
207     }
208
209     bool update_window_dimensions();
210
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);
213
214     uint get_frame_index() const
215     {
216         return m_frame_index;
217     }
218     uint get_total_swaps() const
219     {
220         return m_total_swaps;
221     }
222     int64_t get_last_parsed_call_counter() const
223     {
224         return m_last_parsed_call_counter;
225     }
226     int64_t get_last_processed_call_counter() const
227     {
228         return m_last_processed_call_counter;
229     }
230
231     uint64_t get_frame_draw_counter() const
232     {
233         return m_frame_draw_counter;
234     }
235
236     bool get_at_frame_boundary() const
237     {
238         return m_at_frame_boundary;
239     }
240
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);
243
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
246     {
247         return m_pPending_snapshot;
248     }
249
250     void set_frame_draw_counter_kill_threshold(uint64_t thresh)
251     {
252         m_frame_draw_counter_kill_threshold = thresh;
253     }
254     uint64_t get_frame_draw_counter_kill_threshold() const
255     {
256         return m_frame_draw_counter_kill_threshold;
257     }
258
259     const vogl_trace_stream_start_of_file_packet &get_sof_packet() const
260     {
261         return m_sof_packet;
262     }
263
264     // Will be updated after the ctypes packet is processed, otherwise it'll be invalid
265     const vogl_trace_packet &get_ctypes_packet() const
266     {
267         return m_ctypes_packet;
268     }
269
270     // Will be first updated at init(), then updated after the ctypes packet is processed
271     const vogl_ctypes &get_trace_gl_ctypes() const
272     {
273         return m_trace_gl_ctypes;
274     }
275
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
279     {
280         cWriteTrimFileFromStartOfFrame = 1,
281         cWriteTrimFileOptimizeSnapshot = 2
282     };
283
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);
285
286 private:
287     status_t handle_ShaderSource(GLhandleARB trace_object,
288                                  GLsizei count,
289                                  const vogl_client_memory_array trace_strings_glchar_ptr_array,
290                                  const GLint *pTrace_lengths);
291
292     status_t post_draw_call();
293
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();
297
298     uint m_flags;
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;
306
307     dynamic_string m_dump_frontbuffer_filename;
308
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;
313
314     vogl_ctypes m_trace_gl_ctypes;
315
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;
320
321     vogl_replay_window *m_pWindow;
322
323     vogl_trace_packet m_pending_make_current_packet;
324
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;
328
329     uint m_frame_index;
330     uint m_total_swaps;
331     int64_t m_last_parsed_call_counter;
332     int64_t m_last_processed_call_counter;
333
334     bool m_at_frame_boundary;
335
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;
338
339     typedef vogl::hash_map<GLint, GLint> uniform_location_hash_map;
340     struct glsl_program_state
341     {
342         // maps trace program locations to replay program locations
343         uniform_location_hash_map m_uniform_locations;
344     };
345     typedef vogl::hash_map<GLuint, glsl_program_state> glsl_program_hash_map;
346
347     class context_state
348     {
349         VOGL_NO_COPY_OR_ASSIGNMENT_OP(context_state);
350
351     public:
352         context_state(vogl_gl_replayer &replayer)
353             : m_replayer(replayer)
354         {
355             VOGL_FUNC_TRACER
356
357             m_pShared_state = this;
358             m_ref_count = 1;
359             m_deleted = false;
360
361             m_last_call_counter = 0;
362
363             m_has_been_made_current = false;
364             m_inside_gl_begin = false;
365
366             m_trace_context = 0;
367             m_replay_context = 0;
368
369             m_cur_replay_program = 0;
370             m_cur_trace_program = 0;
371
372             m_current_display_list_handle = -1;
373             m_current_display_list_mode = GL_NONE;
374         }
375
376         bool handle_context_made_current();
377
378         bool is_root_context() const
379         {
380             return m_pShared_state == this;
381         }
382         bool is_share_context() const
383         {
384             return m_pShared_state != this;
385         }
386
387         bool is_composing_display_list() const
388         {
389             return m_current_display_list_handle >= 0;
390         }
391
392         vogl_gl_replayer &m_replayer;
393
394         vogl_context_desc m_context_desc;
395         vogl_context_info m_context_info;
396
397         context_state *m_pShared_state;
398         int m_ref_count;
399         bool m_deleted;
400
401         uint64_t m_last_call_counter;
402
403         bool m_has_been_made_current;
404         bool m_inside_gl_begin;
405
406         vogl_trace_context_ptr_value m_trace_context;
407         GLXContext m_replay_context;
408
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;
416
417         gl_handle_hash_map m_lists;
418
419         gl_sync_hash_map m_syncs;
420
421         // maps trace programs to glsl_program_state's
422         glsl_program_hash_map m_glsl_program_hash_map;
423
424         // maps replay query handles to the last active begin target
425         vogl_handle_hash_map m_query_targets;
426
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
429
430         GLuint m_cur_replay_program;
431         GLuint m_cur_trace_program;
432
433         vogl::vector<GLfloat> m_feedback_buffer;
434         vogl::vector<GLuint> m_select_buffer;
435
436         vogl_capture_context_params m_shadow_state;
437
438         int m_current_display_list_handle;
439         GLenum m_current_display_list_mode;
440     };
441
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;
444
445     vogl_trace_context_ptr_value m_cur_trace_context;
446     GLXContext m_cur_replay_context;
447     context_state *m_pCur_context_state;
448
449     context_state *get_context_state()
450     {
451         return m_pCur_context_state;
452     }
453     context_state *get_shared_state()
454     {
455         return m_pCur_context_state->m_pShared_state;
456     }
457
458     enum
459     {
460         VOGL_MAX_SUPPORTED_GL_VERTEX_ATTRIBUTES = 32,
461         VOGL_MAX_SUPPORTED_GL_TEXCOORD_ARRAYS = 32
462     };
463
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];
467
468     uint8_vec m_screenshot_buffer;
469
470     vogl::vector<uint8> m_index_data;
471
472     uint64_t m_frame_draw_counter;
473     uint64_t m_frame_draw_counter_kill_threshold;
474
475     bool m_is_valid;
476
477     const vogl_blob_manager *m_pBlob_manager;
478
479     const vogl_gl_state_snapshot *m_pPending_snapshot;
480     bool m_delete_pending_snapshot_after_applying;
481
482     // TODO: Make a 1st class snapshot cache class
483     struct snapshot_cache_entry
484     {
485         snapshot_cache_entry()
486             : m_pSnapshot(NULL)
487         {
488         }
489
490         dynamic_string m_name;
491         vogl_gl_state_snapshot *m_pSnapshot;
492     };
493     typedef vogl::vector<snapshot_cache_entry> snapshot_vec;
494     snapshot_vec m_snapshots;
495
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);
498
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();
502
503     void destroy_pending_snapshot();
504
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)
509
510     void destroy_contexts();
511     void clear_contexts();
512
513     // from=replay, to=trace
514     class replay_to_trace_handle_remapper : public vogl_handle_remapper
515     {
516         vogl_gl_replayer &m_replayer;
517
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
520         {
521             VOGL_ASSERT(hash_map.search_table_for_value_get_count(handle) <= 1);
522
523             gl_handle_hash_map::const_iterator it(hash_map.search_table_for_value(handle));
524             if (it != hash_map.end())
525             {
526                 VOGL_ASSERT(it->second == handle);
527                 handle = it->first;
528                 return true;
529             }
530             return false;
531         }
532
533     public:
534         replay_to_trace_handle_remapper(vogl_gl_replayer &replayer)
535             : m_replayer(replayer)
536         {
537         }
538
539         virtual bool is_default_remapper() const
540         {
541             return false;
542         }
543
544         virtual uint64_t remap_handle(vogl_namespace_t handle_namespace, uint64_t replay_handle);
545
546         virtual bool is_valid_handle(vogl_namespace_t handle_namespace, uint64_t replay_handle);
547
548         virtual int32 remap_location(uint32 replay_program, int32 replay_location);
549
550         virtual vogl_trace_ptr_value remap_vertex_attrib_ptr(uint index, vogl_trace_ptr_value ptr_val)
551         {
552             VOGL_NOTE_UNUSED(index);
553             return ptr_val;
554         }
555
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)
557         {
558             VOGL_NOTE_UNUSED(id);
559             VOGL_NOTE_UNUSED(index);
560             return ptr_val;
561         }
562
563         virtual bool determine_from_object_target(vogl_namespace_t handle_namespace, uint64_t replay_handle, GLenum &target);
564
565         virtual bool determine_to_object_target(vogl_namespace_t handle_namespace, uint64_t trace_handle, GLenum &target);
566     };
567
568     replay_to_trace_handle_remapper m_replay_to_trace_remapper;
569
570     // from=trace, to=replay
571     class trace_to_replay_handle_remapper : public vogl_handle_remapper
572     {
573         vogl_gl_replayer &m_replayer;
574
575     public:
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)
579         {
580         }
581
582         virtual bool is_default_remapper() const
583         {
584             return false;
585         }
586
587         virtual uint64_t remap_handle(vogl_namespace_t handle_namespace, uint64_t from_handle);
588
589         virtual bool is_valid_handle(vogl_namespace_t handle_namespace, uint64_t replay_handle);
590
591         virtual int32 remap_location(uint32 trace_program, int32 from_location);
592
593         virtual vogl_trace_ptr_value remap_vertex_attrib_ptr(uint index, vogl_trace_ptr_value ptr_val);
594
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);
596
597         virtual void declare_handle(vogl_namespace_t handle_namespace, uint64_t from_handle, uint64_t to_handle, GLenum target);
598
599         virtual void delete_handle_and_object(vogl_namespace_t handle_namespace, uint64_t from_handle, uint64_t to_handle);
600
601         virtual void declare_location(uint32 from_program_handle, uint32 to_program_handle, int32 from_location, int32 to_location);
602
603         virtual bool determine_from_object_target(vogl_namespace_t handle_namespace, uint64_t trace_handle, GLenum &target);
604
605         virtual bool determine_to_object_target(vogl_namespace_t handle_namespace, uint64_t replay_handle, GLenum &target);
606     };
607
608     inline bool gen_handle(gl_handle_hash_map &handle_hash_map, GLuint trace_handle, GLuint replay_handle)
609     {
610         VOGL_FUNC_TRACER
611
612         if (!trace_handle)
613         {
614             VOGL_ASSERT(!replay_handle);
615             return true;
616         }
617
618         if (!replay_handle)
619         {
620             process_entrypoint_error("%s: Handle gen failed during replay, but succeeded during trace! Trace handle: %u\n", VOGL_METHOD_NAME, trace_handle);
621             return false;
622         }
623         else
624         {
625             gl_handle_hash_map::insert_result result(handle_hash_map.insert(trace_handle, replay_handle));
626             if (!result.second)
627             {
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);
629
630                 gl_handle_hash_map::iterator it = result.first;
631                 it->second = replay_handle;
632             }
633         }
634
635         return true;
636     }
637
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)
640     {
641         VOGL_FUNC_TRACER
642
643         for (GLsizei i = 0; i < n; i++)
644         {
645             if (pReplay_handles)
646                 pReplay_handles[i] = 0;
647
648             if (!pTrace_ids[i])
649                 continue;
650
651             GLuint replay_id = 0;
652             gl_gen_function(1, &replay_id);
653
654             if (!replay_id)
655             {
656                 process_entrypoint_error("%s: GL handle gen call failed, but succeeded in the trace!\n", VOGL_METHOD_NAME);
657                 return false;
658             }
659
660             if (pReplay_handles)
661                 pReplay_handles[i] = replay_id;
662
663             gl_handle_hash_map::insert_result result(handle_hash_map.insert(pTrace_ids[i], replay_id));
664             if (!result.second)
665             {
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]);
667
668                 gl_handle_hash_map::iterator it = result.first;
669                 it->second = replay_id;
670             }
671         }
672
673         return true;
674     }
675
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)
678     {
679         VOGL_FUNC_TRACER
680
681         vogl::vector<GLuint> replay_ids;
682         replay_ids.reserve(trace_n);
683
684         for (int i = 0; i < trace_n; i++)
685         {
686             GLuint trace_id = pTrace_ids[i];
687             if (!trace_id)
688                 continue;
689
690             gl_handle_hash_map::const_iterator it(handle_hash_map.find(trace_id));
691
692             if (it != handle_hash_map.end())
693             {
694                 replay_ids.push_back(it->second);
695
696                 handle_hash_map.erase(pTrace_ids[i]);
697             }
698             else
699             {
700                 replay_ids.push_back(trace_id);
701
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]);
703             }
704         }
705
706         if (replay_ids.size())
707             gl_delete_function(replay_ids.size(), replay_ids.get_ptr());
708     }
709
710     template <typename T>
711     inline void delete_handle(gl_handle_hash_map &handle_hash_map, GLuint trace_id, T gl_delete_function)
712     {
713         VOGL_FUNC_TRACER
714
715         delete_handles(handle_hash_map, 1, &trace_id, gl_delete_function);
716     }
717
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)
720     {
721         VOGL_FUNC_TRACER
722
723         for (GLsizei i = 0; i < n; i++)
724         {
725             if (pReplay_handles)
726                 pReplay_handles[i] = 0;
727
728             if (!pTrace_ids[i])
729                 continue;
730
731             GLuint replay_id = 0;
732             gl_gen_function(1, &replay_id);
733
734             if (!replay_id)
735             {
736                 process_entrypoint_error("%s: GL handle gen call failed, but succeeded in the trace!\n", VOGL_METHOD_NAME);
737                 return false;
738             }
739
740             if (pReplay_handles)
741                 pReplay_handles[i] = replay_id;
742
743             if (!handle_tracker.insert(pTrace_ids[i], replay_id, def_target))
744             {
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]);
746
747                 handle_tracker.erase(pTrace_ids[i]);
748
749                 bool success = handle_tracker.insert(pTrace_ids[i], replay_id, def_target);
750                 VOGL_ASSERT(success);
751                 VOGL_NOTE_UNUSED(success);
752             }
753         }
754
755         return true;
756     }
757
758     inline bool gen_handle(vogl_handle_tracker &handle_tracker, const GLuint trace_id, GLuint replay_id, GLenum def_target)
759     {
760         VOGL_FUNC_TRACER
761
762         if (!trace_id)
763         {
764             VOGL_ASSERT(!replay_id);
765             return true;
766         }
767
768         if (!handle_tracker.insert(trace_id, replay_id, def_target))
769         {
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()));
771
772             handle_tracker.erase(trace_id);
773
774             bool success = handle_tracker.insert(trace_id, replay_id, def_target);
775             VOGL_ASSERT(success);
776             VOGL_NOTE_UNUSED(success);
777         }
778
779         return true;
780     }
781
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)
784     {
785         VOGL_FUNC_TRACER
786
787         vogl::growable_array<GLuint, 32> replay_ids;
788         replay_ids.reserve(trace_n);
789
790         for (int i = 0; i < trace_n; i++)
791         {
792             GLuint trace_id = pTrace_ids[i];
793             if (!trace_id)
794                 continue;
795
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()));
799             else
800                 handle_tracker.erase(trace_id);
801
802             replay_ids.push_back(replay_id);
803         }
804
805         if (replay_ids.size())
806             gl_delete_function(replay_ids.size(), replay_ids.get_ptr());
807     }
808
809     static void delete_program_helper(GLsizei n, const GLuint *pIDs)
810     {
811         VOGL_FUNC_TRACER
812
813         for (GLsizei i = 0; i < n; i++)
814             GL_ENTRYPOINT(glDeleteProgram)(pIDs[i]);
815     }
816
817     static void delete_list_helper(GLsizei n, const GLuint *pIDs)
818     {
819         VOGL_FUNC_TRACER
820
821         for (GLsizei i = 0; i < n; i++)
822             GL_ENTRYPOINT(glDeleteLists)(pIDs[i], 1);
823     }
824
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)
827     {
828         VOGL_FUNC_TRACER
829
830         if (!trace_handle)
831             return 0;
832
833         gl_handle_hash_map::const_iterator it = handle_hash_map.find(trace_handle);
834         if (it == handle_hash_map.end())
835         {
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);
837
838             if (insert_if_not_found)
839                 handle_hash_map.insert(trace_handle, trace_handle);
840
841             return trace_handle;
842         }
843
844         return it->second;
845     }
846
847     inline bool map_handle(vogl_handle_tracker &handle_tracker, GLuint trace_handle, GLuint &replay_handle)
848     {
849         VOGL_FUNC_TRACER
850
851         replay_handle = trace_handle;
852
853         if (!trace_handle)
854             return true;
855
856         if (!handle_tracker.map_handle_to_inv_handle(trace_handle, replay_handle))
857         {
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()));
859             return false;
860         }
861
862         return true;
863     }
864
865     inline GLuint map_handle(vogl_handle_tracker &handle_tracker, GLuint trace_handle, bool *pSuccess = NULL)
866     {
867         VOGL_FUNC_TRACER
868
869         if (!trace_handle)
870         {
871             if (pSuccess)
872                 *pSuccess = true;
873             return trace_handle;
874         }
875
876         GLuint replay_handle = trace_handle;
877         if (!handle_tracker.map_handle_to_inv_handle(trace_handle, replay_handle))
878         {
879             if (pSuccess)
880                 *pSuccess = false;
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;
883         }
884
885         if (pSuccess)
886             *pSuccess = true;
887         return replay_handle;
888     }
889
890     inline context_state *get_trace_context_state(vogl_trace_context_ptr_value trace_context)
891     {
892         VOGL_FUNC_TRACER
893
894         if (!trace_context)
895             return NULL;
896
897         context_hash_map::iterator it = m_contexts.find(trace_context);
898         return (it == m_contexts.end()) ? NULL : it->second;
899     }
900
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);
902
903     GLXContext remap_context(vogl_trace_context_ptr_value trace_context);
904
905     bool destroy_context(vogl_trace_context_ptr_value trace_context);
906
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);
909
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);
912
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);
914
915     GLint determine_uniform_replay_location(GLuint trace_program, GLint trace_location);
916
917     inline GLint determine_uniform_replay_location(GLint trace_location)
918     {
919         return determine_uniform_replay_location(m_pCur_context_state->m_cur_trace_program, trace_location);
920     }
921
922     template <uint N, class T, class F>
923     inline void set_uniformv_helper(F func)
924     {
925         VOGL_FUNC_TRACER
926
927         GLint replay_location = determine_uniform_replay_location(m_pCur_gl_packet->get_param_value<GLint>(0));
928
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);
932
933         func(replay_location, count, pValues);
934     }
935
936     template <uint C, uint R, class T, class F>
937     inline void set_uniform_matrixv_helper(F func)
938     {
939         VOGL_FUNC_TRACER
940
941         GLint replay_location = determine_uniform_replay_location(m_pCur_gl_packet->get_param_value<GLint>(0));
942
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);
947
948         func(replay_location, count, transpose, pValues);
949     }
950
951     // glUniform* helpers
952     template <class T, class F>
953     inline void set_uniform_helper1(F func)
954     {
955         VOGL_FUNC_TRACER
956
957         func(determine_uniform_replay_location(m_pCur_gl_packet->get_param_value<GLint>(0)), m_pCur_gl_packet->get_param_value<T>(1));
958     }
959
960     template <class T, class F>
961     inline void set_uniform_helper2(F func)
962     {
963         VOGL_FUNC_TRACER
964
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));
966     }
967
968     template <class T, class F>
969     inline void set_uniform_helper3(F func)
970     {
971         VOGL_FUNC_TRACER
972
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));
974     }
975
976     template <class T, class F>
977     inline void set_uniform_helper4(F func)
978     {
979         VOGL_FUNC_TRACER
980
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));
982     }
983
984     // glSetProgramUniform* helpers
985     template <class T, class F>
986     inline void set_program_uniform_helper1(F func)
987     {
988         VOGL_FUNC_TRACER
989
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));
993     }
994
995     template <class T, class F>
996     inline void set_program_uniform_helper2(F func)
997     {
998         VOGL_FUNC_TRACER
999
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));
1003     }
1004
1005     template <class T, class F>
1006     inline void set_program_uniform_helper3(F func)
1007     {
1008         VOGL_FUNC_TRACER
1009
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));
1013     }
1014
1015     template <class T, class F>
1016     inline void set_program_uniform_helper4(F func)
1017     {
1018         VOGL_FUNC_TRACER
1019
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));
1023     }
1024
1025     template <uint C, uint R, class T, class F>
1026     inline void set_program_uniform_matrixv_helper(F func)
1027     {
1028         VOGL_FUNC_TRACER
1029
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);
1032
1033         GLint replay_location = determine_uniform_replay_location(trace_handle, m_pCur_gl_packet->get_param_value<GLint>(1));
1034
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);
1039
1040         func(replay_handle, replay_location, count, transpose, pValues);
1041     }
1042
1043     template <uint N, class T, class F>
1044     inline void set_program_uniformv_helper(F func)
1045     {
1046         VOGL_FUNC_TRACER
1047
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);
1050
1051         GLint replay_location = determine_uniform_replay_location(trace_handle, m_pCur_gl_packet->get_param_value<GLint>(1));
1052
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);
1055
1056         VOGL_ASSERT((uint)m_pCur_gl_packet->get_param_client_memory_data_size(3) == sizeof(T) * N * count);
1057
1058         func(replay_handle, replay_location, count, pValues);
1059     }
1060
1061     static void delete_objects_arb(GLsizei n, const GLuint *pHandles)
1062     {
1063         VOGL_FUNC_TRACER
1064
1065         for (GLsizei i = 0; i < n; i++)
1066             GL_ENTRYPOINT(glDeleteObjectARB)(pHandles[i]);
1067     }
1068
1069     template <typename T, typename F>
1070     inline status_t get_vertex_attrib_helper(F entrypoint)
1071     {
1072         if (benchmark_mode())
1073             return cStatusOK;
1074
1075         VOGL_FUNC_TRACER
1076
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);
1081
1082         int n = g_gl_enums.get_pname_count(pname);
1083         if (n <= 0)
1084         {
1085             process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
1086             return cStatusSoftFailure;
1087         }
1088
1089         vogl::vector<T> params(n);
1090         entrypoint(index, pname, params.get_ptr());
1091
1092         if (num_trace_params < static_cast<uint>(n))
1093         {
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;
1096         }
1097         else if (!pTrace_params)
1098         {
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;
1101         }
1102         else
1103         {
1104             if (memcmp(pTrace_params, params.get_ptr(), n * sizeof(T)) != 0)
1105             {
1106                 process_entrypoint_error("%s: Replay's results differ from trace's\n", VOGL_METHOD_NAME);
1107                 return cStatusSoftFailure;
1108             }
1109         }
1110
1111         return cStatusOK;
1112     }
1113
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)
1118     {
1119         VOGL_FUNC_TRACER
1120
1121         const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[id];
1122         VOGL_NOTE_UNUSED(desc);
1123
1124         GLuint buffer = vogl_get_bound_gl_buffer(GL_ARRAY_BUFFER);
1125
1126         GLvoid *pPtr = reinterpret_cast<GLvoid *>(trace_pointer);
1127         if ((!buffer) && (trace_pointer))
1128         {
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())
1132             {
1133                 array_data.resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
1134             }
1135             pPtr = array_data.get_ptr();
1136         }
1137
1138         func(size, type, stride, pPtr);
1139     }
1140
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)
1145     {
1146         VOGL_FUNC_TRACER
1147
1148         const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[id];
1149         VOGL_NOTE_UNUSED(desc);
1150
1151         GLuint buffer = vogl_get_bound_gl_buffer(GL_ARRAY_BUFFER);
1152
1153         GLvoid *pPtr = reinterpret_cast<GLvoid *>(trace_pointer);
1154         if ((!buffer) && (trace_pointer))
1155         {
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())
1159             {
1160                 array_data.resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
1161             }
1162             pPtr = array_data.get_ptr();
1163         }
1164
1165         func(size, type, stride, count, pPtr);
1166     }
1167
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)
1172     {
1173         VOGL_FUNC_TRACER
1174
1175         const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[id];
1176         VOGL_NOTE_UNUSED(desc);
1177
1178         GLuint buffer = vogl_get_bound_gl_buffer(GL_ARRAY_BUFFER);
1179         GLvoid *pPtr = reinterpret_cast<GLvoid *>(trace_pointer);
1180         if ((!buffer) && (trace_pointer))
1181         {
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())
1185             {
1186                 m_client_side_array_data[id].resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
1187             }
1188             pPtr = m_client_side_array_data[id].get_ptr();
1189         }
1190
1191         func(type, stride, pPtr);
1192     }
1193
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)
1198     {
1199         VOGL_FUNC_TRACER
1200
1201         const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[id];
1202         VOGL_NOTE_UNUSED(desc);
1203
1204         GLuint buffer = vogl_get_bound_gl_buffer(GL_ARRAY_BUFFER);
1205         GLvoid *pPtr = reinterpret_cast<GLvoid *>(trace_pointer);
1206         if ((!buffer) && (trace_pointer))
1207         {
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())
1211             {
1212                 m_client_side_array_data[id].resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
1213             }
1214             pPtr = m_client_side_array_data[id].get_ptr();
1215         }
1216
1217         func(type, stride, count, pPtr);
1218     }
1219
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)
1224     {
1225         VOGL_FUNC_TRACER
1226
1227         const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[id];
1228         VOGL_NOTE_UNUSED(desc);
1229
1230         GLuint buffer = vogl_get_bound_gl_buffer(GL_ARRAY_BUFFER);
1231         GLvoid *pPtr = reinterpret_cast<GLvoid *>(trace_pointer);
1232         if ((!buffer) && (trace_pointer))
1233         {
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())
1237             {
1238                 m_client_side_array_data[id].resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
1239             }
1240             pPtr = m_client_side_array_data[id].get_ptr();
1241         }
1242
1243         func(stride, pPtr);
1244     }
1245
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)
1250     {
1251         VOGL_FUNC_TRACER
1252
1253         const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[id];
1254         VOGL_NOTE_UNUSED(desc);
1255
1256         GLuint buffer = vogl_get_bound_gl_buffer(GL_ARRAY_BUFFER);
1257         GLvoid *pPtr = reinterpret_cast<GLvoid *>(trace_pointer);
1258         if ((!buffer) && (trace_pointer))
1259         {
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())
1263             {
1264                 m_client_side_array_data[id].resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
1265             }
1266             pPtr = m_client_side_array_data[id].get_ptr();
1267         }
1268
1269         func(stride, count, static_cast<const GLchar *>(pPtr));
1270     }
1271
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);
1279
1280     status_t switch_contexts(vogl_trace_context_ptr_value trace_context);
1281
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);
1285
1286     bool is_extension_supported(const char *pExt);
1287
1288     bool handle_context_made_current();
1289
1290     void dump_context_attrib_list(const int *pAttrib_list, uint size);
1291
1292     int find_attrib_key(const vogl::vector<int> &attrib_list, int key_to_find);
1293
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);
1297
1298     status_t process_pending_make_current();
1299
1300     status_t process_internal_trace_command(const vogl_trace_gl_entrypoint_packet &gl_packet);
1301
1302     void snapshot_backbuffer();
1303
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);
1310
1311     static void display_list_bind_callback(vogl_namespace_t handle_namespace, GLenum target, GLuint handle, void *pOpaque);
1312
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);
1320
1321     vogl_gl_replayer::status_t process_applying_pending_snapshot();
1322     bool validate_program_and_shader_handle_tables();
1323     bool validate_textures();
1324
1325     void fill_replay_handle_hash_set(vogl_handle_hash_set &replay_handle_hash, const gl_handle_hash_map &trace_to_replay_hash);
1326
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);
1329
1330     bool dump_frontbuffer_to_file(const dynamic_string &filename);
1331
1332     bool benchmark_mode() const
1333     {
1334         return (m_flags & cGLReplayerBenchmarkMode) != 0;
1335     }
1336
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);
1340 };
1341
1342 #endif // VOGL_GL_REPLAYER_H