]> git.cworth.org Git - vogl/blob - src/voglcommon/vogl_gl_replayer.h
Initial vogl checkin
[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     struct mapped_buffer_desc
348     {
349         GLuint m_buffer;
350         GLenum m_target;
351         vogl_trace_ptr_value m_offset;
352         vogl_trace_ptr_value m_length;
353         GLbitfield m_access;
354         bool m_range;
355         void *m_pPtr;
356     };
357
358     class context_state
359     {
360         VOGL_NO_COPY_OR_ASSIGNMENT_OP(context_state);
361
362     public:
363         context_state(vogl_gl_replayer &replayer)
364             : m_replayer(replayer)
365         {
366             VOGL_FUNC_TRACER
367
368             m_pShared_state = this;
369             m_ref_count = 1;
370             m_deleted = false;
371
372             m_last_call_counter = 0;
373
374             m_has_been_made_current = false;
375             m_inside_gl_begin = false;
376
377             m_trace_context = 0;
378             m_replay_context = 0;
379
380             m_cur_replay_program = 0;
381             m_cur_trace_program = 0;
382
383             m_current_display_list_handle = -1;
384             m_current_display_list_mode = GL_NONE;
385         }
386
387         bool handle_context_made_current();
388
389         bool is_root_context() const
390         {
391             return m_pShared_state == this;
392         }
393         bool is_share_context() const
394         {
395             return m_pShared_state != this;
396         }
397
398         bool is_composing_display_list() const
399         {
400             return m_current_display_list_handle >= 0;
401         }
402
403         vogl_gl_replayer &m_replayer;
404
405         vogl_context_desc m_context_desc;
406         vogl_context_info m_context_info;
407
408         context_state *m_pShared_state;
409         int m_ref_count;
410         bool m_deleted;
411
412         uint64_t m_last_call_counter;
413
414         bool m_has_been_made_current;
415         bool m_inside_gl_begin;
416
417         vogl_trace_context_ptr_value m_trace_context;
418         GLXContext m_replay_context;
419
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;
427
428         gl_handle_hash_map m_lists;
429
430         gl_sync_hash_map m_syncs;
431
432         // maps trace programs to glsl_program_state's
433         glsl_program_hash_map m_glsl_program_hash_map;
434
435         // maps replay query handles to the last active begin target
436         vogl_handle_hash_map m_query_targets;
437
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
440
441         GLuint m_cur_replay_program;
442         GLuint m_cur_trace_program;
443
444         vogl::vector<mapped_buffer_desc> m_mapped_buffers;
445
446         vogl::vector<GLfloat> m_feedback_buffer;
447         vogl::vector<GLuint> m_select_buffer;
448
449         vogl_capture_context_params m_shadow_state;
450
451         int m_current_display_list_handle;
452         GLenum m_current_display_list_mode;
453     };
454
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;
457
458     vogl_trace_context_ptr_value m_cur_trace_context;
459     GLXContext m_cur_replay_context;
460     context_state *m_pCur_context_state;
461
462     context_state *get_context_state()
463     {
464         return m_pCur_context_state;
465     }
466     context_state *get_shared_state()
467     {
468         return m_pCur_context_state->m_pShared_state;
469     }
470
471     enum
472     {
473         VOGL_MAX_SUPPORTED_GL_VERTEX_ATTRIBUTES = 32,
474         VOGL_MAX_SUPPORTED_GL_TEXCOORD_ARRAYS = 32
475     };
476
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];
480
481     uint8_vec m_screenshot_buffer;
482
483     vogl::vector<uint8> m_index_data;
484
485     uint64_t m_frame_draw_counter;
486     uint64_t m_frame_draw_counter_kill_threshold;
487
488     bool m_is_valid;
489
490     const vogl_blob_manager *m_pBlob_manager;
491
492     const vogl_gl_state_snapshot *m_pPending_snapshot;
493     bool m_delete_pending_snapshot_after_applying;
494
495     // TODO: Make a 1st class snapshot cache class
496     struct snapshot_cache_entry
497     {
498         snapshot_cache_entry()
499             : m_pSnapshot(NULL)
500         {
501         }
502
503         dynamic_string m_name;
504         vogl_gl_state_snapshot *m_pSnapshot;
505     };
506     typedef vogl::vector<snapshot_cache_entry> snapshot_vec;
507     snapshot_vec m_snapshots;
508
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);
511
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();
515
516     void destroy_pending_snapshot();
517
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)
522
523     void destroy_contexts();
524     void clear_contexts();
525
526     // from=replay, to=trace
527     class replay_to_trace_handle_remapper : public vogl_handle_remapper
528     {
529         vogl_gl_replayer &m_replayer;
530
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
533         {
534             VOGL_ASSERT(hash_map.search_table_for_value_get_count(handle) <= 1);
535
536             gl_handle_hash_map::const_iterator it(hash_map.search_table_for_value(handle));
537             if (it != hash_map.end())
538             {
539                 VOGL_ASSERT(it->second == handle);
540                 handle = it->first;
541                 return true;
542             }
543             return false;
544         }
545
546     public:
547         replay_to_trace_handle_remapper(vogl_gl_replayer &replayer)
548             : m_replayer(replayer)
549         {
550         }
551
552         virtual bool is_default_remapper() const
553         {
554             return false;
555         }
556
557         virtual uint64_t remap_handle(vogl_namespace_t handle_namespace, uint64_t replay_handle);
558
559         virtual bool is_valid_handle(vogl_namespace_t handle_namespace, uint64_t replay_handle);
560
561         virtual int32 remap_location(uint32 replay_program, int32 replay_location);
562
563         virtual vogl_trace_ptr_value remap_vertex_attrib_ptr(uint index, vogl_trace_ptr_value ptr_val)
564         {
565             VOGL_NOTE_UNUSED(index);
566             return ptr_val;
567         }
568
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)
570         {
571             VOGL_NOTE_UNUSED(id);
572             VOGL_NOTE_UNUSED(index);
573             return ptr_val;
574         }
575
576         virtual bool determine_from_object_target(vogl_namespace_t handle_namespace, uint64_t replay_handle, GLenum &target);
577
578         virtual bool determine_to_object_target(vogl_namespace_t handle_namespace, uint64_t trace_handle, GLenum &target);
579     };
580
581     replay_to_trace_handle_remapper m_replay_to_trace_remapper;
582
583     // from=trace, to=replay
584     class trace_to_replay_handle_remapper : public vogl_handle_remapper
585     {
586         vogl_gl_replayer &m_replayer;
587
588     public:
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)
592         {
593         }
594
595         virtual bool is_default_remapper() const
596         {
597             return false;
598         }
599
600         virtual uint64_t remap_handle(vogl_namespace_t handle_namespace, uint64_t from_handle);
601
602         virtual bool is_valid_handle(vogl_namespace_t handle_namespace, uint64_t replay_handle);
603
604         virtual int32 remap_location(uint32 trace_program, int32 from_location);
605
606         virtual vogl_trace_ptr_value remap_vertex_attrib_ptr(uint index, vogl_trace_ptr_value ptr_val);
607
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);
609
610         virtual void declare_handle(vogl_namespace_t handle_namespace, uint64_t from_handle, uint64_t to_handle, GLenum target);
611
612         virtual void delete_handle_and_object(vogl_namespace_t handle_namespace, uint64_t from_handle, uint64_t to_handle);
613
614         virtual void declare_location(uint32 from_program_handle, uint32 to_program_handle, int32 from_location, int32 to_location);
615
616         virtual bool determine_from_object_target(vogl_namespace_t handle_namespace, uint64_t trace_handle, GLenum &target);
617
618         virtual bool determine_to_object_target(vogl_namespace_t handle_namespace, uint64_t replay_handle, GLenum &target);
619     };
620
621     inline bool gen_handle(gl_handle_hash_map &handle_hash_map, GLuint trace_handle, GLuint replay_handle)
622     {
623         VOGL_FUNC_TRACER
624
625         if (!trace_handle)
626         {
627             VOGL_ASSERT(!replay_handle);
628             return true;
629         }
630
631         if (!replay_handle)
632         {
633             process_entrypoint_error("%s: Handle gen failed during replay, but succeeded during trace! Trace handle: %u\n", VOGL_METHOD_NAME, trace_handle);
634             return false;
635         }
636         else
637         {
638             gl_handle_hash_map::insert_result result(handle_hash_map.insert(trace_handle, replay_handle));
639             if (!result.second)
640             {
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);
642
643                 gl_handle_hash_map::iterator it = result.first;
644                 it->second = replay_handle;
645             }
646         }
647
648         return true;
649     }
650
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)
653     {
654         VOGL_FUNC_TRACER
655
656         for (GLsizei i = 0; i < n; i++)
657         {
658             if (pReplay_handles)
659                 pReplay_handles[i] = 0;
660
661             if (!pTrace_ids[i])
662                 continue;
663
664             GLuint replay_id = 0;
665             gl_gen_function(1, &replay_id);
666
667             if (!replay_id)
668             {
669                 process_entrypoint_error("%s: GL handle gen call failed, but succeeded in the trace!\n", VOGL_METHOD_NAME);
670                 return false;
671             }
672
673             if (pReplay_handles)
674                 pReplay_handles[i] = replay_id;
675
676             gl_handle_hash_map::insert_result result(handle_hash_map.insert(pTrace_ids[i], replay_id));
677             if (!result.second)
678             {
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]);
680
681                 gl_handle_hash_map::iterator it = result.first;
682                 it->second = replay_id;
683             }
684         }
685
686         return true;
687     }
688
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)
691     {
692         VOGL_FUNC_TRACER
693
694         vogl::vector<GLuint> replay_ids;
695         replay_ids.reserve(trace_n);
696
697         for (int i = 0; i < trace_n; i++)
698         {
699             GLuint trace_id = pTrace_ids[i];
700             if (!trace_id)
701                 continue;
702
703             gl_handle_hash_map::const_iterator it(handle_hash_map.find(trace_id));
704
705             if (it != handle_hash_map.end())
706             {
707                 replay_ids.push_back(it->second);
708
709                 handle_hash_map.erase(pTrace_ids[i]);
710             }
711             else
712             {
713                 replay_ids.push_back(trace_id);
714
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]);
716             }
717         }
718
719         if (replay_ids.size())
720             gl_delete_function(replay_ids.size(), replay_ids.get_ptr());
721     }
722
723     template <typename T>
724     inline void delete_handle(gl_handle_hash_map &handle_hash_map, GLuint trace_id, T gl_delete_function)
725     {
726         VOGL_FUNC_TRACER
727
728         delete_handles(handle_hash_map, 1, &trace_id, gl_delete_function);
729     }
730
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)
733     {
734         VOGL_FUNC_TRACER
735
736         for (GLsizei i = 0; i < n; i++)
737         {
738             if (pReplay_handles)
739                 pReplay_handles[i] = 0;
740
741             if (!pTrace_ids[i])
742                 continue;
743
744             GLuint replay_id = 0;
745             gl_gen_function(1, &replay_id);
746
747             if (!replay_id)
748             {
749                 process_entrypoint_error("%s: GL handle gen call failed, but succeeded in the trace!\n", VOGL_METHOD_NAME);
750                 return false;
751             }
752
753             if (pReplay_handles)
754                 pReplay_handles[i] = replay_id;
755
756             if (!handle_tracker.insert(pTrace_ids[i], replay_id, def_target))
757             {
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]);
759
760                 handle_tracker.erase(pTrace_ids[i]);
761
762                 bool success = handle_tracker.insert(pTrace_ids[i], replay_id, def_target);
763                 VOGL_ASSERT(success);
764                 VOGL_NOTE_UNUSED(success);
765             }
766         }
767
768         return true;
769     }
770
771     inline bool gen_handle(vogl_handle_tracker &handle_tracker, const GLuint trace_id, GLuint replay_id, GLenum def_target)
772     {
773         VOGL_FUNC_TRACER
774
775         if (!trace_id)
776         {
777             VOGL_ASSERT(!replay_id);
778             return true;
779         }
780
781         if (!handle_tracker.insert(trace_id, replay_id, def_target))
782         {
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()));
784
785             handle_tracker.erase(trace_id);
786
787             bool success = handle_tracker.insert(trace_id, replay_id, def_target);
788             VOGL_ASSERT(success);
789             VOGL_NOTE_UNUSED(success);
790         }
791
792         return true;
793     }
794
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)
797     {
798         VOGL_FUNC_TRACER
799
800         vogl::growable_array<GLuint, 32> replay_ids;
801         replay_ids.reserve(trace_n);
802
803         for (int i = 0; i < trace_n; i++)
804         {
805             GLuint trace_id = pTrace_ids[i];
806             if (!trace_id)
807                 continue;
808
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()));
812             else
813                 handle_tracker.erase(trace_id);
814
815             replay_ids.push_back(replay_id);
816         }
817
818         if (replay_ids.size())
819             gl_delete_function(replay_ids.size(), replay_ids.get_ptr());
820     }
821
822     static void delete_program_helper(GLsizei n, const GLuint *pIDs)
823     {
824         VOGL_FUNC_TRACER
825
826         for (GLsizei i = 0; i < n; i++)
827             GL_ENTRYPOINT(glDeleteProgram)(pIDs[i]);
828     }
829
830     static void delete_list_helper(GLsizei n, const GLuint *pIDs)
831     {
832         VOGL_FUNC_TRACER
833
834         for (GLsizei i = 0; i < n; i++)
835             GL_ENTRYPOINT(glDeleteLists)(pIDs[i], 1);
836     }
837
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)
840     {
841         VOGL_FUNC_TRACER
842
843         if (!trace_handle)
844             return 0;
845
846         gl_handle_hash_map::const_iterator it = handle_hash_map.find(trace_handle);
847         if (it == handle_hash_map.end())
848         {
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);
850
851             if (insert_if_not_found)
852                 handle_hash_map.insert(trace_handle, trace_handle);
853
854             return trace_handle;
855         }
856
857         return it->second;
858     }
859
860     inline bool map_handle(vogl_handle_tracker &handle_tracker, GLuint trace_handle, GLuint &replay_handle)
861     {
862         VOGL_FUNC_TRACER
863
864         replay_handle = trace_handle;
865
866         if (!trace_handle)
867             return true;
868
869         if (!handle_tracker.map_handle_to_inv_handle(trace_handle, replay_handle))
870         {
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()));
872             return false;
873         }
874
875         return true;
876     }
877
878     inline GLuint map_handle(vogl_handle_tracker &handle_tracker, GLuint trace_handle, bool *pSuccess = NULL)
879     {
880         VOGL_FUNC_TRACER
881
882         if (!trace_handle)
883         {
884             if (pSuccess)
885                 *pSuccess = true;
886             return trace_handle;
887         }
888
889         GLuint replay_handle = trace_handle;
890         if (!handle_tracker.map_handle_to_inv_handle(trace_handle, replay_handle))
891         {
892             if (pSuccess)
893                 *pSuccess = false;
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;
896         }
897
898         if (pSuccess)
899             *pSuccess = true;
900         return replay_handle;
901     }
902
903     inline context_state *get_trace_context_state(vogl_trace_context_ptr_value trace_context)
904     {
905         VOGL_FUNC_TRACER
906
907         if (!trace_context)
908             return NULL;
909
910         context_hash_map::iterator it = m_contexts.find(trace_context);
911         return (it == m_contexts.end()) ? NULL : it->second;
912     }
913
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);
915
916     GLXContext remap_context(vogl_trace_context_ptr_value trace_context);
917
918     bool destroy_context(vogl_trace_context_ptr_value trace_context);
919
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);
922
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);
925
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);
927
928     GLint determine_uniform_replay_location(GLuint trace_program, GLint trace_location);
929
930     inline GLint determine_uniform_replay_location(GLint trace_location)
931     {
932         return determine_uniform_replay_location(m_pCur_context_state->m_cur_trace_program, trace_location);
933     }
934
935     template <uint N, class T, class F>
936     inline void set_uniformv_helper(F func)
937     {
938         VOGL_FUNC_TRACER
939
940         GLint replay_location = determine_uniform_replay_location(m_pCur_gl_packet->get_param_value<GLint>(0));
941
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);
945
946         func(replay_location, count, pValues);
947     }
948
949     template <uint C, uint R, class T, class F>
950     inline void set_uniform_matrixv_helper(F func)
951     {
952         VOGL_FUNC_TRACER
953
954         GLint replay_location = determine_uniform_replay_location(m_pCur_gl_packet->get_param_value<GLint>(0));
955
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);
960
961         func(replay_location, count, transpose, pValues);
962     }
963
964     // glUniform* helpers
965     template <class T, class F>
966     inline void set_uniform_helper1(F func)
967     {
968         VOGL_FUNC_TRACER
969
970         func(determine_uniform_replay_location(m_pCur_gl_packet->get_param_value<GLint>(0)), m_pCur_gl_packet->get_param_value<T>(1));
971     }
972
973     template <class T, class F>
974     inline void set_uniform_helper2(F func)
975     {
976         VOGL_FUNC_TRACER
977
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));
979     }
980
981     template <class T, class F>
982     inline void set_uniform_helper3(F func)
983     {
984         VOGL_FUNC_TRACER
985
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));
987     }
988
989     template <class T, class F>
990     inline void set_uniform_helper4(F func)
991     {
992         VOGL_FUNC_TRACER
993
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));
995     }
996
997     // glSetProgramUniform* helpers
998     template <class T, class F>
999     inline void set_program_uniform_helper1(F func)
1000     {
1001         VOGL_FUNC_TRACER
1002
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));
1006     }
1007
1008     template <class T, class F>
1009     inline void set_program_uniform_helper2(F func)
1010     {
1011         VOGL_FUNC_TRACER
1012
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));
1016     }
1017
1018     template <class T, class F>
1019     inline void set_program_uniform_helper3(F func)
1020     {
1021         VOGL_FUNC_TRACER
1022
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));
1026     }
1027
1028     template <class T, class F>
1029     inline void set_program_uniform_helper4(F func)
1030     {
1031         VOGL_FUNC_TRACER
1032
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));
1036     }
1037
1038     template <uint C, uint R, class T, class F>
1039     inline void set_program_uniform_matrixv_helper(F func)
1040     {
1041         VOGL_FUNC_TRACER
1042
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);
1045
1046         GLint replay_location = determine_uniform_replay_location(trace_handle, m_pCur_gl_packet->get_param_value<GLint>(1));
1047
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);
1052
1053         func(replay_handle, replay_location, count, transpose, pValues);
1054     }
1055
1056     template <uint N, class T, class F>
1057     inline void set_program_uniformv_helper(F func)
1058     {
1059         VOGL_FUNC_TRACER
1060
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);
1063
1064         GLint replay_location = determine_uniform_replay_location(trace_handle, m_pCur_gl_packet->get_param_value<GLint>(1));
1065
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);
1068
1069         VOGL_ASSERT((uint)m_pCur_gl_packet->get_param_client_memory_data_size(3) == sizeof(T) * N * count);
1070
1071         func(replay_handle, replay_location, count, pValues);
1072     }
1073
1074     static void delete_objects_arb(GLsizei n, const GLuint *pHandles)
1075     {
1076         VOGL_FUNC_TRACER
1077
1078         for (GLsizei i = 0; i < n; i++)
1079             GL_ENTRYPOINT(glDeleteObjectARB)(pHandles[i]);
1080     }
1081
1082     template <typename T, typename F>
1083     inline status_t get_vertex_attrib_helper(F entrypoint)
1084     {
1085         if (benchmark_mode())
1086             return cStatusOK;
1087
1088         VOGL_FUNC_TRACER
1089
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);
1094
1095         int n = g_gl_enums.get_pname_count(pname);
1096         if (n <= 0)
1097         {
1098             process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
1099             return cStatusSoftFailure;
1100         }
1101
1102         vogl::vector<T> params(n);
1103         entrypoint(index, pname, params.get_ptr());
1104
1105         if (num_trace_params < static_cast<uint>(n))
1106         {
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;
1109         }
1110         else if (!pTrace_params)
1111         {
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;
1114         }
1115         else
1116         {
1117             if (memcmp(pTrace_params, params.get_ptr(), n * sizeof(T)) != 0)
1118             {
1119                 process_entrypoint_error("%s: Replay's results differ from trace's\n", VOGL_METHOD_NAME);
1120                 return cStatusSoftFailure;
1121             }
1122         }
1123
1124         return cStatusOK;
1125     }
1126
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)
1131     {
1132         VOGL_FUNC_TRACER
1133
1134         const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[id];
1135         VOGL_NOTE_UNUSED(desc);
1136
1137         GLuint buffer = vogl_get_bound_gl_buffer(GL_ARRAY_BUFFER);
1138
1139         GLvoid *pPtr = reinterpret_cast<GLvoid *>(trace_pointer);
1140         if ((!buffer) && (trace_pointer))
1141         {
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())
1145             {
1146                 array_data.resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
1147             }
1148             pPtr = array_data.get_ptr();
1149         }
1150
1151         func(size, type, stride, pPtr);
1152     }
1153
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)
1158     {
1159         VOGL_FUNC_TRACER
1160
1161         const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[id];
1162         VOGL_NOTE_UNUSED(desc);
1163
1164         GLuint buffer = vogl_get_bound_gl_buffer(GL_ARRAY_BUFFER);
1165
1166         GLvoid *pPtr = reinterpret_cast<GLvoid *>(trace_pointer);
1167         if ((!buffer) && (trace_pointer))
1168         {
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())
1172             {
1173                 array_data.resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
1174             }
1175             pPtr = array_data.get_ptr();
1176         }
1177
1178         func(size, type, stride, count, pPtr);
1179     }
1180
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)
1185     {
1186         VOGL_FUNC_TRACER
1187
1188         const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[id];
1189         VOGL_NOTE_UNUSED(desc);
1190
1191         GLuint buffer = vogl_get_bound_gl_buffer(GL_ARRAY_BUFFER);
1192         GLvoid *pPtr = reinterpret_cast<GLvoid *>(trace_pointer);
1193         if ((!buffer) && (trace_pointer))
1194         {
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())
1198             {
1199                 m_client_side_array_data[id].resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
1200             }
1201             pPtr = m_client_side_array_data[id].get_ptr();
1202         }
1203
1204         func(type, stride, pPtr);
1205     }
1206
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)
1211     {
1212         VOGL_FUNC_TRACER
1213
1214         const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[id];
1215         VOGL_NOTE_UNUSED(desc);
1216
1217         GLuint buffer = vogl_get_bound_gl_buffer(GL_ARRAY_BUFFER);
1218         GLvoid *pPtr = reinterpret_cast<GLvoid *>(trace_pointer);
1219         if ((!buffer) && (trace_pointer))
1220         {
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())
1224             {
1225                 m_client_side_array_data[id].resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
1226             }
1227             pPtr = m_client_side_array_data[id].get_ptr();
1228         }
1229
1230         func(type, stride, count, pPtr);
1231     }
1232
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)
1237     {
1238         VOGL_FUNC_TRACER
1239
1240         const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[id];
1241         VOGL_NOTE_UNUSED(desc);
1242
1243         GLuint buffer = vogl_get_bound_gl_buffer(GL_ARRAY_BUFFER);
1244         GLvoid *pPtr = reinterpret_cast<GLvoid *>(trace_pointer);
1245         if ((!buffer) && (trace_pointer))
1246         {
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())
1250             {
1251                 m_client_side_array_data[id].resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
1252             }
1253             pPtr = m_client_side_array_data[id].get_ptr();
1254         }
1255
1256         func(stride, pPtr);
1257     }
1258
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)
1263     {
1264         VOGL_FUNC_TRACER
1265
1266         const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[id];
1267         VOGL_NOTE_UNUSED(desc);
1268
1269         GLuint buffer = vogl_get_bound_gl_buffer(GL_ARRAY_BUFFER);
1270         GLvoid *pPtr = reinterpret_cast<GLvoid *>(trace_pointer);
1271         if ((!buffer) && (trace_pointer))
1272         {
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())
1276             {
1277                 m_client_side_array_data[id].resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
1278             }
1279             pPtr = m_client_side_array_data[id].get_ptr();
1280         }
1281
1282         func(stride, count, static_cast<const GLchar *>(pPtr));
1283     }
1284
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);
1292
1293     status_t switch_contexts(vogl_trace_context_ptr_value trace_context);
1294
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);
1297
1298     bool is_extension_supported(const char *pExt);
1299
1300     bool handle_context_made_current();
1301
1302     void dump_context_attrib_list(const int *pAttrib_list, uint size);
1303
1304     int find_attrib_key(const vogl::vector<int> &attrib_list, int key_to_find);
1305
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);
1309
1310     status_t process_pending_make_current();
1311
1312     status_t process_internal_trace_command(const vogl_trace_gl_entrypoint_packet &gl_packet);
1313
1314     void snapshot_backbuffer();
1315
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);
1322
1323     static void display_list_bind_callback(vogl_namespace_t handle_namespace, GLenum target, GLuint handle, void *pOpaque);
1324
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);
1332
1333     vogl_gl_replayer::status_t process_applying_pending_snapshot();
1334     bool validate_program_and_shader_handle_tables();
1335     bool validate_textures();
1336
1337     void fill_replay_handle_hash_set(vogl_handle_hash_set &replay_handle_hash, const gl_handle_hash_map &trace_to_replay_hash);
1338
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);
1341
1342     bool dump_frontbuffer_to_file(const dynamic_string &filename);
1343
1344     bool benchmark_mode() const
1345     {
1346         return (m_flags & cGLReplayerBenchmarkMode) != 0;
1347     }
1348
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);
1352 };
1353
1354 #endif // VOGL_GL_REPLAYER_H