]> git.cworth.org Git - vogl/blob - src/voglcommon/vogl_gl_replayer.cpp
Initial vogl checkin
[vogl] / src / voglcommon / vogl_gl_replayer.cpp
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.cpp
27 #include "vogl_gl_replayer.h"
28 #include "vogl_general_context_state.h"
29 #include "vogl_sync_object.h"
30 #include "vogl_trace_file_writer.h"
31 #include "vogl_texture_format.h"
32 #include "gl_glx_replay_helper_macros.inc"
33 #include "vogl_backtrace.h"
34
35 #define MINIZ_NO_ZLIB_COMPATIBLE_NAMES
36 #include "vogl_miniz.h"
37
38 #include "vogl_timer.h"
39 #include "vogl_file_utils.h"
40 #include "vogl_map.h"
41 #include "vogl_vector.h"
42
43 #define VOGL_GL_REPLAYER_ARRAY_OVERRUN_BYTE_MAGIC 129
44 #define VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC 0x12345678
45 #define VOGL_GL_REPLAYER_ARRAY_OVERRUN_FLOAT_MAGIC -999999.0f
46
47 //----------------------------------------------------------------------------------------------------------------------
48 // glInterleavedArrays helper table
49 //----------------------------------------------------------------------------------------------------------------------
50 struct interleaved_array_desc_entry_t
51 {
52     uint fmt;
53     bool et;
54     bool ec;
55     bool en;
56     uint st;
57     uint sc;
58     uint sv;
59     uint tc;
60     uint pc;
61     uint pn;
62     uint pv;
63     uint s;
64 };
65
66 #define _2f (sizeof(GLfloat) * 2)
67 #define _3f (sizeof(GLfloat) * 3)
68 #define _4f (sizeof(GLfloat) * 4)
69 #define _5f (sizeof(GLfloat) * 5)
70 #define _6f (sizeof(GLfloat) * 6)
71 #define _7f (sizeof(GLfloat) * 7)
72 #define _8f (sizeof(GLfloat) * 8)
73 #define _9f (sizeof(GLfloat) * 9)
74 #define _10f (sizeof(GLfloat) * 10)
75 #define _11f (sizeof(GLfloat) * 11)
76 #define _12f (sizeof(GLfloat) * 12)
77 #define _15f (sizeof(GLfloat) * 15)
78 #define _c (sizeof(GL_UNSIGNED_BYTE) * 4)
79
80 static const interleaved_array_desc_entry_t vogl_g_interleaved_array_descs[] =
81     {
82         // format                               et              ec                      en       st sc sv tc                                                    pc  pn  pv               s
83         { GL_V2F, false, false, false, 0, 0, 2, 0, 0, 0, 0, _2f },
84         { GL_V3F, false, false, false, 0, 0, 3, 0, 0, 0, 0, _3f },
85         { GL_C4UB_V2F, false, true, false, 0, 4, 2, GL_UNSIGNED_BYTE, 0, 0, _c, _c + _2f },
86         { GL_C4UB_V3F, false, true, false, 0, 4, 3, GL_UNSIGNED_BYTE, 0, 0, _c, _c + _3f },
87         { GL_C3F_V3F, false, true, false, 0, 3, 3, GL_FLOAT, 0, 0, _3f, _6f },
88         { GL_N3F_V3F, false, false, true, 0, 0, 3, 0, 0, 0, _3f, _6f },
89         { GL_C4F_N3F_V3F, false, true, true, 0, 4, 3, GL_FLOAT, 0, _4f, _7f, _10f },
90         { GL_T2F_V3F, true, false, false, 2, 0, 3, 0, 0, 0, _2f, _5f },
91         { GL_T4F_V4F, true, false, false, 4, 0, 4, 0, 0, 0, _4f, _8f },
92         { GL_T2F_C4UB_V3F, true, true, false, 2, 4, 3, GL_UNSIGNED_BYTE, _2f, 0, _c + _2f, _c + _5f },
93         { GL_T2F_C3F_V3F, true, true, false, 2, 3, 3, GL_FLOAT, 0, _2f, _5f, _8f },
94         { GL_T2F_N3F_V3F, true, false, true, 2, 0, 3, 0, 0, _2f, _5f, _8f },
95         { GL_T2F_C4F_N3F_V3F, true, true, true, 2, 4, 3, GL_FLOAT, _2f, _6f, _9f, _12f },
96         { GL_T4F_C4F_N3F_V4F, true, true, true, 4, 4, 4, GL_FLOAT, _4f, _8f, _11f, _15f }
97     };
98
99 #undef _2f
100 #undef _3f
101 #undef _4f
102 #undef _5f
103 #undef _6f
104 #undef _7f
105 #undef _8f
106 #undef _9f
107 #undef _10f
108 #undef _11f
109 #undef _12f
110 #undef _15f
111 #undef _c
112
113 #define VOGL_INTERLEAVED_ARRAY_SIZE (sizeof(vogl_g_interleaved_array_descs) / sizeof(vogl_g_interleaved_array_descs[0]))
114
115 //----------------------------------------------------------------------------------------------------------------------
116 // vogl_replayer::vogl_replayer
117 //----------------------------------------------------------------------------------------------------------------------
118 vogl_gl_replayer::vogl_gl_replayer()
119     : m_flags(0),
120       m_swap_sleep_time(0),
121       m_dump_framebuffer_on_draw_prefix("screenshot"),
122       m_screenshot_prefix("screenshot"),
123       m_dump_framebuffer_on_draw_frame_index(-1),
124       m_dump_framebuffer_on_draw_first_gl_call_index(-1),
125       m_dump_framebuffer_on_draw_last_gl_call_index(-1),
126       m_ctypes_packet(&m_trace_gl_ctypes),
127       m_trace_pointer_size_in_bytes(0),
128       m_trace_pointer_size_in_uints(0),
129       m_temp_gl_packet(&m_trace_gl_ctypes),
130       m_temp2_gl_packet(&m_trace_gl_ctypes),
131       m_pCur_gl_packet(NULL),
132       m_pWindow(NULL),
133       m_pending_make_current_packet(&m_trace_gl_ctypes),
134       m_pending_window_resize_width(0),
135       m_pending_window_resize_height(0),
136       m_pending_window_resize_attempt_counter(false),
137       m_frame_index(0),
138       m_total_swaps(0),
139       m_last_parsed_call_counter(-1),
140       m_last_processed_call_counter(-1),
141       m_cur_trace_context(0),
142       m_cur_replay_context(NULL),
143       m_pCur_context_state(NULL),
144       m_frame_draw_counter(0),
145       m_frame_draw_counter_kill_threshold(cUINT64_MAX),
146       m_is_valid(false),
147       m_pBlob_manager(NULL),
148       m_pPending_snapshot(NULL),
149       m_delete_pending_snapshot_after_applying(false),
150       m_replay_to_trace_remapper(*this)
151 {
152     VOGL_FUNC_TRACER
153
154     m_trace_gl_ctypes.init();
155 }
156
157 //----------------------------------------------------------------------------------------------------------------------
158 // vogl_replayer::~vogl_replayer
159 //----------------------------------------------------------------------------------------------------------------------
160 vogl_gl_replayer::~vogl_gl_replayer()
161 {
162     VOGL_FUNC_TRACER
163
164     deinit();
165 }
166
167 //----------------------------------------------------------------------------------------------------------------------
168 // vogl_replayer::init
169 //----------------------------------------------------------------------------------------------------------------------
170 bool vogl_gl_replayer::init(uint flags, vogl_replay_window *pWindow, const vogl_trace_stream_start_of_file_packet &sof_packet, const vogl_blob_manager &blob_manager)
171 {
172     VOGL_FUNC_TRACER
173
174     if (m_is_valid)
175         deinit();
176
177     if ((!pWindow) || (!pWindow->is_opened()))
178     {
179         VOGL_ASSERT_ALWAYS;
180         return false;
181     }
182
183     if ((sof_packet.m_pointer_sizes != sizeof(uint32)) && (sof_packet.m_pointer_sizes != sizeof(uint64_t)))
184     {
185         vogl_error_printf("%s: Invalid trace pointer size (%u)\n", VOGL_METHOD_NAME, m_sof_packet.m_pointer_sizes);
186         return false;
187     }
188
189     m_pBlob_manager = &blob_manager;
190     m_flags = flags;
191     m_pWindow = pWindow;
192
193     m_sof_packet = sof_packet;
194     m_trace_pointer_size_in_bytes = m_sof_packet.m_pointer_sizes;
195     m_trace_pointer_size_in_uints = m_sof_packet.m_pointer_sizes / sizeof(uint);
196
197     m_trace_gl_ctypes.init();
198     m_trace_gl_ctypes.change_pointer_sizes(m_trace_pointer_size_in_bytes);
199
200     if (!m_pWindow->is_opened())
201     {
202         const uint initial_window_width = 1024;
203         const uint initial_window_height = 768;
204         if (!m_pWindow->open(initial_window_width, initial_window_height))
205         {
206             vogl_error_printf("%s: Failed opening window!\n", VOGL_METHOD_NAME);
207             return false;
208         }
209     }
210
211     m_pCur_gl_packet = NULL;
212
213     m_frame_index = 0;
214     m_total_swaps = 0;
215     m_last_parsed_call_counter = 0;
216     m_last_processed_call_counter = 0;
217
218     m_pending_make_current_packet.clear();
219     m_pending_window_resize_width = 0;
220     m_pending_window_resize_height = 0;
221     m_pending_window_resize_attempt_counter = 0;
222
223     m_at_frame_boundary = true;
224
225     m_cur_trace_context = 0;
226     m_cur_replay_context = 0;
227     m_pCur_context_state = NULL;
228
229     m_contexts.clear();
230
231     m_frame_draw_counter = 0;
232     m_frame_draw_counter_kill_threshold = cUINT64_MAX;
233
234     m_is_valid = true;
235
236     return true;
237 }
238
239 //----------------------------------------------------------------------------------------------------------------------
240 // vogl_replayer::deinit
241 //----------------------------------------------------------------------------------------------------------------------
242 void vogl_gl_replayer::deinit()
243 {
244     VOGL_FUNC_TRACER
245
246     destroy_pending_snapshot();
247     destroy_contexts();
248
249     // TODO: Make a 1st class snapshot cache class
250     for (uint i = 0; i < m_snapshots.size(); i++)
251         vogl_delete(m_snapshots[i].m_pSnapshot);
252     m_snapshots.clear();
253
254     m_ctypes_packet.reset();
255
256     m_pCur_gl_packet = NULL;
257
258     m_frame_index = 0;
259     m_total_swaps = 0;
260     m_last_parsed_call_counter = 0;
261     m_last_processed_call_counter = 0;
262
263     m_pending_make_current_packet.clear();
264     m_pending_window_resize_width = 0;
265     m_pending_window_resize_height = 0;
266     m_pending_window_resize_attempt_counter = 0;
267
268     m_at_frame_boundary = true;
269
270     m_cur_trace_context = 0;
271     m_cur_replay_context = 0;
272     m_pCur_context_state = NULL;
273
274     m_frame_draw_counter = 0;
275     m_frame_draw_counter_kill_threshold = cUINT32_MAX;
276
277     m_pBlob_manager = NULL;
278
279     m_flags = 0;
280     m_swap_sleep_time = 0;
281     m_dump_framebuffer_on_draw_prefix = "screenshot";
282     m_screenshot_prefix = "screenshot";
283     m_backbuffer_hash_filename.clear();
284     m_dump_framebuffer_on_draw_frame_index = -1;
285     m_dump_framebuffer_on_draw_first_gl_call_index = -1;
286     m_dump_framebuffer_on_draw_last_gl_call_index = -1;
287
288     m_dump_frontbuffer_filename.clear();
289
290     m_is_valid = false;
291 }
292
293 //----------------------------------------------------------------------------------------------------------------------
294 // vogl_gl_replayer::dump_trace_gl_packet_debug_info
295 //----------------------------------------------------------------------------------------------------------------------
296 void vogl_gl_replayer::dump_trace_gl_packet_debug_info(const vogl_trace_gl_entrypoint_packet &gl_packet)
297 {
298     VOGL_FUNC_TRACER
299
300     vogl_debug_printf("Trace packet: Total size %u, Param size: %u, Client mem size %u, Name value size %u, call %" PRIu64 ", ID: %s (%u), Thread ID: 0x%" PRIX64 ", Trace Context: 0x%" PRIX64 "\n",
301                      gl_packet.m_size,
302                      gl_packet.m_param_size,
303                      gl_packet.m_client_memory_size,
304                      gl_packet.m_name_value_map_size,
305                      gl_packet.m_call_counter,
306                      g_vogl_entrypoint_descs[gl_packet.m_entrypoint_id].m_pName,
307                      gl_packet.m_entrypoint_id,
308                      gl_packet.m_thread_id,
309                      gl_packet.m_context_handle);
310 }
311
312 //----------------------------------------------------------------------------------------------------------------------
313 // vogl_gl_replayer::dump_packet_as_func_call
314 //----------------------------------------------------------------------------------------------------------------------
315 void vogl_gl_replayer::dump_packet_as_func_call(const vogl_trace_packet& trace_packet)
316 {
317     VOGL_FUNC_TRACER
318
319     dynamic_string str;
320     str.reserve(128);
321     if (!trace_packet.pretty_print(str, false))
322         vogl_error_printf("%s: packet pretty print failed!\n", VOGL_METHOD_NAME);
323     else
324         vogl_debug_printf("%s\n", str.get_ptr());
325 }
326
327 //----------------------------------------------------------------------------------------------------------------------
328 // vogl_replayer::process_next_packet
329 //----------------------------------------------------------------------------------------------------------------------
330 vogl_gl_replayer::status_t vogl_gl_replayer::process_next_packet(const vogl_trace_packet &gl_packet)
331 {
332     // TODO: Fix const correctness
333     return process_gl_entrypoint_packet((vogl_trace_packet &)gl_packet);
334 }
335
336 //----------------------------------------------------------------------------------------------------------------------
337 // vogl_replayer::process_next_packet
338 //----------------------------------------------------------------------------------------------------------------------
339 vogl_gl_replayer::status_t vogl_gl_replayer::process_next_packet(vogl_trace_file_reader &trace_reader)
340 {
341     VOGL_FUNC_TRACER
342
343     vogl_trace_file_reader::trace_file_reader_status_t read_status = trace_reader.read_next_packet();
344     if (read_status == vogl_trace_file_reader::cEOF)
345     {
346         vogl_message_printf("At trace file EOF\n");
347         return cStatusAtEOF;
348     }
349     else if (read_status != vogl_trace_file_reader::cOK)
350     {
351         vogl_error_printf("Failed reading from trace file\n");
352         return cStatusHardFailure;
353     }
354
355     status_t status = cStatusOK;
356
357     switch (trace_reader.get_packet_type())
358     {
359         case cTSPTSOF:
360         {
361             // just ignore it
362             break;
363         }
364         case cTSPTGLEntrypoint:
365         {
366             if (!m_temp_gl_packet.deserialize(trace_reader.get_packet_buf().get_ptr(), trace_reader.get_packet_buf().size(), false))
367             {
368                 vogl_error_printf("Failed deserializing GL entrypoint packet\n");
369                 status = cStatusHardFailure;
370                 break;
371             }
372
373             status = process_next_packet(m_temp_gl_packet);
374
375             break;
376         }
377         case cTSPTEOF:
378         {
379             vogl_message_printf("Encountered EOF packet in trace file\n");
380             status = cStatusAtEOF;
381             break;
382         }
383         default:
384         {
385             vogl_error_printf("Encountered unknown packet type in trace file\n");
386             status = cStatusSoftFailure;
387             break;
388         }
389     }
390
391     if (status < 0)
392     {
393         vogl_error_printf("%s: %s failure processing GL entrypoint packet\n", VOGL_METHOD_NAME, (status == cStatusHardFailure) ? "Hard" : "Soft");
394     }
395
396     return status;
397 }
398
399 //----------------------------------------------------------------------------------------------------------------------
400 // vogl_replayer::process_pending_window_resize
401 //----------------------------------------------------------------------------------------------------------------------
402 vogl_gl_replayer::status_t vogl_gl_replayer::process_pending_window_resize(bool *pApplied_snapshot)
403 {
404     VOGL_FUNC_TRACER
405
406     if (pApplied_snapshot)
407         *pApplied_snapshot = false;
408
409     status_t status = cStatusOK;
410
411     if (get_has_pending_window_resize())
412     {
413         status = process_frame_check_for_pending_window_resize();
414         if (status != cStatusOK)
415             return status;
416     }
417
418     if (m_pPending_snapshot)
419     {
420         if (pApplied_snapshot)
421             *pApplied_snapshot = true;
422
423         status_t status = process_applying_pending_snapshot();
424         if (status != cStatusOK)
425             return status;
426     }
427
428     return cStatusOK;
429 }
430
431 //----------------------------------------------------------------------------------------------------------------------
432 // vogl_replayer::process_frame
433 //----------------------------------------------------------------------------------------------------------------------
434 vogl_gl_replayer::status_t vogl_gl_replayer::process_frame(vogl_trace_file_reader &trace_reader)
435 {
436     VOGL_FUNC_TRACER
437
438     status_t status = cStatusOK;
439
440     for (;;)
441     {
442         status = process_next_packet(trace_reader);
443         if ((status == cStatusNextFrame) || (status == cStatusResizeWindow) || (status == cStatusAtEOF) || (status == cStatusHardFailure))
444             break;
445     }
446
447     return status;
448 }
449
450 //----------------------------------------------------------------------------------------------------------------------
451 // vogl_replayer::process_event
452 //----------------------------------------------------------------------------------------------------------------------
453 bool vogl_gl_replayer::update_window_dimensions()
454 {
455     VOGL_FUNC_TRACER
456
457     m_pWindow->update_dimensions();
458
459     return true;
460 }
461
462 //----------------------------------------------------------------------------------------------------------------------
463 // vogl_gl_replayer::dump_frontbuffer_screenshot_before_next_swap
464 //----------------------------------------------------------------------------------------------------------------------
465 bool vogl_gl_replayer::dump_frontbuffer_screenshot_before_next_swap(const dynamic_string &filename)
466 {
467     m_dump_frontbuffer_filename = filename;
468
469     return true;
470 }
471
472 //----------------------------------------------------------------------------------------------------------------------
473 // vogl_gl_replayer::dump_frontbuffer_to_file
474 //----------------------------------------------------------------------------------------------------------------------
475 bool vogl_gl_replayer::dump_frontbuffer_to_file(const dynamic_string &filename)
476 {
477     if ((!m_is_valid) || (!m_pWindow))
478     {
479         VOGL_ASSERT_ALWAYS;
480         return false;
481     }
482
483     uint width = 0, height = 0;
484     m_pWindow->get_actual_dimensions(width, height);
485
486     m_screenshot_buffer.resize(width * height * 3);
487
488     bool success = vogl_copy_buffer_to_image(m_screenshot_buffer.get_ptr(), m_screenshot_buffer.size(), width, height, GL_RGB, GL_UNSIGNED_BYTE, false, 0, GL_FRONT);
489     if (!success)
490     {
491         vogl_error_printf("%s: Failed calling glReadPixels() to take frontbuffer screenshot!\n", VOGL_METHOD_NAME);
492         return false;
493     }
494
495     size_t png_size = 0;
496     void *pPNG_data = tdefl_write_image_to_png_file_in_memory_ex(m_screenshot_buffer.get_ptr(), width, height, 3, &png_size, 1, true);
497
498     success = file_utils::write_buf_to_file(filename.get_ptr(), pPNG_data, png_size);
499     if (!success)
500     {
501         vogl_error_printf("%s: Failed writing PNG screenshot to file \"%s\"\n", filename.get_ptr(), VOGL_METHOD_NAME);
502     }
503     else
504     {
505         vogl_message_printf("Wrote PNG screenshot to file \"%s\"\n", filename.get_ptr());
506     }
507
508     mz_free(pPNG_data);
509
510     return success;
511 }
512
513 //----------------------------------------------------------------------------------------------------------------------
514 // vogl_replayer::trigger_pending_window_resize
515 //----------------------------------------------------------------------------------------------------------------------
516 vogl_gl_replayer::status_t vogl_gl_replayer::trigger_pending_window_resize(uint win_width, uint win_height)
517 {
518     VOGL_FUNC_TRACER
519
520     m_pending_window_resize_width = win_width;
521     m_pending_window_resize_height = win_height;
522     m_pending_window_resize_attempt_counter = 0;
523     m_time_since_pending_window_resize.start();
524
525     m_pWindow->resize(win_width, win_height);
526
527     if (m_flags & cGLReplayerVerboseMode)
528         vogl_debug_printf("%s: Waiting for window to resize to %ux%u\n", VOGL_METHOD_NAME, win_width, win_height);
529
530     return cStatusResizeWindow;
531 }
532
533 //----------------------------------------------------------------------------------------------------------------------
534 // vogl_replayer::clear_pending_window_resize
535 //----------------------------------------------------------------------------------------------------------------------
536 void vogl_gl_replayer::clear_pending_window_resize()
537 {
538     VOGL_FUNC_TRACER
539
540     m_pending_window_resize_width = 0;
541     m_pending_window_resize_height = 0;
542     m_pending_window_resize_attempt_counter = 0;
543 }
544
545 //----------------------------------------------------------------------------------------------------------------------
546 // vogl_replayer::process_frame_check_for_pending_window_resize
547 //----------------------------------------------------------------------------------------------------------------------
548 vogl_gl_replayer::status_t vogl_gl_replayer::process_frame_check_for_pending_window_resize()
549 {
550     VOGL_FUNC_TRACER
551
552     const uint cMaxSecsToWait = 5;
553
554     if (!get_has_pending_window_resize())
555         return cStatusOK;
556
557     if (m_pending_window_resize_attempt_counter >= cMaxSecsToWait)
558     {
559         vogl_warning_printf("Waited too long for window to resize to %ux%u, giving up and continuing replay\n", get_pending_window_resize_width(), get_pending_winow_resize_height());
560
561         clear_pending_window_resize();
562
563         return cStatusOK;
564     }
565
566     uint win_width = 0, win_height = 0;
567     m_pWindow->get_actual_dimensions(win_width, win_height);
568
569     if ((win_width != get_pending_window_resize_width()) ||
570         (win_height != get_pending_winow_resize_height()))
571     {
572         if (m_time_since_pending_window_resize.get_elapsed_secs() < 1.0f)
573         {
574             // sleep 1ms, then retry
575             vogl_sleep(1);
576             return cStatusResizeWindow;
577         }
578
579         // What could possibly go wrong?
580         m_pending_window_resize_attempt_counter++;
581         if (m_pending_window_resize_attempt_counter < cMaxSecsToWait)
582         {
583             m_pWindow->resize(get_pending_window_resize_width(), get_pending_winow_resize_height());
584
585             m_time_since_pending_window_resize.start();
586
587             vogl_warning_printf("Waiting up to 5 secs for window to resize to %ux%u\n", get_pending_window_resize_width(), get_pending_winow_resize_height());
588             return cStatusResizeWindow;
589         }
590     }
591
592     clear_pending_window_resize();
593     m_pWindow->update_dimensions();
594
595     return cStatusOK;
596 }
597
598 //----------------------------------------------------------------------------------------------------------------------
599 // vogl_replayer::destroy_pending_snapshot
600 //----------------------------------------------------------------------------------------------------------------------
601 void vogl_gl_replayer::destroy_pending_snapshot()
602 {
603     VOGL_FUNC_TRACER
604
605     if (m_pPending_snapshot)
606     {
607         if (m_delete_pending_snapshot_after_applying)
608         {
609             // Ensure the snapshot cache can't be pointing to the snapshot, just to be safe.
610             // TODO: Make this a real class damn it.
611             for (uint i = 0; i < m_snapshots.size(); i++)
612             {
613                 if (m_snapshots[i].m_pSnapshot == m_pPending_snapshot)
614                 {
615                     m_snapshots.erase(i);
616                     break;
617                 }
618             }
619
620             vogl_delete(const_cast<vogl_gl_state_snapshot *>(m_pPending_snapshot));
621         }
622
623         m_pPending_snapshot = NULL;
624     }
625
626     m_delete_pending_snapshot_after_applying = false;
627 }
628
629 //----------------------------------------------------------------------------------------------------------------------
630 // vogl_replayer::check_gl_error
631 // Returns *true* on error, just like vogl_check_gl_error()
632 //----------------------------------------------------------------------------------------------------------------------
633 bool vogl_gl_replayer::check_gl_error_internal(bool quietly, const char *pFile, uint line, const char *pFunc)
634 {
635     VOGL_FUNC_TRACER
636
637     bool status = false;
638     for (;;)
639     {
640         // http://www.opengl.org/sdk/docs/man/xhtml/glGetError.xml
641         // "Thus, glGetError should always be called in a loop, until it returns GL_NO_ERROR, if all error flags are to be reset."
642         GLenum gl_err = GL_ENTRYPOINT(glGetError)();
643         if (gl_err == GL_NO_ERROR)
644             break;
645
646         if (!quietly)
647         {
648             process_entrypoint_warning("%s: GL error: 0x%08X (%u): %s (Called from File: %s Line: %u Func: %s)\n", VOGL_METHOD_NAME, gl_err, gl_err, g_gl_enums.find_name("ErrorCode", gl_err), pFile ? pFile : "?", line, pFunc ? pFunc : "?");
649         }
650
651         status = true;
652     }
653
654     return status;
655 }
656
657 //----------------------------------------------------------------------------------------------------------------------
658 // vogl_replayer::clear_contexts
659 //----------------------------------------------------------------------------------------------------------------------
660 void vogl_gl_replayer::clear_contexts()
661 {
662     VOGL_FUNC_TRACER
663
664     for (context_hash_map::iterator it = m_contexts.begin(); it != m_contexts.end(); ++it)
665     {
666         context_state *pContext_state = it->second;
667         it->second = NULL;
668         vogl_delete(pContext_state);
669     }
670
671     m_contexts.clear();
672
673     m_cur_trace_context = 0;
674     m_cur_replay_context = NULL;
675     m_pCur_context_state = NULL;
676 }
677
678 //----------------------------------------------------------------------------------------------------------------------
679 // vogl_replayer::destroy_contexts
680 //----------------------------------------------------------------------------------------------------------------------
681 void vogl_gl_replayer::destroy_contexts()
682 {
683     VOGL_FUNC_TRACER
684
685     if ((m_contexts.size()) && (m_pWindow->get_display()) && (GL_ENTRYPOINT(glXMakeCurrent)) && (GL_ENTRYPOINT(glXDestroyContext)))
686     {
687         GL_ENTRYPOINT(glXMakeCurrent)(m_pWindow->get_display(), (GLXDrawable)NULL, NULL);
688
689         vogl::vector<context_state *> contexts_to_destroy;
690         for (context_hash_map::const_iterator it = m_contexts.begin(); it != m_contexts.end(); ++it)
691             contexts_to_destroy.push_back(it->second);
692
693         // Delete "tail" contexts (ones that are not referenced by any other context) in sharegroups first.
694         while (contexts_to_destroy.size())
695         {
696             for (int i = 0; i < static_cast<int>(contexts_to_destroy.size()); i++)
697             {
698                 context_state *pContext_state = contexts_to_destroy[i];
699
700                 vogl_trace_ptr_value trace_context = pContext_state->m_context_desc.get_trace_context();
701
702                 bool skip_context = false;
703                 for (int j = 0; j < static_cast<int>(contexts_to_destroy.size()); j++)
704                 {
705                     if (i == j)
706                         continue;
707
708                     if (contexts_to_destroy[j]->m_context_desc.get_trace_share_context() == trace_context)
709                     {
710                         skip_context = true;
711                         break;
712                     }
713                 }
714
715                 if (skip_context)
716                     continue;
717
718                 // This context may have been the sharegroup's root and could have been already deleted.
719                 if (!pContext_state->m_deleted)
720                 {
721                     GL_ENTRYPOINT(glXDestroyContext)(m_pWindow->get_display(), pContext_state->m_replay_context);
722                 }
723
724                 contexts_to_destroy.erase(i);
725                 i--;
726             }
727         }
728     }
729
730     clear_contexts();
731 }
732
733 //----------------------------------------------------------------------------------------------------------------------
734 // vogl_replayer::define_new_context
735 //----------------------------------------------------------------------------------------------------------------------
736 vogl_gl_replayer::context_state *vogl_gl_replayer::define_new_context(
737     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)
738 {
739     VOGL_FUNC_TRACER
740
741     if ((!trace_context) || (!replay_context))
742     {
743         VOGL_ASSERT_ALWAYS;
744         return NULL;
745     }
746
747     context_state *pContext_state = vogl_new(context_state, *this);
748
749     pContext_state->m_trace_context = trace_context;
750     pContext_state->m_replay_context = replay_context;
751
752     pContext_state->m_context_desc.init(creation_func, direct, trace_context, trace_share_context, vogl_context_attribs(pAttrib_list, attrib_list_size));
753
754     if (trace_share_context)
755     {
756         for (context_hash_map::const_iterator it = m_contexts.begin(); it != m_contexts.end(); ++it)
757         {
758             if (trace_share_context == it->first)
759             {
760                 context_state *pShare_context = it->second;
761                 while (!pShare_context->is_root_context())
762                     pShare_context = pShare_context->m_pShared_state;
763
764                 pContext_state->m_pShared_state = pShare_context;
765                 pContext_state->m_pShared_state->m_ref_count++;
766
767                 break;
768             }
769         }
770
771         if (!pContext_state->m_pShared_state)
772         {
773             process_entrypoint_error("%s: Unable to find trace share context handle 0x%" PRIX64 "!\n", VOGL_METHOD_NAME, trace_share_context);
774         }
775     }
776
777     m_contexts.insert(trace_context, pContext_state);
778
779     return pContext_state;
780 }
781
782 //----------------------------------------------------------------------------------------------------------------------
783 // vogl_replayer::remap_context
784 //----------------------------------------------------------------------------------------------------------------------
785 GLXContext vogl_gl_replayer::remap_context(vogl_trace_context_ptr_value trace_context)
786 {
787     VOGL_FUNC_TRACER
788
789     if (!trace_context)
790         return NULL;
791
792     context_hash_map::iterator it = m_contexts.find(trace_context);
793     return (it == m_contexts.end()) ? NULL : it->second->m_replay_context;
794 }
795
796 //----------------------------------------------------------------------------------------------------------------------
797 // vogl_replayer::destroy_context
798 //----------------------------------------------------------------------------------------------------------------------
799 bool vogl_gl_replayer::destroy_context(vogl_trace_context_ptr_value trace_context)
800 {
801     VOGL_FUNC_TRACER
802
803     VOGL_ASSERT(trace_context);
804
805     context_hash_map::iterator it = m_contexts.find(trace_context);
806     if (it == m_contexts.end())
807         return false;
808
809     context_state *pContext_state = it->second;
810     VOGL_ASSERT(pContext_state->m_ref_count >= 1);
811     VOGL_ASSERT(!pContext_state->m_deleted);
812
813     if (pContext_state->is_share_context())
814     {
815         VOGL_ASSERT(pContext_state->m_ref_count == 1);
816
817         context_state *pShare_context = pContext_state->m_pShared_state;
818         VOGL_ASSERT(pShare_context->m_ref_count >= 1);
819
820         pShare_context->m_ref_count--;
821         if (!pShare_context->m_ref_count)
822         {
823             VOGL_ASSERT(pShare_context->m_deleted);
824
825             vogl_trace_context_ptr_value trace_share_context = pShare_context->m_context_desc.get_trace_context();
826
827             vogl_delete(pShare_context);
828
829             bool removed = m_contexts.erase(trace_share_context);
830             VOGL_NOTE_UNUSED(removed);
831             VOGL_ASSERT(removed);
832         }
833
834         vogl_delete(pContext_state);
835
836         bool removed = m_contexts.erase(trace_context);
837         VOGL_NOTE_UNUSED(removed);
838         VOGL_ASSERT(removed);
839     }
840     else
841     {
842         pContext_state->m_deleted = true;
843         pContext_state->m_ref_count--;
844
845         if (!pContext_state->m_ref_count)
846         {
847             it->second = NULL;
848
849             vogl_delete(pContext_state);
850
851             bool removed = m_contexts.erase(trace_context);
852             VOGL_NOTE_UNUSED(removed);
853             VOGL_ASSERT(removed);
854         }
855     }
856
857     return true;
858 }
859
860 //----------------------------------------------------------------------------------------------------------------------
861 // vogl_replayer::set_client_side_array_data
862 // glVertexPointer, glNormalPointer, etc. client side data
863 //----------------------------------------------------------------------------------------------------------------------
864 bool vogl_gl_replayer::set_client_side_array_data(const key_value_map &map, GLuint start, GLuint end, GLuint basevertex)
865 {
866     VOGL_FUNC_TRACER
867
868     // TODO: Add early out
869     GLint prev_client_active_texture = 0;
870     GL_ENTRYPOINT(glGetIntegerv)(GL_CLIENT_ACTIVE_TEXTURE, &prev_client_active_texture);
871
872     const uint tex_coords = math::minimum<uint>(m_pCur_context_state->m_context_info.is_core_profile() ? m_pCur_context_state->m_context_info.get_max_texture_units() : m_pCur_context_state->m_context_info.get_max_texture_coords(), VOGL_MAX_SUPPORTED_GL_TEXCOORD_ARRAYS);
873
874     for (uint client_array_iter = 0; client_array_iter < VOGL_NUM_CLIENT_SIDE_ARRAY_DESCS; client_array_iter++)
875     {
876         const vogl_client_side_array_desc_t &desc = g_vogl_client_side_array_descs[client_array_iter];
877
878         const bool is_texcoord_array = (client_array_iter == vogl_texcoord_pointer_array_id);
879
880         uint n = 1;
881         uint base_key_index = 0x1000 + client_array_iter;
882
883         // Special case texcoord pointers, which are accessed via the client active texture.
884         if (is_texcoord_array)
885         {
886             n = tex_coords;
887             base_key_index = 0x2000;
888         }
889
890         for (uint inner_iter = 0; inner_iter < n; inner_iter++)
891         {
892             uint key_index = base_key_index + inner_iter;
893
894             const uint8_vec *pVertex_blob = map.get_blob(static_cast<uint16>(key_index));
895             // TODO: Check for case where blob (or map) is not present, but they still access client side data, this is a bad error
896             if (!pVertex_blob)
897                 continue;
898
899             if (is_texcoord_array)
900             {
901                 GL_ENTRYPOINT(glClientActiveTexture)(GL_TEXTURE0 + inner_iter);
902             }
903
904             GLboolean is_enabled = GL_ENTRYPOINT(glIsEnabled)(desc.m_is_enabled);
905             if (!is_enabled)
906                 continue;
907
908             GLint binding = 0;
909             GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_binding, &binding);
910             if (binding)
911                 continue;
912
913             GLvoid *ptr = NULL;
914             GL_ENTRYPOINT(glGetPointerv)(desc.m_get_pointer, &ptr);
915             if (!ptr)
916                 continue;
917
918             uint8_vec &array_data = is_texcoord_array ? m_client_side_texcoord_data[inner_iter] : m_client_side_array_data[client_array_iter];
919             if (ptr != array_data.get_ptr())
920             {
921                 VOGL_ASSERT_ALWAYS;
922                 return false;
923             }
924
925             GLint type = GL_BOOL;
926             if (desc.m_get_type)
927             {
928                 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_type, &type);
929             }
930
931             GLint stride = 0;
932             GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_stride, &stride);
933
934             GLint size = 1;
935             if (desc.m_get_size)
936             {
937                 GL_ENTRYPOINT(glGetIntegerv)(desc.m_get_size, &size);
938             }
939
940             uint type_size = vogl_get_gl_type_size(type);
941             if (!type_size)
942             {
943                 process_entrypoint_error("%s: Can't determine type size of enabled client side array set by func %s\n", VOGL_METHOD_NAME, g_vogl_entrypoint_descs[desc.m_entrypoint].m_pName);
944                 continue;
945             }
946
947             if ((desc.m_entrypoint == VOGL_ENTRYPOINT_glIndexPointer) || (desc.m_entrypoint == VOGL_ENTRYPOINT_glIndexPointerEXT) ||
948                 (desc.m_entrypoint == VOGL_ENTRYPOINT_glFogCoordPointer) || (desc.m_entrypoint == VOGL_ENTRYPOINT_glFogCoordPointerEXT) ||
949                 (desc.m_entrypoint == VOGL_ENTRYPOINT_glEdgeFlagPointer) || (desc.m_entrypoint == VOGL_ENTRYPOINT_glEdgeFlagPointerEXT))
950             {
951                 size = 1;
952             }
953             else if ((desc.m_entrypoint == VOGL_ENTRYPOINT_glNormalPointer) || (desc.m_entrypoint == VOGL_ENTRYPOINT_glNormalPointerEXT))
954             {
955                 size = 3;
956             }
957             else if ((size < 1) && (size > 4))
958             {
959                 process_entrypoint_error("%s: Size of client side array set by func %s must be between 1 and 4\n", VOGL_METHOD_NAME, g_vogl_entrypoint_descs[desc.m_entrypoint].m_pName);
960                 continue;
961             }
962
963             if (!stride)
964                 stride = type_size * size;
965
966             uint first_vertex_ofs = (start + basevertex) * stride;
967             uint last_vertex_ofs = (end + basevertex) * stride;
968             uint vertex_data_size = (last_vertex_ofs + stride) - first_vertex_ofs;
969             uint total_data_size = last_vertex_ofs + stride;
970
971 #if 0
972                         if (!pVertex_blob)
973                         {
974                                 process_entrypoint_error("%s: Failed finding client side vertex data blob set by func %s \n", VOGL_METHOD_NAME,  g_vogl_entrypoint_descs[desc.m_entrypoint].m_pName);
975                                 continue;
976                         }
977 #endif
978
979             uint8_vec temp_blob;
980             if (vertex_data_size != pVertex_blob->size())
981             {
982                 process_entrypoint_error("%s: %s will access more client side data (%u bytes) than stored in the trace (%u bytes), using what is in the trace and using zeros for the rest\n", VOGL_METHOD_NAME, g_vogl_entrypoint_descs[desc.m_entrypoint].m_pName, vertex_data_size, pVertex_blob->size());
983                 temp_blob = *pVertex_blob;
984                 temp_blob.resize(vertex_data_size);
985                 pVertex_blob = &temp_blob;
986             }
987
988             uint bytes_remaining_at_end = math::maximum<int>(0, (int)VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE - (int)first_vertex_ofs);
989             uint bytes_to_copy = math::minimum<uint>(pVertex_blob->size(), bytes_remaining_at_end);
990             if (bytes_to_copy != pVertex_blob->size())
991             {
992                 // Can't resize buffer, it could move and that would invalidate any VAO pointer bindings.
993                 process_entrypoint_error("%s: %s accesses too much client side data (%u bytes), increase VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE\n", VOGL_METHOD_NAME, g_vogl_entrypoint_descs[desc.m_entrypoint].m_pName, first_vertex_ofs + total_data_size);
994             }
995
996             VOGL_ASSERT((first_vertex_ofs + bytes_to_copy) <= array_data.size());
997
998             memcpy(array_data.get_ptr() + first_vertex_ofs, pVertex_blob->get_ptr(), bytes_to_copy);
999         }
1000     }
1001
1002     GL_ENTRYPOINT(glClientActiveTexture)(prev_client_active_texture);
1003
1004     return true;
1005 }
1006
1007 //----------------------------------------------------------------------------------------------------------------------
1008 // vogl_replayer::set_client_side_vertex_attrib_array_data
1009 // glVertexAttrib client side data
1010 //----------------------------------------------------------------------------------------------------------------------
1011 bool vogl_gl_replayer::set_client_side_vertex_attrib_array_data(const key_value_map &map, GLuint start, GLuint end, GLuint basevertex)
1012 {
1013     VOGL_FUNC_TRACER
1014
1015     // TODO: Add early out
1016
1017     for (int vertex_attrib_index = 0; vertex_attrib_index < static_cast<int>(m_pCur_context_state->m_context_info.get_max_vertex_attribs()); vertex_attrib_index++)
1018     {
1019         const uint8_vec *pVertex_blob = map.get_blob(static_cast<uint16>(vertex_attrib_index));
1020
1021         // TODO: Check for case where blob (or map) is not present, but they still access client side data, this is a bad error
1022         if (!pVertex_blob)
1023             continue;
1024
1025         GLint enabled = 0;
1026         GL_ENTRYPOINT(glGetVertexAttribiv)(vertex_attrib_index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &enabled);
1027         if (!enabled)
1028             continue;
1029
1030         GLint cur_buf = 0;
1031         GL_ENTRYPOINT(glGetVertexAttribiv)(vertex_attrib_index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &cur_buf);
1032         if (cur_buf)
1033             continue;
1034
1035         GLvoid *attrib_ptr = NULL;
1036         GL_ENTRYPOINT(glGetVertexAttribPointerv)(vertex_attrib_index, GL_VERTEX_ATTRIB_ARRAY_POINTER, &attrib_ptr);
1037         if (!attrib_ptr)
1038             continue;
1039
1040         if (attrib_ptr != m_client_side_vertex_attrib_data[vertex_attrib_index].get_ptr())
1041         {
1042             VOGL_ASSERT_ALWAYS;
1043             continue;
1044         }
1045
1046         GLint attrib_size = 0;
1047         GL_ENTRYPOINT(glGetVertexAttribiv)(vertex_attrib_index, GL_VERTEX_ATTRIB_ARRAY_SIZE, &attrib_size);
1048
1049         GLint attrib_type = 0;
1050         GL_ENTRYPOINT(glGetVertexAttribiv)(vertex_attrib_index, GL_VERTEX_ATTRIB_ARRAY_TYPE, &attrib_type);
1051
1052         GLint attrib_stride = 0;
1053         GL_ENTRYPOINT(glGetVertexAttribiv)(vertex_attrib_index, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &attrib_stride);
1054
1055 #if 0
1056                 if (!pVertex_blob)
1057                 {
1058                         process_entrypoint_error("%s: Failed finding client side vertex data blob for generic vertex attrib %u\n", VOGL_METHOD_NAME, vertex_attrib_index);
1059                         continue;
1060                 }
1061 #endif
1062
1063         uint num_comps = 4;
1064         if ((attrib_size != GL_BGRA) && (attrib_size < 1) && (attrib_size > 4))
1065         {
1066             process_entrypoint_error("%s: Enabled vertex attribute index %i has invalid size 0x%0X\n", VOGL_METHOD_NAME, vertex_attrib_index, attrib_size);
1067             continue;
1068         }
1069         if ((attrib_size >= 1) && (attrib_size <= 4))
1070             num_comps = attrib_size;
1071
1072         uint type_size = vogl_get_gl_type_size(attrib_type);
1073         if (!type_size)
1074         {
1075             process_entrypoint_error("%s: Vertex attribute index %i has unsupported type 0x%0X\n", VOGL_METHOD_NAME, vertex_attrib_index, attrib_type);
1076             continue;
1077         }
1078
1079         uint stride = attrib_stride ? attrib_stride : (type_size * num_comps);
1080
1081         uint first_vertex_ofs = (start + basevertex) * stride;
1082         uint last_vertex_ofs = (end + basevertex) * stride;
1083         uint vertex_data_size = (last_vertex_ofs + stride) - first_vertex_ofs;
1084         uint total_data_size = last_vertex_ofs + stride;
1085
1086         uint8_vec temp_blob;
1087         if (vertex_data_size != pVertex_blob->size())
1088         {
1089             process_entrypoint_error("%s: Vertex attribute index %i will access more client side data (%u bytes) than stored in the trace (%u bytes), using what is in the trace and using zeros for the rest\n", VOGL_METHOD_NAME, vertex_attrib_index, vertex_data_size, pVertex_blob->size());
1090             temp_blob = *pVertex_blob;
1091             temp_blob.resize(vertex_data_size);
1092             pVertex_blob = &temp_blob;
1093         }
1094
1095         uint bytes_remaining_at_end = math::maximum<int>(0, (int)VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE - (int)first_vertex_ofs);
1096         uint bytes_to_copy = math::minimum<uint>(pVertex_blob->size(), bytes_remaining_at_end);
1097         if (bytes_to_copy != pVertex_blob->size())
1098         {
1099             // Can't resize buffer, it could move and that would invalidate any VAO pointer bindings.
1100             process_entrypoint_error("%s: Vertex attribute index %i accesses too much client side data (%u bytes), increase VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE\n", VOGL_METHOD_NAME, vertex_attrib_index, first_vertex_ofs + total_data_size);
1101         }
1102
1103         VOGL_ASSERT((first_vertex_ofs + bytes_to_copy) <= m_client_side_vertex_attrib_data[vertex_attrib_index].size());
1104
1105         memcpy(m_client_side_vertex_attrib_data[vertex_attrib_index].get_ptr() + first_vertex_ofs, pVertex_blob->get_ptr(), bytes_to_copy);
1106     }
1107
1108     return true;
1109 }
1110
1111 //----------------------------------------------------------------------------------------------------------------------
1112 // vogl_replayer::draw_elements_client_side_array_setup
1113 //----------------------------------------------------------------------------------------------------------------------
1114 bool vogl_gl_replayer::draw_elements_client_side_array_setup(
1115     GLenum mode,
1116     GLuint start,
1117     GLuint end,
1118     GLsizei count,
1119     GLenum type,
1120     vogl_trace_ptr_value trace_indices_ptr_value, const GLvoid *&pIndices,
1121     GLint basevertex,
1122     bool has_valid_start_end,
1123     bool indexed)
1124 {
1125     VOGL_FUNC_TRACER
1126
1127     VOGL_NOTE_UNUSED(mode);
1128
1129     pIndices = NULL;
1130
1131     GLuint element_array_buffer = 0;
1132     uint index_size = 0;
1133     if (indexed)
1134     {
1135         index_size = vogl_get_gl_type_size(type);
1136         if (!index_size)
1137         {
1138             process_entrypoint_error("%s: Invalid type parameter 0x%08X\n", VOGL_METHOD_NAME, type);
1139             return false;
1140         }
1141
1142         element_array_buffer = vogl_get_bound_gl_buffer(GL_ELEMENT_ARRAY_BUFFER);
1143         if (element_array_buffer)
1144         {
1145             // trace_indices_ptr_value is actually an offset into the buffer, not a real trace ptr
1146             pIndices = reinterpret_cast<GLvoid *>(trace_indices_ptr_value);
1147         }
1148     }
1149
1150     if (count <= 0)
1151     {
1152         process_entrypoint_warning("%s: count parameter is <= 0 (%i)\n", VOGL_METHOD_NAME, count);
1153         return true;
1154     }
1155
1156     const key_value_map &map = m_pCur_gl_packet->get_key_value_map();
1157     if (!map.size())
1158     {
1159         if ((indexed) && (!element_array_buffer) && (trace_indices_ptr_value))
1160         {
1161             process_entrypoint_error("%s: No element array buffer is bound, but key value map doesn't have an indices blob. Can't remap indices pointer!\n", VOGL_METHOD_NAME);
1162             if (trace_indices_ptr_value)
1163             {
1164                 // We can't remap the pointer to valid memory, so give up.
1165                 return false;
1166             }
1167         }
1168
1169         // TODO: Check for client side array usage but no data in blob (which would be a desync or error)
1170         return true;
1171     }
1172
1173     // TODO: If a VAO is bound, client side data isn't supported according to this:
1174     // http://www.opengl.org/registry/specs/ARB/vertex_array_object.txt
1175
1176     //GLint current_vertex_array_binding = 0;
1177     //ACTUAL_GL_ENTRYPOINT(glGetIntegerv)(GL_VERTEX_ARRAY_BINDING, &current_vertex_array_binding);
1178
1179     if ((indexed) && (!element_array_buffer))
1180     {
1181         const uint8_vec *pIndices_vec = map.get_blob(string_hash("indices"));
1182         if (!pIndices_vec)
1183         {
1184             process_entrypoint_error("%s: No element array buffer is bound, but key value map doesn't have an indices blob\n", VOGL_METHOD_NAME);
1185             return false;
1186         }
1187
1188         pIndices = pIndices_vec->get_ptr();
1189         if (!pIndices)
1190         {
1191             process_entrypoint_error("%s: No element array buffer is bound, but key value map has an empty indices blob\n", VOGL_METHOD_NAME);
1192             return false;
1193         }
1194
1195         if ((pIndices_vec->size() / index_size) != static_cast<uint>(count))
1196         {
1197             process_entrypoint_error("%s: Client side index data blob stored in packet is too small (wanted %u indices, got %u indices)\n", VOGL_METHOD_NAME, count, pIndices_vec->size() / index_size);
1198             return false;
1199         }
1200     }
1201
1202     if ((indexed) && (!has_valid_start_end))
1203     {
1204         uint total_index_data_size = count * index_size;
1205
1206         const uint8 *pIndices_to_scan = static_cast<const uint8 *>(pIndices);
1207
1208         if (element_array_buffer)
1209         {
1210             if (m_index_data.size() < total_index_data_size)
1211                 m_index_data.resize(total_index_data_size);
1212
1213             pIndices_to_scan = m_index_data.get_ptr();
1214
1215             check_gl_error();
1216
1217             GL_ENTRYPOINT(glGetBufferSubData)(GL_ELEMENT_ARRAY_BUFFER, (GLintptr)pIndices, total_index_data_size, m_index_data.get_ptr());
1218
1219             if (check_gl_error())
1220             {
1221                 process_entrypoint_warning("%s: GL error while trying to retrieve index buffer data\n", VOGL_METHOD_NAME);
1222
1223                 memset(m_index_data.get_ptr(), 0, total_index_data_size);
1224             }
1225         }
1226
1227         start = cUINT32_MAX;
1228         end = 0;
1229
1230         for (int i = 0; i < count; i++)
1231         {
1232             uint v;
1233
1234             if (type == GL_UNSIGNED_BYTE)
1235                 v = pIndices_to_scan[i];
1236             else if (type == GL_UNSIGNED_SHORT)
1237                 v = reinterpret_cast<const uint16 *>(pIndices_to_scan)[i];
1238             else if (type == GL_UNSIGNED_INT)
1239                 v = reinterpret_cast<const uint32 *>(pIndices_to_scan)[i];
1240             else
1241             {
1242                 process_entrypoint_error("%s: Invalid index type\n", VOGL_METHOD_NAME);
1243                 return false;
1244             }
1245
1246             start = math::minimum(start, v);
1247             end = math::maximum(end, v);
1248         }
1249
1250         has_valid_start_end = true;
1251     }
1252
1253     if (!set_client_side_array_data(map, start, end, basevertex))
1254         return false;
1255
1256     if (!set_client_side_vertex_attrib_array_data(map, start, end, basevertex))
1257         return false;
1258
1259     return true;
1260 }
1261
1262 //----------------------------------------------------------------------------------------------------------------------
1263 // vogl_replayer::determine_uniform_replay_location
1264 //----------------------------------------------------------------------------------------------------------------------
1265 GLint vogl_gl_replayer::determine_uniform_replay_location(GLuint trace_program, GLint trace_location)
1266 {
1267     VOGL_FUNC_TRACER
1268
1269     GLint replay_location = trace_location;
1270
1271     glsl_program_hash_map::iterator it = get_shared_state()->m_glsl_program_hash_map.find(trace_program);
1272     if (it == get_shared_state()->m_glsl_program_hash_map.end())
1273     {
1274         process_entrypoint_warning("%s: Failed looking up current trace program in GLSL program hash map\n", VOGL_METHOD_NAME);
1275     }
1276     else
1277     {
1278         glsl_program_state &state = it->second;
1279
1280         uniform_location_hash_map::const_iterator loc_it = state.m_uniform_locations.find(trace_location);
1281         if (loc_it == state.m_uniform_locations.end())
1282         {
1283             process_entrypoint_warning("%s: Failed looking up uniform location index\n", VOGL_METHOD_NAME);
1284         }
1285         else
1286         {
1287             replay_location = loc_it->second;
1288         }
1289     }
1290     return replay_location;
1291 }
1292
1293 //----------------------------------------------------------------------------------------------------------------------
1294 // vogl_replayer::process_entrypoint_print_summary_context
1295 //----------------------------------------------------------------------------------------------------------------------
1296 void vogl_gl_replayer::process_entrypoint_print_summary_context(eConsoleMessageType msg_type)
1297 {
1298     VOGL_FUNC_TRACER
1299
1300     if (!m_pCur_gl_packet)
1301         return;
1302
1303     console::printf(msg_type, "While processing GL entrypoint packet func %s, frame %u, swaps %u, GL call counter %" PRIu64 ", packet start trace context 0x%" PRIX64 ", cur trace context 0x%" PRIX64 ", trace thread 0x%" PRIX64 ":\n",
1304                     g_vogl_entrypoint_descs[m_pCur_gl_packet->get_entrypoint_id()].m_pName,
1305                     m_frame_index, m_total_swaps,
1306                     m_pCur_gl_packet->get_entrypoint_packet().m_call_counter,
1307                     m_pCur_gl_packet->get_entrypoint_packet().m_context_handle,
1308                     m_cur_trace_context,
1309                     m_pCur_gl_packet->get_entrypoint_packet().m_thread_id);
1310
1311 #if 0
1312         dynamic_string_array backtrace;
1313         if (get_printable_backtrace(backtrace))
1314         {
1315                 console::printf("Backtrace:\n");
1316                 for (uint i = 0; i < backtrace.size(); i++)
1317                         console::printf("%s\n", backtrace[i].get_ptr());
1318         }
1319 #endif
1320 }
1321
1322 //----------------------------------------------------------------------------------------------------------------------
1323 // vogl_replayer::print_detailed_context
1324 //----------------------------------------------------------------------------------------------------------------------
1325 void vogl_gl_replayer::print_detailed_context(eConsoleMessageType msg_type)
1326 {
1327     VOGL_FUNC_TRACER
1328
1329     json_node node;
1330
1331     vogl_loose_file_blob_manager blob_file_manager;
1332     blob_file_manager.init(cBMFWritable);
1333
1334     vogl_trace_packet::json_serialize_params serialize_params;
1335     serialize_params.m_output_basename = "replay_error";
1336     serialize_params.m_cur_frame = m_frame_index;
1337     serialize_params.m_blob_file_size_threshold = 1024;
1338     serialize_params.m_pBlob_manager = (m_flags & cGLReplayerDumpPacketBlobFilesOnError) ? &blob_file_manager : NULL;
1339     m_pCur_gl_packet->json_serialize(node, serialize_params);
1340
1341     dynamic_string node_str;
1342     node.serialize(node_str, true, 0);
1343     console::printf(msg_type, "Packet at call counter %" PRIu64 " as JSON:\n%s\n", m_pCur_gl_packet->get_entrypoint_packet().m_call_counter, node_str.get_ptr());
1344 }
1345
1346 //----------------------------------------------------------------------------------------------------------------------
1347 // vogl_replayer::process_entrypoint_msg_print_detailed_context
1348 //----------------------------------------------------------------------------------------------------------------------
1349 void vogl_gl_replayer::process_entrypoint_msg_print_detailed_context(eConsoleMessageType msg_type)
1350 {
1351     VOGL_FUNC_TRACER
1352
1353     dump_packet_as_func_call(*m_pCur_gl_packet);
1354
1355     if (!(m_flags & cGLReplayerDumpPacketsOnError))
1356         return;
1357
1358     print_detailed_context(msg_type);
1359 }
1360
1361 //----------------------------------------------------------------------------------------------------------------------
1362 // vogl_replayer::process_entrypoint_info
1363 //----------------------------------------------------------------------------------------------------------------------
1364 void vogl_gl_replayer::process_entrypoint_info(const char *pFmt, ...)
1365 {
1366     VOGL_FUNC_TRACER
1367
1368     process_entrypoint_print_summary_context(cInfoConsoleMessage);
1369
1370     va_list args;
1371     va_start(args, pFmt);
1372     console::vprintf(cInfoConsoleMessage, pFmt, args);
1373     va_end(args);
1374
1375     process_entrypoint_msg_print_detailed_context(cInfoConsoleMessage);
1376 }
1377
1378 //----------------------------------------------------------------------------------------------------------------------
1379 // vogl_replayer::process_entrypoint_message
1380 //----------------------------------------------------------------------------------------------------------------------
1381 void vogl_gl_replayer::process_entrypoint_message(const char *pFmt, ...)
1382 {
1383     VOGL_FUNC_TRACER
1384
1385     process_entrypoint_print_summary_context(cMessageConsoleMessage);
1386
1387     va_list args;
1388     va_start(args, pFmt);
1389     console::vprintf(cMessageConsoleMessage, pFmt, args);
1390     va_end(args);
1391
1392     process_entrypoint_msg_print_detailed_context(cInfoConsoleMessage);
1393 }
1394
1395 //----------------------------------------------------------------------------------------------------------------------
1396 // vogl_replayer::process_entrypoint_warning
1397 //----------------------------------------------------------------------------------------------------------------------
1398 void vogl_gl_replayer::process_entrypoint_warning(const char *pFmt, ...)
1399 {
1400     VOGL_FUNC_TRACER
1401
1402     process_entrypoint_print_summary_context(cWarningConsoleMessage);
1403
1404     va_list args;
1405     va_start(args, pFmt);
1406     console::vprintf(cWarningConsoleMessage, pFmt, args);
1407     va_end(args);
1408
1409     process_entrypoint_msg_print_detailed_context(cInfoConsoleMessage);
1410 }
1411
1412 //----------------------------------------------------------------------------------------------------------------------
1413 // vogl_replayer::process_entrypoint_error
1414 //----------------------------------------------------------------------------------------------------------------------
1415 void vogl_gl_replayer::process_entrypoint_error(const char *pFmt, ...)
1416 {
1417     VOGL_FUNC_TRACER
1418
1419     process_entrypoint_print_summary_context(cErrorConsoleMessage);
1420
1421     va_list args;
1422     va_start(args, pFmt);
1423     console::vprintf(cErrorConsoleMessage, pFmt, args);
1424     va_end(args);
1425
1426     process_entrypoint_msg_print_detailed_context(cInfoConsoleMessage);
1427 }
1428
1429 //----------------------------------------------------------------------------------------------------------------------
1430 // vogl_replayer::switch_contexts
1431 //----------------------------------------------------------------------------------------------------------------------
1432 vogl_gl_replayer::status_t vogl_gl_replayer::switch_contexts(vogl_trace_context_ptr_value trace_context)
1433 {
1434     VOGL_FUNC_TRACER
1435
1436     //vogl_trace_context_ptr_value trace_context = gl_packet.m_context_handle;
1437     if (trace_context == m_cur_trace_context)
1438         return cStatusOK;
1439
1440     if (m_flags & cGLReplayerDebugMode)
1441     {
1442         process_entrypoint_message("%s: Forcing context switch via glXMakeCurrent, from current trace context 0x%" PRIX64 " to new context 0x%" PRIX64 "\n", VOGL_METHOD_NAME, cast_val_to_uint64(m_cur_trace_context), cast_val_to_uint64(trace_context));
1443     }
1444
1445     // pContext_state will be NULL if they are unmapping!
1446     context_state *pContext_state = get_trace_context_state(trace_context);
1447     GLXContext replay_context = pContext_state ? pContext_state->m_replay_context : 0;
1448
1449     const Display *dpy = m_pWindow->get_display();
1450     GLXDrawable drawable = replay_context ? m_pWindow->get_xwindow() : (GLXDrawable)NULL;
1451
1452     Bool result = GL_ENTRYPOINT(glXMakeCurrent)(dpy, drawable, replay_context);
1453     if (!result)
1454     {
1455         process_entrypoint_error("%s: Failed switching current trace context to 0x%" PRIX64 "\n", VOGL_METHOD_NAME, trace_context);
1456         return cStatusHardFailure;
1457     }
1458
1459     m_cur_trace_context = trace_context;
1460     m_cur_replay_context = replay_context;
1461     m_pCur_context_state = pContext_state;
1462
1463     return cStatusOK;
1464 }
1465
1466 //----------------------------------------------------------------------------------------------------------------------
1467 // vogl_replayer::debug_callback_arb
1468 //----------------------------------------------------------------------------------------------------------------------
1469 void vogl_gl_replayer::debug_callback_arb(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, GLvoid *pUser_param)
1470 {
1471     VOGL_FUNC_TRACER
1472
1473     VOGL_NOTE_UNUSED(length);
1474
1475     char final_message[4096];
1476
1477     context_state *pContext_state = (context_state *)(pUser_param);
1478
1479     vogl_format_debug_output_arb(final_message, sizeof(final_message), source, type, id, severity, reinterpret_cast<const char *>(message));
1480
1481     if (pContext_state)
1482     {
1483         vogl_warning_printf("%s: Trace context: 0x%" PRIX64 ", Replay context 0x%" PRIX64 ", Last trace call counter: %" PRIu64 "\n%s\n", VOGL_FUNCTION_NAME,
1484                            cast_val_to_uint64(pContext_state->m_trace_context), cast_val_to_uint64(pContext_state->m_replay_context), cast_val_to_uint64(pContext_state->m_last_call_counter), final_message);
1485     }
1486     else
1487     {
1488         vogl_warning_printf("%s: %s\n", VOGL_FUNCTION_NAME, final_message);
1489     }
1490 }
1491
1492 //----------------------------------------------------------------------------------------------------------------------
1493 // vogl_replayer::is_extension_supported
1494 //----------------------------------------------------------------------------------------------------------------------
1495 bool vogl_gl_replayer::is_extension_supported(const char *pExt)
1496 {
1497     VOGL_FUNC_TRACER
1498
1499     if ((m_pCur_context_state) && (m_pCur_context_state->m_context_info.is_valid()))
1500     {
1501         return m_pCur_context_state->m_context_info.supports_extension(pExt);
1502     }
1503
1504     VOGL_ASSERT_ALWAYS;
1505
1506     return true;
1507 }
1508
1509 //----------------------------------------------------------------------------------------------------------------------
1510 // vogl_replayer::context_state::handle_context_made_current
1511 //----------------------------------------------------------------------------------------------------------------------
1512 bool vogl_gl_replayer::context_state::handle_context_made_current()
1513 {
1514     VOGL_FUNC_TRACER
1515
1516     if (m_has_been_made_current)
1517         return true;
1518
1519     VOGL_CHECK_GL_ERROR;
1520
1521     m_has_been_made_current = true;
1522
1523     if (!m_context_info.init(m_context_desc))
1524     {
1525         vogl_error_printf("%s: vogl_context_info::init() failed!\n", VOGL_METHOD_NAME);
1526         return false;
1527     }
1528
1529     if (!m_context_info.get_max_vertex_attribs())
1530     {
1531         vogl_warning_printf("%s: GL_MAX_VERTEX_ATTRIBS is 0\n", VOGL_METHOD_NAME);
1532     }
1533     else if (m_context_info.get_max_vertex_attribs() >= VOGL_MAX_SUPPORTED_GL_VERTEX_ATTRIBUTES)
1534     {
1535         vogl_error_printf("%s: GL_MAX_VERTEX_ATTRIBS is too large, max supported is %u. Please increase VOGL_MAX_SUPPORTED_GL_VERTEX_ATTRIBUTES.\n", VOGL_METHOD_NAME, VOGL_MAX_SUPPORTED_GL_VERTEX_ATTRIBUTES);
1536         return false;
1537     }
1538
1539     if (m_replayer.m_flags & cGLReplayerLowLevelDebugMode)
1540     {
1541         vogl_debug_printf("%s: Creating dummy handles\n", VOGL_METHOD_NAME);
1542
1543         // HACK HACK
1544         // Generate a bunch of replay handles, so the trace and replay namespaces are totally different to shake out handle or target remapping bugs
1545         // TODO: All more object types
1546         vogl::vector<GLuint> dummy_handles(65536);
1547
1548         GL_ENTRYPOINT(glGenTextures)(4000, dummy_handles.get_ptr());
1549         GL_ENTRYPOINT(glGenBuffers)(6000, dummy_handles.get_ptr());
1550         GL_ENTRYPOINT(glGenLists)(8000);
1551         GL_ENTRYPOINT(glGenQueries)(10000, dummy_handles.get_ptr());
1552
1553         GL_ENTRYPOINT(glGenVertexArrays)(12000, dummy_handles.get_ptr());
1554         GL_ENTRYPOINT(glGenProgramsARB)(14000, dummy_handles.get_ptr());
1555         GL_ENTRYPOINT(glGenFramebuffers)(16000, dummy_handles.get_ptr());
1556         GL_ENTRYPOINT(glGenSamplers)(18000, dummy_handles.get_ptr());
1557         GL_ENTRYPOINT(glGenRenderbuffers)(20000, dummy_handles.get_ptr());
1558
1559         for (uint i = 0; i < 22000; i++)
1560             GL_ENTRYPOINT(glCreateProgram)();
1561
1562         vogl_debug_printf("%s: Finished creating dummy handles\n", VOGL_METHOD_NAME);
1563     }
1564
1565     VOGL_CHECK_GL_ERROR;
1566
1567     return true;
1568 }
1569
1570 //----------------------------------------------------------------------------------------------------------------------
1571 // vogl_replayer::handle_context_made_current
1572 //----------------------------------------------------------------------------------------------------------------------
1573 bool vogl_gl_replayer::handle_context_made_current()
1574 {
1575     VOGL_FUNC_TRACER
1576
1577     if (!m_pCur_context_state->handle_context_made_current())
1578         return false;
1579
1580     if ((m_pCur_context_state->m_context_info.is_debug_context()) && (GL_ENTRYPOINT(glDebugMessageCallbackARB)) && (m_pCur_context_state->m_context_info.supports_extension("GL_ARB_debug_output")))
1581     {
1582         GL_ENTRYPOINT(glDebugMessageCallbackARB)(debug_callback_arb, (GLvoid *)m_pCur_context_state);
1583         GL_ENTRYPOINT(glEnable)(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
1584         check_gl_error();
1585     }
1586
1587     if (m_flags & cGLReplayerVerboseMode)
1588     {
1589         vogl_debug_printf("%s: Trace context: 0x%" PRIX64 ", replay context 0x%" PRIX64 ", GL_VERSION: %s\n",
1590                          VOGL_METHOD_NAME,
1591                          (uint64_t)m_cur_trace_context,
1592                          (uint64_t)m_cur_replay_context,
1593                          m_pCur_context_state->m_context_info.get_version_str().get_ptr());
1594     }
1595
1596     return true;
1597 }
1598
1599 //----------------------------------------------------------------------------------------------------------------------
1600 // vogl_replayer::dump_context_attrib_list
1601 //----------------------------------------------------------------------------------------------------------------------
1602 void vogl_gl_replayer::dump_context_attrib_list(const int *pAttrib_list, uint size)
1603 {
1604     VOGL_FUNC_TRACER
1605
1606     if (!pAttrib_list)
1607     {
1608         vogl_debug_printf("Attrib list is NULL\n");
1609         return;
1610     }
1611     vogl_debug_printf("Context attribs:\n");
1612
1613     uint ofs = 0;
1614     for (;;)
1615     {
1616         if (ofs >= size)
1617         {
1618             vogl_error_printf("%s: Attrib list ended prematurely (must end in a 0 key)\n", VOGL_METHOD_NAME);
1619             break;
1620         }
1621
1622         uint key = pAttrib_list[ofs];
1623         if (!key)
1624             break;
1625         ofs++;
1626
1627         if (ofs >= size)
1628         {
1629             vogl_error_printf("%s: Attrib list ended prematurely (must end in a 0 key)\n", VOGL_METHOD_NAME);
1630             break;
1631         }
1632
1633         uint value = pAttrib_list[ofs];
1634         ofs++;
1635
1636         vogl_debug_printf("Key: %s (0x%08X), Value: 0x%08X\n", g_gl_enums.find_name(key, "GLX"), key, value);
1637     }
1638     vogl_debug_printf("End of context attribs\n");
1639 }
1640
1641 //----------------------------------------------------------------------------------------------------------------------
1642 // vogl_replayer::find_attrib_key
1643 //----------------------------------------------------------------------------------------------------------------------
1644 int vogl_gl_replayer::find_attrib_key(const vogl::vector<int> &attrib_list, int key_to_find)
1645 {
1646     VOGL_FUNC_TRACER
1647
1648     uint ofs = 0;
1649     while (ofs < attrib_list.size())
1650     {
1651         int key = attrib_list[ofs];
1652         if (!key)
1653             break;
1654
1655         if (++ofs >= attrib_list.size())
1656         {
1657             process_entrypoint_warning("%s: Failed parsing attrib list, this call is probably going to fail\n", VOGL_METHOD_NAME);
1658             break;
1659         }
1660
1661         if (key == key_to_find)
1662             return ofs;
1663         ofs++;
1664     }
1665
1666     return -1;
1667 }
1668
1669 //----------------------------------------------------------------------------------------------------------------------
1670 // vogl_replayer::create_context_attribs
1671 //----------------------------------------------------------------------------------------------------------------------
1672 vogl_gl_replayer::status_t vogl_gl_replayer::create_context_attribs(
1673     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,
1674     const int *pTrace_attrib_list, int trace_attrib_list_size, bool expecting_attribs)
1675 {
1676     VOGL_FUNC_TRACER
1677
1678     vogl::vector<int> temp_attrib_list;
1679
1680     if ((pTrace_attrib_list) && (trace_attrib_list_size))
1681     {
1682         temp_attrib_list.append(pTrace_attrib_list, trace_attrib_list_size);
1683         if (temp_attrib_list.back() != 0)
1684         {
1685             process_entrypoint_warning("%s: attrib list does not end with 0\n", VOGL_METHOD_NAME);
1686         }
1687     }
1688     else
1689     {
1690         if (expecting_attribs)
1691         {
1692             if (m_flags & cGLReplayerVerboseMode)
1693                 process_entrypoint_message("%s: No attrib list found in trace, assuming an attrib list ending with 0\n", VOGL_METHOD_NAME);
1694         }
1695
1696         temp_attrib_list.push_back(0);
1697     }
1698
1699     if (m_flags & cGLReplayerForceDebugContexts)
1700     {
1701         // See http://www.opengl.org/registry/specs/ARB/glx_create_context.txt
1702         int context_flags_ofs = find_attrib_key(temp_attrib_list, GLX_CONTEXT_FLAGS_ARB);
1703         if (context_flags_ofs < 0)
1704         {
1705             temp_attrib_list.back() = GLX_CONTEXT_FLAGS_ARB;
1706             temp_attrib_list.push_back(GLX_CONTEXT_DEBUG_BIT_ARB);
1707             temp_attrib_list.push_back(0);
1708
1709             if (m_flags & cGLReplayerVerboseMode)
1710                 process_entrypoint_warning("%s: Appending GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB to attrib list to enable debug context\n", VOGL_METHOD_NAME);
1711         }
1712         else
1713         {
1714             temp_attrib_list[context_flags_ofs] |= GLX_CONTEXT_DEBUG_BIT_ARB;
1715
1716             if (m_flags & cGLReplayerVerboseMode)
1717                 process_entrypoint_warning("%s: Slamming on GLX_CONTEXT_DEBUG_BIT_ARB bit to enable debug context\n", VOGL_METHOD_NAME);
1718         }
1719
1720         int context_major_version_ofs = find_attrib_key(temp_attrib_list, GLX_CONTEXT_MAJOR_VERSION_ARB);
1721         int context_minor_version_ofs = find_attrib_key(temp_attrib_list, GLX_CONTEXT_MINOR_VERSION_ARB);
1722
1723         bool slammed_up_to_3_0 = false;
1724         if (context_major_version_ofs < 0)
1725         {
1726 // Don't slam up if they haven't requested a specific GL version, the driver will give us the most recent version that is backwards compatible with 1.0 (i.e. 4.3 for NVidia's current dirver).
1727 #if 0
1728                         temp_attrib_list.back() = GLX_CONTEXT_MAJOR_VERSION_ARB;
1729                         temp_attrib_list.push_back(3);
1730                         temp_attrib_list.push_back(0);
1731
1732                         slammed_up_to_3_0 = true;
1733 #endif
1734         }
1735         else if (temp_attrib_list[context_major_version_ofs] < 3)
1736         {
1737             temp_attrib_list[context_major_version_ofs] = 3;
1738
1739             slammed_up_to_3_0 = true;
1740         }
1741
1742         if (slammed_up_to_3_0)
1743         {
1744             if (context_minor_version_ofs < 0)
1745             {
1746                 temp_attrib_list.back() = GLX_CONTEXT_MINOR_VERSION_ARB;
1747                 temp_attrib_list.push_back(0);
1748                 temp_attrib_list.push_back(0);
1749             }
1750             else
1751             {
1752                 temp_attrib_list[context_minor_version_ofs] = 0;
1753             }
1754
1755             process_entrypoint_warning("%s: Forcing GL context version up to 3.0 due to debug context usage\n", VOGL_METHOD_NAME);
1756         }
1757     }
1758
1759     const int *pAttrib_list = temp_attrib_list.get_ptr();
1760     const uint attrib_list_size = temp_attrib_list.size();
1761
1762     if (m_flags & cGLReplayerVerboseMode)
1763         dump_context_attrib_list(pAttrib_list, attrib_list_size);
1764
1765     GLXContext replay_context = GL_ENTRYPOINT(glXCreateContextAttribsARB)(dpy, config, replay_share_context, direct, pAttrib_list);
1766     if (!replay_context)
1767     {
1768         if (trace_context)
1769         {
1770             process_entrypoint_error("%s: Failed creating new GL context!\n", VOGL_METHOD_NAME);
1771             return cStatusHardFailure;
1772         }
1773         else
1774         {
1775             process_entrypoint_warning("%s: Successfully created a new GL context where the traced app failed!\n", VOGL_METHOD_NAME);
1776         }
1777     }
1778
1779     if (replay_context)
1780     {
1781         if (trace_context)
1782         {
1783             context_state *pContext_state = define_new_context(trace_context, replay_context, trace_share_context, direct, VOGL_ENTRYPOINT_glXCreateContextAttribsARB, pAttrib_list, attrib_list_size);
1784             VOGL_NOTE_UNUSED(pContext_state);
1785         }
1786         else
1787         {
1788             GL_ENTRYPOINT(glXDestroyContext)(m_pWindow->get_display(), replay_context);
1789         }
1790     }
1791
1792     return cStatusOK;
1793 }
1794
1795 //----------------------------------------------------------------------------------------------------------------------
1796 // vogl_replayer::process_pending_make_current
1797 //----------------------------------------------------------------------------------------------------------------------
1798 vogl_gl_replayer::status_t vogl_gl_replayer::process_pending_make_current()
1799 {
1800     VOGL_FUNC_TRACER
1801
1802     if (!m_pending_make_current_packet.is_valid())
1803         return cStatusOK;
1804
1805     vogl_trace_packet &gl_packet = m_pending_make_current_packet;
1806
1807     Bool trace_result = gl_packet.get_return_value<Bool>();
1808
1809     gl_entrypoint_id_t entrypoint_id = gl_packet.get_entrypoint_id();
1810     VOGL_ASSERT((entrypoint_id == VOGL_ENTRYPOINT_glXMakeCurrent) || (entrypoint_id == VOGL_ENTRYPOINT_glXMakeContextCurrent));
1811
1812     // pContext_state will be NULL if they are unmapping!
1813     vogl_trace_ptr_value trace_context = gl_packet.get_param_ptr_value((entrypoint_id == VOGL_ENTRYPOINT_glXMakeCurrent) ? 2 : 3);
1814     context_state *pContext_state = get_trace_context_state(trace_context);
1815     GLXContext replay_context = pContext_state ? pContext_state->m_replay_context : 0;
1816
1817     if ((trace_context) && (!replay_context))
1818     {
1819         process_entrypoint_error("%s, Failed remapping GL context\n", VOGL_METHOD_NAME);
1820         m_pending_make_current_packet.clear();
1821         return cStatusHardFailure;
1822     }
1823
1824     const Display *dpy = m_pWindow->get_display();
1825     GLXDrawable drawable = replay_context ? m_pWindow->get_xwindow() : (GLXDrawable)NULL;
1826
1827     Bool result = GL_ENTRYPOINT(glXMakeCurrent)(dpy, drawable, replay_context);
1828     if (!result)
1829     {
1830         if (trace_result)
1831         {
1832             process_entrypoint_error("%s: Failed making context current, but in the trace this call succeeded!\n", VOGL_METHOD_NAME);
1833             m_pending_make_current_packet.clear();
1834             return cStatusHardFailure;
1835         }
1836         else
1837         {
1838             process_entrypoint_warning("%s: Failed making context current, in the trace this call also failed\n", VOGL_METHOD_NAME);
1839         }
1840     }
1841     else
1842     {
1843         m_cur_trace_context = trace_context;
1844         m_cur_replay_context = replay_context;
1845         m_pCur_context_state = pContext_state;
1846
1847         if (!trace_result)
1848         {
1849             process_entrypoint_warning("%s: Context was successfuly made current, but this operation failed in the trace\n", VOGL_METHOD_NAME);
1850         }
1851
1852         if (m_cur_replay_context)
1853         {
1854             int viewport_x = gl_packet.get_key_value_map().get_int(string_hash("viewport_x"));
1855             int viewport_y = gl_packet.get_key_value_map().get_int(string_hash("viewport_y"));
1856             int viewport_width = gl_packet.get_key_value_map().get_int(string_hash("viewport_width"));
1857             int viewport_height = gl_packet.get_key_value_map().get_int(string_hash("viewport_height"));
1858             int win_width = gl_packet.get_key_value_map().get_int(string_hash("win_width"));
1859             int win_height = gl_packet.get_key_value_map().get_int(string_hash("win_height"));
1860
1861             if (!m_pCur_context_state->m_has_been_made_current)
1862             {
1863                 vogl_printf("glXMakeCurrent(): Trace Viewport: [%u,%u,%u,%u], Window: [%u %u]\n",
1864                            viewport_x, viewport_y,
1865                            viewport_width, viewport_height,
1866                            win_width, win_height);
1867             }
1868
1869             GLint cur_viewport[4];
1870             GL_ENTRYPOINT(glGetIntegerv)(GL_VIEWPORT, cur_viewport);
1871
1872             uint cur_win_width = 0, cur_win_height = 0;
1873             m_pWindow->get_actual_dimensions(cur_win_width, cur_win_height);
1874
1875             if (!m_pCur_context_state->m_has_been_made_current)
1876             {
1877                 vogl_printf("glXMakeCurrent(): Replay Viewport: [%u,%u,%u,%u], Window: [%u %u]\n",
1878                            cur_viewport[0], cur_viewport[1],
1879                            cur_viewport[2], cur_viewport[3],
1880                            cur_win_width, cur_win_height);
1881             }
1882
1883             if ((cur_viewport[0] != viewport_x) || (cur_viewport[1] != viewport_y) || (cur_viewport[2] != viewport_width) || (cur_viewport[3] != viewport_height))
1884             {
1885                 process_entrypoint_warning("%s: Replay viewport differs from traces!\n", VOGL_METHOD_NAME);
1886             }
1887
1888             if (!handle_context_made_current())
1889                 return cStatusHardFailure;
1890         }
1891     }
1892
1893     m_last_processed_call_counter = gl_packet.get_call_counter();
1894
1895     m_pending_make_current_packet.clear();
1896
1897     return cStatusOK;
1898 }
1899
1900 //----------------------------------------------------------------------------------------------------------------------
1901 // vogl_process_internal_trace_command_ctypes_packet
1902 //----------------------------------------------------------------------------------------------------------------------
1903 bool vogl_process_internal_trace_command_ctypes_packet(const key_value_map &kvm, const vogl_ctypes &ctypes)
1904 {
1905     VOGL_FUNC_TRACER
1906
1907     // TODO: Implement the code to map trace ctypes to replay ctypes. That's going to be fun.
1908     int num_trace_ctypes = kvm.get_int("num_ctypes");
1909     VOGL_VERIFY(num_trace_ctypes == VOGL_NUM_CTYPES);
1910
1911     // TODO: This just verifies that the replayer's idea of each ctype matches the tracer's.
1912     // This will need to be revisited once we port to other OS's.
1913     // TODO: Move the ctypes crap into the SOF packet or something, it's not easy to deal with this packet on the fly.
1914     for (int ctype_iter = 0; ctype_iter < num_trace_ctypes; ctype_iter++)
1915     {
1916         const vogl_ctype_desc_t &desc = ctypes[static_cast<vogl_ctype_t>(ctype_iter)];
1917
1918         uint base_index = ctype_iter << 8;
1919         dynamic_string name(kvm.get_string(base_index++));
1920         dynamic_string ctype(kvm.get_string(base_index++));
1921         int size = kvm.get_int(base_index++);
1922         uint loki_type_flags = kvm.get_uint(base_index++);
1923         bool is_pointer = kvm.get_bool(base_index++);
1924         bool is_opaque_pointer = kvm.get_bool(base_index++);
1925         bool is_pointer_diff = kvm.get_bool(base_index++);
1926         bool is_opaque_type = kvm.get_bool(base_index++);
1927
1928         VOGL_VERIFY(name.compare(desc.m_pName, true) == 0);
1929         VOGL_VERIFY(ctype.compare(desc.m_pCType, true) == 0);
1930         if (!desc.m_is_opaque_type)
1931         {
1932             VOGL_VERIFY(size == desc.m_size);
1933         }
1934
1935         const uint loki_type_check_mask = ~(LOKI_TYPE_BITMASK(LOKI_IS_SIGNED_LONG) | LOKI_TYPE_BITMASK(LOKI_IS_UNSIGNED_LONG));
1936         VOGL_VERIFY((loki_type_flags & loki_type_check_mask) == (desc.m_loki_type_flags & loki_type_check_mask));
1937
1938         VOGL_VERIFY(is_pointer == desc.m_is_pointer);
1939         VOGL_VERIFY(is_opaque_pointer == desc.m_is_opaque_pointer);
1940         VOGL_VERIFY(is_pointer_diff == desc.m_is_pointer_diff);
1941         VOGL_VERIFY(is_opaque_type == desc.m_is_opaque_type);
1942     }
1943
1944     return true;
1945 }
1946
1947 //----------------------------------------------------------------------------------------------------------------------
1948 // vogl_replayer::process_internal_trace_command
1949 //----------------------------------------------------------------------------------------------------------------------
1950 vogl_gl_replayer::status_t vogl_gl_replayer::process_internal_trace_command(const vogl_trace_gl_entrypoint_packet &gl_packet)
1951 {
1952     VOGL_FUNC_TRACER
1953
1954     VOGL_NOTE_UNUSED(gl_packet);
1955
1956     GLuint cmd = m_pCur_gl_packet->get_param_value<GLuint>(0);
1957     GLuint size = m_pCur_gl_packet->get_param_value<GLuint>(1);
1958     VOGL_NOTE_UNUSED(size);
1959     vogl_trace_ptr_value trace_data_ptr_value = m_pCur_gl_packet->get_param_ptr_value(2);
1960     VOGL_NOTE_UNUSED(trace_data_ptr_value);
1961
1962     vogl_gl_replayer::status_t status = cStatusOK;
1963
1964     switch (cmd)
1965     {
1966         case cITCRDemarcation:
1967         {
1968             break;
1969         }
1970         case cITCRKeyValueMap:
1971         {
1972             const key_value_map &kvm = m_pCur_gl_packet->get_key_value_map();
1973
1974             dynamic_string cmd_type(kvm.get_string("command_type"));
1975             if (cmd_type == "state_snapshot")
1976             {
1977                 dynamic_string text_id(kvm.get_string("id"));
1978                 dynamic_string binary_id(kvm.get_string("binary_id"));
1979                 if (text_id.is_empty() && binary_id.is_empty())
1980                 {
1981                     process_entrypoint_error("%s: Missing id and binary_id fields in glInternalTraceCommandRAD key_value_map command type: \"%s\"\n", VOGL_METHOD_NAME, cmd_type.get_ptr());
1982                     return cStatusHardFailure;
1983                 }
1984
1985                 dynamic_string id_to_use(text_id.is_empty() ? binary_id : text_id);
1986
1987                 // TODO: Make a 1st class snapshot cache class
1988                 // TODO: This could fail if the user hand modifies the snapshot in some way - add an option to disable caching.
1989                 vogl_gl_state_snapshot *pSnapshot = NULL;
1990                 if (m_flags & cGLReplayerSnapshotCaching)
1991                 {
1992                     for (uint snapshot_index = 0; snapshot_index < m_snapshots.size(); snapshot_index++)
1993                     {
1994                         if (!m_snapshots[snapshot_index].m_name.compare(id_to_use, false))
1995                         {
1996                             pSnapshot = m_snapshots[snapshot_index].m_pSnapshot;
1997                             if (snapshot_index)
1998                             {
1999                                 snapshot_cache_entry cache_entry(m_snapshots[snapshot_index]);
2000                                 m_snapshots.erase(snapshot_index);
2001                                 m_snapshots.insert(0, cache_entry);
2002                             }
2003                             break;
2004                         }
2005                     }
2006                 }
2007
2008                 if (!pSnapshot)
2009                 {
2010                     timed_scope ts("Deserialize snapshot time");
2011
2012                     if (!m_pBlob_manager)
2013                     {
2014                         process_entrypoint_error("%s: Failed reading snapshot blob data \"%s\"!\n", VOGL_METHOD_NAME, id_to_use.get_ptr());
2015                         return cStatusHardFailure;
2016                     }
2017
2018                     uint8_vec snapshot_data;
2019
2020                     if (!m_pBlob_manager->get(id_to_use, snapshot_data) || (snapshot_data.is_empty()))
2021                     {
2022                         process_entrypoint_error("%s: Failed reading snapshot blob data \"%s\"!\n", VOGL_METHOD_NAME, id_to_use.get_ptr());
2023                         return cStatusHardFailure;
2024                     }
2025
2026                     vogl_message_printf("%s: Deserializing state snapshot \"%s\", %u bytes\n", VOGL_METHOD_NAME, id_to_use.get_ptr(), snapshot_data.size());
2027
2028                     json_document doc;
2029
2030                     bool success;
2031                     if (id_to_use == text_id)
2032                         success = doc.deserialize(reinterpret_cast<const char *>(snapshot_data.get_ptr()), snapshot_data.size());
2033                     else
2034                         success = doc.binary_deserialize(snapshot_data);
2035                     if (!success || (!doc.get_root()))
2036                     {
2037                         process_entrypoint_error("%s: Failed deserializing JSON snapshot blob data \"%s\"!\n", VOGL_METHOD_NAME, id_to_use.get_ptr());
2038                         return cStatusHardFailure;
2039                     }
2040
2041                     pSnapshot = vogl_new(vogl_gl_state_snapshot);
2042                     if (!pSnapshot->deserialize(*doc.get_root(), *m_pBlob_manager, &m_trace_gl_ctypes))
2043                     {
2044                         vogl_delete(pSnapshot);
2045                         pSnapshot = NULL;
2046
2047                         process_entrypoint_error("%s: Failed deserializing snapshot blob data \"%s\"!\n", VOGL_METHOD_NAME, id_to_use.get_ptr());
2048                         return cStatusHardFailure;
2049                     }
2050
2051                     if (m_flags & cGLReplayerSnapshotCaching)
2052                     {
2053                         snapshot_cache_entry new_cache_entry;
2054                         new_cache_entry.m_name = id_to_use;
2055                         new_cache_entry.m_pSnapshot = pSnapshot;
2056                         m_snapshots.insert(0, new_cache_entry);
2057
2058                         // FIXME: Even 3-4 snapshots in memory may be too much in 32-bit mode for some large apps.
2059                         while (m_snapshots.size() > 3)
2060                         {
2061                             vogl_delete(m_snapshots.back().m_pSnapshot);
2062                             m_snapshots.resize(m_snapshots.size() - 1);
2063                         }
2064                     }
2065                 }
2066
2067                 status = begin_applying_snapshot(pSnapshot, (m_flags & cGLReplayerSnapshotCaching) ? false : true);
2068
2069                 if ((status != cStatusOK) && (status != cStatusResizeWindow))
2070                 {
2071                     if (m_flags & cGLReplayerSnapshotCaching)
2072                     {
2073                         VOGL_ASSERT(m_snapshots[0].m_pSnapshot == pSnapshot);
2074
2075                         vogl_delete(m_snapshots[0].m_pSnapshot);
2076                         m_snapshots.erase(0U);
2077                     }
2078
2079                     if (m_flags & cGLReplayerSnapshotCaching)
2080                     {
2081                         vogl_delete(pSnapshot);
2082                         pSnapshot = NULL;
2083                     }
2084
2085                     process_entrypoint_error("%s: Failed applying GL snapshot from blob data \"%s\"!\n", VOGL_METHOD_NAME, id_to_use.get_ptr());
2086                     return status;
2087                 }
2088
2089                 vogl_message_printf("%s: Successfully applied GL state snapshot from blob \"%s\"\n", VOGL_METHOD_NAME, id_to_use.get_ptr());
2090             }
2091             else if (cmd_type == "ctypes")
2092             {
2093                 m_ctypes_packet = *m_pCur_gl_packet;
2094
2095                 if (!vogl_process_internal_trace_command_ctypes_packet(kvm, m_trace_gl_ctypes))
2096                     return cStatusHardFailure;
2097             }
2098             else if (cmd_type == "entrypoints")
2099             {
2100                 // TODO
2101             }
2102             else
2103             {
2104                 process_entrypoint_warning("%s: Unknown glInternalTraceCommandRAD key_value_map command type: \"%s\"\n", VOGL_METHOD_NAME, cmd_type.get_ptr());
2105             }
2106             break;
2107         }
2108         default:
2109         {
2110             process_entrypoint_warning("%s: Unknown glInternalTraceCommandRAD command type: %u\n", VOGL_METHOD_NAME, cmd);
2111             break;
2112         }
2113     }
2114
2115     return status;
2116 }
2117
2118 //----------------------------------------------------------------------------------------------------------------------
2119 // vogl_replayer::check_program_binding_shadow
2120 //----------------------------------------------------------------------------------------------------------------------
2121 bool vogl_gl_replayer::check_program_binding_shadow()
2122 {
2123     VOGL_FUNC_TRACER
2124
2125     if (!m_pCur_context_state)
2126         return true;
2127
2128     // Make sure shadow is good
2129     GLint actual_current_replay_program = 0;
2130     GL_ENTRYPOINT(glGetIntegerv)(GL_CURRENT_PROGRAM, &actual_current_replay_program);
2131     check_gl_error();
2132
2133     if (m_pCur_context_state->m_cur_replay_program == static_cast<GLuint>(actual_current_replay_program))
2134         return true;
2135
2136     // OK, on AMD it plays games with GL_CURRENT_PROGRAM when the currently bound program is deleted. Check for this scenario.
2137     bool is_still_program = GL_ENTRYPOINT(glIsProgram)(m_pCur_context_state->m_cur_replay_program) != 0;
2138     if ((!check_gl_error()) && (is_still_program))
2139     {
2140         GLint marked_for_deletion = GL_FALSE;
2141         GL_ENTRYPOINT(glGetProgramiv)(m_pCur_context_state->m_cur_replay_program, GL_DELETE_STATUS, &marked_for_deletion);
2142
2143         if ((!check_gl_error()) && (marked_for_deletion))
2144             return true;
2145     }
2146
2147     VOGL_VERIFY(0);
2148     return false;
2149 }
2150
2151 //----------------------------------------------------------------------------------------------------------------------
2152 // vogl_replayer::handle_use_program
2153 //----------------------------------------------------------------------------------------------------------------------
2154 void vogl_gl_replayer::handle_use_program(GLuint trace_handle, gl_entrypoint_id_t entrypoint_id)
2155 {
2156     VOGL_FUNC_TRACER
2157
2158     // TODO: This code assumes the non-ARB entrypoints are being used, which works fine on NV but who knows what'll happen on other drivers.
2159     check_program_binding_shadow();
2160
2161     GLuint replay_handle = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle);
2162     VOGL_ASSERT(!trace_handle || get_shared_state()->m_shadow_state.m_objs.get_target(trace_handle) == VOGL_PROGRAM_OBJECT);
2163     VOGL_ASSERT(!trace_handle || get_shared_state()->m_shadow_state.m_objs.get_target_inv(replay_handle) == VOGL_PROGRAM_OBJECT);
2164
2165     // For safety, absorb any previous error.
2166     check_gl_error();
2167
2168     GLuint prev_replay_program = m_pCur_context_state->m_cur_replay_program;
2169     GLuint prev_trace_program = m_pCur_context_state->m_cur_trace_program;
2170
2171     bool prev_is_program = false;
2172     GLint prev_link_status = false;
2173     GLint prev_is_marked_for_deletion = false;
2174     vogl::growable_array<GLuint, 8> prev_attached_replay_shaders;
2175
2176     if ((prev_replay_program) && (replay_handle != prev_replay_program))
2177     {
2178         prev_is_program = GL_ENTRYPOINT(glIsProgram)(prev_replay_program);
2179         check_gl_error_quietly();
2180
2181         if (prev_is_program)
2182         {
2183             GL_ENTRYPOINT(glGetProgramiv)(prev_replay_program, GL_DELETE_STATUS, &prev_is_marked_for_deletion);
2184             check_gl_error_quietly();
2185
2186             GL_ENTRYPOINT(glGetProgramiv)(prev_replay_program, GL_LINK_STATUS, &prev_link_status);
2187             check_gl_error_quietly();
2188
2189             if (prev_is_marked_for_deletion)
2190             {
2191                 // The currently bound program is marked for deletion, so record which shaders are attached to it in case the program is actually deleted by the driver on the UseProgram() call.
2192                 GLint num_attached_shaders = 0;
2193                 GL_ENTRYPOINT(glGetProgramiv)(prev_replay_program, GL_ATTACHED_SHADERS, &num_attached_shaders);
2194                 check_gl_error_quietly();
2195
2196                 if (num_attached_shaders)
2197                 {
2198                     prev_attached_replay_shaders.resize(num_attached_shaders);
2199
2200                     GLsizei actual_count = 0;
2201                     GL_ENTRYPOINT(glGetAttachedShaders)(prev_replay_program, num_attached_shaders, &actual_count, prev_attached_replay_shaders.get_ptr());
2202                     check_gl_error_quietly();
2203
2204                     VOGL_ASSERT(actual_count == num_attached_shaders);
2205                 }
2206             }
2207         }
2208     }
2209
2210     if (entrypoint_id == VOGL_ENTRYPOINT_glUseProgram)
2211         GL_ENTRYPOINT(glUseProgram)(replay_handle);
2212     else
2213         GL_ENTRYPOINT(glUseProgramObjectARB)(replay_handle);
2214
2215     // Can't shadow if glUseProgram failed.
2216     if (check_gl_error())
2217         return;
2218
2219     if ((prev_replay_program) && (prev_replay_program != replay_handle))
2220     {
2221         bool is_prev_still_program = GL_ENTRYPOINT(glIsProgram)(prev_replay_program);
2222         if (!is_prev_still_program)
2223         {
2224             VOGL_ASSERT(prev_is_program);
2225             VOGL_ASSERT(prev_is_marked_for_deletion);
2226
2227             // The previously bound program is really dead now, kill it from our tables and also check up on any shaders it was attached to.
2228             bool was_deleted = get_shared_state()->m_shadow_state.m_objs.erase(prev_trace_program);
2229             VOGL_ASSERT(was_deleted);
2230             VOGL_NOTE_UNUSED(was_deleted);
2231
2232             was_deleted = get_shared_state()->m_glsl_program_hash_map.erase(prev_trace_program);
2233             VOGL_ASSERT(was_deleted);
2234
2235             was_deleted = get_shared_state()->m_shadow_state.m_linked_programs.remove_snapshot(prev_replay_program);
2236             if ((prev_link_status) && (!was_deleted))
2237             {
2238                 VOGL_ASSERT_ALWAYS;
2239             }
2240
2241             for (uint i = 0; i < prev_attached_replay_shaders.size(); i++)
2242             {
2243                 GLuint replay_shader_handle = prev_attached_replay_shaders[i];
2244
2245                 bool is_still_shader = GL_ENTRYPOINT(glIsShader)(replay_shader_handle);
2246                 check_gl_error_quietly();
2247
2248                 if (is_still_shader)
2249                     continue;
2250
2251                 if (!get_shared_state()->m_shadow_state.m_objs.contains_inv(replay_shader_handle))
2252                 {
2253                     // We didn't create this shader handle, the AMD driver did on a program binary link, so ignore it.
2254                     continue;
2255                 }
2256
2257                 // The attached shader is now really dead.
2258                 VOGL_ASSERT(get_shared_state()->m_shadow_state.m_objs.get_target_inv(replay_shader_handle) == VOGL_SHADER_OBJECT);
2259                 if (!get_shared_state()->m_shadow_state.m_objs.erase_inv(replay_shader_handle))
2260                 {
2261                     process_entrypoint_error("%s: Failed finding attached GL shader %u in objects hash table, while handling the actual deletion of trace program %u replay program %u\n", VOGL_METHOD_NAME, replay_shader_handle, prev_trace_program, prev_replay_program);
2262                 }
2263             }
2264         }
2265     }
2266
2267     m_pCur_context_state->m_cur_replay_program = replay_handle;
2268     m_pCur_context_state->m_cur_trace_program = trace_handle;
2269 }
2270
2271 //----------------------------------------------------------------------------------------------------------------------
2272 // vogl_replayer::handle_delete_program
2273 //----------------------------------------------------------------------------------------------------------------------
2274 void vogl_gl_replayer::handle_delete_program(GLuint trace_handle)
2275 {
2276     VOGL_FUNC_TRACER
2277
2278     check_program_binding_shadow();
2279
2280     // Note: This mixes ARB and non-ARB funcs. to probe around, which is evil.
2281
2282     GLuint replay_handle = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle);
2283     VOGL_ASSERT(get_shared_state()->m_shadow_state.m_objs.get_target(trace_handle) == VOGL_PROGRAM_OBJECT);
2284     VOGL_ASSERT(get_shared_state()->m_shadow_state.m_objs.get_target_inv(replay_handle) == VOGL_PROGRAM_OBJECT);
2285
2286     context_state *pContext_shareroot = m_pCur_context_state->m_pShared_state;
2287     for (context_hash_map::iterator it = m_contexts.begin(); it != m_contexts.end(); ++it)
2288     {
2289         if (it->first == m_pCur_context_state->m_context_desc.get_trace_context())
2290             continue;
2291
2292         context_state *pContext = it->second;
2293         if (pContext->m_pShared_state == pContext_shareroot)
2294         {
2295             if (pContext->m_cur_trace_program == trace_handle)
2296             {
2297                 process_entrypoint_error("%s: Trace program %u replay program %u is being deleted on context 0x%" PRIx64 ", but it's currently bound to trace context 0x%" PRIx64 "! This scenario is not currently supported with sharelists.\n",
2298                                          VOGL_METHOD_NAME, trace_handle, replay_handle,
2299                                          cast_val_to_uint64(m_pCur_context_state->m_context_desc.get_trace_context()),
2300                                          cast_val_to_uint64(it->first));
2301             }
2302         }
2303     }
2304
2305     bool is_program = GL_ENTRYPOINT(glIsProgram)(replay_handle) != 0;
2306     check_gl_error_quietly();
2307
2308     vogl::growable_array<GLuint, 8> attached_replay_shaders;
2309
2310     if ((is_program) && (replay_handle))
2311     {
2312         GLint num_attached_shaders = 0;
2313         GL_ENTRYPOINT(glGetProgramiv)(replay_handle, GL_ATTACHED_SHADERS, &num_attached_shaders);
2314         check_gl_error_quietly();
2315
2316         if (num_attached_shaders)
2317         {
2318             attached_replay_shaders.resize(num_attached_shaders);
2319
2320             GLsizei actual_count = 0;
2321             GL_ENTRYPOINT(glGetAttachedShaders)(replay_handle, num_attached_shaders, &actual_count, attached_replay_shaders.get_ptr());
2322             check_gl_error_quietly();
2323
2324             VOGL_ASSERT(actual_count == num_attached_shaders);
2325         }
2326     }
2327
2328     GL_ENTRYPOINT(glDeleteProgram)(replay_handle);
2329
2330     bool deletion_succeeded = !check_gl_error();
2331     if (!deletion_succeeded)
2332     {
2333         VOGL_ASSERT(!is_program);
2334
2335         process_entrypoint_warning("%s: Failed deleting program, trace handle %u GL handle %u\n", VOGL_METHOD_NAME, trace_handle, replay_handle);
2336         return;
2337     }
2338
2339     if (!replay_handle)
2340         return;
2341
2342     bool is_still_program = GL_ENTRYPOINT(glIsProgram)(replay_handle) != 0;
2343     check_gl_error_quietly();
2344
2345     GLint marked_for_deletion = 0;
2346     if (is_still_program)
2347     {
2348         // It must still be bound to the context, or referred to in some other way that we don't know about.
2349         GL_ENTRYPOINT(glGetProgramiv)(replay_handle, GL_DELETE_STATUS, &marked_for_deletion);
2350         bool delete_status_check_succeeded = !check_gl_error_quietly();
2351
2352         VOGL_VERIFY(delete_status_check_succeeded);
2353         VOGL_VERIFY(marked_for_deletion);
2354     }
2355     else if (!is_still_program)
2356     {
2357         VOGL_ASSERT(is_program);
2358
2359         // The program is really gone now.
2360         bool was_deleted = get_shared_state()->m_shadow_state.m_objs.erase(trace_handle);
2361         VOGL_ASSERT(was_deleted);
2362         VOGL_NOTE_UNUSED(was_deleted);
2363
2364         was_deleted = get_shared_state()->m_glsl_program_hash_map.erase(trace_handle);
2365         VOGL_ASSERT(was_deleted);
2366
2367         get_shared_state()->m_shadow_state.m_linked_programs.remove_snapshot(replay_handle);
2368
2369         if (m_pCur_context_state->m_cur_replay_program == replay_handle)
2370         {
2371             // This shouldn't happen - if the program is still bound to the context then it should still be a program.
2372             VOGL_ASSERT_ALWAYS;
2373             m_pCur_context_state->m_cur_replay_program = 0;
2374             m_pCur_context_state->m_cur_trace_program = 0;
2375         }
2376
2377         for (uint i = 0; i < attached_replay_shaders.size(); i++)
2378         {
2379             GLuint replay_shader_handle = attached_replay_shaders[i];
2380
2381             bool is_still_shader = GL_ENTRYPOINT(glIsShader)(replay_shader_handle) != 0;
2382             check_gl_error_quietly();
2383
2384             if (is_still_shader)
2385                 continue;
2386
2387             if (!get_shared_state()->m_shadow_state.m_objs.contains_inv(replay_shader_handle))
2388             {
2389                 // We didn't create this shader handle, the AMD driver did on a program binary link, so ignore it.
2390                 continue;
2391             }
2392
2393             // The attached shader is now really dead.
2394             VOGL_ASSERT(get_shared_state()->m_shadow_state.m_objs.get_target_inv(replay_shader_handle) == VOGL_SHADER_OBJECT);
2395             if (!get_shared_state()->m_shadow_state.m_objs.erase_inv(replay_shader_handle))
2396             {
2397                 process_entrypoint_error("%s: Failed finding attached GL shader %u in objects hash table, while handling the actual deletion of trace program %u replay program %u\n", VOGL_METHOD_NAME, replay_shader_handle, trace_handle, replay_handle);
2398             }
2399         }
2400     }
2401 }
2402
2403 //----------------------------------------------------------------------------------------------------------------------
2404 // vogl_replayer::handle_delete_shader
2405 //----------------------------------------------------------------------------------------------------------------------
2406 void vogl_gl_replayer::handle_delete_shader(GLuint trace_handle)
2407 {
2408     VOGL_FUNC_TRACER
2409
2410     check_program_binding_shadow();
2411
2412     check_gl_error();
2413
2414     // Note: This mixes ARB and non-ARB funcs. to probe around, which is evil.
2415
2416     GLuint replay_handle = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle);
2417     VOGL_ASSERT(get_shared_state()->m_shadow_state.m_objs.get_target(trace_handle) == VOGL_SHADER_OBJECT);
2418     VOGL_ASSERT(get_shared_state()->m_shadow_state.m_objs.get_target_inv(replay_handle) == VOGL_SHADER_OBJECT);
2419
2420     GL_ENTRYPOINT(glDeleteShader)(replay_handle);
2421
2422     bool deletion_succeeded = !check_gl_error();
2423     if (!deletion_succeeded)
2424     {
2425         process_entrypoint_warning("%s: Failed deleting shader, trace handle %u GL handle %u\n", VOGL_METHOD_NAME, trace_handle, replay_handle);
2426         return;
2427     }
2428
2429     if (!replay_handle)
2430         return;
2431
2432     bool is_still_shader = GL_ENTRYPOINT(glIsShader)(replay_handle);
2433     check_gl_error_quietly();
2434
2435     if (!is_still_shader)
2436     {
2437         // The shader is really gone.
2438         bool was_deleted = get_shared_state()->m_shadow_state.m_objs.erase(trace_handle);
2439         VOGL_ASSERT(was_deleted);
2440         VOGL_NOTE_UNUSED(was_deleted);
2441     }
2442     else
2443     {
2444         GLint marked_for_deletion = 0;
2445         GL_ENTRYPOINT(glGetShaderiv)(replay_handle, GL_DELETE_STATUS, &marked_for_deletion);
2446         check_gl_error_quietly();
2447
2448         VOGL_VERIFY(marked_for_deletion);
2449
2450         // The shader is attached to a live program object (which may or may not be actually in the marked_as_deleted state)
2451         // we'll get around to it when the program object is deleted, or when they remove the program object from the current state.
2452     }
2453 }
2454
2455 //----------------------------------------------------------------------------------------------------------------------
2456 // vogl_replayer::handle_detach_shader
2457 //----------------------------------------------------------------------------------------------------------------------
2458 void vogl_gl_replayer::handle_detach_shader(gl_entrypoint_id_t entrypoint_id)
2459 {
2460     GLuint trace_program = m_pCur_gl_packet->get_param_value<GLuint>(0);
2461     GLuint replay_program = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_program);
2462
2463     GLuint trace_shader = m_pCur_gl_packet->get_param_value<GLuint>(1);
2464     GLuint replay_shader = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_shader);
2465
2466     check_gl_error();
2467
2468     // Note: This mixes ARB and non-ARB funcs. to probe around, which is evil.
2469
2470     GLboolean was_shader = GL_ENTRYPOINT(glIsShader)(replay_shader);
2471     check_gl_error_quietly();
2472
2473     GLint marked_for_deletion = 0;
2474     GL_ENTRYPOINT(glGetShaderiv)(replay_shader, GL_DELETE_STATUS, &marked_for_deletion);
2475     check_gl_error_quietly();
2476
2477     if (entrypoint_id == VOGL_ENTRYPOINT_glDetachObjectARB)
2478         GL_ENTRYPOINT(glDetachObjectARB)(replay_program, replay_shader);
2479     else
2480     {
2481         VOGL_ASSERT(entrypoint_id == VOGL_ENTRYPOINT_glDetachShader);
2482         GL_ENTRYPOINT(glDetachShader)(replay_program, replay_shader);
2483     }
2484
2485     bool detach_failed = check_gl_error();
2486
2487     GLboolean is_shader = GL_ENTRYPOINT(glIsShader)(replay_shader);
2488     check_gl_error_quietly();
2489
2490     if (!detach_failed)
2491     {
2492         if ((marked_for_deletion) && (was_shader) && (!is_shader))
2493         {
2494             // The shader is really gone now.
2495             bool was_deleted = get_shared_state()->m_shadow_state.m_objs.erase(trace_shader);
2496             VOGL_ASSERT(was_deleted);
2497             VOGL_NOTE_UNUSED(was_deleted);
2498         }
2499     }
2500 }
2501
2502 //----------------------------------------------------------------------------------------------------------------------
2503 // vogl_gl_replayer::handle_link_program
2504 //----------------------------------------------------------------------------------------------------------------------
2505 void vogl_gl_replayer::handle_link_program(gl_entrypoint_id_t entrypoint_id)
2506 {
2507     check_gl_error();
2508
2509     GLuint trace_handle = m_pCur_gl_packet->get_param_value<GLuint>(0);
2510     GLuint replay_handle = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle);
2511
2512     GLboolean is_program = GL_ENTRYPOINT(glIsProgram)(replay_handle);
2513     check_gl_error();
2514     if (!is_program)
2515     {
2516         process_entrypoint_warning("%s: Handle is not a program, trace program 0x%X replay program 0x%X\n", VOGL_METHOD_NAME, trace_handle, replay_handle);
2517     }
2518
2519     const json_document *pDoc = m_pCur_gl_packet->get_key_value_map().get_json_document("metadata");
2520
2521     if (!pDoc)
2522     {
2523         process_entrypoint_warning("%s: JSON metadata document is missing, program will be linked without setting its attributes or initializing the uniform location shadow, trace program 0x%X replay program 0x%X\n", VOGL_METHOD_NAME, trace_handle, replay_handle);
2524     }
2525     else if ((pDoc) && (!pDoc->is_object()))
2526     {
2527         process_entrypoint_warning("%s: JSON metadata document must be an object, trace program 0x%X replay program 0x%X\n", VOGL_METHOD_NAME, trace_handle, replay_handle);
2528         pDoc = NULL;
2529     }
2530
2531     int trace_active_attributes = 0;
2532     int trace_active_uniforms = 0;
2533     int trace_active_uniform_blocks = 0;
2534     int trace_link_status = 1;
2535
2536     VOGL_NOTE_UNUSED(trace_active_uniforms);
2537     VOGL_NOTE_UNUSED(trace_active_uniform_blocks);
2538
2539     if (pDoc)
2540     {
2541         const json_node &doc_root = *pDoc->get_root();
2542
2543         trace_link_status = doc_root.value_as_int("link_status");
2544         trace_active_attributes = doc_root.value_as_int("total_active_attributes");
2545         trace_active_uniforms = doc_root.value_as_int("total_active_uniforms");
2546         trace_active_uniform_blocks = doc_root.value_as_int("active_uniform_blocks");
2547
2548         const json_node *pAttrib_node = doc_root.find_child_array("active_attribs");
2549         if (pAttrib_node)
2550         {
2551             for (uint i = 0; i < pAttrib_node->size(); i++)
2552             {
2553                 const json_node *pAttrib = pAttrib_node->get_child(i);
2554                 if (!pAttrib)
2555                 {
2556                     VOGL_ASSERT_ALWAYS;
2557                     continue;
2558                 }
2559
2560                 const char *pName = pAttrib->value_as_string_ptr("name");
2561                 int attrib_loc = pAttrib->value_as_int("location", -1);
2562
2563                 if ((pName) && (pName[0]) && (attrib_loc >= 0))
2564                 {
2565                     if (entrypoint_id == VOGL_ENTRYPOINT_glLinkProgramARB)
2566                         GL_ENTRYPOINT(glBindAttribLocationARB)(replay_handle, attrib_loc, pName);
2567                     else
2568                         GL_ENTRYPOINT(glBindAttribLocation)(replay_handle, attrib_loc, reinterpret_cast<const GLchar *>(pName));
2569
2570                     check_gl_error();
2571                 }
2572             }
2573         }
2574
2575         const json_node *pOutputs_object = doc_root.find_child_array("active_outputs");
2576         if (pOutputs_object)
2577         {
2578             for (uint i = 0; i < pOutputs_object->size(); i++)
2579             {
2580                 const json_node *pOutput_node = pOutputs_object->get_child(i);
2581                 if (!pOutput_node)
2582                     continue;
2583
2584                 dynamic_string name(pOutput_node->value_as_string("name"));
2585                 if ((name.is_empty()) || (name.begins_with("gl_", true)))
2586                     continue;
2587
2588                 int location = pOutput_node->value_as_int("location");
2589                 int location_index = pOutput_node->value_as_int("location_index");
2590
2591                 if (m_pCur_context_state->m_context_info.supports_extension("GL_ARB_blend_func_extended") && GL_ENTRYPOINT(glBindFragDataLocationIndexed))
2592                 {
2593                     GL_ENTRYPOINT(glBindFragDataLocationIndexed)(replay_handle, location, location_index, reinterpret_cast<const GLchar *>(name.get_ptr()));
2594                 }
2595                 else
2596                 {
2597                     if (location_index)
2598                         process_entrypoint_error("%s: GL_ARB_blend_func_extended is not supported, but trace program %u GL program %u uses a non-zero location index\n", VOGL_METHOD_NAME, trace_handle, replay_handle);
2599
2600                     GL_ENTRYPOINT(glBindFragDataLocation)(replay_handle, location, reinterpret_cast<const GLchar *>(name.get_ptr()));
2601                 }
2602
2603                 check_gl_error();
2604             }
2605         }
2606
2607         GLenum transform_feedback_mode = vogl_get_json_value_as_enum(doc_root, "transform_feedback_mode");
2608         GLint num_varyings = doc_root.value_as_int("transform_feedback_num_varyings");
2609         if (num_varyings)
2610         {
2611             const json_node *pTransform_feedback_varyings = doc_root.find_child_array("transform_feedback_varyings");
2612             if (pTransform_feedback_varyings)
2613             {
2614                 dynamic_string_array names;
2615
2616                 for (uint i = 0; i < pTransform_feedback_varyings->size(); i++)
2617                 {
2618                     const json_node *pVarying_node = pTransform_feedback_varyings->get_child(i);
2619                     if (!pVarying_node)
2620                         continue;
2621
2622                     GLint index = pVarying_node->value_as_int("index");
2623                     if (index < 0)
2624                         continue;
2625
2626                     dynamic_string name(pVarying_node->value_as_string("name"));
2627
2628                     //GLsizei size(pVarying_node->value_as_int("size"));
2629                     //GLenum type(vogl_get_json_value_as_enum(*pVarying_node, "type"));
2630
2631                     names.ensure_element_is_valid(index);
2632                     names[index] = name;
2633                 }
2634
2635                 vogl::vector<GLchar *> varyings(names.size());
2636                 for (uint i = 0; i < names.size(); i++)
2637                     varyings[i] = (GLchar *)(names[i].get_ptr());
2638
2639                 GL_ENTRYPOINT(glTransformFeedbackVaryings)(replay_handle, varyings.size(), varyings.get_ptr(), transform_feedback_mode);
2640                 check_gl_error();
2641             }
2642         }
2643     }
2644
2645     switch (entrypoint_id)
2646     {
2647         case VOGL_ENTRYPOINT_glLinkProgram:
2648         {
2649             GL_ENTRYPOINT(glLinkProgram)(replay_handle);
2650             break;
2651         }
2652         case VOGL_ENTRYPOINT_glLinkProgramARB:
2653         {
2654             GL_ENTRYPOINT(glLinkProgramARB)(replay_handle);
2655             break;
2656         }
2657         case VOGL_ENTRYPOINT_glProgramBinary:
2658         {
2659             GL_ENTRYPOINT(glProgramBinary)(replay_handle, m_pCur_gl_packet->get_param_value<GLenum>(1), m_pCur_gl_packet->get_param_client_memory<GLvoid>(2), m_pCur_gl_packet->get_param_value<GLsizei>(3));
2660             break;
2661         }
2662         default:
2663         {
2664             VOGL_ASSERT_ALWAYS;
2665             return;
2666         }
2667     }
2668
2669     check_gl_error();
2670
2671     GLint replay_link_status = 0;
2672     GLint replay_active_attributes = 0;
2673     if (entrypoint_id == VOGL_ENTRYPOINT_glLinkProgramARB)
2674     {
2675         GL_ENTRYPOINT(glGetObjectParameterivARB)(replay_handle, GL_OBJECT_LINK_STATUS_ARB, &replay_link_status);
2676         check_gl_error();
2677
2678         GL_ENTRYPOINT(glGetObjectParameterivARB)(replay_handle, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &replay_active_attributes);
2679         check_gl_error();
2680     }
2681     else
2682     {
2683         GL_ENTRYPOINT(glGetProgramiv)(replay_handle, GL_LINK_STATUS, &replay_link_status);
2684         check_gl_error();
2685
2686         GL_ENTRYPOINT(glGetProgramiv)(replay_handle, GL_ACTIVE_ATTRIBUTES, &replay_active_attributes);
2687         check_gl_error();
2688     }
2689
2690     if ((replay_link_status) || (!get_shared_state()->m_shadow_state.m_linked_programs.find_snapshot(replay_handle)))
2691     {
2692         bool success;
2693         if (entrypoint_id == VOGL_ENTRYPOINT_glProgramBinary)
2694             success = get_shared_state()->m_shadow_state.m_linked_programs.add_snapshot(m_pCur_context_state->m_context_info, m_replay_to_trace_remapper, replay_handle, m_pCur_gl_packet->get_param_value<GLenum>(1), m_pCur_gl_packet->get_param_client_memory<GLvoid>(2), m_pCur_gl_packet->get_param_value<GLsizei>(3));
2695         else
2696             success = get_shared_state()->m_shadow_state.m_linked_programs.add_snapshot(m_pCur_context_state->m_context_info, m_replay_to_trace_remapper, replay_handle);
2697
2698         if (!success)
2699             process_entrypoint_warning("%s: Failed inserting into link time program shadow, trace program 0x%X replay program 0x%X\n", VOGL_METHOD_NAME, trace_handle, replay_handle);
2700     }
2701
2702     if ((pDoc) && (replay_link_status != trace_link_status))
2703     {
2704         process_entrypoint_warning("%s: Trace link status (%i) differs from replay link status (%i), trace program 0x%X replay program 0x%X\n", VOGL_METHOD_NAME, trace_link_status, replay_link_status, trace_handle, replay_handle);
2705     }
2706
2707     if (!replay_link_status)
2708     {
2709         vogl::vector<GLchar> log;
2710
2711         if (entrypoint_id == VOGL_ENTRYPOINT_glLinkProgramARB)
2712         {
2713             GLsizei length = 0;
2714             GL_ENTRYPOINT(glGetObjectParameterivARB)(replay_handle, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
2715             check_gl_error();
2716
2717             if (length)
2718             {
2719                 log.resize(length);
2720
2721                 GLint actual_length = 0;
2722                 GL_ENTRYPOINT(glGetInfoLogARB)(replay_handle, log.size(), &actual_length, reinterpret_cast<GLcharARB *>(log.get_ptr()));
2723                 check_gl_error();
2724             }
2725         }
2726         else
2727         {
2728             GLint length = 0;
2729             GL_ENTRYPOINT(glGetProgramiv)(replay_handle, GL_INFO_LOG_LENGTH, &length);
2730             check_gl_error();
2731
2732             if (length)
2733             {
2734                 log.resize(length);
2735
2736                 GL_ENTRYPOINT(glGetShaderInfoLog)(replay_handle, log.size(), &length, log.get_ptr());
2737                 check_gl_error();
2738             }
2739         }
2740
2741         if ((log.size()) && (log[0]))
2742         {
2743             process_entrypoint_message("%s: Info log for trace object %u, replay object %u:\n%s\n", VOGL_METHOD_NAME, trace_handle, replay_handle, log.get_ptr());
2744         }
2745     }
2746
2747     if ((pDoc) && (replay_active_attributes != trace_active_attributes))
2748     {
2749         process_entrypoint_warning("%s: Number of trace active attributes (%i) differs from number of replay active attributes (%i) after linking program, trace program 0x%X replay program 0x%X\n", VOGL_METHOD_NAME, trace_active_attributes, replay_active_attributes, trace_handle, replay_handle);
2750     }
2751
2752     const json_node *pUniforms_node = pDoc ? pDoc->get_root()->find_child_array("active_uniforms") : NULL;
2753
2754     if (pUniforms_node)
2755     {
2756         glsl_program_hash_map::iterator it = get_shared_state()->m_glsl_program_hash_map.find(trace_handle);
2757         if (it == get_shared_state()->m_glsl_program_hash_map.end())
2758             it = get_shared_state()->m_glsl_program_hash_map.insert(trace_handle).first;
2759         glsl_program_state &prog_state = it->second;
2760
2761         for (uint i = 0; i < pUniforms_node->size(); i++)
2762         {
2763             const json_node *pUniform = pUniforms_node->get_child(i);
2764             if (!pUniform)
2765             {
2766                 VOGL_ASSERT_ALWAYS;
2767                 continue;
2768             }
2769
2770             const char *pName = pUniform->value_as_string_ptr("name");
2771             if (!pName)
2772             {
2773                 VOGL_ASSERT_ALWAYS;
2774                 continue;
2775             }
2776             int trace_loc = pUniform->value_as_int("location");
2777             int trace_array_size = pUniform->value_as_int("size");
2778             //int trace_type = pUniform->value_as_int("type");
2779
2780             VOGL_ASSERT(trace_array_size >= 1);
2781
2782             if ((trace_loc < 0) || (trace_array_size <= 0))
2783                 continue;
2784
2785             if (trace_array_size > 1)
2786             {
2787                 dynamic_string element_name;
2788                 for (int i = 0; i < trace_array_size; i++)
2789                 {
2790                     element_name = pName;
2791                     int start_bracket_ofs = element_name.find_right('[');
2792                     if (start_bracket_ofs >= 0)
2793                         element_name.left(start_bracket_ofs);
2794                     element_name.format_append("[%u]", i);
2795
2796                     GLint element_trace_loc = trace_loc + i;
2797                     GLint element_replay_loc;
2798                     if (entrypoint_id == VOGL_ENTRYPOINT_glLinkProgramARB)
2799                         element_replay_loc = GL_ENTRYPOINT(glGetUniformLocationARB)(replay_handle, reinterpret_cast<const GLcharARB *>(element_name.get_ptr()));
2800                     else
2801                         element_replay_loc = GL_ENTRYPOINT(glGetUniformLocation)(replay_handle, reinterpret_cast<const GLchar *>(element_name.get_ptr()));
2802                     check_gl_error();
2803
2804                     if (element_replay_loc < 0)
2805                     {
2806                         process_entrypoint_warning("%s: glGetUniformLocation: Trace active array uniform %s trace location %i trace array size %i is not active during replay, trace program 0x%X replay program 0x%X\n", VOGL_METHOD_NAME, element_name.get_ptr(), trace_loc, trace_array_size, trace_handle, replay_handle);
2807                     }
2808                     else
2809                     {
2810                         prog_state.m_uniform_locations.erase(element_trace_loc);
2811                         prog_state.m_uniform_locations.insert(element_trace_loc, element_replay_loc);
2812                     }
2813                 }
2814             }
2815             else if (trace_array_size == 1)
2816             {
2817                 GLint replay_loc;
2818                 if (entrypoint_id == VOGL_ENTRYPOINT_glLinkProgramARB)
2819                     replay_loc = GL_ENTRYPOINT(glGetUniformLocationARB)(replay_handle, reinterpret_cast<const GLcharARB *>(pName));
2820                 else
2821                     replay_loc = GL_ENTRYPOINT(glGetUniformLocation)(replay_handle, reinterpret_cast<const GLchar *>(pName));
2822                 check_gl_error();
2823
2824                 if (replay_loc < 0)
2825                 {
2826                     process_entrypoint_warning("%s: glGetUniformLocation: Trace active uniform %s trace location %i is not active during replay, trace program 0x%X replay program 0x%X\n", VOGL_METHOD_NAME, pName, trace_loc, trace_handle, replay_handle);
2827                 }
2828                 else
2829                 {
2830                     prog_state.m_uniform_locations.erase(trace_loc);
2831                     prog_state.m_uniform_locations.insert(trace_loc, replay_loc);
2832                 }
2833             }
2834         } // i
2835     }
2836 }
2837
2838 //----------------------------------------------------------------------------------------------------------------------
2839 // vogl_gl_replayer::post_draw_call
2840 // Called after each draw call or blit.
2841 //----------------------------------------------------------------------------------------------------------------------
2842 vogl_gl_replayer::status_t vogl_gl_replayer::post_draw_call()
2843 {
2844     VOGL_FUNC_TRACER
2845
2846     if (m_pCur_context_state->m_inside_gl_begin)
2847         return cStatusOK;
2848
2849     if (check_gl_error())
2850         return cStatusGLError;
2851
2852     bool is_draw = vogl_is_draw_entrypoint(m_pCur_gl_packet->get_entrypoint_id());
2853
2854     if ((m_flags & cGLReplayerDumpShadersOnDraw) && (is_draw))
2855     {
2856         dump_current_shaders();
2857     }
2858
2859     if (m_flags & cGLReplayerDumpFramebufferOnDraws)
2860     {
2861         bool should_dump = false;
2862
2863         if (m_dump_framebuffer_on_draw_frame_index != -1)
2864         {
2865             if (m_frame_index == m_dump_framebuffer_on_draw_frame_index)
2866                 should_dump = true;
2867         }
2868         else if ((m_dump_framebuffer_on_draw_first_gl_call_index >= 0) && (m_dump_framebuffer_on_draw_last_gl_call_index >= 0))
2869         {
2870             should_dump = math::is_within_closed_range<uint64_t>(m_last_parsed_call_counter, m_dump_framebuffer_on_draw_first_gl_call_index, m_dump_framebuffer_on_draw_last_gl_call_index);
2871         }
2872         else
2873         {
2874             should_dump = true;
2875         }
2876
2877         if (should_dump)
2878         {
2879             dump_current_framebuffer();
2880         }
2881     }
2882
2883     m_frame_draw_counter += is_draw;
2884
2885     return cStatusOK;
2886 }
2887
2888 //----------------------------------------------------------------------------------------------------------------------
2889 // vogl_gl_replayer::dump_framebuffer
2890 //----------------------------------------------------------------------------------------------------------------------
2891 bool vogl_gl_replayer::dump_framebuffer(uint width, uint height, GLuint read_framebuffer, GLenum read_buffer, GLenum internal_format, uint orig_samples, GLuint replay_texture, GLuint replay_rbo)
2892 {
2893     VOGL_FUNC_TRACER
2894
2895     uint trace_read_framebuffer = 0;
2896     if (read_framebuffer)
2897     {
2898         gl_handle_hash_map::const_iterator it = get_context_state()->m_framebuffers.search_table_for_value(read_framebuffer);
2899         if (it != get_context_state()->m_framebuffers.end())
2900             trace_read_framebuffer = it->second;
2901     }
2902
2903     uint trace_texture = replay_texture;
2904     if (replay_texture)
2905     {
2906         if (!get_shared_state()->m_shadow_state.m_textures.map_inv_handle_to_handle(replay_texture, trace_texture))
2907             vogl_warning_printf("%s: Failed finding GL handle %u in texture handle shadow!\n", VOGL_METHOD_NAME, replay_texture);
2908     }
2909
2910     uint trace_rbo = 0;
2911     if (replay_rbo)
2912     {
2913         if (!get_shared_state()->m_shadow_state.m_rbos.map_inv_handle_to_handle(replay_rbo, trace_rbo))
2914             vogl_error_printf("%s: Failed finding GL handle %u in RBO handle shadow!\n", VOGL_METHOD_NAME, replay_rbo);
2915     }
2916
2917     m_screenshot_buffer.resize(width * height * 3);
2918
2919     bool success = vogl_copy_buffer_to_image(m_screenshot_buffer.get_ptr(), m_screenshot_buffer.size(), width, height, GL_RGB, GL_UNSIGNED_BYTE, false, read_framebuffer, read_buffer, 0);
2920
2921     if (!success)
2922     {
2923         process_entrypoint_warning("%s: vogl_copy_buffer_to_image() failed!\n", VOGL_METHOD_NAME);
2924         return false;
2925     }
2926
2927     size_t png_size = 0;
2928     void *pPNG_data = tdefl_write_image_to_png_file_in_memory_ex(m_screenshot_buffer.get_ptr(), width, height, 3, &png_size, 1, true);
2929
2930     dynamic_string screenshot_filename(cVarArg, "%s_GLCTR%08llu_%s_FR%06u_DCTR%05llu_W%04i_H%04i_FBO%04u_%s",
2931                                        m_dump_framebuffer_on_draw_prefix.get_ptr(),
2932                                        (unsigned long long)m_pCur_gl_packet->get_call_counter(),
2933                                        g_vogl_entrypoint_descs[m_pCur_gl_packet->get_entrypoint_id()].m_pName,
2934                                        m_frame_index,
2935                                        (unsigned long long)m_frame_draw_counter,
2936                                        width, height,
2937                                        trace_read_framebuffer,
2938                                        g_gl_enums.find_gl_name(read_buffer));
2939
2940     if (internal_format != GL_NONE)
2941     {
2942         screenshot_filename += "_";
2943         screenshot_filename += g_gl_enums.find_gl_image_format_name(internal_format);
2944     }
2945
2946     if (orig_samples != 0)
2947         screenshot_filename += dynamic_string(cVarArg, "_MSAA%u", orig_samples);
2948     if (replay_texture)
2949         screenshot_filename += dynamic_string(cVarArg, "_TEX%04u", replay_texture);
2950     if (replay_rbo)
2951         screenshot_filename += dynamic_string(cVarArg, "_RBO%04u", replay_rbo);
2952
2953     screenshot_filename += ".png";
2954
2955     file_utils::create_directories(file_utils::get_pathname(screenshot_filename.get_ptr()), false);
2956
2957     if (!file_utils::write_buf_to_file(screenshot_filename.get_ptr(), pPNG_data, png_size))
2958     {
2959         process_entrypoint_error("%s: Failed writing framebuffer screenshot to file \"%s\"\n", VOGL_METHOD_NAME, screenshot_filename.get_ptr());
2960         success = false;
2961     }
2962     else
2963     {
2964         vogl_printf("%s: Wrote framebuffer screenshot to file \"%s\"\n", VOGL_METHOD_NAME, screenshot_filename.get_ptr());
2965     }
2966
2967     mz_free(pPNG_data);
2968
2969     return success;
2970 }
2971
2972 //----------------------------------------------------------------------------------------------------------------------
2973 // vogl_gl_replayer::dump_current_framebuffer
2974 //----------------------------------------------------------------------------------------------------------------------
2975 void vogl_gl_replayer::dump_current_framebuffer()
2976 {
2977     VOGL_FUNC_TRACER
2978
2979     uint draw_framebuffer_binding = vogl_get_gl_integer(GL_DRAW_FRAMEBUFFER_BINDING);
2980
2981     uint max_draw_buffers = vogl_get_gl_integer(GL_MAX_DRAW_BUFFERS);
2982     if (!max_draw_buffers)
2983     {
2984         process_entrypoint_warning("%s: GL_MAX_DRAW_BUFFERS is 0\n", VOGL_METHOD_NAME);
2985         return;
2986     }
2987
2988     //GL_COLOR_ATTACHMENT0-GL_COLOR_ATTACHMENT15, GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT
2989
2990     vogl::vector<GLenum> draw_buffers(max_draw_buffers);
2991     for (uint i = 0; i < max_draw_buffers; i++)
2992         draw_buffers[i] = vogl_get_gl_integer(GL_DRAW_BUFFER0 + i);
2993
2994     if (!draw_framebuffer_binding)
2995     {
2996         for (uint i = 0; i < max_draw_buffers; i++)
2997             if (draw_buffers[i] != GL_NONE)
2998                 dump_framebuffer(m_pWindow->get_width(), m_pWindow->get_height(), 0, draw_buffers[i], GL_NONE, 0, 0, 0);
2999         return;
3000     }
3001
3002     // TODO: We should probably keep around a persistent set of per-context (or sharelist) remappers
3003     vogl_framebuffer_state fbo_state;
3004     if (!fbo_state.snapshot(m_pCur_context_state->m_context_info, m_replay_to_trace_remapper, draw_framebuffer_binding, GL_NONE))
3005     {
3006         process_entrypoint_warning("%s: Unable to snapshot current FBO %u\n", VOGL_METHOD_NAME, draw_framebuffer_binding);
3007         return;
3008     }
3009
3010     for (uint i = 0; i < draw_buffers.size(); i++)
3011     {
3012         if (draw_buffers[i] == GL_NONE)
3013             continue;
3014
3015         const vogl_framebuffer_attachment *pAttachment = fbo_state.get_attachments().find_value(draw_buffers[i]);
3016         if (!pAttachment)
3017         {
3018             process_entrypoint_warning("%s: Can't find draw buffer %s in currently bound FBO %u\n", VOGL_METHOD_NAME, g_gl_enums.find_gl_name(draw_buffers[i]), draw_framebuffer_binding);
3019             continue;
3020         }
3021
3022         if (pAttachment->get_type() == GL_FRAMEBUFFER_DEFAULT)
3023             continue;
3024         else if (pAttachment->get_type() == GL_RENDERBUFFER)
3025         {
3026             GLuint rbo_handle = pAttachment->get_param(GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
3027             if (!rbo_handle)
3028                 continue;
3029
3030             vogl_renderbuffer_state rbo_state;
3031             if (!rbo_state.snapshot(m_pCur_context_state->m_context_info, m_replay_to_trace_remapper, rbo_handle, GL_NONE))
3032             {
3033                 process_entrypoint_warning("%s: Failed getting RBO %u's' state!\n", VOGL_METHOD_NAME, rbo_handle);
3034                 continue;
3035             }
3036
3037             if (rbo_state.get_desc().get_int_or_default(GL_RENDERBUFFER_DEPTH_SIZE) || rbo_state.get_desc().get_int_or_default(GL_RENDERBUFFER_STENCIL_SIZE))
3038                 continue;
3039
3040             uint width = rbo_state.get_desc().get_int_or_default(GL_RENDERBUFFER_WIDTH);
3041             uint height = rbo_state.get_desc().get_int_or_default(GL_RENDERBUFFER_HEIGHT);
3042             uint samples = rbo_state.get_desc().get_int_or_default(GL_RENDERBUFFER_SAMPLES);
3043             GLenum internal_format = rbo_state.get_desc().get_int_or_default(GL_RENDERBUFFER_INTERNAL_FORMAT);
3044
3045             if ((!width) || (!height) || (!internal_format))
3046             {
3047                 process_entrypoint_warning("%s: Unable to determine FBO %u color attachment %u's RBO %u's dimensions\n", VOGL_METHOD_NAME, draw_framebuffer_binding, i, rbo_handle);
3048                 continue;
3049             }
3050
3051             if (samples > 1)
3052             {
3053                 vogl_scoped_binding_state orig_framebuffers(GL_DRAW_FRAMEBUFFER, GL_READ_FRAMEBUFFER, GL_RENDERBUFFER);
3054
3055                 GLuint temp_rbo = 0;
3056                 GL_ENTRYPOINT(glGenRenderbuffers)(1, &temp_rbo);
3057                 check_gl_error();
3058
3059                 if (!temp_rbo)
3060                     continue;
3061
3062                 GL_ENTRYPOINT(glBindRenderbuffer)(GL_RENDERBUFFER, temp_rbo);
3063                 check_gl_error();
3064
3065                 GL_ENTRYPOINT(glRenderbufferStorage)(GL_RENDERBUFFER, internal_format, width, height);
3066                 check_gl_error();
3067
3068                 GLuint temp_fbo = 0;
3069                 GL_ENTRYPOINT(glGenFramebuffers)(1, &temp_fbo);
3070                 check_gl_error();
3071
3072                 GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, temp_fbo);
3073                 check_gl_error();
3074
3075                 GL_ENTRYPOINT(glFramebufferRenderbuffer)(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, temp_rbo);
3076                 check_gl_error();
3077
3078                 GLenum draw_buf = GL_COLOR_ATTACHMENT0;
3079                 GL_ENTRYPOINT(glDrawBuffers)(1, &draw_buf);
3080                 check_gl_error();
3081
3082                 GL_ENTRYPOINT(glReadBuffer)(GL_NONE);
3083                 check_gl_error();
3084
3085                 GLenum cur_status = GL_ENTRYPOINT(glCheckFramebufferStatus)(GL_DRAW_FRAMEBUFFER);
3086                 check_gl_error();
3087
3088                 if (cur_status == GL_FRAMEBUFFER_COMPLETE)
3089                 {
3090                     GL_ENTRYPOINT(glBindFramebuffer)(GL_READ_FRAMEBUFFER, draw_framebuffer_binding);
3091                     check_gl_error();
3092
3093                     // Save the framebuffer's readbuffer (it's per-framebuffer state, not context state).
3094                     vogl_scoped_state_saver state_saver(cGSTReadBuffer);
3095
3096                     GL_ENTRYPOINT(glReadBuffer)(draw_buffers[i]);
3097                     check_gl_error();
3098
3099                     GL_ENTRYPOINT(glBlitFramebuffer)(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
3100
3101                     if (!check_gl_error())
3102                         dump_framebuffer(width, height, temp_fbo, GL_COLOR_ATTACHMENT0, internal_format, samples, 0, rbo_handle);
3103                     else
3104                     {
3105                         process_entrypoint_warning("%s: Failed downsampling FBO %u color attachment %u's RBO %u to temporary RBO\n", VOGL_METHOD_NAME, draw_framebuffer_binding, i, rbo_handle);
3106                     }
3107                 }
3108
3109                 GL_ENTRYPOINT(glBindRenderbuffer)(GL_RENDERBUFFER, 0);
3110                 check_gl_error();
3111
3112                 GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, 0);
3113                 check_gl_error();
3114
3115                 GL_ENTRYPOINT(glDeleteFramebuffers)(1, &temp_fbo);
3116                 check_gl_error();
3117
3118                 GL_ENTRYPOINT(glDeleteRenderbuffers)(1, &temp_rbo);
3119                 check_gl_error();
3120             }
3121             else
3122             {
3123                 dump_framebuffer(width, height, draw_framebuffer_binding, draw_buffers[i], internal_format, 0, 0, rbo_handle);
3124             }
3125         }
3126         else if (pAttachment->get_type() == GL_TEXTURE)
3127         {
3128             GLuint tex_handle = pAttachment->get_param(GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
3129             if (!tex_handle)
3130             {
3131                 process_entrypoint_warning("%s: Current FBO %u has a invalid object name\n", VOGL_METHOD_NAME, draw_framebuffer_binding);
3132                 continue;
3133             }
3134
3135             GLenum target = get_shared_state()->m_shadow_state.m_textures.get_target_inv(tex_handle);
3136             if (target == GL_NONE)
3137             {
3138                 process_entrypoint_warning("%s: Current FBO %u first color attachment's type is GL_TEXTURE, but unable to determine the texture's target type, GL texture handle %u\n", VOGL_METHOD_NAME, draw_framebuffer_binding, tex_handle);
3139                 continue;
3140             }
3141
3142             if ((target == GL_TEXTURE_CUBE_MAP) || (target == GL_TEXTURE_CUBE_MAP_ARRAY))
3143                 target = pAttachment->get_param(GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE);
3144
3145             if (!utils::is_in_set<GLenum, GLenum>(target, GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_1D_ARRAY, GL_TEXTURE_2D_ARRAY, GL_TEXTURE_RECTANGLE, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_CUBE_MAP_ARRAY))
3146             {
3147                 process_entrypoint_warning("%s: Unsupported FBO attachment texture target type (%s), GL texture handle %u\n", VOGL_METHOD_NAME, g_gl_enums.find_gl_name(target), tex_handle);
3148                 continue;
3149             }
3150
3151             uint level = pAttachment->get_param(GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL);
3152             uint layer = pAttachment->get_param(GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER);
3153             VOGL_NOTE_UNUSED(layer);
3154
3155             GLint width = 0, height = 0, samples = 0;
3156             GLenum internal_format = GL_NONE;
3157
3158             {
3159                 vogl_scoped_binding_state binding_saver;
3160                 binding_saver.save_textures();
3161
3162                 GL_ENTRYPOINT(glBindTexture)(target, tex_handle);
3163                 check_gl_error();
3164
3165                 GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, level, GL_TEXTURE_WIDTH, &width);
3166                 check_gl_error();
3167
3168                 GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, level, GL_TEXTURE_HEIGHT, &height);
3169                 check_gl_error();
3170
3171                 GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, level, GL_TEXTURE_INTERNAL_FORMAT, reinterpret_cast<GLint *>(&internal_format));
3172                 check_gl_error();
3173
3174                 if (m_pCur_context_state->m_context_info.supports_extension("GL_ARB_texture_multisample"))
3175                 {
3176                     GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, level, GL_TEXTURE_SAMPLES, &samples);
3177                     check_gl_error();
3178                 }
3179             }
3180
3181             if ((!width) || (!height))
3182             {
3183                 process_entrypoint_warning("%s: Unable to determine FBO %u color attachment %u's texture %u's dimensions\n", VOGL_METHOD_NAME, draw_framebuffer_binding, i, tex_handle);
3184                 continue;
3185             }
3186
3187             if (samples > 1)
3188             {
3189                 process_entrypoint_warning("%s: Can't dump multisample texture FBO attachments yet\n", VOGL_METHOD_NAME);
3190                 continue;
3191             }
3192
3193             dump_framebuffer(width, height, draw_framebuffer_binding, draw_buffers[i], internal_format, 0, tex_handle, 0);
3194         }
3195     }
3196 }
3197
3198 //----------------------------------------------------------------------------------------------------------------------
3199 // vogl_gl_replayer::dump_current_shaders
3200 //----------------------------------------------------------------------------------------------------------------------
3201 void vogl_gl_replayer::dump_current_shaders()
3202 {
3203     VOGL_FUNC_TRACER
3204
3205     if (!m_pCur_context_state)
3206         return;
3207
3208     check_gl_error();
3209
3210     const GLuint replay_program = m_pCur_context_state->m_cur_replay_program;
3211
3212     // Get the current program.
3213     GLuint current_program = 0;
3214     GL_ENTRYPOINT(glGetIntegerv)(GL_CURRENT_PROGRAM, (GLint *)(&current_program));
3215     check_gl_error();
3216
3217     VOGL_ASSERT(replay_program == current_program);
3218
3219     if (!current_program)
3220         return;
3221
3222     // Get the attached shaders.
3223     GLsizei attached_shader_count = -1;
3224     GL_ENTRYPOINT(glGetProgramiv)(replay_program, GL_ATTACHED_SHADERS, &attached_shader_count);
3225     check_gl_error();
3226
3227     if (!attached_shader_count)
3228         return;
3229
3230     vogl::vector<GLuint> shaders(attached_shader_count);
3231     GLsizei actual_shader_count = 0;
3232     GL_ENTRYPOINT(glGetAttachedShaders)(replay_program,
3233                                         attached_shader_count,
3234                                         &actual_shader_count,
3235                                         shaders.get_ptr());
3236     check_gl_error();
3237
3238     VOGL_ASSERT(attached_shader_count == actual_shader_count); // Sanity check.
3239
3240     vogl_printf("Trace context 0x%" PRIx64 ", GL draw counter %" PRIu64 ", frame %u, replay program %u trace program %u has %d attached shaders:\n",
3241                cast_val_to_uint64(m_cur_trace_context), m_last_parsed_call_counter, m_frame_index,
3242                replay_program, m_pCur_context_state->m_cur_trace_program,
3243                attached_shader_count);
3244
3245     // Get source from shaders.
3246     vogl::vector<GLchar> source; // Shared buffer for each iteration.
3247     for (GLsizei i = 0; i < attached_shader_count; ++i)
3248     {
3249         const GLuint shader = shaders[i];
3250         GLint shader_type = 0;
3251         GL_ENTRYPOINT(glGetShaderiv)(shader, GL_SHADER_TYPE, &shader_type);
3252         check_gl_error();
3253
3254         vogl_printf("\n%s: %u\n", g_gl_enums.find_gl_name(shader_type), shader);
3255
3256         GLint source_length = -1; // Includes NUL terminator.
3257         GL_ENTRYPOINT(glGetShaderiv)(shader, GL_SHADER_SOURCE_LENGTH, &source_length);
3258         check_gl_error();
3259
3260         VOGL_ASSERT(source_length > 0);
3261
3262         source.resize(source_length);
3263         GLint actual_length = 0; // Excludes NUL terminator!
3264         GL_ENTRYPOINT(glGetShaderSource)(shader, source_length, &actual_length, source.get_ptr());
3265         check_gl_error();
3266
3267         VOGL_ASSERT(source_length == actual_length + 1); // Sanity check.
3268         vogl_printf("%.*s\n", source_length, source.get_const_ptr());
3269     }
3270     vogl_printf("========\n");
3271 }
3272
3273 //----------------------------------------------------------------------------------------------------------------------
3274 // vogl_gl_replayer::handle_ShaderSource
3275 // Handle ShaderSource and ShaderSourceARB.
3276 //----------------------------------------------------------------------------------------------------------------------
3277 vogl_gl_replayer::status_t vogl_gl_replayer::handle_ShaderSource(GLhandleARB trace_object,
3278                                                                GLsizei count,
3279                                                                const vogl_client_memory_array trace_strings_glchar_ptr_array,
3280                                                                const GLint *pTrace_lengths)
3281 {
3282     VOGL_FUNC_TRACER
3283
3284     GLhandleARB replay_object = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_object);
3285
3286     // m_pCur_gl_packet->get_param_client_memory_data_size(2) / sizeof(const GLchar *);
3287     const uint trace_strings_count = trace_strings_glchar_ptr_array.size();
3288     const uint trace_lengths_count = m_pCur_gl_packet->get_param_client_memory_data_size(3) / sizeof(const GLint);
3289
3290     if ((trace_strings_glchar_ptr_array.get_ptr()) &&
3291         (trace_strings_count != static_cast<uint>(count)))
3292     {
3293         process_entrypoint_error("%s: Trace strings array has an invalid count (expected %u, got %u)\n",
3294                                  VOGL_METHOD_NAME, count, trace_strings_count);
3295         return cStatusHardFailure;
3296     }
3297
3298     if ((pTrace_lengths) && (trace_lengths_count != static_cast<uint>(count)))
3299     {
3300         process_entrypoint_error("%s: Trace lengths array has an invalid count (expected %u, got %u)\n",
3301                                  VOGL_METHOD_NAME, count, trace_lengths_count);
3302         return cStatusHardFailure;
3303     }
3304
3305     vogl::vector<const GLcharARB *> strings(count);
3306     vogl::vector<GLint> lengths(count);
3307
3308     const key_value_map &map = m_pCur_gl_packet->get_key_value_map();
3309
3310     vogl::vector<uint8_vec> blobs(count);
3311
3312     for (GLsizei i = 0; i < count; i++)
3313     {
3314         strings[i] = NULL;
3315         if ((trace_strings_glchar_ptr_array.get_ptr()) &&
3316             (trace_strings_glchar_ptr_array.get_element<vogl_trace_ptr_value>(i) != 0))
3317         {
3318             strings[i] = "";
3319         }
3320
3321         lengths[i] = pTrace_lengths ? pTrace_lengths[i] : 0;
3322
3323         key_value_map::const_iterator it = map.find(i);
3324         if (it == map.end())
3325         {
3326             if (lengths[i] > 0)
3327             {
3328                 process_entrypoint_error("%s: Failed finding blob for non-empty string %i in packet's key value map\n",
3329                                          VOGL_METHOD_NAME, i);
3330                 return cStatusHardFailure;
3331             }
3332             continue;
3333         }
3334
3335         const uint8_vec *pBlob = it->second.get_blob();
3336         if (!pBlob)
3337         {
3338             process_entrypoint_error("%s: Can't convert string %i to a blob\n", VOGL_METHOD_NAME, i);
3339             return cStatusHardFailure;
3340         }
3341
3342         blobs[i] = *pBlob;
3343         uint8_vec &blob = blobs[i];
3344
3345         if ((pTrace_lengths) && (pTrace_lengths[i] >= 0))
3346         {
3347             if (static_cast<uint>(pTrace_lengths[i]) != blob.size())
3348             {
3349                 process_entrypoint_warning("%s: Length value (%u) stored in length array at index %u doesn't match string %u's length - changing to match\n", VOGL_METHOD_NAME, pTrace_lengths[i], i, blob.size());
3350                 lengths[i] = blob.size();
3351             }
3352         }
3353         else
3354         {
3355             if ((blob.size()) && (blob.back() != '\0'))
3356             {
3357                 process_entrypoint_warning("%s: String %u doesn't end in 0 terminator - appending terminator\n", VOGL_METHOD_NAME, i);
3358
3359                 blob.push_back('\0');
3360             }
3361
3362             VOGL_ASSERT(blob.size() &&
3363                           (blob.back() == '\0') &&
3364                           (blob.size() == (1 + vogl_strlen(reinterpret_cast<const char *>(blob.get_ptr())))));
3365         }
3366
3367         strings[i] = reinterpret_cast<const GLcharARB *>(blob.get_ptr());
3368     }
3369
3370     if (m_pCur_gl_packet->get_entrypoint_id() == VOGL_ENTRYPOINT_glShaderSource)
3371     {
3372         GL_ENTRYPOINT(glShaderSource)(replay_object,
3373                                       count,
3374                                       trace_strings_glchar_ptr_array.get_ptr() ? (GLchar * const *)strings.get_ptr() : NULL,
3375                                       pTrace_lengths ? lengths.get_ptr() : NULL);
3376     }
3377     else
3378     {
3379         GL_ENTRYPOINT(glShaderSourceARB)(replay_object,
3380                                          count,
3381                                          trace_strings_glchar_ptr_array.get_ptr() ? strings.get_ptr() : NULL,
3382                                          pTrace_lengths ? lengths.get_ptr() : NULL);
3383     }
3384     return cStatusOK;
3385 }
3386
3387 //----------------------------------------------------------------------------------------------------------------------
3388 // vogl_gl_replayer::display_list_bind_callback
3389 // handle is in the trace namespace
3390 //----------------------------------------------------------------------------------------------------------------------
3391 void vogl_gl_replayer::display_list_bind_callback(vogl_namespace_t handle_namespace, GLenum target, GLuint handle, void *pOpaque)
3392 {
3393     VOGL_FUNC_TRACER
3394
3395     vogl_gl_replayer *pReplayer = static_cast<vogl_gl_replayer *>(pOpaque);
3396
3397     if (handle_namespace == VOGL_NAMESPACE_TEXTURES)
3398     {
3399         if ((handle) && (target != GL_NONE))
3400         {
3401             // A conditional update because we can't really test to see if the bind inside the display list really succeeded.
3402             pReplayer->get_shared_state()->m_shadow_state.m_textures.conditional_update(handle, GL_NONE, target);
3403         }
3404     }
3405     else
3406     {
3407         // TODO - right now the display list whitelist doens't let anything else get bound.
3408         pReplayer->process_entrypoint_warning("%s: Unsupported bind in display lists, namespace %s target %s trace handle %u\n", VOGL_FUNCTION_NAME, vogl_get_namespace_name(handle_namespace), g_gl_enums.find_gl_name(target), handle);
3409     }
3410 }
3411
3412 //----------------------------------------------------------------------------------------------------------------------
3413 // Helper macros - slightly simplifies hand-generating entrypoints with EXT/ARB/etc. variants
3414 //----------------------------------------------------------------------------------------------------------------------
3415 #define SWITCH_GL_ENTRYPOINT2(e0, e1, ...)                 \
3416     if (entrypoint_id == VOGL_JOIN(VOGL_ENTRYPOINT_, e0)) \
3417         result = GL_ENTRYPOINT(e0)(__VA_ARGS__);           \
3418     else                                                   \
3419         result = GL_ENTRYPOINT(e1)(__VA_ARGS__);
3420
3421 #define SWITCH_GL_ENTRYPOINT3(e0, e1, e2, ...)                  \
3422     if (entrypoint_id == VOGL_JOIN(VOGL_ENTRYPOINT_, e0))      \
3423         result = GL_ENTRYPOINT(e0)(__VA_ARGS__);                \
3424     else if (entrypoint_id == VOGL_JOIN(VOGL_ENTRYPOINT_, e1)) \
3425         result = GL_ENTRYPOINT(e1)(__VA_ARGS__);                \
3426     else                                                        \
3427         result = GL_ENTRYPOINT(e2)(__VA_ARGS__);
3428
3429 #define SWITCH_GL_ENTRYPOINT2_VOID(e0, e1, ...)            \
3430     if (entrypoint_id == VOGL_JOIN(VOGL_ENTRYPOINT_, e0)) \
3431         GL_ENTRYPOINT(e0)(__VA_ARGS__);                    \
3432     else                                                   \
3433         GL_ENTRYPOINT(e1)(__VA_ARGS__);
3434
3435 #define SWITCH_GL_ENTRYPOINT3_VOID(e0, e1, e2, ...)             \
3436     if (entrypoint_id == VOGL_JOIN(VOGL_ENTRYPOINT_, e0))      \
3437         GL_ENTRYPOINT(e0)(__VA_ARGS__);                         \
3438     else if (entrypoint_id == VOGL_JOIN(VOGL_ENTRYPOINT_, e1)) \
3439         GL_ENTRYPOINT(e1)(__VA_ARGS__);                         \
3440     else                                                        \
3441         GL_ENTRYPOINT(e2)(__VA_ARGS__);
3442
3443 //----------------------------------------------------------------------------------------------------------------------
3444 // vogl_replayer::process_gl_entrypoint_packet
3445 // This will be called during replaying, or when building display lists during state restoring.
3446 //----------------------------------------------------------------------------------------------------------------------
3447 vogl_gl_replayer::status_t vogl_gl_replayer::process_gl_entrypoint_packet(vogl_trace_packet& trace_packet)
3448 {
3449     m_pCur_gl_packet = &trace_packet;
3450
3451     status_t status = cStatusOK;
3452
3453     if (m_pPending_snapshot)
3454     {
3455         status = process_applying_pending_snapshot();
3456         if (status != cStatusOK)
3457             return status;
3458     }
3459
3460     if (m_pending_make_current_packet.is_valid())
3461     {
3462         status = process_pending_make_current();
3463         if (status != cStatusOK)
3464             return status;
3465     }
3466
3467     const vogl_trace_gl_entrypoint_packet &entrypoint_packet = trace_packet.get_entrypoint_packet();
3468
3469     m_last_parsed_call_counter = entrypoint_packet.m_call_counter;
3470
3471     status = process_gl_entrypoint_packet_internal(trace_packet);
3472
3473     if (status != cStatusResizeWindow)
3474         m_last_processed_call_counter = entrypoint_packet.m_call_counter;
3475
3476     m_pCur_gl_packet = NULL;
3477
3478     return status;
3479 }
3480
3481 //----------------------------------------------------------------------------------------------------------------------
3482 // vogl_replayer::process_gl_entrypoint_packet_internal
3483 // This will be called during replaying, or when building display lists during state restoring.
3484 //----------------------------------------------------------------------------------------------------------------------
3485 vogl_gl_replayer::status_t vogl_gl_replayer::process_gl_entrypoint_packet_internal(vogl_trace_packet& trace_packet)
3486 {
3487     VOGL_FUNC_TRACER
3488
3489     m_at_frame_boundary = false;
3490
3491     const vogl_trace_gl_entrypoint_packet &gl_entrypoint_packet = trace_packet.get_entrypoint_packet();
3492     const gl_entrypoint_id_t entrypoint_id = trace_packet.get_entrypoint_id();
3493
3494     if (m_flags & cGLReplayerDebugMode)
3495         dump_trace_gl_packet_debug_info(gl_entrypoint_packet);
3496
3497     if (m_flags & cGLReplayerDebugMode)
3498         dump_packet_as_func_call(trace_packet);
3499
3500     if (m_flags & cGLReplayerDumpAllPackets)
3501         print_detailed_context(cDebugConsoleMessage);
3502
3503     if (entrypoint_id == VOGL_ENTRYPOINT_glInternalTraceCommandRAD)
3504         return process_internal_trace_command(gl_entrypoint_packet);
3505
3506     status_t status = cStatusOK;
3507
3508     if (gl_entrypoint_packet.m_context_handle != m_cur_trace_context)
3509     {
3510         status = switch_contexts(gl_entrypoint_packet.m_context_handle);
3511         if (status != cStatusOK)
3512             return status;
3513     }
3514
3515     bool processed_glx_packet = true;
3516     switch (entrypoint_id)
3517     {
3518         case VOGL_ENTRYPOINT_glXDestroyContext:
3519         {
3520             const Display *dpy = m_pWindow->get_display();
3521
3522             vogl_trace_context_ptr_value trace_context = trace_packet.get_param_ptr_value(1);
3523             GLXContext replay_context = remap_context(trace_context);
3524
3525             if ((trace_context) && (!replay_context))
3526             {
3527                 process_entrypoint_error("%s: Failed remapping GL trace context 0x%" PRIx64 "\n", VOGL_METHOD_NAME, (uint64_t)trace_context);
3528                 return cStatusHardFailure;
3529             }
3530
3531             if (trace_context == m_cur_trace_context)
3532             {
3533                 process_entrypoint_warning("%s: glXDestroyContext() called while trace context 0x%" PRIx64 " is still current, forcing it to not be current\n",
3534                                            VOGL_METHOD_NAME, (uint64_t)trace_context);
3535
3536                 m_cur_trace_context = 0;
3537                 m_cur_replay_context = 0;
3538                 m_pCur_context_state = NULL;
3539             }
3540
3541             GL_ENTRYPOINT(glXDestroyContext)(dpy, replay_context);
3542
3543             destroy_context(trace_context);
3544
3545             break;
3546         }
3547         case VOGL_ENTRYPOINT_glXMakeCurrent:
3548         case VOGL_ENTRYPOINT_glXMakeContextCurrent:
3549         {
3550             Bool trace_result = trace_packet.get_return_value<Bool>();
3551
3552             vogl_trace_context_ptr_value trace_context = trace_packet.get_param_ptr_value((entrypoint_id == VOGL_ENTRYPOINT_glXMakeCurrent) ? 2 : 3);
3553
3554             // pContext_state can be NULL!
3555             context_state *pContext_state = get_trace_context_state(trace_context);
3556             GLXContext replay_context = pContext_state ? pContext_state->m_replay_context : 0;
3557
3558             if ((trace_context) && (!replay_context))
3559             {
3560                 process_entrypoint_error("%s, Failed remapping GL context\n", VOGL_METHOD_NAME);
3561                 return cStatusHardFailure;
3562             }
3563
3564             int viewport_x = trace_packet.get_key_value_map().get_int(string_hash("viewport_x"));
3565             VOGL_NOTE_UNUSED(viewport_x);
3566             int viewport_y = trace_packet.get_key_value_map().get_int(string_hash("viewport_y"));
3567             VOGL_NOTE_UNUSED(viewport_y);
3568             int viewport_width = trace_packet.get_key_value_map().get_int(string_hash("viewport_width"));
3569             VOGL_NOTE_UNUSED(viewport_width);
3570             int viewport_height = trace_packet.get_key_value_map().get_int(string_hash("viewport_height"));
3571             VOGL_NOTE_UNUSED(viewport_height);
3572             int win_width = trace_packet.get_key_value_map().get_int(string_hash("win_width"));
3573             int win_height = trace_packet.get_key_value_map().get_int(string_hash("win_height"));
3574
3575             // We may need to defer the make current until the window is the proper size, because the initial GL viewport's state depends on the Window size. Ugh.
3576             if ((trace_context) && (trace_result))
3577             {
3578                 if ((win_width) && (win_height))
3579                 {
3580                     if (!(m_flags & cGLReplayerLockWindowDimensions))
3581                     {
3582                         if ((m_pWindow->get_width() != win_width) || (m_pWindow->get_height() != win_height))
3583                         {
3584                             m_pending_make_current_packet = *m_pCur_gl_packet;
3585
3586                             status = trigger_pending_window_resize(win_width, win_height);
3587
3588                             vogl_printf("%s: Deferring glXMakeCurrent() until window resizes to %ux%u\n", VOGL_METHOD_NAME, win_width, win_height);
3589                         }
3590                     }
3591                 }
3592             }
3593
3594             if (status != cStatusResizeWindow)
3595             {
3596                 const Display *dpy = m_pWindow->get_display();
3597                 GLXDrawable drawable = replay_context ? m_pWindow->get_xwindow() : (GLXDrawable)NULL;
3598
3599                 Bool result = GL_ENTRYPOINT(glXMakeCurrent)(dpy, drawable, replay_context);
3600                 if (!result)
3601                 {
3602                     if (trace_result)
3603                     {
3604                         process_entrypoint_error("%s: Failed making context current, but in the trace this call succeeded!\n", VOGL_METHOD_NAME);
3605                         return cStatusHardFailure;
3606                     }
3607                     else
3608                     {
3609                         process_entrypoint_warning("%s: Failed making context current, in the trace this call also failed\n", VOGL_METHOD_NAME);
3610                     }
3611                 }
3612                 else
3613                 {
3614                     m_cur_trace_context = trace_context;
3615                     m_cur_replay_context = replay_context;
3616                     m_pCur_context_state = pContext_state;
3617
3618                     if (!trace_result)
3619                     {
3620                         process_entrypoint_warning("%s: Context was successfuly made current, but this operation failed in the trace\n", VOGL_METHOD_NAME);
3621                     }
3622
3623 #if 0
3624                                 vogl_printf("glXMakeCurrent(): Trace Viewport: [%u,%u,%u,%u], Window: [%u %u]\n",
3625                                            viewport_x, viewport_y,
3626                                            viewport_width, viewport_height,
3627                                            win_width, win_height);
3628 #endif
3629
3630                     if (m_cur_replay_context)
3631                     {
3632                         if (!handle_context_made_current())
3633                             return cStatusHardFailure;
3634                     }
3635                 }
3636             }
3637
3638             break;
3639         }
3640         case VOGL_ENTRYPOINT_glXQueryVersion:
3641         {
3642             int major = 0, minor = 0;
3643             Bool status = GL_ENTRYPOINT(glXQueryVersion)(m_pWindow->get_display(), &major, &minor);
3644             process_entrypoint_message("%s: glXQueryVersion returned major %u minor %u status %u, trace recorded major %u minor %u status %u\n", VOGL_METHOD_NAME, major, minor, status,
3645                                        *trace_packet.get_param_client_memory<int>(1),
3646                                        *trace_packet.get_param_client_memory<int>(2),
3647                                        trace_packet.get_return_value<Bool>());
3648
3649             break;
3650         }
3651         case VOGL_ENTRYPOINT_glXChooseFBConfig:
3652         {
3653             // TODO
3654             break;
3655         }
3656         case VOGL_ENTRYPOINT_glXGetFBConfigAttrib:
3657         {
3658             // TODO
3659             break;
3660         }
3661         case VOGL_ENTRYPOINT_glXGetVisualFromFBConfig:
3662         {
3663             // TODO
3664             break;
3665         }
3666         case VOGL_ENTRYPOINT_glXGetProcAddress:
3667         case VOGL_ENTRYPOINT_glXGetProcAddressARB:
3668         {
3669             const GLubyte *procName = trace_packet.get_param_client_memory<GLubyte>(0);
3670             vogl_trace_ptr_value trace_func_ptr_value = trace_packet.get_return_ptr_value();
3671
3672             void *pFunc = (void *)GL_ENTRYPOINT(glXGetProcAddress)(procName);
3673
3674             if ((pFunc != NULL) != (trace_func_ptr_value != 0))
3675             {
3676                 process_entrypoint_warning("%s: glXGetProcAddress of function %s %s in the replay, but %s in the trace\n", VOGL_METHOD_NAME,
3677                                            (const char *)procName,
3678                                            (pFunc != NULL) ? "succeeded" : "failed",
3679                                            (trace_func_ptr_value != 0) ? "succeeded" : "failed");
3680             }
3681
3682             break;
3683         }
3684         case VOGL_ENTRYPOINT_glXCreateNewContext:
3685         {
3686             Display *dpy = m_pWindow->get_display();
3687             GLXFBConfig fb_config = m_pWindow->get_fb_configs()[0];
3688             int render_type = trace_packet.get_param_value<GLint>(2);
3689
3690             vogl_trace_context_ptr_value trace_share_context = trace_packet.get_param_ptr_value(3);
3691             GLXContext replay_share_context = remap_context(trace_share_context);
3692
3693             if ((trace_share_context) && (!replay_share_context))
3694             {
3695                 process_entrypoint_warning("%s: Failed remapping trace sharelist context 0x%" PRIx64 "!\n", VOGL_METHOD_NAME, cast_val_to_uint64(trace_share_context));
3696             }
3697
3698             Bool direct = trace_packet.get_param_value<Bool>(4);
3699             vogl_trace_context_ptr_value trace_context = trace_packet.get_return_ptr_value();
3700
3701             if (m_flags & cGLReplayerForceDebugContexts)
3702             {
3703                 process_entrypoint_warning("%s: glxCreateNewContext() called but we're trying to force debug contexts, which requires us to call glXCreateContextAttribsARB(). This may fail if the user has called glXCreateWindow().\n", VOGL_METHOD_NAME);
3704
3705                 status = create_context_attribs(trace_context, dpy, fb_config, trace_share_context, replay_share_context, direct, NULL, 0, false);
3706                 if (status != cStatusOK)
3707                     return status;
3708             }
3709             else
3710             {
3711                 GLXContext replay_context = GL_ENTRYPOINT(glXCreateNewContext)(dpy, fb_config, render_type, replay_share_context, direct);
3712
3713                 if (!replay_context)
3714                 {
3715                     if (trace_context)
3716                     {
3717                         process_entrypoint_error("%s: Failed creating new GL context!\n", VOGL_METHOD_NAME);
3718                         return cStatusHardFailure;
3719                     }
3720                     else
3721                     {
3722                         process_entrypoint_warning("%s: Successfully created a new GL context where the traced app failed!\n", VOGL_METHOD_NAME);
3723                     }
3724                 }
3725
3726                 if (replay_context)
3727                 {
3728                     if (trace_context)
3729                     {
3730                         context_state *pContext_state = define_new_context(trace_context, replay_context, trace_share_context, direct, VOGL_ENTRYPOINT_glXCreateNewContext, NULL, 0);
3731                         VOGL_NOTE_UNUSED(pContext_state);
3732                     }
3733                     else
3734                     {
3735                         GL_ENTRYPOINT(glXDestroyContext)(m_pWindow->get_display(), replay_context);
3736                     }
3737                 }
3738             }
3739
3740             break;
3741         }
3742         case VOGL_ENTRYPOINT_glXCreateContext:
3743         {
3744             Display *dpy = m_pWindow->get_display();
3745
3746             vogl_trace_context_ptr_value trace_share_context = trace_packet.get_param_ptr_value(2);
3747             GLXContext replay_share_context = remap_context(trace_share_context);
3748
3749             if ((trace_share_context) && (!replay_share_context))
3750             {
3751                 process_entrypoint_warning("%s: Failed remapping trace sharelist context 0x%" PRIx64 "!\n", VOGL_METHOD_NAME, cast_val_to_uint64(trace_share_context));
3752             }
3753
3754             GLXFBConfig fb_config = m_pWindow->get_fb_configs()[0];
3755             Bool direct = trace_packet.get_param_value<Bool>(3);
3756             vogl_trace_context_ptr_value trace_context = trace_packet.get_return_ptr_value();
3757
3758             if (m_flags & cGLReplayerForceDebugContexts)
3759             {
3760                 status = create_context_attribs(trace_context, dpy, fb_config, trace_share_context, replay_share_context, direct, NULL, 0, false);
3761                 if (status != cStatusOK)
3762                     return status;
3763             }
3764             else
3765             {
3766                 XVisualInfo *pVisual_info = GL_ENTRYPOINT(glXGetVisualFromFBConfig)(dpy, fb_config);
3767
3768                 GLXContext replay_context = GL_ENTRYPOINT(glXCreateContext)(dpy, pVisual_info, replay_share_context, direct);
3769
3770                 if (!replay_context)
3771                 {
3772                     if (trace_context)
3773                     {
3774                         process_entrypoint_error("%s: Failed creating new GL context!\n", VOGL_METHOD_NAME);
3775                         return cStatusHardFailure;
3776                     }
3777                     else
3778                     {
3779                         process_entrypoint_warning("%s: Successfully created a new GL context where the traced app failed!\n", VOGL_METHOD_NAME);
3780                     }
3781                 }
3782
3783                 if (replay_context)
3784                 {
3785                     if (trace_context)
3786                     {
3787                         context_state *pContext_state = define_new_context(trace_context, replay_context, trace_share_context, direct, VOGL_ENTRYPOINT_glXCreateContext, NULL, 0);
3788                         VOGL_NOTE_UNUSED(pContext_state);
3789                     }
3790                     else
3791                     {
3792                         GL_ENTRYPOINT(glXDestroyContext)(m_pWindow->get_display(), replay_context);
3793                     }
3794                 }
3795             }
3796
3797             break;
3798         }
3799         case VOGL_ENTRYPOINT_glXCreateContextAttribsARB:
3800         {
3801             Display *dpy = m_pWindow->get_display();
3802             GLXFBConfig fb_config = m_pWindow->get_fb_configs()[0];
3803
3804             vogl_trace_ptr_value trace_share_context = trace_packet.get_param_ptr_value(2);
3805             GLXContext replay_share_context = remap_context(trace_share_context);
3806
3807             if ((trace_share_context) && (!replay_share_context))
3808             {
3809                 process_entrypoint_warning("%s: Failed remapping trace sharelist context 0x%" PRIx64 "!\n", VOGL_METHOD_NAME, cast_val_to_uint64(trace_share_context));
3810             }
3811
3812             Bool direct = trace_packet.get_param_value<Bool>(3);
3813             const int *pTrace_attrib_list = static_cast<const int *>(trace_packet.get_param_client_memory_ptr(4));
3814             const uint trace_attrib_list_size = trace_packet.get_param_client_memory_data_size(4) / sizeof(int);
3815
3816             vogl_trace_ptr_value trace_context = trace_packet.get_return_ptr_value();
3817
3818             status = create_context_attribs(trace_context, dpy, fb_config, trace_share_context, replay_share_context, direct, pTrace_attrib_list, trace_attrib_list_size, true);
3819             if (status != cStatusOK)
3820                 return status;
3821
3822             break;
3823         }
3824         case VOGL_ENTRYPOINT_glXSwapBuffers:
3825         {
3826             check_program_binding_shadow();
3827
3828             if (m_flags & cGLReplayerLowLevelDebugMode)
3829             {
3830                 if (!validate_program_and_shader_handle_tables())
3831                     vogl_warning_printf("%s: Failed validating program/shaders against handle mapping tables\n", VOGL_METHOD_NAME);
3832                 if (!validate_textures())
3833                     vogl_warning_printf("%s: Failed validating texture handles against handle mapping tables\n", VOGL_METHOD_NAME);
3834             }
3835
3836             const Display *dpy = m_pWindow->get_display();
3837             GLXDrawable drawable = m_pWindow->get_xwindow();
3838
3839             if ((m_flags & cGLReplayerHashBackbuffer) || (m_flags & cGLReplayerDumpScreenshots) || (m_flags & cGLReplayerDumpBackbufferHashes))
3840             {
3841                 snapshot_backbuffer();
3842             }
3843
3844             if (m_dump_frontbuffer_filename.has_content())
3845             {
3846                 dump_frontbuffer_to_file(m_dump_frontbuffer_filename);
3847                 m_dump_frontbuffer_filename.clear();
3848             }
3849
3850             GL_ENTRYPOINT(glXSwapBuffers)(dpy, drawable);
3851
3852             if (m_swap_sleep_time)
3853                 vogl_sleep(m_swap_sleep_time);
3854
3855             status = cStatusNextFrame;
3856
3857             m_at_frame_boundary = true;
3858
3859             if (m_flags & cGLReplayerDebugMode)
3860             {
3861                 vogl_debug_printf("%s: glXSwapBuffers() processed at end of frame %u, swap %u, last GL call counter %" PRIu64 "\n", VOGL_METHOD_NAME, m_frame_index, m_total_swaps, m_last_parsed_call_counter);
3862             }
3863
3864             m_frame_index++;
3865             m_total_swaps++;
3866
3867             m_frame_draw_counter = 0;
3868
3869             int win_width = trace_packet.get_key_value_map().get_int(string_hash("win_width"));
3870             int win_height = trace_packet.get_key_value_map().get_int(string_hash("win_height"));
3871             if ((win_width) && (win_height))
3872             {
3873                 if (!(m_flags & cGLReplayerLockWindowDimensions))
3874                 {
3875                     if ((win_width != m_pWindow->get_width()) || (win_height != m_pWindow->get_height()))
3876                     {
3877                         // TODO: This resize might need to be deferred until the window system actually resizes the window.
3878                         //m_pWindow->resize(win_width, win_height);
3879                         trigger_pending_window_resize(win_width, win_height);
3880
3881                         vogl_printf("%s: Resizing window after swap to %ux%u\n", VOGL_METHOD_NAME, win_width, win_height);
3882                     }
3883                 }
3884             }
3885
3886             break;
3887         }
3888         case VOGL_ENTRYPOINT_glXWaitX:
3889         {
3890             VOGL_REPLAY_LOAD_PARAMS_HELPER_glXWaitX;
3891
3892             VOGL_REPLAY_CALL_GL_HELPER_glXWaitX;
3893
3894             break;
3895         }
3896         case VOGL_ENTRYPOINT_glXWaitGL:
3897         {
3898             VOGL_REPLAY_LOAD_PARAMS_HELPER_glXWaitGL;
3899
3900             VOGL_REPLAY_CALL_GL_HELPER_glXWaitGL;
3901
3902             break;
3903         }
3904         case VOGL_ENTRYPOINT_glXIsDirect:
3905         {
3906             const Display *dpy = m_pWindow->get_display();
3907
3908             vogl_trace_ptr_value trace_context = trace_packet.get_param_ptr_value(1);
3909             GLXContext replay_context = remap_context(trace_context);
3910
3911             Bool replay_is_direct = GL_ENTRYPOINT(glXIsDirect)(dpy, replay_context);
3912             Bool trace_is_direct = trace_packet.get_return_value<Bool>();
3913
3914             if (replay_is_direct != trace_is_direct)
3915             {
3916                 process_entrypoint_warning("%s: glXIsDirect() returned different results while replaying (%u) vs tracing (%u)!\n", VOGL_METHOD_NAME, replay_is_direct, trace_is_direct);
3917             }
3918
3919             break;
3920         }
3921         case VOGL_ENTRYPOINT_glXGetCurrentContext:
3922         {
3923             GLXContext replay_context = GL_ENTRYPOINT(glXGetCurrentContext)();
3924             vogl_trace_ptr_value trace_context = trace_packet.get_return_ptr_value();
3925
3926             if ((replay_context != 0) != (trace_context != 0))
3927             {
3928                 process_entrypoint_warning("%s: glXGetCurrentContext() returned different results while replaying (0x%" PRIX64 ") vs tracing (0x%" PRIX64 ")!\n", VOGL_METHOD_NAME, (uint64_t)replay_context, (uint64_t)trace_context);
3929             }
3930
3931             break;
3932         }
3933         case VOGL_ENTRYPOINT_glXCreateWindow:
3934         case VOGL_ENTRYPOINT_glXDestroyWindow:
3935         case VOGL_ENTRYPOINT_glXChooseVisual:
3936         case VOGL_ENTRYPOINT_glXGetCurrentDisplay:
3937         case VOGL_ENTRYPOINT_glXQueryDrawable:
3938         case VOGL_ENTRYPOINT_glXQueryExtension:
3939         case VOGL_ENTRYPOINT_glXQueryExtensionsString:
3940         case VOGL_ENTRYPOINT_glXSwapIntervalEXT:
3941         case VOGL_ENTRYPOINT_glXSwapIntervalSGI:
3942         case VOGL_ENTRYPOINT_glXGetCurrentDrawable:
3943         case VOGL_ENTRYPOINT_glXGetCurrentReadDrawable:
3944         case VOGL_ENTRYPOINT_glXQueryContext:
3945         case VOGL_ENTRYPOINT_glXGetClientString:
3946         case VOGL_ENTRYPOINT_glXGetConfig:
3947         case VOGL_ENTRYPOINT_glXGetFBConfigs:
3948         {
3949             // TODO
3950             break;
3951         }
3952         default:
3953         {
3954             processed_glx_packet = false;
3955             break;
3956         }
3957     }
3958
3959     if (processed_glx_packet)
3960     {
3961         // TODO: Check for GLX errors?
3962         return status;
3963     }
3964
3965     if (!m_cur_replay_context)
3966     {
3967         process_entrypoint_error("%s: Trace contains a GL call with no current context! Skipping call.\n", VOGL_METHOD_NAME);
3968         return cStatusSoftFailure;
3969     }
3970
3971     VOGL_ASSERT(m_pCur_context_state);
3972     m_pCur_context_state->m_last_call_counter = m_last_parsed_call_counter;
3973
3974 #ifdef VOGL_BUILD_DEBUG
3975     VOGL_ASSERT(get_trace_context_state(m_cur_trace_context) == m_pCur_context_state);
3976 #endif
3977
3978     // Add call to current display list
3979     if ((get_context_state()->is_composing_display_list()) && (g_vogl_entrypoint_descs[entrypoint_id].m_is_listable))
3980     {
3981         if (!vogl_display_list_state::is_call_listable(entrypoint_id, trace_packet))
3982         {
3983             if (!g_vogl_entrypoint_descs[entrypoint_id].m_whitelisted_for_displaylists)
3984                 process_entrypoint_error("%s: Failed serializing trace packet into display list shadow! Call is not listable.\n", VOGL_FUNCTION_NAME);
3985             else
3986                 process_entrypoint_warning("%s: Failed serializing trace packet into display list shadow! Call with these parameters is not listable.\n", VOGL_FUNCTION_NAME);
3987         }
3988         else
3989         {
3990             if (!get_shared_state()->m_shadow_state.m_display_lists.add_packet_to_list(get_context_state()->m_current_display_list_handle, entrypoint_id, trace_packet))
3991             {
3992                 process_entrypoint_warning("%s: Failed adding current packet to display list shadow!\n", VOGL_METHOD_NAME);
3993             }
3994         }
3995     }
3996
3997     switch (entrypoint_id)
3998     {
3999 // ----- Create simple auto-generated replay funcs - voglgen creates this inc file from the funcs in gl_glx_simple_replay_funcs.txt
4000 // These simple GL entrypoints only take value params that don't require handle remapping, or simple pointers to client memory
4001 // (typically pointers to fixed size buffers, or params directly controlling the size of buffers).
4002 #define VOGL_SIMPLE_REPLAY_FUNC_BEGIN(name, num_params) \
4003     case VOGL_ENTRYPOINT_##name:                        \
4004     { GL_ENTRYPOINT(name)(
4005 #define VOGL_SIMPLE_REPLAY_FUNC_PARAM_VALUE(type, index) trace_packet.get_param_value<type>(index)
4006 #define VOGL_SIMPLE_REPLAY_FUNC_PARAM_SEPERATOR ,
4007 #define VOGL_SIMPLE_REPLAY_FUNC_PARAM_CLIENT_MEMORY(type, index) trace_packet.get_param_client_memory<type>(index)
4008 #define VOGL_SIMPLE_REPLAY_FUNC_END(name) ); \
4009     break;                                  \
4010     }
4011 #include "gl_glx_simple_replay_funcs.inc"
4012 #undef VOGL_SIMPLE_REPLAY_FUNC_BEGIN
4013 #undef VOGL_SIMPLE_REPLAY_FUNC_PARAM_VALUE
4014 #undef VOGL_SIMPLE_REPLAY_FUNC_PARAM_SEPERATOR
4015 #undef VOGL_SIMPLE_REPLAY_FUNC_PARAM_CLIENT_MEMORY
4016 #undef VOGL_SIMPLE_REPLAY_FUNC_PARAM_END
4017         // -----
4018         case VOGL_ENTRYPOINT_glXUseXFont:
4019         {
4020             const key_value_map &key_value_map = trace_packet.get_key_value_map();
4021
4022             const dynamic_string *pFont_name = key_value_map.get_string_ptr("font_name");
4023             if ((!pFont_name) || (pFont_name->is_empty()))
4024             {
4025                 process_entrypoint_warning("%s: Couldn't find font_name key, or key was empty - unable to call glXUseXFont()!\n", VOGL_METHOD_NAME);
4026             }
4027             else
4028             {
4029                 XFontStruct *pFont = XLoadQueryFont(m_pWindow->get_display(), pFont_name->get_ptr());
4030                 if (!pFont)
4031                 {
4032                     process_entrypoint_warning("%s: Couldn't load X font %s  - unable to call glXUseXFont()!\n", VOGL_METHOD_NAME, pFont_name->get_ptr());
4033                 }
4034                 else
4035                 {
4036                     GLint first = trace_packet.get_param_value<int>(1);
4037                     GLint count = trace_packet.get_param_value<int>(2);
4038                     int trace_list_base = trace_packet.get_param_value<int>(3);
4039                     GLuint replay_list_base = map_handle(get_shared_state()->m_lists, trace_list_base);
4040
4041                     GL_ENTRYPOINT(glXUseXFont)(pFont->fid, first, count, replay_list_base);
4042
4043                     XFreeFont(m_pWindow->get_display(), pFont);
4044
4045                     if (get_context_state()->is_composing_display_list())
4046                     {
4047                         process_entrypoint_warning("%s: glXUseXFont() called while composing a display list!\n", VOGL_METHOD_NAME);
4048                     }
4049                     else
4050                     {
4051                         if (!get_shared_state()->m_shadow_state.m_display_lists.glx_font(pFont_name->get_ptr(), first, count, trace_list_base))
4052                         {
4053                             process_entrypoint_warning("%s: Failed updating display list shadow\n", VOGL_METHOD_NAME);
4054                         }
4055                     }
4056                 }
4057             }
4058
4059             break;
4060         }
4061         case VOGL_ENTRYPOINT_glBlitFramebufferEXT:
4062         {
4063             VOGL_REPLAY_LOAD_PARAMS_HELPER_glBlitFramebufferEXT;
4064
4065             VOGL_REPLAY_CALL_GL_HELPER_glBlitFramebufferEXT;
4066
4067             if ((status = post_draw_call()) != cStatusOK)
4068                 return status;
4069
4070             break;
4071         }
4072         case VOGL_ENTRYPOINT_glBlitFramebuffer:
4073         {
4074             VOGL_REPLAY_LOAD_PARAMS_HELPER_glBlitFramebuffer;
4075
4076             VOGL_REPLAY_CALL_GL_HELPER_glBlitFramebuffer;
4077
4078             if ((status = post_draw_call()) != cStatusOK)
4079                 return status;
4080
4081             break;
4082         }
4083         case VOGL_ENTRYPOINT_glBegin:
4084         {
4085             if (m_pCur_context_state->m_inside_gl_begin)
4086             {
4087                 process_entrypoint_warning("%s: Got a glBegin while already inside a glBegin\n", VOGL_METHOD_NAME);
4088             }
4089             m_pCur_context_state->m_inside_gl_begin = true;
4090
4091             g_vogl_actual_gl_entrypoints.m_glBegin(trace_packet.get_param_value<GLenum>(0));
4092
4093             break;
4094         }
4095         case VOGL_ENTRYPOINT_glEnd:
4096         {
4097             if (!m_pCur_context_state->m_inside_gl_begin)
4098             {
4099                 process_entrypoint_warning("%s: Got glEnd without a matching glBegin\n", VOGL_METHOD_NAME);
4100             }
4101             m_pCur_context_state->m_inside_gl_begin = false;
4102
4103             g_vogl_actual_gl_entrypoints.m_glEnd();
4104
4105             if ((status = post_draw_call()) != cStatusOK)
4106                 return status;
4107
4108             break;
4109         }
4110         case VOGL_ENTRYPOINT_glGetError:
4111         {
4112             // TODO: Compare trace error vs. replay error
4113
4114             break;
4115         }
4116         case VOGL_ENTRYPOINT_glGetStringi:
4117         {
4118             if (!benchmark_mode())
4119             {
4120                 const GLubyte *pStr = GL_ENTRYPOINT(glGetStringi)(
4121                     trace_packet.get_param_value<GLenum>(0),
4122                     trace_packet.get_param_value<GLuint>(1));
4123                 VOGL_NOTE_UNUSED(pStr);
4124
4125                 // TODO: Compare vs. trace's?
4126             }
4127
4128             break;
4129         }
4130         case VOGL_ENTRYPOINT_glGetString:
4131         {
4132             if (!benchmark_mode())
4133             {
4134                 const GLubyte *pStr = GL_ENTRYPOINT(glGetString)(
4135                     trace_packet.get_param_value<GLenum>(0));
4136                 VOGL_NOTE_UNUSED(pStr);
4137
4138                 // TODO: Compare vs. trace's?
4139             }
4140
4141             break;
4142         }
4143         case VOGL_ENTRYPOINT_glGenFramebuffers:
4144         case VOGL_ENTRYPOINT_glGenFramebuffersEXT:
4145         {
4146             if (!gen_handles(get_context_state()->m_framebuffers,
4147                              trace_packet.get_param_value<GLsizei>(0),
4148                              static_cast<const GLuint *>(trace_packet.get_param_client_memory_ptr(1)),
4149                              (entrypoint_id == VOGL_ENTRYPOINT_glGenFramebuffers) ? GL_ENTRYPOINT(glGenFramebuffers) : GL_ENTRYPOINT(glGenFramebuffersEXT), NULL))
4150                 return cStatusHardFailure;
4151
4152             break;
4153         }
4154         case VOGL_ENTRYPOINT_glBindFramebuffer:
4155         case VOGL_ENTRYPOINT_glBindFramebufferEXT:
4156         {
4157             GLenum target = trace_packet.get_param_value<GLenum>(0);
4158             GLuint trace_handle = trace_packet.get_param_value<GLuint>(1);
4159
4160             GLuint replay_handle = map_handle(get_context_state()->m_framebuffers, trace_handle);
4161
4162             SWITCH_GL_ENTRYPOINT2_VOID(glBindFramebuffer, glBindFramebufferEXT, target, replay_handle);
4163
4164             break;
4165         }
4166         case VOGL_ENTRYPOINT_glGetRenderbufferParameterivEXT:
4167         case VOGL_ENTRYPOINT_glGetRenderbufferParameteriv:
4168         {
4169             if (!benchmark_mode())
4170             {
4171                 GLenum target = trace_packet.get_param_value<GLenum>(0);
4172                 GLenum pname = trace_packet.get_param_value<GLenum>(1);
4173                 GLint *pTrace_params = trace_packet.get_param_client_memory<GLint>(2);
4174                 uint trace_params_size = trace_packet.get_param_client_memory_data_size(2);
4175                 uint trace_params_count = trace_params_size / sizeof(GLint);
4176
4177                 int n = g_gl_enums.get_pname_count(pname);
4178                 if (n <= 0)
4179                 {
4180                     process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
4181                     return cStatusSoftFailure;
4182                 }
4183                 else if (n < static_cast<int>(trace_params_count))
4184                 {
4185                     process_entrypoint_error("%s: Expected %i GLint's for GL pname 0x%08X, but trace only contains %i GLint's\n", VOGL_METHOD_NAME, n, pname, trace_params_count);
4186                     return cStatusSoftFailure;
4187                 }
4188                 else
4189                 {
4190                     vogl::growable_array<GLint, 16> params(n + 1);
4191                     params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC;
4192
4193                     SWITCH_GL_ENTRYPOINT2_VOID(glGetRenderbufferParameteriv, glGetRenderbufferParameterivEXT, target, pname, params.get_ptr());
4194
4195                     VOGL_VERIFY(params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC);
4196
4197                     if (memcmp(pTrace_params, params.get_ptr(), n * sizeof(GLint)) != 0)
4198                     {
4199                         process_entrypoint_warning("%s: Replay's returned GLint data differed from trace's, pname %s target %s\n", VOGL_METHOD_NAME, g_gl_enums.find_gl_name(pname), g_gl_enums.find_gl_name(target));
4200                     }
4201                 }
4202             }
4203
4204             break;
4205         }
4206         case VOGL_ENTRYPOINT_glCheckFramebufferStatus:
4207         case VOGL_ENTRYPOINT_glCheckFramebufferStatusEXT:
4208         {
4209             GLenum result;
4210             SWITCH_GL_ENTRYPOINT2(glCheckFramebufferStatus, glCheckFramebufferStatusEXT, trace_packet.get_param_value<GLenum>(0));
4211
4212             GLenum trace_status = trace_packet.get_return_value<GLenum>();
4213             if (result != trace_status)
4214             {
4215                 process_entrypoint_warning("%s: glCheckFramebufferStatus returned status 0x%08X during trace, but status 0x%08X during replay\n", VOGL_METHOD_NAME, trace_status, result);
4216             }
4217             break;
4218         }
4219         case VOGL_ENTRYPOINT_glDeleteFramebuffers:
4220         {
4221             delete_handles(get_context_state()->m_framebuffers, trace_packet.get_param_value<GLsizei>(0), static_cast<const GLuint *>(trace_packet.get_param_client_memory_ptr(1)), GL_ENTRYPOINT(glDeleteFramebuffers));
4222             break;
4223         }
4224         case VOGL_ENTRYPOINT_glDeleteFramebuffersEXT:
4225         {
4226             delete_handles(get_context_state()->m_framebuffers, trace_packet.get_param_value<GLsizei>(0), static_cast<const GLuint *>(trace_packet.get_param_client_memory_ptr(1)), GL_ENTRYPOINT(glDeleteFramebuffersEXT));
4227             break;
4228         }
4229         case VOGL_ENTRYPOINT_glFramebufferTexture:
4230         {
4231             GLenum target = trace_packet.get_param_value<GLenum>(0);
4232             GLenum attachment = trace_packet.get_param_value<GLenum>(1);
4233             GLuint trace_texture = trace_packet.get_param_value<GLuint>(2);
4234             GLuint replay_texture = trace_texture;
4235             GLint level = trace_packet.get_param_value<GLint>(3);
4236
4237             if (!get_shared_state()->m_shadow_state.m_textures.map_handle_to_inv_handle(trace_texture, replay_texture))
4238             {
4239                 if (trace_texture)
4240                     process_entrypoint_warning("%s: Couldn't map trace texture ID %u to GL texture ID, using trace texture ID instead\n", VOGL_METHOD_NAME, trace_texture);
4241             }
4242
4243             GL_ENTRYPOINT(glFramebufferTexture)(target, attachment, replay_texture, level);
4244
4245             break;
4246         }
4247         case VOGL_ENTRYPOINT_glFramebufferTextureLayer:
4248         case VOGL_ENTRYPOINT_glFramebufferTextureLayerEXT:
4249         {
4250             GLenum target = trace_packet.get_param_value<GLenum>(0);
4251             GLenum attachment = trace_packet.get_param_value<GLenum>(1);
4252             GLuint trace_texture = trace_packet.get_param_value<GLuint>(2);
4253             GLuint replay_texture = trace_texture;
4254             GLint level = trace_packet.get_param_value<GLint>(3);
4255             GLint layer = trace_packet.get_param_value<GLint>(4);
4256
4257             if (!get_shared_state()->m_shadow_state.m_textures.map_handle_to_inv_handle(trace_texture, replay_texture))
4258             {
4259                 if (trace_texture)
4260                     process_entrypoint_warning("%s: Couldn't map trace texture ID %u to GL texture ID, using trace texture ID instead\n", VOGL_METHOD_NAME, trace_texture);
4261             }
4262
4263             SWITCH_GL_ENTRYPOINT2_VOID(glFramebufferTextureLayer, glFramebufferTextureLayerEXT, target, attachment, replay_texture, level, layer);
4264
4265             break;
4266         }
4267         case VOGL_ENTRYPOINT_glFramebufferTexture1DEXT:
4268         case VOGL_ENTRYPOINT_glFramebufferTexture1D:
4269         case VOGL_ENTRYPOINT_glFramebufferTexture2DEXT:
4270         case VOGL_ENTRYPOINT_glFramebufferTexture2D:
4271         case VOGL_ENTRYPOINT_glFramebufferTexture3DEXT:
4272         case VOGL_ENTRYPOINT_glFramebufferTexture3D:
4273         {
4274             GLenum target = trace_packet.get_param_value<GLenum>(0);
4275             GLenum attachment = trace_packet.get_param_value<GLenum>(1);
4276             GLenum textarget = trace_packet.get_param_value<GLenum>(2);
4277             GLuint trace_texture = trace_packet.get_param_value<GLuint>(3);
4278             GLuint replay_texture = trace_texture;
4279             GLint level = trace_packet.get_param_value<GLint>(4);
4280
4281             if (!get_shared_state()->m_shadow_state.m_textures.map_handle_to_inv_handle(trace_texture, replay_texture))
4282             {
4283                 if (trace_texture)
4284                     process_entrypoint_warning("%s: Couldn't map trace texture ID %u to GL texture ID, using trace texture ID instead\n", VOGL_METHOD_NAME, trace_texture);
4285             }
4286
4287             switch (entrypoint_id)
4288             {
4289                 case VOGL_ENTRYPOINT_glFramebufferTexture1DEXT:
4290                     GL_ENTRYPOINT(glFramebufferTexture1DEXT)(target, attachment, textarget, replay_texture, level);
4291                     break;
4292                 case VOGL_ENTRYPOINT_glFramebufferTexture1D:
4293                     GL_ENTRYPOINT(glFramebufferTexture1D)(target, attachment, textarget, replay_texture, level);
4294                     break;
4295                 case VOGL_ENTRYPOINT_glFramebufferTexture2DEXT:
4296                     GL_ENTRYPOINT(glFramebufferTexture2DEXT)(target, attachment, textarget, replay_texture, level);
4297                     break;
4298                 case VOGL_ENTRYPOINT_glFramebufferTexture2D:
4299                     GL_ENTRYPOINT(glFramebufferTexture2D)(target, attachment, textarget, replay_texture, level);
4300                     break;
4301                 case VOGL_ENTRYPOINT_glFramebufferTexture3DEXT:
4302                     GL_ENTRYPOINT(glFramebufferTexture3DEXT)(target, attachment, textarget, replay_texture, level, trace_packet.get_param_value<GLint>(5));
4303                     break;
4304                 case VOGL_ENTRYPOINT_glFramebufferTexture3D:
4305                     GL_ENTRYPOINT(glFramebufferTexture3D)(target, attachment, textarget, replay_texture, level, trace_packet.get_param_value<GLint>(5));
4306                     break;
4307                 default:
4308                     break;
4309             }
4310
4311             break;
4312         }
4313         case VOGL_ENTRYPOINT_glGenTextures:
4314         {
4315             if (!gen_handles(get_shared_state()->m_shadow_state.m_textures, trace_packet.get_param_value<GLsizei>(0), static_cast<const GLuint *>(trace_packet.get_param_client_memory_ptr(1)), GL_ENTRYPOINT(glGenTextures), NULL, GL_NONE))
4316                 return cStatusHardFailure;
4317             break;
4318         }
4319         case VOGL_ENTRYPOINT_glGenTexturesEXT:
4320         {
4321             if (!gen_handles(get_shared_state()->m_shadow_state.m_textures, trace_packet.get_param_value<GLsizei>(0), static_cast<const GLuint *>(trace_packet.get_param_client_memory_ptr(1)), GL_ENTRYPOINT(glGenTexturesEXT), NULL, GL_NONE))
4322                 return cStatusHardFailure;
4323             break;
4324         }
4325         case VOGL_ENTRYPOINT_glDeleteTextures:
4326         {
4327             delete_handles(get_shared_state()->m_shadow_state.m_textures, trace_packet.get_param_value<GLsizei>(0), static_cast<const GLuint *>(trace_packet.get_param_client_memory_ptr(1)), GL_ENTRYPOINT(glDeleteTextures));
4328             break;
4329         }
4330         case VOGL_ENTRYPOINT_glDeleteTexturesEXT:
4331         {
4332             delete_handles(get_shared_state()->m_shadow_state.m_textures, trace_packet.get_param_value<GLsizei>(0), static_cast<const GLuint *>(trace_packet.get_param_client_memory_ptr(1)), GL_ENTRYPOINT(glDeleteTexturesEXT));
4333             break;
4334         }
4335         case VOGL_ENTRYPOINT_glBindMultiTextureEXT:
4336         {
4337             VOGL_REPLAY_LOAD_PARAMS_HELPER_glBindMultiTextureEXT;
4338
4339             GLuint trace_texture = texture;
4340             map_handle(get_shared_state()->m_shadow_state.m_textures, trace_texture, texture);
4341
4342             if ((texture) && (get_context_state()->m_current_display_list_mode != GL_COMPILE))
4343                 check_gl_error();
4344
4345             VOGL_REPLAY_CALL_GL_HELPER_glBindMultiTextureEXT;
4346
4347             if ((texture) && (get_context_state()->m_current_display_list_mode != GL_COMPILE))
4348             {
4349                 if (!check_gl_error())
4350                     get_shared_state()->m_shadow_state.m_textures.update(trace_texture, texture, target);
4351             }
4352
4353             break;
4354         }
4355         case VOGL_ENTRYPOINT_glBindTexture:
4356         case VOGL_ENTRYPOINT_glBindTextureEXT:
4357         {
4358             VOGL_REPLAY_LOAD_PARAMS_HELPER_glBindTexture;
4359
4360             GLuint trace_texture = texture;
4361             map_handle(get_shared_state()->m_shadow_state.m_textures, trace_texture, texture);
4362
4363             if ((texture) && (get_context_state()->m_current_display_list_mode != GL_COMPILE))
4364                 check_gl_error();
4365
4366             SWITCH_GL_ENTRYPOINT2_VOID(glBindTexture, glBindTextureEXT, target, texture);
4367
4368             if ((texture) && (get_context_state()->m_current_display_list_mode != GL_COMPILE))
4369             {
4370                 if (!check_gl_error())
4371                     get_shared_state()->m_shadow_state.m_textures.update(trace_texture, texture, target);
4372             }
4373
4374             break;
4375         }
4376         case VOGL_ENTRYPOINT_glBindSampler:
4377         {
4378             GLuint replay_handle = map_handle(get_shared_state()->m_sampler_objects, trace_packet.get_param_value<GLuint>(1));
4379             GL_ENTRYPOINT(glBindSampler)(trace_packet.get_param_value<GLuint>(0), replay_handle);
4380             break;
4381         }
4382         case VOGL_ENTRYPOINT_glDeleteSamplers:
4383         {
4384             delete_handles(get_shared_state()->m_sampler_objects, trace_packet.get_param_value<GLsizei>(0), static_cast<const GLuint *>(trace_packet.get_param_client_memory_ptr(1)), GL_ENTRYPOINT(glDeleteSamplers));
4385             break;
4386         }
4387         case VOGL_ENTRYPOINT_glGenSamplers:
4388         {
4389             if (!gen_handles(get_shared_state()->m_sampler_objects, trace_packet.get_param_value<GLsizei>(0), static_cast<const GLuint *>(trace_packet.get_param_client_memory_ptr(1)), GL_ENTRYPOINT(glGenSamplers), NULL))
4390                 return cStatusHardFailure;
4391             break;
4392         }
4393
4394         case VOGL_ENTRYPOINT_glSamplerParameterf:
4395         {
4396             VOGL_REPLAY_LOAD_PARAMS_HELPER_glSamplerParameterf;
4397             sampler = map_handle(get_shared_state()->m_sampler_objects, sampler);
4398             VOGL_REPLAY_CALL_GL_HELPER_glSamplerParameterf;
4399             break;
4400         }
4401         case VOGL_ENTRYPOINT_glSamplerParameteri:
4402         {
4403             VOGL_REPLAY_LOAD_PARAMS_HELPER_glSamplerParameteri;
4404             sampler = map_handle(get_shared_state()->m_sampler_objects, sampler);
4405             VOGL_REPLAY_CALL_GL_HELPER_glSamplerParameteri;
4406             break;
4407         }
4408         case VOGL_ENTRYPOINT_glSamplerParameterfv:
4409         {
4410             VOGL_REPLAY_LOAD_PARAMS_HELPER_glSamplerParameterfv;
4411             sampler = map_handle(get_shared_state()->m_sampler_objects, sampler);
4412             VOGL_REPLAY_CALL_GL_HELPER_glSamplerParameterfv;
4413             break;
4414         }
4415         case VOGL_ENTRYPOINT_glSamplerParameteriv:
4416         {
4417             VOGL_REPLAY_LOAD_PARAMS_HELPER_glSamplerParameteriv;
4418             sampler = map_handle(get_shared_state()->m_sampler_objects, sampler);
4419             VOGL_REPLAY_CALL_GL_HELPER_glSamplerParameteriv;
4420             break;
4421         }
4422         case VOGL_ENTRYPOINT_glSamplerParameterIiv:
4423         {
4424             VOGL_REPLAY_LOAD_PARAMS_HELPER_glSamplerParameterIiv;
4425             sampler = map_handle(get_shared_state()->m_sampler_objects, sampler);
4426             VOGL_REPLAY_CALL_GL_HELPER_glSamplerParameterIiv;
4427             break;
4428         }
4429         case VOGL_ENTRYPOINT_glSamplerParameterIuiv:
4430         {
4431             VOGL_REPLAY_LOAD_PARAMS_HELPER_glSamplerParameterIuiv;
4432             sampler = map_handle(get_shared_state()->m_sampler_objects, sampler);
4433             VOGL_REPLAY_CALL_GL_HELPER_glSamplerParameterIuiv;
4434             break;
4435         }
4436         case VOGL_ENTRYPOINT_glGenBuffers:
4437         case VOGL_ENTRYPOINT_glGenBuffersARB:
4438         {
4439             uint n = trace_packet.get_param_value<GLsizei>(0);
4440             const GLuint *pTrace_handles = static_cast<const GLuint *>(trace_packet.get_param_client_memory_ptr(1));
4441
4442             if (entrypoint_id == VOGL_ENTRYPOINT_glGenBuffers)
4443             {
4444                 if (!gen_handles(get_shared_state()->m_buffers, n, pTrace_handles, GL_ENTRYPOINT(glGenBuffers), NULL))
4445                     return cStatusHardFailure;
4446             }
4447             else
4448             {
4449                 if (!gen_handles(get_shared_state()->m_buffers, n, pTrace_handles, GL_ENTRYPOINT(glGenBuffersARB), NULL))
4450                     return cStatusHardFailure;
4451             }
4452
4453             if (pTrace_handles)
4454             {
4455                 for (uint i = 0; i < n; i++)
4456                 {
4457                     if (pTrace_handles[i])
4458                         get_shared_state()->m_buffer_targets.insert(pTrace_handles[i], GL_NONE);
4459                 }
4460             }
4461
4462             break;
4463         }
4464         case VOGL_ENTRYPOINT_glDeleteBuffers:
4465         case VOGL_ENTRYPOINT_glDeleteBuffersARB:
4466         {
4467             GLsizei trace_n = trace_packet.get_param_value<GLsizei>(0);
4468             const GLuint *pTrace_ids = static_cast<const GLuint *>(trace_packet.get_param_client_memory_ptr(1));
4469             uint trace_ids_count = trace_packet.get_param_client_memory_data_size(1);
4470
4471             if ((pTrace_ids) && (static_cast<GLsizei>(trace_ids_count) < trace_n))
4472             {
4473                 process_entrypoint_warning("%s: trace_ids trace array is too small\n", VOGL_METHOD_NAME);
4474                 return cStatusHardFailure;
4475             }
4476
4477             for (GLsizei iter = 0; iter < trace_n; iter++)
4478             {
4479                 GLuint trace_id = pTrace_ids[iter];
4480                 if (!trace_id)
4481                     continue;
4482
4483                 if (!get_shared_state()->m_buffer_targets.erase(trace_id))
4484                 {
4485                     process_entrypoint_warning("%s: Couldn't find trace buffer id %u in buffer target map!\n", VOGL_METHOD_NAME, trace_id);
4486                 }
4487
4488                 gl_handle_hash_map::const_iterator it = get_shared_state()->m_buffers.find(trace_id);
4489                 if (it == get_shared_state()->m_buffers.end())
4490                 {
4491                     process_entrypoint_warning("%s: Couldn't map trace buffer id %u to GL buffer id\n", VOGL_METHOD_NAME, trace_id);
4492                     continue;
4493                 }
4494
4495                 GLuint replay_id = it->second;
4496
4497                 for (uint i = 0; i < get_shared_state()->m_mapped_buffers.size(); i++)
4498                 {
4499                     if (get_shared_state()->m_mapped_buffers[i].m_buffer == replay_id)
4500                     {
4501                         process_entrypoint_warning("%s: glDeleteBuffers() called on mapped trace buffer %u GL buffer %u\n", VOGL_METHOD_NAME, trace_id, replay_id);
4502
4503                         get_shared_state()->m_mapped_buffers.erase_unordered(i);
4504                         break;
4505                     }
4506                 }
4507             }
4508
4509             if (entrypoint_id == VOGL_ENTRYPOINT_glDeleteBuffers)
4510                 delete_handles(get_shared_state()->m_buffers, trace_n, pTrace_ids, GL_ENTRYPOINT(glDeleteBuffers));
4511             else
4512                 delete_handles(get_shared_state()->m_buffers, trace_n, pTrace_ids, GL_ENTRYPOINT(glDeleteBuffersARB));
4513
4514             break;
4515         }
4516         case VOGL_ENTRYPOINT_glGenProgramsARB:
4517         {
4518             // arb program objects
4519             VOGL_REPLAY_LOAD_PARAMS_HELPER_glGenProgramsARB;
4520
4521             if (!gen_handles(get_shared_state()->m_arb_programs, n, pTrace_programs, GL_ENTRYPOINT(glGenProgramsARB), NULL))
4522                 return cStatusHardFailure;
4523
4524             for (GLsizei i = 0; (pTrace_programs) && (i < n); i++)
4525                 if (pTrace_programs[i])
4526                     get_shared_state()->m_arb_program_targets.insert(pTrace_programs[i], GL_NONE);
4527
4528             break;
4529         }
4530         case VOGL_ENTRYPOINT_glDeleteProgramsARB:
4531         {
4532             // arb program objects
4533             VOGL_REPLAY_LOAD_PARAMS_HELPER_glDeleteProgramsARB;
4534
4535             for (GLsizei i = 0; (pTrace_programs) && (i < n); i++)
4536                 get_shared_state()->m_arb_program_targets.erase(pTrace_programs[i]);
4537
4538             delete_handles(get_shared_state()->m_arb_programs, n, pTrace_programs, GL_ENTRYPOINT(glDeleteProgramsARB));
4539             break;
4540         }
4541         case VOGL_ENTRYPOINT_glBindProgramARB:
4542         {
4543             // arb program objects
4544             VOGL_REPLAY_LOAD_PARAMS_HELPER_glBindProgramARB;
4545
4546             GLuint trace_program = program;
4547             gl_handle_hash_map::const_iterator it;
4548             if (program)
4549             {
4550                 it = get_shared_state()->m_arb_programs.find(program);
4551                 if (it != get_shared_state()->m_arb_programs.end())
4552                     program = it->second;
4553                 else
4554                     process_entrypoint_warning("%s: Couldn't map trace handle %u to GL handle, using trace handle instead (handle may not have been genned)\n", VOGL_METHOD_NAME, program);
4555             }
4556
4557             check_gl_error();
4558
4559             VOGL_REPLAY_CALL_GL_HELPER_glBindProgramARB;
4560
4561             if (!check_gl_error() && (get_context_state()->m_current_display_list_mode != GL_COMPILE))
4562             {
4563                 if (trace_program)
4564                 {
4565                     if (it == get_shared_state()->m_arb_programs.end())
4566                         get_shared_state()->m_arb_programs.insert(trace_program, program);
4567
4568                     get_shared_state()->m_arb_program_targets[trace_program] = target;
4569                 }
4570             }
4571             else
4572             {
4573                 process_entrypoint_warning("%s: GL error while binding ARB program, trace handle %u GL handle %u target %s\n", VOGL_METHOD_NAME, trace_program, program, g_gl_enums.find_gl_name(target));
4574                 return cStatusGLError;
4575             }
4576
4577             break;
4578         }
4579         case VOGL_ENTRYPOINT_glIsProgramARB:
4580         {
4581             if (!benchmark_mode())
4582             {
4583                 VOGL_REPLAY_LOAD_PARAMS_HELPER_glIsProgramARB;
4584
4585                 GLuint trace_program = program;
4586                 program = map_handle(get_shared_state()->m_arb_programs, program);
4587
4588                 GLboolean replay_result = VOGL_REPLAY_CALL_GL_HELPER_glIsProgramARB;
4589                 GLboolean trace_result = trace_packet.get_return_value<GLboolean>();
4590
4591                 if (trace_result != replay_result)
4592                     process_entrypoint_error("%s: Replay's returned GLboolean differed from trace's! Replay: %u Trace: %u, trace ARB program: %u replay ARB program %u\n", VOGL_METHOD_NAME, static_cast<uint>(replay_result), static_cast<uint>(trace_result), trace_program, program);
4593             }
4594
4595             break;
4596         }
4597         case VOGL_ENTRYPOINT_glGenQueries:
4598         case VOGL_ENTRYPOINT_glGenQueriesARB:
4599         {
4600             GLsizei n = trace_packet.get_param_value<GLsizei>(0);
4601             vogl::growable_array<GLuint, 16> replay_handles(n);
4602
4603             if (!gen_handles(get_shared_state()->m_queries, n, static_cast<const GLuint *>(trace_packet.get_param_client_memory_ptr(1)), (entrypoint_id == VOGL_ENTRYPOINT_glGenQueries) ? GL_ENTRYPOINT(glGenQueries) : GL_ENTRYPOINT(glGenQueriesARB), replay_handles.get_ptr()))
4604                 return cStatusHardFailure;
4605
4606             for (GLsizei i = 0; i < n; i++)
4607                 get_shared_state()->m_query_targets[replay_handles[i]] = GL_NONE;
4608
4609             break;
4610         }
4611         case VOGL_ENTRYPOINT_glDeleteQueries:
4612         case VOGL_ENTRYPOINT_glDeleteQueriesARB:
4613         {
4614             GLsizei n = trace_packet.get_param_value<GLsizei>(0);
4615             const GLuint *pTrace_ids = static_cast<const GLuint *>(trace_packet.get_param_client_memory_ptr(1));
4616
4617             if (pTrace_ids)
4618             {
4619                 for (GLsizei i = 0; i < n; i++)
4620                 {
4621                     GLuint trace_id = pTrace_ids[i];
4622                     if (!trace_id)
4623                         continue;
4624                     gl_handle_hash_map::const_iterator it(get_shared_state()->m_queries.find(trace_id));
4625                     if (it != get_shared_state()->m_queries.end())
4626                         get_shared_state()->m_query_targets.erase(it->second);
4627                 }
4628             }
4629
4630             if (entrypoint_id == VOGL_ENTRYPOINT_glDeleteQueries)
4631                 delete_handles(get_shared_state()->m_queries, trace_packet.get_param_value<GLsizei>(0), static_cast<const GLuint *>(trace_packet.get_param_client_memory_ptr(1)), GL_ENTRYPOINT(glDeleteQueries));
4632             else
4633                 delete_handles(get_shared_state()->m_queries, trace_packet.get_param_value<GLsizei>(0), static_cast<const GLuint *>(trace_packet.get_param_client_memory_ptr(1)), GL_ENTRYPOINT(glDeleteQueriesARB));
4634
4635             break;
4636         }
4637         case VOGL_ENTRYPOINT_glGenRenderbuffersEXT:
4638         {
4639             if (!gen_handles(get_shared_state()->m_shadow_state.m_rbos, trace_packet.get_param_value<GLsizei>(0), static_cast<const GLuint *>(trace_packet.get_param_client_memory_ptr(1)), GL_ENTRYPOINT(glGenRenderbuffersEXT), NULL, GL_NONE))
4640                 return cStatusHardFailure;
4641             break;
4642         }
4643         case VOGL_ENTRYPOINT_glGenRenderbuffers:
4644         {
4645             if (!gen_handles(get_shared_state()->m_shadow_state.m_rbos, trace_packet.get_param_value<GLsizei>(0), static_cast<const GLuint *>(trace_packet.get_param_client_memory_ptr(1)), GL_ENTRYPOINT(glGenRenderbuffers), NULL, GL_NONE))
4646                 return cStatusHardFailure;
4647             break;
4648         }
4649         case VOGL_ENTRYPOINT_glDeleteRenderbuffersEXT:
4650         {
4651             delete_handles(get_shared_state()->m_shadow_state.m_rbos, trace_packet.get_param_value<GLsizei>(0), static_cast<const GLuint *>(trace_packet.get_param_client_memory_ptr(1)), GL_ENTRYPOINT(glDeleteRenderbuffersEXT));
4652             break;
4653         }
4654         case VOGL_ENTRYPOINT_glDeleteRenderbuffers:
4655         {
4656             delete_handles(get_shared_state()->m_shadow_state.m_rbos, trace_packet.get_param_value<GLsizei>(0), static_cast<const GLuint *>(trace_packet.get_param_client_memory_ptr(1)), GL_ENTRYPOINT(glDeleteRenderbuffers));
4657             break;
4658         }
4659         case VOGL_ENTRYPOINT_glIsRenderbuffer:
4660         {
4661             if (!benchmark_mode())
4662             {
4663                 GLboolean replay_result = GL_ENTRYPOINT(glIsRenderbuffer)(map_handle(get_shared_state()->m_shadow_state.m_rbos, trace_packet.get_param_value<GLuint>(0)));
4664                 GLboolean trace_result = trace_packet.get_return_value<GLboolean>();
4665                 if (replay_result != trace_result)
4666                 {
4667                     process_entrypoint_warning("%s: Replay's returned GLboolean data differed from trace's (got %i, expected %i)\n", VOGL_METHOD_NAME, replay_result, replay_result);
4668                 }
4669             }
4670             break;
4671         }
4672         case VOGL_ENTRYPOINT_glIsRenderbufferEXT:
4673         {
4674             if (!benchmark_mode())
4675             {
4676                 GLboolean replay_result = GL_ENTRYPOINT(glIsRenderbufferEXT)(map_handle(get_shared_state()->m_shadow_state.m_rbos, trace_packet.get_param_value<GLuint>(0)));
4677                 GLboolean trace_result = trace_packet.get_return_value<GLboolean>();
4678                 if (replay_result != trace_result)
4679                 {
4680                     process_entrypoint_warning("%s: Replay's returned GLboolean data differed from trace's (got %i, expected %i)\n", VOGL_METHOD_NAME, replay_result, replay_result);
4681                 }
4682             }
4683             break;
4684         }
4685         case VOGL_ENTRYPOINT_glBindRenderbufferEXT:
4686         {
4687             GL_ENTRYPOINT(glBindRenderbufferEXT)(trace_packet.get_param_value<GLenum>(0), map_handle(get_shared_state()->m_shadow_state.m_rbos, trace_packet.get_param_value<GLuint>(1)));
4688             break;
4689         }
4690         case VOGL_ENTRYPOINT_glBindRenderbuffer:
4691         {
4692             GL_ENTRYPOINT(glBindRenderbuffer)(trace_packet.get_param_value<GLenum>(0), map_handle(get_shared_state()->m_shadow_state.m_rbos, trace_packet.get_param_value<GLuint>(1)));
4693             break;
4694         }
4695         case VOGL_ENTRYPOINT_glFramebufferRenderbufferEXT:
4696         {
4697             GL_ENTRYPOINT(glFramebufferRenderbufferEXT)(
4698                 trace_packet.get_param_value<GLenum>(0),
4699                 trace_packet.get_param_value<GLenum>(1),
4700                 trace_packet.get_param_value<GLenum>(2),
4701                 map_handle(get_shared_state()->m_shadow_state.m_rbos, trace_packet.get_param_value<GLuint>(3)));
4702             break;
4703         }
4704         case VOGL_ENTRYPOINT_glFramebufferRenderbuffer:
4705         {
4706             GL_ENTRYPOINT(glFramebufferRenderbuffer)(
4707                 trace_packet.get_param_value<GLenum>(0),
4708                 trace_packet.get_param_value<GLenum>(1),
4709                 trace_packet.get_param_value<GLenum>(2),
4710                 map_handle(get_shared_state()->m_shadow_state.m_rbos, trace_packet.get_param_value<GLuint>(3)));
4711             break;
4712         }
4713         case VOGL_ENTRYPOINT_glUseProgramObjectARB:
4714         case VOGL_ENTRYPOINT_glUseProgram:
4715         {
4716             GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
4717             handle_use_program(trace_handle, entrypoint_id);
4718             break;
4719         }
4720         case VOGL_ENTRYPOINT_glProgramParameteri:
4721         case VOGL_ENTRYPOINT_glProgramParameteriARB:
4722         case VOGL_ENTRYPOINT_glProgramParameteriEXT:
4723         {
4724             VOGL_REPLAY_LOAD_PARAMS_HELPER_glProgramParameteri;
4725
4726             program = map_handle(get_shared_state()->m_shadow_state.m_objs, program);
4727
4728             if (entrypoint_id == VOGL_ENTRYPOINT_glProgramParameteriARB)
4729                 VOGL_REPLAY_CALL_GL_HELPER_glProgramParameteriARB;
4730             else if (entrypoint_id == VOGL_ENTRYPOINT_glProgramParameteriEXT)
4731                 VOGL_REPLAY_CALL_GL_HELPER_glProgramParameteriEXT;
4732             else
4733                 VOGL_REPLAY_CALL_GL_HELPER_glProgramParameteri;
4734
4735             break;
4736         }
4737         case VOGL_ENTRYPOINT_glBindFragDataLocation:
4738         case VOGL_ENTRYPOINT_glBindFragDataLocationEXT:
4739         {
4740             VOGL_REPLAY_LOAD_PARAMS_HELPER_glBindFragDataLocation;
4741
4742             program = map_handle(get_shared_state()->m_shadow_state.m_objs, program);
4743
4744             if (entrypoint_id == VOGL_ENTRYPOINT_glBindFragDataLocation)
4745                 VOGL_REPLAY_CALL_GL_HELPER_glBindFragDataLocation;
4746             else
4747                 VOGL_REPLAY_CALL_GL_HELPER_glBindFragDataLocationEXT;
4748
4749             break;
4750         }
4751         case VOGL_ENTRYPOINT_glBindFragDataLocationIndexed:
4752         {
4753             VOGL_REPLAY_LOAD_PARAMS_HELPER_glBindFragDataLocationIndexed;
4754
4755             program = map_handle(get_shared_state()->m_shadow_state.m_objs, program);
4756
4757             VOGL_REPLAY_CALL_GL_HELPER_glBindFragDataLocationIndexed;
4758
4759             break;
4760         }
4761         case VOGL_ENTRYPOINT_glValidateProgramARB:
4762         {
4763             VOGL_REPLAY_LOAD_PARAMS_HELPER_glValidateProgramARB;
4764
4765             programObj = map_handle(get_shared_state()->m_shadow_state.m_objs, programObj);
4766
4767             VOGL_REPLAY_CALL_GL_HELPER_glValidateProgramARB;
4768
4769             break;
4770         }
4771         case VOGL_ENTRYPOINT_glValidateProgram:
4772         {
4773             VOGL_REPLAY_LOAD_PARAMS_HELPER_glValidateProgram;
4774
4775             program = map_handle(get_shared_state()->m_shadow_state.m_objs, program);
4776
4777             VOGL_REPLAY_CALL_GL_HELPER_glValidateProgram;
4778
4779             break;
4780         }
4781         case VOGL_ENTRYPOINT_glCreateProgram:
4782         case VOGL_ENTRYPOINT_glCreateProgramObjectARB:
4783         {
4784             GLuint trace_handle = trace_packet.get_return_value<GLuint>();
4785             if (trace_handle)
4786             {
4787                 GLuint replay_handle;
4788
4789                 if (entrypoint_id == VOGL_ENTRYPOINT_glCreateProgram)
4790                     replay_handle = GL_ENTRYPOINT(glCreateProgram)();
4791                 else
4792                     replay_handle = GL_ENTRYPOINT(glCreateProgramObjectARB)();
4793
4794                 VOGL_ASSERT(!replay_handle || (GL_ENTRYPOINT(glIsProgram)(replay_handle) != 0));
4795
4796                 if (!gen_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle, replay_handle, VOGL_PROGRAM_OBJECT))
4797                     return cStatusHardFailure;
4798             }
4799             break;
4800         }
4801         case VOGL_ENTRYPOINT_glDeleteProgram:
4802         {
4803             GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
4804             handle_delete_program(trace_handle);
4805
4806             break;
4807         }
4808         case VOGL_ENTRYPOINT_glDeleteObjectARB:
4809         {
4810             GLuint trace_handle = trace_packet.get_param_value<GLenum>(0);
4811             GLenum target = get_shared_state()->m_shadow_state.m_objs.get_target(trace_handle);
4812
4813             if (target == VOGL_SHADER_OBJECT)
4814                 handle_delete_shader(trace_handle);
4815             else if (target == VOGL_PROGRAM_OBJECT)
4816                 handle_delete_program(trace_handle);
4817             else
4818             {
4819                 GLuint replay_handle = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle);
4820
4821                 process_entrypoint_error("%s: Failed determining if trace handle %u relay handle %u is a shader or program -- unable to delete object!\n", VOGL_METHOD_NAME, trace_handle, replay_handle);
4822                 return cStatusSoftFailure;
4823             }
4824
4825             break;
4826         }
4827         case VOGL_ENTRYPOINT_glDeleteShader:
4828         {
4829             GLuint trace_shader = trace_packet.get_param_value<GLuint>(0);
4830             handle_delete_shader(trace_shader);
4831
4832             break;
4833         }
4834         case VOGL_ENTRYPOINT_glCreateShader:
4835         case VOGL_ENTRYPOINT_glCreateShaderObjectARB:
4836         {
4837             GLuint trace_handle = trace_packet.get_return_value<GLuint>();
4838             if (trace_handle)
4839             {
4840                 GLuint replay_handle;
4841
4842                 if (entrypoint_id == VOGL_ENTRYPOINT_glCreateShader)
4843                     replay_handle = GL_ENTRYPOINT(glCreateShader)(trace_packet.get_param_value<GLenum>(0));
4844                 else
4845                     replay_handle = GL_ENTRYPOINT(glCreateShaderObjectARB)(trace_packet.get_param_value<GLenum>(0));
4846
4847                 VOGL_ASSERT(!replay_handle || (GL_ENTRYPOINT(glIsShader)(replay_handle) != 0));
4848
4849                 if (!gen_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle, replay_handle, VOGL_SHADER_OBJECT))
4850                     return cStatusHardFailure;
4851             }
4852             break;
4853         }
4854         case VOGL_ENTRYPOINT_glAttachShader:
4855         {
4856             GL_ENTRYPOINT(glAttachShader)(
4857                 map_handle(get_shared_state()->m_shadow_state.m_objs, trace_packet.get_param_value<GLuint>(0)),
4858                 map_handle(get_shared_state()->m_shadow_state.m_objs, trace_packet.get_param_value<GLuint>(1)));
4859             break;
4860         }
4861         case VOGL_ENTRYPOINT_glAttachObjectARB:
4862         {
4863             GL_ENTRYPOINT(glAttachObjectARB)(
4864                 map_handle(get_shared_state()->m_shadow_state.m_objs, trace_packet.get_param_value<GLhandleARB>(0)),
4865                 map_handle(get_shared_state()->m_shadow_state.m_objs, trace_packet.get_param_value<GLhandleARB>(1)));
4866             break;
4867         }
4868         case VOGL_ENTRYPOINT_glDetachShader:
4869         {
4870             handle_detach_shader(entrypoint_id);
4871
4872             break;
4873         }
4874         case VOGL_ENTRYPOINT_glDetachObjectARB:
4875         {
4876             GLhandleARB trace_object_handle = trace_packet.get_param_value<GLhandleARB>(1);
4877
4878             GLenum target = get_shared_state()->m_shadow_state.m_objs.get_target(trace_object_handle);
4879
4880             if (target == VOGL_SHADER_OBJECT)
4881                 handle_detach_shader(entrypoint_id);
4882             else
4883             {
4884                 GLuint replay_object_handle = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_object_handle);
4885                 GL_ENTRYPOINT(glDetachObjectARB)(map_handle(get_shared_state()->m_shadow_state.m_objs, trace_packet.get_param_value<GLhandleARB>(0)), replay_object_handle);
4886             }
4887
4888             break;
4889         }
4890         case VOGL_ENTRYPOINT_glBindAttribLocation:
4891         {
4892             GL_ENTRYPOINT(glBindAttribLocation)(
4893                 map_handle(get_shared_state()->m_shadow_state.m_objs, trace_packet.get_param_value<GLuint>(0)),
4894                 trace_packet.get_param_value<GLuint>(1),
4895                 trace_packet.get_param_client_memory<GLchar>(2));
4896             break;
4897         }
4898         case VOGL_ENTRYPOINT_glBindAttribLocationARB:
4899         {
4900             GL_ENTRYPOINT(glBindAttribLocationARB)(
4901                 map_handle(get_shared_state()->m_shadow_state.m_objs, trace_packet.get_param_value<GLhandleARB>(0)),
4902                 trace_packet.get_param_value<GLuint>(1),
4903                 trace_packet.get_param_client_memory<GLcharARB>(2));
4904             break;
4905         }
4906         case VOGL_ENTRYPOINT_glGetObjectParameterivARB:
4907         {
4908             if (!benchmark_mode())
4909             {
4910                 GLenum pname = trace_packet.get_param_value<GLenum>(1);
4911                 const GLint *pParams = trace_packet.get_param_client_memory<GLint>(2);
4912
4913                 int n = g_gl_enums.get_pname_count(pname);
4914                 if (n <= 0)
4915                 {
4916                     process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
4917                     return cStatusSoftFailure;
4918                 }
4919                 else
4920                 {
4921                     vogl::growable_array<GLint, 16> params(n + 1);
4922                     params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC;
4923
4924                     GL_ENTRYPOINT(glGetObjectParameterivARB)(
4925                         map_handle(get_shared_state()->m_shadow_state.m_objs, trace_packet.get_param_value<GLhandleARB>(0)),
4926                         pname,
4927                         params.get_ptr());
4928
4929                     VOGL_VERIFY(params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC);
4930
4931                     if (memcmp(pParams, params.get_ptr(), n * sizeof(GLint)) != 0)
4932                     {
4933                         process_entrypoint_warning("%s: Replay's returned GLint data differed from trace's, pname %s\n", VOGL_METHOD_NAME, g_gl_enums.find_gl_name(pname));
4934                     }
4935                 }
4936             }
4937             break;
4938         }
4939         case VOGL_ENTRYPOINT_glGetBufferParameteriv:
4940         {
4941             if (!benchmark_mode())
4942             {
4943                 GLenum target = trace_packet.get_param_value<GLenum>(0);
4944                 GLenum value = trace_packet.get_param_value<GLenum>(1);
4945                 const GLint *pTrace_data = trace_packet.get_param_client_memory<GLint>(2);
4946
4947                 int n = g_gl_enums.get_pname_count(value);
4948                 if (n <= 0)
4949                 {
4950                     process_entrypoint_error("%s: Can't determine count of GL value 0x%08X\n", VOGL_METHOD_NAME, value);
4951                     return cStatusSoftFailure;
4952                 }
4953                 else
4954                 {
4955                     vogl::growable_array<GLint, 16> data(n + 1);
4956                     data[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC;
4957
4958                     GL_ENTRYPOINT(glGetBufferParameteriv)(target, value, data.get_ptr());
4959
4960                     VOGL_VERIFY(data[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC);
4961
4962                     GLint trace_data = pTrace_data ? pTrace_data[0] : -1;
4963                     if (data[0] != trace_data)
4964                     {
4965                         process_entrypoint_warning("%s: Replay's returned GLint differed from trace's!\n", VOGL_METHOD_NAME);
4966                         vogl_warning_printf("Trace data: %i, Replay data: %i\n", trace_data, data[0]);
4967                     }
4968                 }
4969             }
4970
4971             break;
4972         }
4973
4974         case VOGL_ENTRYPOINT_glGetBufferPointerv:
4975         {
4976             if (!benchmark_mode())
4977             {
4978                 GLvoid *pReplay_ptr = NULL;
4979                 GL_ENTRYPOINT(glGetBufferPointerv)(trace_packet.get_param_value<GLenum>(0), trace_packet.get_param_value<GLenum>(1), &pReplay_ptr);
4980
4981                 vogl_client_memory_array trace_void_ptr_array = trace_packet.get_param_client_memory_array(2);
4982                 vogl_trace_ptr_value first_trace_ptr = trace_void_ptr_array.get_ptr() ? trace_void_ptr_array.get_element<vogl_trace_ptr_value>(0) : 0;
4983
4984                 if ((pReplay_ptr != NULL) != (first_trace_ptr != 0))
4985                 {
4986                     process_entrypoint_warning("%s: First replay's returned GLvoid* differed from trace's!\n", VOGL_METHOD_NAME);
4987                     vogl_warning_printf("Trace: 0x%" PRIx64 ", Replay: 0x%" PRIx64 "\n", first_trace_ptr, reinterpret_cast<uint64_t>(pReplay_ptr));
4988                 }
4989             }
4990
4991             break;
4992         }
4993         case VOGL_ENTRYPOINT_glShaderSource:
4994         case VOGL_ENTRYPOINT_glShaderSourceARB:
4995         {
4996             const status_t status = handle_ShaderSource(trace_packet.get_param_value<GLhandleARB>(0),
4997                                                         trace_packet.get_param_value<GLsizei>(1),
4998                                                         trace_packet.get_param_client_memory_array(2),
4999                                                         trace_packet.get_param_client_memory<const GLint>(3));
5000             if (status != cStatusOK)
5001                 return status;
5002             break;
5003         }
5004         case VOGL_ENTRYPOINT_glGetProgramInfoLog:
5005         {
5006             GLuint trace_object = trace_packet.get_param_value<GLuint>(0);
5007             GLuint replay_object = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_object);
5008
5009             GLint length = -1;
5010             GL_ENTRYPOINT(glGetProgramiv)(replay_object, GL_INFO_LOG_LENGTH, &length);
5011             if (length < 0)
5012             {
5013                 process_entrypoint_error("%s: Failed retrieving info log length for trace object %u, reply object %u\n", VOGL_METHOD_NAME, trace_object, replay_object);
5014                 return cStatusSoftFailure;
5015             }
5016             else
5017             {
5018                 vogl::vector<GLchar> log(length);
5019
5020                 GLsizei actual_length = 0;
5021                 GL_ENTRYPOINT(glGetProgramInfoLog)(replay_object, length, &actual_length, log.get_ptr());
5022
5023                 if (actual_length)
5024                 {
5025                     process_entrypoint_message("%s: Info log for trace object %u, replay object %u:\n%s\n", VOGL_METHOD_NAME, trace_object, replay_object, log.get_ptr());
5026                 }
5027             }
5028
5029             break;
5030         }
5031         case VOGL_ENTRYPOINT_glGetPointerv:
5032         {
5033             if (!benchmark_mode())
5034             {
5035                 GLvoid *ptr = NULL;
5036                 GL_ENTRYPOINT(glGetPointerv)(trace_packet.get_param_value<GLenum>(0), &ptr);
5037
5038                 // TODO: Differ vs. trace's in some way?
5039             }
5040
5041             break;
5042         }
5043         case VOGL_ENTRYPOINT_glGetInfoLogARB:
5044         {
5045             GLhandleARB trace_object = trace_packet.get_param_value<GLhandleARB>(0);
5046             GLhandleARB replay_object = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_object);
5047
5048             GLsizei length = -1;
5049             GL_ENTRYPOINT(glGetObjectParameterivARB)(replay_object, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
5050             if (length < 0)
5051             {
5052                 process_entrypoint_error("%s: Failed retrieving info log length for trace object %u, reply object %u\n", VOGL_METHOD_NAME, trace_object, replay_object);
5053                 return cStatusSoftFailure;
5054             }
5055             else
5056             {
5057                 vogl::vector<GLcharARB> log(length);
5058
5059                 GLsizei actual_length = 0;
5060                 GL_ENTRYPOINT(glGetInfoLogARB)(replay_object, length, &actual_length, log.get_ptr());
5061
5062                 if (actual_length)
5063                 {
5064                     process_entrypoint_message("%s: Info log for trace object %u, replay object %u:\n%s\n", VOGL_METHOD_NAME, trace_object, replay_object, log.get_ptr());
5065                 }
5066             }
5067
5068             break;
5069         }
5070         case VOGL_ENTRYPOINT_glGetUniformLocation:
5071         {
5072             GLhandleARB trace_handle = trace_packet.get_param_value<GLhandleARB>(0);
5073             GLhandleARB replay_handle = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle);
5074             GLint trace_loc = trace_packet.get_return_value<GLint>();
5075
5076             if (replay_handle)
5077             {
5078                 const GLchar *pName = trace_packet.get_param_client_memory<GLchar>(1);
5079
5080                 GLint replay_loc = GL_ENTRYPOINT(glGetUniformLocation)(replay_handle, pName);
5081                 if (replay_loc < 0)
5082                 {
5083                     if (trace_loc >= 0)
5084                         process_entrypoint_warning("%s: glGetUniformLocation: Function succeeded during trace, but failed during replay! (name: %s trace_handle: %u, trace_loc: %i)\n", VOGL_METHOD_NAME, (const char *)pName, trace_handle, trace_loc);
5085                 }
5086                 else
5087                 {
5088                     if (trace_loc < 0)
5089                         process_entrypoint_warning("%s: glGetUniformLocation: Function failed during trace, but succeeded during replay! (name: %s trace_handle: %u, trace_loc: %i)\n", VOGL_METHOD_NAME, (const char *)pName, trace_handle, trace_loc);
5090                     else
5091                     {
5092                         glsl_program_hash_map::iterator it = get_shared_state()->m_glsl_program_hash_map.find(trace_handle);
5093                         if (it == get_shared_state()->m_glsl_program_hash_map.end())
5094                             it = get_shared_state()->m_glsl_program_hash_map.insert(trace_handle).first;
5095
5096                         glsl_program_state &state = it->second;
5097                         state.m_uniform_locations.erase(trace_loc);
5098                         state.m_uniform_locations.insert(trace_loc, replay_loc);
5099                     }
5100                 }
5101             }
5102
5103             break;
5104         }
5105         case VOGL_ENTRYPOINT_glGetUniformLocationARB:
5106         {
5107             GLhandleARB trace_handle = trace_packet.get_param_value<GLhandleARB>(0);
5108             GLhandleARB replay_handle = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle);
5109             GLint trace_loc = trace_packet.get_return_value<GLint>();
5110
5111             if (replay_handle)
5112             {
5113                 const GLcharARB *pName = trace_packet.get_param_client_memory<GLcharARB>(1);
5114
5115                 GLint replay_loc = GL_ENTRYPOINT(glGetUniformLocationARB)(replay_handle, pName);
5116                 if (replay_loc < 0)
5117                 {
5118                     if (trace_loc >= 0)
5119                         process_entrypoint_warning("%s: glGetUniformLocationARB: Function succeeded during trace, but failed during replay! (name: %s trace_handle: %u, trace_loc: %i)\n", VOGL_METHOD_NAME, (const char *)pName, trace_handle, trace_loc);
5120                 }
5121                 else
5122                 {
5123                     if (trace_loc < 0)
5124                         process_entrypoint_warning("%s: glGetUniformLocationARB: Function failed during trace, but succeeded during replay! (name: %s trace_handle: %u, trace_loc: %i)\n", VOGL_METHOD_NAME, (const char *)pName, trace_handle, trace_loc);
5125                     else
5126                     {
5127                         glsl_program_hash_map::iterator it = get_shared_state()->m_glsl_program_hash_map.find(trace_handle);
5128                         if (it == get_shared_state()->m_glsl_program_hash_map.end())
5129                             it = get_shared_state()->m_glsl_program_hash_map.insert(trace_handle).first;
5130
5131                         glsl_program_state &state = it->second;
5132                         state.m_uniform_locations.erase(trace_loc);
5133                         state.m_uniform_locations.insert(trace_loc, replay_loc);
5134                     }
5135                 }
5136             }
5137
5138             break;
5139         }
5140         case VOGL_ENTRYPOINT_glGetActiveAttrib:
5141         case VOGL_ENTRYPOINT_glGetActiveUniform:
5142         {
5143             if (!benchmark_mode())
5144             {
5145                 GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
5146                 GLuint replay_handle = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle);
5147
5148                 GLuint index = trace_packet.get_param_value<GLuint>(1);
5149                 GLsizei bufSize = trace_packet.get_param_value<GLsizei>(2);
5150
5151                 GLsizei *pTrace_length = trace_packet.get_param_client_memory<GLsizei>(3);
5152                 GLint *pTrace_size = trace_packet.get_param_client_memory<GLint>(4);
5153                 GLenum *pTrace_type = trace_packet.get_param_client_memory<GLenum>(5);
5154                 GLchar *pTrace_name = trace_packet.get_param_client_memory<GLchar>(6);
5155
5156                 vogl::growable_array<GLchar, 1024> name_buf(bufSize + 1); // + 1 guarantees non-empty and null terminated
5157
5158                 GLsizei len = 0;
5159                 GLint size = 0;
5160                 GLenum type = 0;
5161
5162                 if (entrypoint_id == VOGL_ENTRYPOINT_glGetActiveAttrib)
5163                     GL_ENTRYPOINT(glGetActiveAttrib)(replay_handle, index, bufSize, &len, &size, &type, name_buf.get_ptr());
5164                 else
5165                     GL_ENTRYPOINT(glGetActiveUniform)(replay_handle, index, bufSize, &len, &size, &type, name_buf.get_ptr());
5166
5167                 bool mismatch = false;
5168
5169                 GLsizei trace_len = 0;
5170                 if (pTrace_length)
5171                 {
5172                     trace_len = pTrace_length[0];
5173                     if (trace_len != len)
5174                         mismatch = true;
5175                 }
5176
5177                 GLint trace_size = 0;
5178                 if (pTrace_size)
5179                 {
5180                     trace_size = pTrace_size[0];
5181                     if (trace_size != size)
5182                         mismatch = true;
5183                 }
5184
5185                 GLenum trace_type = 0;
5186                 if (pTrace_type)
5187                 {
5188                     trace_type = pTrace_type[0];
5189                     if (trace_type != type)
5190                         mismatch = true;
5191                 }
5192
5193                 if ((bufSize) && (pTrace_name))
5194                 {
5195                     uint n = vogl_strlen((const char *)pTrace_name) + 1;
5196                     if (bufSize < (GLsizei)n)
5197                         mismatch = true;
5198                     else if (memcmp(name_buf.get_ptr(), pTrace_name, n) != 0)
5199                         mismatch = true;
5200                 }
5201
5202                 if (mismatch)
5203                 {
5204                     process_entrypoint_warning("%s: Replay of %s returned data differed from trace's\n", VOGL_METHOD_NAME, trace_packet.get_entrypoint_desc().m_pName);
5205                     vogl_warning_printf("Trace handle: %u, index: %u, bufSize: %u, trace_len: %u, trace_type: %u, name: %s\n",
5206                                        (uint)trace_handle, (uint)index, (uint)bufSize, (uint)trace_len, (uint)trace_type, (pTrace_name != NULL) ? (const char *)pTrace_name : "");
5207                     vogl_warning_printf("GL handle: %u, index: %u, bufSize: %u, trace_len: %u, trace_type: %u, name: %s\n",
5208                                        (uint)replay_handle, (uint)index, (uint)bufSize, (uint)len, (uint)type, name_buf.get_ptr());
5209                 }
5210             }
5211
5212             break;
5213         }
5214         case VOGL_ENTRYPOINT_glGetAttachedShaders:
5215         {
5216             if (!benchmark_mode())
5217             {
5218                 GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
5219                 GLuint replay_handle = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle);
5220
5221                 GLsizei max_count = trace_packet.get_param_value<GLsizei>(1);
5222                 GLsizei count = 0;
5223                 vogl::growable_array<GLuint, 16> shaders(max_count);
5224
5225                 GL_ENTRYPOINT(glGetAttachedShaders)(replay_handle, trace_packet.get_param_value<GLsizei>(1), &count, shaders.get_ptr());
5226
5227                 // TODO: Diff results
5228             }
5229
5230             break;
5231         }
5232         case VOGL_ENTRYPOINT_glGetAttribLocation:
5233         {
5234             if (!benchmark_mode())
5235             {
5236                 GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
5237                 GLuint replay_handle = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle);
5238
5239                 const GLchar *pName = trace_packet.get_param_client_memory<GLchar>(1);
5240
5241                 GLint replay_result = GL_ENTRYPOINT(glGetAttribLocation)(replay_handle, pName);
5242                 GLint trace_result = trace_packet.get_return_value<GLint>();
5243
5244                 if (replay_result != trace_result)
5245                 {
5246                     process_entrypoint_warning("%s: Replay of %s returned data differed from trace's\n", VOGL_METHOD_NAME, trace_packet.get_entrypoint_desc().m_pName);
5247                     vogl_warning_printf("Trace value: %i, replay: %i\n", trace_result, replay_result);
5248                 }
5249             }
5250
5251             break;
5252         }
5253         case VOGL_ENTRYPOINT_glGetProgramivARB:
5254         {
5255             if (!benchmark_mode())
5256             {
5257                 GLenum pname = trace_packet.get_param_value<GLenum>(1);
5258                 const GLint *pParams = trace_packet.get_param_client_memory<GLint>(2);
5259                 uint params_size = trace_packet.get_param_client_memory_data_size(2);
5260                 uint params_count = params_size / sizeof(GLint);
5261
5262                 int n = g_gl_enums.get_pname_count(pname);
5263                 if (n <= 0)
5264                 {
5265                     process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
5266                     return cStatusSoftFailure;
5267                 }
5268                 else
5269                 {
5270                     vogl::growable_array<GLint, 16> params(n + 1);
5271                     params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC;
5272
5273                     GL_ENTRYPOINT(glGetProgramivARB)(
5274                         trace_packet.get_param_value<GLenum>(0),
5275                         pname,
5276                         params.get_ptr());
5277
5278                     VOGL_VERIFY(params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC);
5279
5280                     if (params_count != static_cast<uint>(n))
5281                     {
5282                         process_entrypoint_warning("%s: Size of replay's params array differs from trace's\n", VOGL_METHOD_NAME);
5283                     }
5284                     else if (pParams && memcmp(pParams, params.get_ptr(), n * sizeof(GLint)) != 0)
5285                     {
5286                         process_entrypoint_warning("%s: Replay's returned GLint data differed from trace's, pname %s\n", VOGL_METHOD_NAME, g_gl_enums.find_gl_name(pname));
5287                     }
5288                 }
5289             }
5290
5291             break;
5292         }
5293         case VOGL_ENTRYPOINT_glGetProgramiv:
5294         {
5295             if (!benchmark_mode())
5296             {
5297                 GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
5298                 GLuint replay_handle = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle);
5299
5300                 GLenum pname = trace_packet.get_param_value<GLenum>(1);
5301
5302                 const GLint *pParams = trace_packet.get_param_client_memory<GLint>(2);
5303                 uint params_size = trace_packet.get_param_client_memory_data_size(2);
5304                 uint params_count = params_size / sizeof(GLint);
5305
5306                 int n = g_gl_enums.get_pname_count(pname);
5307                 if (n <= 0)
5308                 {
5309                     process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
5310                     return cStatusSoftFailure;
5311                 }
5312                 else
5313                 {
5314                     vogl::growable_array<GLint, 16> params(n + 1);
5315                     params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC;
5316
5317                     GL_ENTRYPOINT(glGetProgramiv)(
5318                         replay_handle,
5319                         pname,
5320                         params.get_ptr());
5321
5322                     VOGL_VERIFY(params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC);
5323
5324                     if (params_count != static_cast<uint>(n))
5325                     {
5326                         process_entrypoint_warning("%s: Size of replay's params array differs from trace's\n", VOGL_METHOD_NAME);
5327                     }
5328                     else if (pParams && memcmp(pParams, params.get_ptr(), n * sizeof(GLint)) != 0)
5329                     {
5330                         process_entrypoint_warning("%s: Replay's returned GLint data differed from trace's, pname %s\n", VOGL_METHOD_NAME, g_gl_enums.find_gl_name(pname));
5331                     }
5332                 }
5333             }
5334
5335             break;
5336         }
5337         case VOGL_ENTRYPOINT_glLinkProgram:
5338         case VOGL_ENTRYPOINT_glLinkProgramARB:
5339         case VOGL_ENTRYPOINT_glProgramBinary:
5340         {
5341             handle_link_program(entrypoint_id);
5342
5343             break;
5344         }
5345         case VOGL_ENTRYPOINT_glCompileShader:
5346         {
5347             GL_ENTRYPOINT(glCompileShader)(map_handle(get_shared_state()->m_shadow_state.m_objs, trace_packet.get_param_value<GLuint>(0)));
5348             break;
5349         }
5350         case VOGL_ENTRYPOINT_glCompileShaderARB:
5351         {
5352             GL_ENTRYPOINT(glCompileShaderARB)(map_handle(get_shared_state()->m_shadow_state.m_objs, trace_packet.get_param_value<GLhandleARB>(0)));
5353             break;
5354         }
5355         case VOGL_ENTRYPOINT_glGetShaderiv:
5356         {
5357             if (!benchmark_mode())
5358             {
5359                 GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
5360                 GLuint replay_handle = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle);
5361
5362                 GLenum pname = trace_packet.get_param_value<GLenum>(1);
5363                 GLint params = 0;
5364
5365                 const GLint *pClient_params = trace_packet.get_param_client_memory<GLint>(2);
5366
5367                 GL_ENTRYPOINT(glGetShaderiv)(replay_handle, pname, &params);
5368
5369                 if ((pClient_params) && (*pClient_params != params))
5370                 {
5371                     process_entrypoint_warning("%s: Replay's returned data differed from trace's\n", VOGL_METHOD_NAME);
5372                     vogl_warning_printf("Trace data: %i, Replay data: %i\n", pClient_params ? *pClient_params : 0, params);
5373                 }
5374             }
5375
5376             break;
5377         }
5378         case VOGL_ENTRYPOINT_glGetShaderInfoLog:
5379         {
5380             GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
5381             GLuint replay_handle = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle);
5382
5383             GLsizei trace_max_length = trace_packet.get_param_value<GLsizei>(1);
5384             const GLsizei *pTrace_length = trace_packet.get_param_client_memory<GLsizei>(2);
5385             VOGL_NOTE_UNUSED(pTrace_length);
5386             const GLchar *pTrace_info_log = trace_packet.get_param_client_memory<GLchar>(3);
5387             VOGL_NOTE_UNUSED(pTrace_info_log);
5388
5389             vogl::growable_array<GLchar, 512> log(trace_max_length);
5390             GLsizei length = 0;
5391             GL_ENTRYPOINT(glGetShaderInfoLog)(replay_handle, trace_max_length, &length, log.get_ptr());
5392
5393             if (length)
5394             {
5395                 process_entrypoint_message("%s: Info log for trace object %u, replay object %u:\n%s\n", VOGL_METHOD_NAME, trace_handle, replay_handle, log.get_ptr());
5396             }
5397
5398             break;
5399         }
5400         case VOGL_ENTRYPOINT_glGetBooleanv:
5401         {
5402             if (!benchmark_mode())
5403             {
5404                 GLenum pname = trace_packet.get_param_value<GLenum>(0);
5405                 const GLboolean *pParams = trace_packet.get_param_client_memory<GLboolean>(1);
5406
5407                 int n = g_gl_enums.get_pname_count(pname);
5408                 if (n <= 0)
5409                 {
5410                     process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X (%s)\n", VOGL_METHOD_NAME, pname, g_gl_enums.find_gl_name(pname));
5411                     return cStatusSoftFailure;
5412                 }
5413                 else
5414                 {
5415                     vogl::growable_array<GLboolean, 16> params(n + 1);
5416                     params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_BYTE_MAGIC;
5417
5418                     GL_ENTRYPOINT(glGetBooleanv)(pname, params.get_ptr());
5419
5420                     VOGL_VERIFY(params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_BYTE_MAGIC);
5421
5422                     if (memcmp(pParams, params.get_ptr(), n * sizeof(GLboolean)) != 0)
5423                     {
5424                         process_entrypoint_warning("%s: Replay's returned GLboolean data for pname 0x%08X (%s) differed from trace's\n", VOGL_METHOD_NAME, pname, g_gl_enums.find_gl_name(pname));
5425                     }
5426                 }
5427             }
5428
5429             break;
5430         }
5431         case VOGL_ENTRYPOINT_glGetDoublev:
5432         {
5433             if (!benchmark_mode())
5434             {
5435                 GLenum pname = trace_packet.get_param_value<GLenum>(0);
5436                 const GLdouble *pParams = trace_packet.get_param_client_memory<GLdouble>(1);
5437
5438                 int n = g_gl_enums.get_pname_count(pname);
5439                 if (n <= 0)
5440                 {
5441                     process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
5442                     return cStatusSoftFailure;
5443                 }
5444                 else
5445                 {
5446                     vogl::growable_array<GLdouble, 17> params(n + 1);
5447                     params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_FLOAT_MAGIC;
5448
5449                     GL_ENTRYPOINT(glGetDoublev)(pname, params.get_ptr());
5450
5451                     VOGL_VERIFY(params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_FLOAT_MAGIC);
5452
5453                     if (memcmp(pParams, params.get_ptr(), n * sizeof(GLdouble)) != 0)
5454                     {
5455                         process_entrypoint_warning("%s: Replay's returned GLdouble data differed from trace's\n", VOGL_METHOD_NAME);
5456                     }
5457                 }
5458             }
5459
5460             break;
5461         }
5462         case VOGL_ENTRYPOINT_glGetFloatv:
5463         {
5464             if (!benchmark_mode())
5465             {
5466                 GLenum pname = trace_packet.get_param_value<GLenum>(0);
5467                 const GLfloat *pTrace_params = trace_packet.get_param_client_memory<GLfloat>(1);
5468                 uint trace_params_count = trace_packet.get_param_client_memory_data_size(1) / sizeof(GLfloat);
5469
5470                 int n = g_gl_enums.get_pname_count(pname);
5471                 if (n <= 0)
5472                 {
5473                     process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
5474                     return cStatusSoftFailure;
5475                 }
5476
5477                 vogl::growable_array<GLfloat, 17> params(n + 1);
5478                 params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_FLOAT_MAGIC;
5479
5480                 GL_ENTRYPOINT(glGetFloatv)(pname, params.get_ptr());
5481
5482                 VOGL_VERIFY(params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_FLOAT_MAGIC);
5483
5484                 if (static_cast<int>(trace_params_count) < n)
5485                     process_entrypoint_warning("%s: Replay param array size (%u) does not match the expected size (%u)\n", VOGL_METHOD_NAME, trace_params_count, n);
5486                 else if (memcmp(pTrace_params, params.get_ptr(), n * sizeof(GLfloat)) != 0)
5487                 {
5488                     process_entrypoint_warning("%s: Replay's returned GLfloat data differed from trace's\n", VOGL_METHOD_NAME);
5489                 }
5490             }
5491
5492             break;
5493         }
5494         case VOGL_ENTRYPOINT_glGetIntegerv:
5495         {
5496             if (!benchmark_mode())
5497             {
5498                 GLenum pname = trace_packet.get_param_value<GLenum>(0);
5499                 const GLint *pTrace_params = trace_packet.get_param_client_memory<GLint>(1);
5500                 uint trace_params_count = trace_packet.get_param_client_memory_data_size(1) / sizeof(GLint);
5501
5502                 int n = g_gl_enums.get_pname_count(pname);
5503                 if (n <= 0)
5504                 {
5505                     process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
5506                     return cStatusSoftFailure;
5507                 }
5508
5509                 vogl::growable_array<GLint, 16> params(n + 1);
5510                 params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC;
5511
5512                 GL_ENTRYPOINT(glGetIntegerv)(pname, params.get_ptr());
5513
5514                 VOGL_VERIFY(params[n] == (GLint)VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC);
5515
5516                 bool is_binding = false;
5517                 switch (pname)
5518                 {
5519                     case GL_ARRAY_BUFFER_BINDING:
5520                     case GL_COLOR_ARRAY_BUFFER_BINDING:
5521                     case GL_DISPATCH_INDIRECT_BUFFER_BINDING:
5522                     case GL_DRAW_FRAMEBUFFER_BINDING:
5523                     case GL_EDGE_FLAG_ARRAY_BUFFER_BINDING:
5524                     case GL_ELEMENT_ARRAY_BUFFER_BINDING:
5525                     case GL_FOG_COORD_ARRAY_BUFFER_BINDING:
5526                     case GL_INDEX_ARRAY_BUFFER_BINDING:
5527                     case GL_NORMAL_ARRAY_BUFFER_BINDING:
5528                     case GL_PIXEL_PACK_BUFFER_BINDING:
5529                     case GL_PIXEL_UNPACK_BUFFER_BINDING:
5530                     case GL_PROGRAM_PIPELINE_BINDING:
5531                     case GL_READ_FRAMEBUFFER_BINDING:
5532                     case GL_RENDERBUFFER_BINDING:
5533                     case GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING:
5534                     case GL_SHADER_STORAGE_BUFFER_BINDING:
5535                     case GL_TEXTURE_BINDING_1D:
5536                     case GL_TEXTURE_BINDING_1D_ARRAY:
5537                     case GL_TEXTURE_BINDING_2D:
5538                     case GL_TEXTURE_BINDING_2D_ARRAY:
5539                     case GL_TEXTURE_BINDING_2D_MULTISAMPLE:
5540                     case GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY:
5541                     case GL_TEXTURE_BINDING_3D:
5542                     case GL_TEXTURE_BINDING_BUFFER:
5543                     case GL_TEXTURE_BINDING_CUBE_MAP:
5544                     case GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING:
5545                     case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
5546                     case GL_TRANSFORM_FEEDBACK_BUFFER_START:
5547                     case GL_UNIFORM_BUFFER_BINDING:
5548                     case GL_VERTEX_ARRAY_BINDING:
5549                     case GL_VERTEX_ARRAY_BUFFER_BINDING:
5550                     case GL_CURRENT_PROGRAM:
5551                     {
5552                         is_binding = true;
5553                         break;
5554                     }
5555                     default:
5556                         break;
5557                 }
5558
5559                 // Don't bother diffing bindings, the trace's are in the trace domain while the glGet's results are in the replay domain.
5560                 if (!is_binding)
5561                 {
5562                     if (static_cast<int>(trace_params_count) < n)
5563                     {
5564                         process_entrypoint_warning("%s: Replay param array size (%u) does not match the expected size (%u)\n", VOGL_METHOD_NAME, trace_params_count, n);
5565                     }
5566                     else if (memcmp(pTrace_params, params.get_ptr(), n * sizeof(GLint)) != 0)
5567                     {
5568                         process_entrypoint_warning("%s: Replay's returned GLint data differed from trace's, pname %s\n", VOGL_METHOD_NAME, g_gl_enums.find_gl_name(pname));
5569                         for (int i = 0; i < n; i++)
5570                             vogl_printf("GLint %u: Trace: %i, Replay: %i\n", i, pTrace_params[i], params[i]);
5571                     }
5572                 }
5573             }
5574
5575             break;
5576         }
5577         // glProgramUniform's
5578         case VOGL_ENTRYPOINT_glProgramUniform1f:
5579         {
5580             set_program_uniform_helper1<GLfloat>(GL_ENTRYPOINT(glProgramUniform1f));
5581             break;
5582         }
5583         case VOGL_ENTRYPOINT_glProgramUniform1i:
5584         {
5585             set_program_uniform_helper1<GLint>(GL_ENTRYPOINT(glProgramUniform1i));
5586             break;
5587         }
5588         case VOGL_ENTRYPOINT_glProgramUniform1ui:
5589         {
5590             set_program_uniform_helper1<GLuint>(GL_ENTRYPOINT(glProgramUniform1ui));
5591             break;
5592         }
5593         case VOGL_ENTRYPOINT_glProgramUniform2f:
5594         {
5595             set_program_uniform_helper2<GLfloat>(GL_ENTRYPOINT(glProgramUniform2f));
5596             break;
5597         }
5598         case VOGL_ENTRYPOINT_glProgramUniform2i:
5599         {
5600             set_program_uniform_helper2<GLint>(GL_ENTRYPOINT(glProgramUniform2i));
5601             break;
5602         }
5603         case VOGL_ENTRYPOINT_glProgramUniform2ui:
5604         {
5605             set_program_uniform_helper2<GLuint>(GL_ENTRYPOINT(glProgramUniform2ui));
5606             break;
5607         }
5608         case VOGL_ENTRYPOINT_glProgramUniform3f:
5609         {
5610             set_program_uniform_helper3<GLfloat>(GL_ENTRYPOINT(glProgramUniform3f));
5611             break;
5612         }
5613         case VOGL_ENTRYPOINT_glProgramUniform3i:
5614         {
5615             set_program_uniform_helper3<GLint>(GL_ENTRYPOINT(glProgramUniform3i));
5616             break;
5617         }
5618         case VOGL_ENTRYPOINT_glProgramUniform3ui:
5619         {
5620             set_program_uniform_helper3<GLuint>(GL_ENTRYPOINT(glProgramUniform3ui));
5621             break;
5622         }
5623         case VOGL_ENTRYPOINT_glProgramUniform4f:
5624         {
5625             set_program_uniform_helper4<GLfloat>(GL_ENTRYPOINT(glProgramUniform4f));
5626             break;
5627         }
5628         case VOGL_ENTRYPOINT_glProgramUniform4i:
5629         {
5630             set_program_uniform_helper4<GLint>(GL_ENTRYPOINT(glProgramUniform4i));
5631             break;
5632         }
5633         case VOGL_ENTRYPOINT_glProgramUniform4ui:
5634         {
5635             set_program_uniform_helper4<GLuint>(GL_ENTRYPOINT(glProgramUniform4ui));
5636             break;
5637         }
5638         case VOGL_ENTRYPOINT_glProgramUniform1fv:
5639         {
5640             set_program_uniformv_helper<1, float>(GL_ENTRYPOINT(glProgramUniform1fv));
5641             break;
5642         }
5643         case VOGL_ENTRYPOINT_glProgramUniform2fv:
5644         {
5645             set_program_uniformv_helper<2, float>(GL_ENTRYPOINT(glProgramUniform2fv));
5646             break;
5647         }
5648         case VOGL_ENTRYPOINT_glProgramUniform3fv:
5649         {
5650             set_program_uniformv_helper<3, float>(GL_ENTRYPOINT(glProgramUniform3fv));
5651             break;
5652         }
5653         case VOGL_ENTRYPOINT_glProgramUniform4fv:
5654         {
5655             set_program_uniformv_helper<4, float>(GL_ENTRYPOINT(glProgramUniform4fv));
5656             break;
5657         }
5658         case VOGL_ENTRYPOINT_glProgramUniform1iv:
5659         {
5660             set_program_uniformv_helper<1, GLint>(GL_ENTRYPOINT(glProgramUniform1iv));
5661             break;
5662         }
5663         case VOGL_ENTRYPOINT_glProgramUniform2iv:
5664         {
5665             set_program_uniformv_helper<2, GLint>(GL_ENTRYPOINT(glProgramUniform2iv));
5666             break;
5667         }
5668         case VOGL_ENTRYPOINT_glProgramUniform3iv:
5669         {
5670             set_program_uniformv_helper<3, GLint>(GL_ENTRYPOINT(glProgramUniform3iv));
5671             break;
5672         }
5673         case VOGL_ENTRYPOINT_glProgramUniform4iv:
5674         {
5675             set_program_uniformv_helper<4, GLint>(GL_ENTRYPOINT(glProgramUniform4iv));
5676             break;
5677         }
5678         case VOGL_ENTRYPOINT_glProgramUniform1uiv:
5679         {
5680             set_program_uniformv_helper<1, GLuint>(GL_ENTRYPOINT(glProgramUniform1uiv));
5681             break;
5682         }
5683         case VOGL_ENTRYPOINT_glProgramUniform2uiv:
5684         {
5685             set_program_uniformv_helper<2, GLuint>(GL_ENTRYPOINT(glProgramUniform2uiv));
5686             break;
5687         }
5688         case VOGL_ENTRYPOINT_glProgramUniform3uiv:
5689         {
5690             set_program_uniformv_helper<3, GLuint>(GL_ENTRYPOINT(glProgramUniform3uiv));
5691             break;
5692         }
5693         case VOGL_ENTRYPOINT_glProgramUniform4uiv:
5694         {
5695             set_program_uniformv_helper<4, GLuint>(GL_ENTRYPOINT(glProgramUniform4uiv));
5696             break;
5697         }
5698         case VOGL_ENTRYPOINT_glProgramUniformMatrix2fv:
5699         {
5700             set_program_uniform_matrixv_helper<2, 2, float>(GL_ENTRYPOINT(glProgramUniformMatrix2fv));
5701             break;
5702         }
5703         case VOGL_ENTRYPOINT_glProgramUniformMatrix3fv:
5704         {
5705             set_program_uniform_matrixv_helper<3, 3, float>(GL_ENTRYPOINT(glProgramUniformMatrix3fv));
5706             break;
5707         }
5708         case VOGL_ENTRYPOINT_glProgramUniformMatrix4fv:
5709         {
5710             set_program_uniform_matrixv_helper<4, 4, float>(GL_ENTRYPOINT(glProgramUniformMatrix4fv));
5711             break;
5712         }
5713         case VOGL_ENTRYPOINT_glProgramUniformMatrix2x3fv:
5714         {
5715             set_program_uniform_matrixv_helper<2, 3, float>(GL_ENTRYPOINT(glProgramUniformMatrix2x3fv));
5716             break;
5717         }
5718         case VOGL_ENTRYPOINT_glProgramUniformMatrix3x2fv:
5719         {
5720             set_program_uniform_matrixv_helper<3, 2, float>(GL_ENTRYPOINT(glProgramUniformMatrix3x2fv));
5721             break;
5722         }
5723         case VOGL_ENTRYPOINT_glProgramUniformMatrix2x4fv:
5724         {
5725             set_program_uniform_matrixv_helper<2, 4, float>(GL_ENTRYPOINT(glProgramUniformMatrix2x4fv));
5726             break;
5727         }
5728         case VOGL_ENTRYPOINT_glProgramUniformMatrix4x2fv:
5729         {
5730             set_program_uniform_matrixv_helper<4, 2, float>(GL_ENTRYPOINT(glProgramUniformMatrix4x2fv));
5731             break;
5732         }
5733         case VOGL_ENTRYPOINT_glProgramUniformMatrix3x4fv:
5734         {
5735             set_program_uniform_matrixv_helper<3, 4, float>(GL_ENTRYPOINT(glProgramUniformMatrix3x4fv));
5736             break;
5737         }
5738         case VOGL_ENTRYPOINT_glProgramUniformMatrix4x3fv:
5739         {
5740             set_program_uniform_matrixv_helper<4, 3, float>(GL_ENTRYPOINT(glProgramUniformMatrix4x3fv));
5741             break;
5742         }
5743         // glUniform's
5744         case VOGL_ENTRYPOINT_glUniform1f:
5745         {
5746             set_uniform_helper1<GLfloat>(GL_ENTRYPOINT(glUniform1f));
5747             break;
5748         }
5749         case VOGL_ENTRYPOINT_glUniform1fARB:
5750         {
5751             set_uniform_helper1<GLfloat>(GL_ENTRYPOINT(glUniform1fARB));
5752             break;
5753         }
5754         case VOGL_ENTRYPOINT_glUniform2f:
5755         {
5756             set_uniform_helper2<GLfloat>(GL_ENTRYPOINT(glUniform2f));
5757             break;
5758         }
5759         case VOGL_ENTRYPOINT_glUniform2fARB:
5760         {
5761             set_uniform_helper2<GLfloat>(GL_ENTRYPOINT(glUniform2fARB));
5762             break;
5763         }
5764         case VOGL_ENTRYPOINT_glUniform3f:
5765         {
5766             set_uniform_helper3<GLfloat>(GL_ENTRYPOINT(glUniform3f));
5767             break;
5768         }
5769         case VOGL_ENTRYPOINT_glUniform3fARB:
5770         {
5771             set_uniform_helper3<GLfloat>(GL_ENTRYPOINT(glUniform3fARB));
5772             break;
5773         }
5774         case VOGL_ENTRYPOINT_glUniform4f:
5775         {
5776             set_uniform_helper4<GLfloat>(GL_ENTRYPOINT(glUniform4f));
5777             break;
5778         }
5779         case VOGL_ENTRYPOINT_glUniform4fARB:
5780         {
5781             set_uniform_helper4<GLfloat>(GL_ENTRYPOINT(glUniform4fARB));
5782             break;
5783         }
5784         case VOGL_ENTRYPOINT_glUniform1i:
5785         {
5786             set_uniform_helper1<GLint>(GL_ENTRYPOINT(glUniform1i));
5787             break;
5788         }
5789         case VOGL_ENTRYPOINT_glUniform1iARB:
5790         {
5791             set_uniform_helper1<GLint>(GL_ENTRYPOINT(glUniform1iARB));
5792             break;
5793         }
5794         case VOGL_ENTRYPOINT_glUniform2i:
5795         {
5796             set_uniform_helper2<GLint>(GL_ENTRYPOINT(glUniform2i));
5797             break;
5798         }
5799         case VOGL_ENTRYPOINT_glUniform2iARB:
5800         {
5801             set_uniform_helper2<GLint>(GL_ENTRYPOINT(glUniform2iARB));
5802             break;
5803         }
5804         case VOGL_ENTRYPOINT_glUniform3i:
5805         {
5806             set_uniform_helper3<GLint>(GL_ENTRYPOINT(glUniform3i));
5807             break;
5808         }
5809         case VOGL_ENTRYPOINT_glUniform3iARB:
5810         {
5811             set_uniform_helper3<GLint>(GL_ENTRYPOINT(glUniform3iARB));
5812             break;
5813         }
5814         case VOGL_ENTRYPOINT_glUniform4i:
5815         {
5816             set_uniform_helper4<GLint>(GL_ENTRYPOINT(glUniform4i));
5817             break;
5818         }
5819         case VOGL_ENTRYPOINT_glUniform4iARB:
5820         {
5821             set_uniform_helper4<GLint>(GL_ENTRYPOINT(glUniform4iARB));
5822             break;
5823         }
5824         case VOGL_ENTRYPOINT_glUniform1ui:
5825         {
5826             set_uniform_helper1<GLuint>(GL_ENTRYPOINT(glUniform1ui));
5827             break;
5828         }
5829         case VOGL_ENTRYPOINT_glUniform1uiEXT:
5830         {
5831             set_uniform_helper1<GLuint>(GL_ENTRYPOINT(glUniform1uiEXT));
5832             break;
5833         }
5834         case VOGL_ENTRYPOINT_glUniform2ui:
5835         {
5836             set_uniform_helper2<GLuint>(GL_ENTRYPOINT(glUniform2ui));
5837             break;
5838         }
5839         case VOGL_ENTRYPOINT_glUniform2uiEXT:
5840         {
5841             set_uniform_helper2<GLuint>(GL_ENTRYPOINT(glUniform2uiEXT));
5842             break;
5843         }
5844         case VOGL_ENTRYPOINT_glUniform3ui:
5845         {
5846             set_uniform_helper3<GLuint>(GL_ENTRYPOINT(glUniform3ui));
5847             break;
5848         }
5849         case VOGL_ENTRYPOINT_glUniform3uiEXT:
5850         {
5851             set_uniform_helper3<GLuint>(GL_ENTRYPOINT(glUniform3uiEXT));
5852             break;
5853         }
5854         case VOGL_ENTRYPOINT_glUniform4ui:
5855         {
5856             set_uniform_helper4<GLuint>(GL_ENTRYPOINT(glUniform4ui));
5857             break;
5858         }
5859         case VOGL_ENTRYPOINT_glUniform4uiEXT:
5860         {
5861             set_uniform_helper4<GLuint>(GL_ENTRYPOINT(glUniform4uiEXT));
5862             break;
5863         }
5864         case VOGL_ENTRYPOINT_glUniform1uiv:
5865         {
5866             set_uniformv_helper<1, GLuint>(GL_ENTRYPOINT(glUniform1uiv));
5867             break;
5868         }
5869         case VOGL_ENTRYPOINT_glUniform1uivEXT:
5870         {
5871             set_uniformv_helper<1, GLuint>(GL_ENTRYPOINT(glUniform1uivEXT));
5872             break;
5873         }
5874         case VOGL_ENTRYPOINT_glUniform2uiv:
5875         {
5876             set_uniformv_helper<2, GLuint>(GL_ENTRYPOINT(glUniform2uiv));
5877             break;
5878         }
5879         case VOGL_ENTRYPOINT_glUniform2uivEXT:
5880         {
5881             set_uniformv_helper<2, GLuint>(GL_ENTRYPOINT(glUniform2uivEXT));
5882             break;
5883         }
5884         case VOGL_ENTRYPOINT_glUniform3uiv:
5885         {
5886             set_uniformv_helper<3, GLuint>(GL_ENTRYPOINT(glUniform3uiv));
5887             break;
5888         }
5889         case VOGL_ENTRYPOINT_glUniform3uivEXT:
5890         {
5891             set_uniformv_helper<3, GLuint>(GL_ENTRYPOINT(glUniform3uivEXT));
5892             break;
5893         }
5894         case VOGL_ENTRYPOINT_glUniform4uiv:
5895         {
5896             set_uniformv_helper<4, GLuint>(GL_ENTRYPOINT(glUniform4uiv));
5897             break;
5898         }
5899         case VOGL_ENTRYPOINT_glUniform4uivEXT:
5900         {
5901             set_uniformv_helper<4, GLuint>(GL_ENTRYPOINT(glUniform4uivEXT));
5902             break;
5903         }
5904         case VOGL_ENTRYPOINT_glUniform1iv:
5905         {
5906             set_uniformv_helper<1, GLint>(GL_ENTRYPOINT(glUniform1iv));
5907             break;
5908         }
5909         case VOGL_ENTRYPOINT_glUniform1ivARB:
5910         {
5911             set_uniformv_helper<1, GLint>(GL_ENTRYPOINT(glUniform1ivARB));
5912             break;
5913         }
5914         case VOGL_ENTRYPOINT_glUniform2iv:
5915         {
5916             set_uniformv_helper<2, GLint>(GL_ENTRYPOINT(glUniform2iv));
5917             break;
5918         }
5919         case VOGL_ENTRYPOINT_glUniform2ivARB:
5920         {
5921             set_uniformv_helper<2, GLint>(GL_ENTRYPOINT(glUniform2ivARB));
5922             break;
5923         }
5924         case VOGL_ENTRYPOINT_glUniform3iv:
5925         {
5926             set_uniformv_helper<3, GLint>(GL_ENTRYPOINT(glUniform3iv));
5927             break;
5928         }
5929         case VOGL_ENTRYPOINT_glUniform3ivARB:
5930         {
5931             set_uniformv_helper<3, GLint>(GL_ENTRYPOINT(glUniform3ivARB));
5932             break;
5933         }
5934         case VOGL_ENTRYPOINT_glUniform4iv:
5935         {
5936             set_uniformv_helper<4, GLint>(GL_ENTRYPOINT(glUniform4iv));
5937             break;
5938         }
5939         case VOGL_ENTRYPOINT_glUniform4ivARB:
5940         {
5941             set_uniformv_helper<4, GLint>(GL_ENTRYPOINT(glUniform4ivARB));
5942             break;
5943         }
5944         case VOGL_ENTRYPOINT_glUniform1fv:
5945         {
5946             set_uniformv_helper<1, GLfloat>(GL_ENTRYPOINT(glUniform1fv));
5947             break;
5948         }
5949         case VOGL_ENTRYPOINT_glUniform1fvARB:
5950         {
5951             set_uniformv_helper<1, GLfloat>(GL_ENTRYPOINT(glUniform1fvARB));
5952             break;
5953         }
5954         case VOGL_ENTRYPOINT_glUniform2fv:
5955         {
5956             set_uniformv_helper<2, GLfloat>(GL_ENTRYPOINT(glUniform2fv));
5957             break;
5958         }
5959         case VOGL_ENTRYPOINT_glUniform2fvARB:
5960         {
5961             set_uniformv_helper<2, GLfloat>(GL_ENTRYPOINT(glUniform2fvARB));
5962             break;
5963         }
5964         case VOGL_ENTRYPOINT_glUniform3fv:
5965         {
5966             set_uniformv_helper<3, GLfloat>(GL_ENTRYPOINT(glUniform3fv));
5967             break;
5968         }
5969         case VOGL_ENTRYPOINT_glUniform3fvARB:
5970         {
5971             set_uniformv_helper<3, GLfloat>(GL_ENTRYPOINT(glUniform3fvARB));
5972             break;
5973         }
5974         case VOGL_ENTRYPOINT_glUniform4fv:
5975         {
5976             set_uniformv_helper<4, GLfloat>(GL_ENTRYPOINT(glUniform4fv));
5977             break;
5978         }
5979         case VOGL_ENTRYPOINT_glUniform4fvARB:
5980         {
5981             set_uniformv_helper<4, GLfloat>(GL_ENTRYPOINT(glUniform4fvARB));
5982             break;
5983         }
5984         case VOGL_ENTRYPOINT_glUniformMatrix2fvARB:
5985         {
5986             set_uniform_matrixv_helper<2, 2, GLfloat>(GL_ENTRYPOINT(glUniformMatrix2fvARB));
5987             break;
5988         }
5989         case VOGL_ENTRYPOINT_glUniformMatrix2fv:
5990         {
5991             set_uniform_matrixv_helper<2, 2, GLfloat>(GL_ENTRYPOINT(glUniformMatrix2fv));
5992             break;
5993         }
5994         case VOGL_ENTRYPOINT_glUniformMatrix3fvARB:
5995         {
5996             set_uniform_matrixv_helper<3, 3, GLfloat>(GL_ENTRYPOINT(glUniformMatrix3fvARB));
5997             break;
5998         }
5999         case VOGL_ENTRYPOINT_glUniformMatrix3fv:
6000         {
6001             set_uniform_matrixv_helper<3, 3, GLfloat>(GL_ENTRYPOINT(glUniformMatrix3fv));
6002             break;
6003         }
6004         case VOGL_ENTRYPOINT_glUniformMatrix4fvARB:
6005         {
6006             set_uniform_matrixv_helper<4, 4, GLfloat>(GL_ENTRYPOINT(glUniformMatrix4fvARB));
6007             break;
6008         }
6009         case VOGL_ENTRYPOINT_glUniformMatrix4fv:
6010         {
6011             set_uniform_matrixv_helper<4, 4, GLfloat>(GL_ENTRYPOINT(glUniformMatrix4fv));
6012             break;
6013         }
6014         case VOGL_ENTRYPOINT_glUniformMatrix2x3fv:
6015         {
6016             set_uniform_matrixv_helper<2, 3, GLfloat>(GL_ENTRYPOINT(glUniformMatrix2x3fv));
6017             break;
6018         }
6019         case VOGL_ENTRYPOINT_glUniformMatrix3x2fv:
6020         {
6021             set_uniform_matrixv_helper<3, 2, GLfloat>(GL_ENTRYPOINT(glUniformMatrix3x2fv));
6022             break;
6023         }
6024         case VOGL_ENTRYPOINT_glUniformMatrix2x4fv:
6025         {
6026             set_uniform_matrixv_helper<2, 4, GLfloat>(GL_ENTRYPOINT(glUniformMatrix2x4fv));
6027             break;
6028         }
6029         case VOGL_ENTRYPOINT_glUniformMatrix4x2fv:
6030         {
6031             set_uniform_matrixv_helper<4, 2, GLfloat>(GL_ENTRYPOINT(glUniformMatrix4x2fv));
6032             break;
6033         }
6034         case VOGL_ENTRYPOINT_glUniformMatrix3x4fv:
6035         {
6036             set_uniform_matrixv_helper<3, 4, GLfloat>(GL_ENTRYPOINT(glUniformMatrix3x4fv));
6037             break;
6038         }
6039         case VOGL_ENTRYPOINT_glUniformMatrix4x3fv:
6040         {
6041             set_uniform_matrixv_helper<4, 3, GLfloat>(GL_ENTRYPOINT(glUniformMatrix4x3fv));
6042             break;
6043         }
6044         case VOGL_ENTRYPOINT_glBeginQuery:
6045         case VOGL_ENTRYPOINT_glBeginQueryARB:
6046         {
6047             GLenum target = trace_packet.get_param_value<GLenum>(0);
6048             GLuint trace_handle = trace_packet.get_param_value<GLuint>(1);
6049             GLuint replay_handle = map_handle(get_shared_state()->m_queries, trace_handle);
6050
6051             if (!m_pCur_context_state->m_inside_gl_begin)
6052                 check_gl_error();
6053
6054             if (entrypoint_id == VOGL_ENTRYPOINT_glBeginQuery)
6055                 GL_ENTRYPOINT(glBeginQuery)(target, replay_handle);
6056             else
6057                 GL_ENTRYPOINT(glBeginQueryARB)(target, replay_handle);
6058
6059             if ((replay_handle) && (!m_pCur_context_state->m_inside_gl_begin) && (get_context_state()->m_current_display_list_mode != GL_COMPILE))
6060             {
6061                 if (check_gl_error())
6062                     return cStatusGLError;
6063
6064                 get_shared_state()->m_query_targets[replay_handle] = target;
6065             }
6066
6067             break;
6068         }
6069         case VOGL_ENTRYPOINT_glEndQuery:
6070         {
6071             GL_ENTRYPOINT(glEndQuery)(trace_packet.get_param_value<GLenum>(0));
6072             break;
6073         }
6074         case VOGL_ENTRYPOINT_glEndQueryARB:
6075         {
6076             GL_ENTRYPOINT(glEndQueryARB)(trace_packet.get_param_value<GLenum>(0));
6077             break;
6078         }
6079         case VOGL_ENTRYPOINT_glGetQueryObjectiv:
6080         {
6081             GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
6082             GLuint replay_handle = map_handle(get_shared_state()->m_queries, trace_handle);
6083
6084             GLenum pname = trace_packet.get_param_value<GLenum>(1);
6085
6086             int n = g_gl_enums.get_pname_count(pname);
6087             if (n <= 0)
6088             {
6089                 process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
6090                 return cStatusSoftFailure;
6091             }
6092             else
6093             {
6094                 vogl::growable_array<GLint, 16> params(n + 1);
6095                 params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC;
6096
6097                 GL_ENTRYPOINT(glGetQueryObjectiv)(replay_handle, pname, params.get_ptr());
6098
6099                 VOGL_VERIFY(params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC);
6100             }
6101
6102             break;
6103         }
6104         case VOGL_ENTRYPOINT_glGetQueryObjectivARB:
6105         {
6106             GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
6107             GLuint replay_handle = map_handle(get_shared_state()->m_queries, trace_handle);
6108
6109             GLenum pname = trace_packet.get_param_value<GLenum>(1);
6110
6111             int n = g_gl_enums.get_pname_count(pname);
6112             if (n <= 0)
6113             {
6114                 process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
6115                 return cStatusSoftFailure;
6116             }
6117             else
6118             {
6119                 vogl::growable_array<GLint, 16> params(n + 1);
6120                 params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC;
6121
6122                 GL_ENTRYPOINT(glGetQueryObjectivARB)(replay_handle, pname, params.get_ptr());
6123
6124                 VOGL_VERIFY(params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC);
6125             }
6126
6127             break;
6128         }
6129         case VOGL_ENTRYPOINT_glGetQueryObjectuiv:
6130         {
6131             GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
6132             GLuint replay_handle = map_handle(get_shared_state()->m_queries, trace_handle);
6133
6134             GLenum pname = trace_packet.get_param_value<GLenum>(1);
6135
6136             int n = g_gl_enums.get_pname_count(pname);
6137             if (n <= 0)
6138             {
6139                 process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
6140                 return cStatusSoftFailure;
6141             }
6142             else
6143             {
6144                 vogl::growable_array<GLuint, 16> params(n + 1);
6145                 params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC;
6146
6147                 GL_ENTRYPOINT(glGetQueryObjectuiv)(replay_handle, pname, params.get_ptr());
6148
6149                 VOGL_VERIFY(params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC);
6150             }
6151
6152             break;
6153         }
6154         case VOGL_ENTRYPOINT_glGetQueryObjectuivARB:
6155         {
6156             GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
6157             GLuint replay_handle = map_handle(get_shared_state()->m_queries, trace_handle);
6158
6159             GLenum pname = trace_packet.get_param_value<GLenum>(1);
6160
6161             int n = g_gl_enums.get_pname_count(pname);
6162             if (n <= 0)
6163             {
6164                 process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
6165                 return cStatusSoftFailure;
6166             }
6167             else
6168             {
6169                 vogl::growable_array<GLuint, 16> params(n + 1);
6170                 params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC;
6171
6172                 GL_ENTRYPOINT(glGetQueryObjectuivARB)(replay_handle, pname, params.get_ptr());
6173
6174                 VOGL_VERIFY(params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC);
6175             }
6176
6177             break;
6178         }
6179         case VOGL_ENTRYPOINT_glQueryCounter:
6180         {
6181             VOGL_REPLAY_LOAD_PARAMS_HELPER_glQueryCounter;
6182
6183             id = map_handle(get_shared_state()->m_queries, id);
6184
6185             VOGL_REPLAY_CALL_GL_HELPER_glQueryCounter;
6186
6187             break;
6188         }
6189         case VOGL_ENTRYPOINT_glGetQueryObjecti64v:
6190         {
6191             VOGL_REPLAY_LOAD_PARAMS_HELPER_glGetQueryObjecti64v;
6192             VOGL_NOTE_UNUSED(pTrace_params);
6193
6194             id = map_handle(get_shared_state()->m_queries, id);
6195
6196             int n = g_gl_enums.get_pname_count(pname);
6197             if (n <= 0)
6198             {
6199                 process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
6200                 return cStatusSoftFailure;
6201             }
6202
6203             vogl::growable_array<GLint64, 16> temp_params(n + 1);
6204             temp_params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC;
6205
6206             GLint64 *pReplay_params = temp_params.get_ptr();
6207
6208             VOGL_REPLAY_CALL_GL_HELPER_glGetQueryObjecti64v;
6209
6210             VOGL_VERIFY(temp_params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC);
6211
6212             break;
6213         }
6214         case VOGL_ENTRYPOINT_glGetQueryObjectui64v:
6215         {
6216             VOGL_REPLAY_LOAD_PARAMS_HELPER_glGetQueryObjectui64v;
6217             VOGL_NOTE_UNUSED(pTrace_params);
6218
6219             id = map_handle(get_shared_state()->m_queries, id);
6220
6221             int n = g_gl_enums.get_pname_count(pname);
6222             if (n <= 0)
6223             {
6224                 process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
6225                 return cStatusSoftFailure;
6226             }
6227
6228             vogl::growable_array<GLuint64, 16> temp_params(n + 1);
6229             temp_params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC;
6230
6231             GLuint64 *pReplay_params = temp_params.get_ptr();
6232
6233             VOGL_REPLAY_CALL_GL_HELPER_glGetQueryObjectui64v;
6234
6235             VOGL_VERIFY(temp_params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC);
6236
6237             break;
6238         }
6239         case VOGL_ENTRYPOINT_glBindBuffer:
6240         case VOGL_ENTRYPOINT_glBindBufferARB:
6241         {
6242             GLenum target = trace_packet.get_param_value<GLenum>(0);
6243             GLuint trace_handle = trace_packet.get_param_value<GLuint>(1);
6244             GLuint replay_handle = map_handle(get_shared_state()->m_buffers, trace_handle);
6245
6246             check_gl_error();
6247
6248             SWITCH_GL_ENTRYPOINT2_VOID(glBindBuffer, glBindBufferARB, target, replay_handle);
6249
6250             if (check_gl_error())
6251                 return cStatusGLError;
6252
6253             if ((trace_handle) && (get_context_state()->m_current_display_list_mode != GL_COMPILE))
6254             {
6255                 GLuint *pBinding = get_shared_state()->m_buffer_targets.find_value(trace_handle);
6256                 if (!pBinding)
6257                     process_entrypoint_error("%s: Couldn't find trace buffer handle 0x%X in buffer target map!\n", VOGL_METHOD_NAME, trace_handle);
6258                 else if (*pBinding == GL_NONE)
6259                     *pBinding = target;
6260             }
6261
6262             break;
6263         }
6264         case VOGL_ENTRYPOINT_glBindBufferBase:
6265         case VOGL_ENTRYPOINT_glBindBufferBaseEXT:
6266         case VOGL_ENTRYPOINT_glBindBufferBaseNV:
6267         {
6268             VOGL_REPLAY_LOAD_PARAMS_HELPER_glBindBufferBase;
6269
6270             GLuint trace_buffer = buffer;
6271             buffer = map_handle(get_shared_state()->m_buffers, buffer);
6272
6273             check_gl_error();
6274
6275             if (entrypoint_id == VOGL_ENTRYPOINT_glBindBufferBaseNV)
6276                 VOGL_REPLAY_CALL_GL_HELPER_glBindBufferBaseNV;
6277             else if (entrypoint_id == VOGL_ENTRYPOINT_glBindBufferBaseEXT)
6278                 VOGL_REPLAY_CALL_GL_HELPER_glBindBufferBaseEXT;
6279             else
6280                 VOGL_REPLAY_CALL_GL_HELPER_glBindBufferBase;
6281
6282             if (check_gl_error())
6283                 return cStatusGLError;
6284
6285             if ((trace_buffer) && (get_context_state()->m_current_display_list_mode != GL_COMPILE))
6286             {
6287                 GLuint *pBinding = get_shared_state()->m_buffer_targets.find_value(trace_buffer);
6288                 if (!pBinding)
6289                     process_entrypoint_error("%s: Couldn't find trace buffer handle 0x%X in buffer target map!\n", VOGL_METHOD_NAME, trace_buffer);
6290                 else if (*pBinding == GL_NONE)
6291                     *pBinding = target;
6292             }
6293
6294             break;
6295         }
6296         case VOGL_ENTRYPOINT_glBindBufferRange:
6297         case VOGL_ENTRYPOINT_glBindBufferRangeEXT:
6298         case VOGL_ENTRYPOINT_glBindBufferRangeNV:
6299         {
6300             VOGL_REPLAY_LOAD_PARAMS_HELPER_glBindBufferRange;
6301
6302             GLuint trace_buffer = buffer;
6303             buffer = map_handle(get_shared_state()->m_buffers, buffer);
6304
6305             check_gl_error();
6306
6307             if (entrypoint_id == VOGL_ENTRYPOINT_glBindBufferRangeNV)
6308                 VOGL_REPLAY_CALL_GL_HELPER_glBindBufferRangeNV;
6309             else if (entrypoint_id == VOGL_ENTRYPOINT_glBindBufferRangeEXT)
6310                 VOGL_REPLAY_CALL_GL_HELPER_glBindBufferRangeEXT;
6311             else
6312                 VOGL_REPLAY_CALL_GL_HELPER_glBindBufferRange;
6313
6314             if (check_gl_error())
6315                 return cStatusGLError;
6316
6317             if ((trace_buffer) && (get_context_state()->m_current_display_list_mode != GL_COMPILE))
6318             {
6319                 GLuint *pBinding = get_shared_state()->m_buffer_targets.find_value(trace_buffer);
6320                 if (!pBinding)
6321                     process_entrypoint_error("%s: Couldn't find trace buffer handle 0x%X in buffer target map!\n", VOGL_METHOD_NAME, trace_buffer);
6322                 else if (*pBinding == GL_NONE)
6323                     *pBinding = target;
6324             }
6325
6326             break;
6327         }
6328         case VOGL_ENTRYPOINT_glFenceSync:
6329         {
6330             vogl_sync_ptr_value trace_handle = trace_packet.get_return_ptr_value();
6331             if (trace_handle)
6332             {
6333                 GLsync replay_handle = GL_ENTRYPOINT(glFenceSync)(trace_packet.get_param_value<GLenum>(0), trace_packet.get_param_value<GLbitfield>(1));
6334                 if (!replay_handle)
6335                 {
6336                     process_entrypoint_error("%s: glFenceSync on trace handle 0x%" PRIX64 " succeeded in the trace, but failed during replay!\n", VOGL_METHOD_NAME, trace_handle);
6337                     return cStatusHardFailure;
6338                 }
6339                 else
6340                 {
6341                     get_shared_state()->m_syncs.insert(trace_handle, replay_handle);
6342                 }
6343             }
6344
6345             break;
6346         }
6347         case VOGL_ENTRYPOINT_glWaitSync:
6348         case VOGL_ENTRYPOINT_glClientWaitSync:
6349         {
6350             vogl_sync_ptr_value trace_sync = trace_packet.get_param_ptr_value(0);
6351             GLsync replay_sync = NULL;
6352
6353             gl_sync_hash_map::const_iterator it = get_shared_state()->m_syncs.find(trace_sync);
6354             if (it == get_shared_state()->m_syncs.end())
6355             {
6356                 if (trace_sync)
6357                 {
6358                     process_entrypoint_error("%s: Unable to map trace sync handle 0x%" PRIX64 " to GL handle\n", VOGL_METHOD_NAME, trace_sync);
6359                     return cStatusHardFailure;
6360                 }
6361             }
6362             else
6363             {
6364                 replay_sync = it->second;
6365             }
6366
6367             if (entrypoint_id == VOGL_ENTRYPOINT_glWaitSync)
6368                 GL_ENTRYPOINT(glWaitSync)(replay_sync, trace_packet.get_param_value<GLbitfield>(1), trace_packet.get_param_value<GLuint64>(2));
6369             else
6370                 GL_ENTRYPOINT(glClientWaitSync)(replay_sync, trace_packet.get_param_value<GLbitfield>(1), trace_packet.get_param_value<GLuint64>(2));
6371
6372             break;
6373         }
6374         case VOGL_ENTRYPOINT_glDeleteSync:
6375         {
6376             vogl_sync_ptr_value trace_sync = trace_packet.get_param_ptr_value(0);
6377             GLsync replay_sync = NULL;
6378
6379             gl_sync_hash_map::const_iterator it = get_shared_state()->m_syncs.find(trace_sync);
6380             if (it == get_shared_state()->m_syncs.end())
6381             {
6382                 if (trace_sync)
6383                 {
6384                     process_entrypoint_error("%s: Unable to map trace sync handle 0x%" PRIX64 " to GL handle\n", VOGL_METHOD_NAME, trace_sync);
6385                     return cStatusHardFailure;
6386                 }
6387             }
6388             else
6389             {
6390                 replay_sync = it->second;
6391             }
6392
6393             GL_ENTRYPOINT(glDeleteSync)(replay_sync);
6394
6395             if (trace_sync)
6396             {
6397                 get_shared_state()->m_syncs.erase(trace_sync);
6398             }
6399
6400             break;
6401         }
6402         case VOGL_ENTRYPOINT_glVertexPointer:
6403         {
6404             vertex_array_helper(trace_packet.get_param_value<GLint>(0), trace_packet.get_param_value<GLenum>(1), trace_packet.get_param_value<GLsizei>(2), trace_packet.get_param_ptr_value(3),
6405                                 vogl_vertex_pointer_array_id, GL_ENTRYPOINT(glVertexPointer), m_client_side_array_data[vogl_vertex_pointer_array_id]);
6406             break;
6407         }
6408         case VOGL_ENTRYPOINT_glVertexPointerEXT:
6409         {
6410             VOGL_REPLAY_LOAD_PARAMS_HELPER_glVertexPointerEXT;
6411             VOGL_NOTE_UNUSED(pTrace_pointer);
6412
6413             vertex_array_helper_count(size, type, stride, count, trace_packet.get_param_ptr_value(4), vogl_vertex_pointer_array_id, GL_ENTRYPOINT(glVertexPointerEXT), m_client_side_array_data[vogl_vertex_pointer_array_id]);
6414             break;
6415         }
6416         case VOGL_ENTRYPOINT_glColorPointer:
6417         {
6418             vertex_array_helper(trace_packet.get_param_value<GLint>(0), trace_packet.get_param_value<GLenum>(1), trace_packet.get_param_value<GLsizei>(2), trace_packet.get_param_ptr_value(3),
6419                                 vogl_color_pointer_array_id, GL_ENTRYPOINT(glColorPointer), m_client_side_array_data[vogl_color_pointer_array_id]);
6420             break;
6421         }
6422         case VOGL_ENTRYPOINT_glColorPointerEXT:
6423         {
6424             VOGL_REPLAY_LOAD_PARAMS_HELPER_glColorPointerEXT;
6425             VOGL_NOTE_UNUSED(pTrace_pointer);
6426
6427             vertex_array_helper_count(size, type, stride, count, trace_packet.get_param_ptr_value(4), vogl_color_pointer_array_id, GL_ENTRYPOINT(glColorPointerEXT), m_client_side_array_data[vogl_color_pointer_array_id]);
6428             break;
6429         }
6430         case VOGL_ENTRYPOINT_glSecondaryColorPointer:
6431         {
6432             vertex_array_helper(trace_packet.get_param_value<GLint>(0), trace_packet.get_param_value<GLenum>(1), trace_packet.get_param_value<GLsizei>(2), trace_packet.get_param_ptr_value(3),
6433                                 vogl_secondary_color_pointer_array_id, GL_ENTRYPOINT(glSecondaryColorPointer), m_client_side_array_data[vogl_secondary_color_pointer_array_id]);
6434             break;
6435         }
6436         case VOGL_ENTRYPOINT_glSecondaryColorPointerEXT:
6437         {
6438             vertex_array_helper(trace_packet.get_param_value<GLint>(0), trace_packet.get_param_value<GLenum>(1), trace_packet.get_param_value<GLsizei>(2), trace_packet.get_param_ptr_value(3),
6439                                 vogl_secondary_color_pointer_array_id, GL_ENTRYPOINT(glSecondaryColorPointerEXT), m_client_side_array_data[vogl_secondary_color_pointer_array_id]);
6440             break;
6441         }
6442         case VOGL_ENTRYPOINT_glTexCoordPointer:
6443         {
6444             GLint cur_client_active_texture = 0;
6445             GL_ENTRYPOINT(glGetIntegerv)(GL_CLIENT_ACTIVE_TEXTURE, &cur_client_active_texture);
6446
6447             int tex_index = cur_client_active_texture - GL_TEXTURE0;
6448             if ((tex_index < 0) || (tex_index >= VOGL_MAX_SUPPORTED_GL_TEXCOORD_ARRAYS))
6449             {
6450                 process_entrypoint_error("%s: glTexCoordPointer/glTexCoordPointerEXT called with an invalid or unsupported client active texture (0x%08X)\n", VOGL_METHOD_NAME, cur_client_active_texture);
6451                 return cStatusSoftFailure;
6452             }
6453
6454             vertex_array_helper(trace_packet.get_param_value<GLint>(0), trace_packet.get_param_value<GLenum>(1), trace_packet.get_param_value<GLsizei>(2), trace_packet.get_param_ptr_value(3),
6455                                 vogl_texcoord_pointer_array_id, GL_ENTRYPOINT(glTexCoordPointer), m_client_side_texcoord_data[tex_index]);
6456             break;
6457         }
6458         case VOGL_ENTRYPOINT_glTexCoordPointerEXT:
6459         {
6460             VOGL_REPLAY_LOAD_PARAMS_HELPER_glTexCoordPointerEXT;
6461             VOGL_NOTE_UNUSED(pTrace_pointer);
6462
6463             GLint cur_client_active_texture = 0;
6464             GL_ENTRYPOINT(glGetIntegerv)(GL_CLIENT_ACTIVE_TEXTURE, &cur_client_active_texture);
6465
6466             int tex_index = cur_client_active_texture - GL_TEXTURE0;
6467             if ((tex_index < 0) || (tex_index >= VOGL_MAX_SUPPORTED_GL_TEXCOORD_ARRAYS))
6468             {
6469                 process_entrypoint_error("%s: glTexCoordPointer/glTexCoordPointerEXT called with an invalid or unsupported client active texture (0x%08X)\n", VOGL_METHOD_NAME, cur_client_active_texture);
6470                 return cStatusSoftFailure;
6471             }
6472
6473             vertex_array_helper_count(size, type, stride, count, trace_packet.get_param_ptr_value(4), vogl_texcoord_pointer_array_id, GL_ENTRYPOINT(glTexCoordPointerEXT), m_client_side_texcoord_data[tex_index]);
6474             break;
6475         }
6476         case VOGL_ENTRYPOINT_glFogCoordPointer:
6477         {
6478             vertex_array_helper_no_size(trace_packet.get_param_value<GLenum>(0), trace_packet.get_param_value<GLsizei>(1), trace_packet.get_param_ptr_value(2),
6479                                         vogl_fog_coord_pointer_array_id, GL_ENTRYPOINT(glFogCoordPointer));
6480             break;
6481         }
6482         case VOGL_ENTRYPOINT_glFogCoordPointerEXT:
6483         {
6484             vertex_array_helper_no_size(trace_packet.get_param_value<GLenum>(0), trace_packet.get_param_value<GLsizei>(1), trace_packet.get_param_ptr_value(2),
6485                                         vogl_fog_coord_pointer_array_id, GL_ENTRYPOINT(glFogCoordPointerEXT));
6486             break;
6487         }
6488         case VOGL_ENTRYPOINT_glIndexPointer:
6489         {
6490             vertex_array_helper_no_size(trace_packet.get_param_value<GLenum>(0), trace_packet.get_param_value<GLsizei>(1), trace_packet.get_param_ptr_value(2),
6491                                         vogl_index_pointer_array_id, GL_ENTRYPOINT(glIndexPointer));
6492             break;
6493         }
6494         case VOGL_ENTRYPOINT_glIndexPointerEXT:
6495         {
6496             VOGL_REPLAY_LOAD_PARAMS_HELPER_glIndexPointerEXT;
6497             VOGL_NOTE_UNUSED(pTrace_pointer);
6498
6499             vertex_array_helper_no_size_count(type, stride, count, trace_packet.get_param_ptr_value(3), vogl_index_pointer_array_id, GL_ENTRYPOINT(glIndexPointerEXT));
6500             break;
6501         }
6502         case VOGL_ENTRYPOINT_glNormalPointer:
6503         {
6504             vertex_array_helper_no_size(trace_packet.get_param_value<GLenum>(0), trace_packet.get_param_value<GLsizei>(1), trace_packet.get_param_ptr_value(2),
6505                                         vogl_normal_pointer_array_id, GL_ENTRYPOINT(glNormalPointer));
6506             break;
6507         }
6508         case VOGL_ENTRYPOINT_glNormalPointerEXT:
6509         {
6510             VOGL_REPLAY_LOAD_PARAMS_HELPER_glNormalPointerEXT;
6511             VOGL_NOTE_UNUSED(pTrace_pointer);
6512
6513             vertex_array_helper_no_size_count(type, stride, count, trace_packet.get_param_ptr_value(3), vogl_normal_pointer_array_id, GL_ENTRYPOINT(glNormalPointerEXT));
6514             break;
6515         }
6516         case VOGL_ENTRYPOINT_glEdgeFlagPointer:
6517         {
6518             vertex_array_helper_no_type_no_size(trace_packet.get_param_value<GLsizei>(0), trace_packet.get_param_ptr_value(1),
6519                                                 vogl_edge_flag_pointer_array_id, GL_ENTRYPOINT(glEdgeFlagPointer));
6520             break;
6521         }
6522         case VOGL_ENTRYPOINT_glEdgeFlagPointerEXT:
6523         {
6524             VOGL_REPLAY_LOAD_PARAMS_HELPER_glEdgeFlagPointerEXT;
6525             VOGL_NOTE_UNUSED(pTrace_pointer);
6526
6527             vertex_array_helper_no_type_no_size_count(stride, count, trace_packet.get_param_ptr_value(2), vogl_edge_flag_pointer_array_id, GL_ENTRYPOINT(glEdgeFlagPointerEXT));
6528             break;
6529         }
6530         case VOGL_ENTRYPOINT_glInterleavedArrays:
6531         {
6532             // TODO: Test this more!
6533             GLenum format = trace_packet.get_param_value<GLenum>(0);
6534             GLsizei stride = trace_packet.get_param_value<GLsizei>(1);
6535             const vogl_trace_ptr_value trace_pointer_value = trace_packet.get_param_ptr_value(2);
6536
6537             uint fmt_index;
6538             for (fmt_index = 0; fmt_index < VOGL_INTERLEAVED_ARRAY_SIZE; fmt_index++)
6539                 if (format == vogl_g_interleaved_array_descs[fmt_index].fmt)
6540                     break;
6541             if (fmt_index == VOGL_INTERLEAVED_ARRAY_SIZE)
6542             {
6543                 process_entrypoint_error("%s: Invalid interleaved vertex format: 0x%X \n", VOGL_METHOD_NAME, format);
6544                 return cStatusSoftFailure;
6545             }
6546
6547             if (stride < 0)
6548             {
6549                 process_entrypoint_error("%s: Invalid interleaved vertex stride: %i\n", VOGL_METHOD_NAME, static_cast<int>(stride));
6550                 return cStatusSoftFailure;
6551             }
6552
6553             const interleaved_array_desc_entry_t &fmt = vogl_g_interleaved_array_descs[fmt_index];
6554
6555             if (!stride)
6556             {
6557                 stride = fmt.s;
6558                 VOGL_ASSERT(stride > 0);
6559             }
6560
6561             GL_ENTRYPOINT(glDisableClientState)(GL_EDGE_FLAG_ARRAY);
6562             GL_ENTRYPOINT(glDisableClientState)(GL_INDEX_ARRAY);
6563             GL_ENTRYPOINT(glDisableClientState)(GL_SECONDARY_COLOR_ARRAY);
6564             GL_ENTRYPOINT(glDisableClientState)(GL_FOG_COORD_ARRAY);
6565
6566             check_gl_error();
6567
6568             if (fmt.et)
6569             {
6570                 GLint cur_client_active_texture = 0;
6571                 GL_ENTRYPOINT(glGetIntegerv)(GL_CLIENT_ACTIVE_TEXTURE, &cur_client_active_texture);
6572
6573                 int tex_index = cur_client_active_texture - GL_TEXTURE0;
6574                 if ((tex_index < 0) || (tex_index >= VOGL_MAX_SUPPORTED_GL_TEXCOORD_ARRAYS))
6575                 {
6576                     process_entrypoint_error("%s: glInterleavedArrays called with an invalid or unsupported client active texture (0x%08X)\n", VOGL_METHOD_NAME, cur_client_active_texture);
6577                     return cStatusSoftFailure;
6578                 }
6579
6580                 GL_ENTRYPOINT(glEnableClientState)(GL_TEXTURE_COORD_ARRAY);
6581                 vertex_array_helper(fmt.st, GL_FLOAT, stride, trace_pointer_value,
6582                                     vogl_texcoord_pointer_array_id, GL_ENTRYPOINT(glTexCoordPointer), m_client_side_texcoord_data[tex_index]);
6583             }
6584             else
6585             {
6586                 GL_ENTRYPOINT(glDisableClientState)(GL_TEXTURE_COORD_ARRAY);
6587             }
6588
6589             check_gl_error();
6590
6591             if (fmt.ec)
6592             {
6593                 GL_ENTRYPOINT(glEnableClientState)(GL_COLOR_ARRAY);
6594                 vertex_array_helper(fmt.sc, fmt.tc, stride, trace_pointer_value + fmt.pc,
6595                                     vogl_color_pointer_array_id, GL_ENTRYPOINT(glColorPointer), m_client_side_array_data[vogl_color_pointer_array_id]);
6596             }
6597             else
6598             {
6599                 GL_ENTRYPOINT(glDisableClientState)(GL_COLOR_ARRAY);
6600             }
6601
6602             check_gl_error();
6603
6604             if (fmt.en)
6605             {
6606                 GL_ENTRYPOINT(glEnableClientState)(GL_NORMAL_ARRAY);
6607                 vertex_array_helper_no_size(GL_FLOAT, stride, trace_pointer_value + fmt.pn,
6608                                             vogl_normal_pointer_array_id, GL_ENTRYPOINT(glNormalPointer));
6609             }
6610             else
6611             {
6612                 GL_ENTRYPOINT(glDisableClientState)(GL_NORMAL_ARRAY);
6613             }
6614
6615             check_gl_error();
6616
6617             GL_ENTRYPOINT(glEnableClientState)(GL_VERTEX_ARRAY);
6618             vertex_array_helper(fmt.sv, GL_FLOAT, stride, trace_pointer_value + fmt.pv,
6619                                 vogl_vertex_pointer_array_id, GL_ENTRYPOINT(glVertexPointer), m_client_side_array_data[vogl_vertex_pointer_array_id]);
6620
6621             break;
6622         }
6623         case VOGL_ENTRYPOINT_glVertexAttribIPointer:
6624         case VOGL_ENTRYPOINT_glVertexAttribIPointerEXT:
6625         {
6626             GLuint index = trace_packet.get_param_value<GLuint>(0);
6627             GLint size = trace_packet.get_param_value<GLint>(1);
6628             GLenum type = trace_packet.get_param_value<GLenum>(2);
6629             GLsizei stride = trace_packet.get_param_value<GLsizei>(3);
6630             vogl_trace_ptr_value trace_pointer = trace_packet.get_param_ptr_value(4);
6631
6632             if (index >= m_pCur_context_state->m_context_info.get_max_vertex_attribs())
6633             {
6634                 process_entrypoint_error("%s: Generic vertex attribute index is too large\n", VOGL_METHOD_NAME);
6635                 return cStatusSoftFailure;
6636             }
6637
6638             GLuint buffer = vogl_get_bound_gl_buffer(GL_ARRAY_BUFFER);
6639             void *pPtr = reinterpret_cast<void *>(trace_pointer);
6640             if ((!buffer) && (trace_pointer))
6641             {
6642                 // We've got a trace pointer to client side memory, but we don't have it until the actual draw.
6643                 // So point this guy into one of our client size memory buffers that's hopefully large enough.
6644                 if (!m_client_side_vertex_attrib_data[index].size())
6645                 {
6646                     m_client_side_vertex_attrib_data[index].resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
6647                 }
6648                 pPtr = m_client_side_vertex_attrib_data[index].get_ptr();
6649             }
6650
6651             if (entrypoint_id == VOGL_ENTRYPOINT_glVertexAttribIPointer)
6652                 GL_ENTRYPOINT(glVertexAttribIPointer)(index, size, type, stride, pPtr);
6653             else
6654                 GL_ENTRYPOINT(glVertexAttribIPointerEXT)(index, size, type, stride, pPtr);
6655
6656             break;
6657         }
6658         case VOGL_ENTRYPOINT_glVertexAttribPointerARB:
6659         case VOGL_ENTRYPOINT_glVertexAttribPointer:
6660         {
6661             GLuint index = trace_packet.get_param_value<GLuint>(0);
6662             GLint size = trace_packet.get_param_value<GLint>(1);
6663             GLenum type = trace_packet.get_param_value<GLenum>(2);
6664             GLboolean normalized = trace_packet.get_param_value<GLboolean>(3);
6665             GLsizei stride = trace_packet.get_param_value<GLsizei>(4);
6666             vogl_trace_ptr_value trace_pointer = trace_packet.get_param_ptr_value(5);
6667
6668             if (index >= m_pCur_context_state->m_context_info.get_max_vertex_attribs())
6669             {
6670                 process_entrypoint_error("%s: Generic vertex attribute index is too large\n", VOGL_METHOD_NAME);
6671                 return cStatusSoftFailure;
6672             }
6673
6674             GLuint buffer = vogl_get_bound_gl_buffer(GL_ARRAY_BUFFER);
6675             void *pPtr = reinterpret_cast<void *>(trace_pointer);
6676             if ((!buffer) && (trace_pointer))
6677             {
6678                 // We've got a trace pointer to client side memory, but we don't have it until the actual draw.
6679                 // So point this guy into one of our client size memory buffers that's hopefully large enough.
6680                 if (!m_client_side_vertex_attrib_data[index].size())
6681                 {
6682                     m_client_side_vertex_attrib_data[index].resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
6683                 }
6684                 pPtr = m_client_side_vertex_attrib_data[index].get_ptr();
6685             }
6686
6687             if (entrypoint_id == VOGL_ENTRYPOINT_glVertexAttribPointer)
6688                 GL_ENTRYPOINT(glVertexAttribPointer)(index, size, type, normalized, stride, pPtr);
6689             else
6690                 GL_ENTRYPOINT(glVertexAttribPointerARB)(index, size, type, normalized, stride, pPtr);
6691
6692             break;
6693         }
6694         case VOGL_ENTRYPOINT_glDrawRangeElements:
6695         case VOGL_ENTRYPOINT_glDrawRangeElementsEXT:
6696         {
6697             GLenum mode = trace_packet.get_param_value<GLenum>(0);
6698             GLuint start = trace_packet.get_param_value<GLuint>(1);
6699             GLuint end = trace_packet.get_param_value<GLuint>(2);
6700             GLsizei count = trace_packet.get_param_value<GLsizei>(3);
6701             GLenum type = trace_packet.get_param_value<GLenum>(4);
6702             vogl_trace_ptr_value trace_indices_ptr_value = trace_packet.get_param_ptr_value(5);
6703
6704             const GLvoid *pIndices;
6705             if (!draw_elements_client_side_array_setup(mode, start, end, count, type, trace_indices_ptr_value, pIndices, 0, true, true))
6706                 return cStatusSoftFailure;
6707
6708             if (m_frame_draw_counter < m_frame_draw_counter_kill_threshold)
6709             {
6710                 if (entrypoint_id == VOGL_ENTRYPOINT_glDrawRangeElements)
6711                     GL_ENTRYPOINT(glDrawRangeElements)(mode, start, end, count, type, pIndices);
6712                 else
6713                     GL_ENTRYPOINT(glDrawRangeElementsEXT)(mode, start, end, count, type, pIndices);
6714             }
6715
6716             break;
6717         }
6718         case VOGL_ENTRYPOINT_glDrawRangeElementsBaseVertex:
6719         {
6720             GLenum mode = trace_packet.get_param_value<GLenum>(0);
6721             GLuint start = trace_packet.get_param_value<GLuint>(1);
6722             GLuint end = trace_packet.get_param_value<GLuint>(2);
6723             GLsizei count = trace_packet.get_param_value<GLsizei>(3);
6724             GLenum type = trace_packet.get_param_value<GLenum>(4);
6725             vogl_trace_ptr_value trace_indices_ptr_value = trace_packet.get_param_ptr_value(5);
6726             GLint basevertex = trace_packet.get_param_value<GLint>(6);
6727
6728             const GLvoid *pIndices;
6729             if (!draw_elements_client_side_array_setup(mode, start, end, count, type, trace_indices_ptr_value, pIndices, basevertex, true, true))
6730                 return cStatusSoftFailure;
6731
6732             if (m_frame_draw_counter < m_frame_draw_counter_kill_threshold)
6733             {
6734                 GL_ENTRYPOINT(glDrawRangeElementsBaseVertex)(mode, start, end, count, type, pIndices, basevertex);
6735             }
6736
6737             break;
6738         }
6739         case VOGL_ENTRYPOINT_glDrawElements:
6740         {
6741             GLenum mode = trace_packet.get_param_value<GLenum>(0);
6742             GLsizei count = trace_packet.get_param_value<GLsizei>(1);
6743             GLenum type = trace_packet.get_param_value<GLenum>(2);
6744             vogl_trace_ptr_value trace_indices_ptr_value = trace_packet.get_param_ptr_value(3);
6745
6746             const GLvoid *pIndices;
6747             if (!draw_elements_client_side_array_setup(mode, 0, 0, count, type, trace_indices_ptr_value, pIndices, 0, false, true))
6748                 return cStatusSoftFailure;
6749
6750             if (m_frame_draw_counter < m_frame_draw_counter_kill_threshold)
6751             {
6752                 GL_ENTRYPOINT(glDrawElements)(mode, count, type, pIndices);
6753             }
6754
6755             break;
6756         }
6757         case VOGL_ENTRYPOINT_glDrawArraysInstanced:
6758         case VOGL_ENTRYPOINT_glDrawArraysInstancedEXT:
6759         {
6760             VOGL_REPLAY_LOAD_PARAMS_HELPER_glDrawArraysInstanced;
6761
6762             const GLvoid *pIndices = NULL;
6763             if (!draw_elements_client_side_array_setup(mode, first, first + count - 1, count, GL_UNSIGNED_BYTE, 0, pIndices, 0, true, false))
6764                 return cStatusSoftFailure;
6765
6766             if (entrypoint_id == VOGL_ENTRYPOINT_glDrawArraysInstancedEXT)
6767             {
6768                 GLsizei start = first, primcount = instancecount;
6769                 VOGL_REPLAY_CALL_GL_HELPER_glDrawArraysInstancedEXT;
6770             }
6771             else
6772                 VOGL_REPLAY_CALL_GL_HELPER_glDrawArraysInstanced;
6773
6774             break;
6775         }
6776         case VOGL_ENTRYPOINT_glDrawArrays:
6777         case VOGL_ENTRYPOINT_glDrawArraysEXT:
6778         {
6779             GLenum mode = trace_packet.get_param_value<GLenum>(0);
6780             GLint first = trace_packet.get_param_value<GLint>(1);
6781             GLsizei count = trace_packet.get_param_value<GLsizei>(2);
6782
6783             const GLvoid *pIndices = NULL;
6784             if (!draw_elements_client_side_array_setup(mode, first, first + count - 1, count, GL_UNSIGNED_BYTE, 0, pIndices, 0, true, false))
6785                 return cStatusSoftFailure;
6786
6787             if (m_frame_draw_counter < m_frame_draw_counter_kill_threshold)
6788             {
6789                 if (entrypoint_id == VOGL_ENTRYPOINT_glDrawArraysEXT)
6790                     GL_ENTRYPOINT(glDrawArraysEXT)(mode, first, count);
6791                 else
6792                     GL_ENTRYPOINT(glDrawArrays)(mode, first, count);
6793             }
6794
6795             break;
6796         }
6797         case VOGL_ENTRYPOINT_glDrawElementsInstanced:
6798         case VOGL_ENTRYPOINT_glDrawElementsInstancedARB:
6799         case VOGL_ENTRYPOINT_glDrawElementsInstancedEXT:
6800         {
6801             GLenum mode = trace_packet.get_param_value<GLenum>(0);
6802             GLsizei count = trace_packet.get_param_value<GLsizei>(1);
6803             GLenum type = trace_packet.get_param_value<GLenum>(2);
6804             vogl_trace_ptr_value trace_indices_ptr_value = trace_packet.get_param_ptr_value(3);
6805             GLsizei primcount = trace_packet.get_param_value<GLsizei>(4);
6806
6807             const GLvoid *pIndices;
6808             if (!draw_elements_client_side_array_setup(mode, 0, 0, count, type, trace_indices_ptr_value, pIndices, 0, false, true))
6809                 return cStatusSoftFailure;
6810
6811             if (m_frame_draw_counter < m_frame_draw_counter_kill_threshold)
6812             {
6813                 if (entrypoint_id == VOGL_ENTRYPOINT_glDrawElementsInstanced)
6814                     GL_ENTRYPOINT(glDrawElementsInstanced)(mode, count, type, pIndices, primcount);
6815                 else if (entrypoint_id == VOGL_ENTRYPOINT_glDrawElementsInstancedEXT)
6816                     GL_ENTRYPOINT(glDrawElementsInstancedEXT)(mode, count, type, pIndices, primcount);
6817                 else
6818                     GL_ENTRYPOINT(glDrawElementsInstancedARB)(mode, count, type, pIndices, primcount);
6819             }
6820
6821             break;
6822         }
6823         case VOGL_ENTRYPOINT_glDrawElementsInstancedBaseVertex:
6824         {
6825             GLenum mode = trace_packet.get_param_value<GLenum>(0);
6826             GLsizei count = trace_packet.get_param_value<GLsizei>(1);
6827             GLenum type = trace_packet.get_param_value<GLenum>(2);
6828             vogl_trace_ptr_value trace_indices_ptr_value = trace_packet.get_param_ptr_value(3);
6829             GLsizei primcount = trace_packet.get_param_value<GLsizei>(4);
6830             GLint basevertex = trace_packet.get_param_value<GLint>(5);
6831
6832             const GLvoid *pIndices;
6833             if (!draw_elements_client_side_array_setup(mode, 0, 0, count, type, trace_indices_ptr_value, pIndices, basevertex, false, true))
6834                 return cStatusSoftFailure;
6835
6836             if (m_frame_draw_counter < m_frame_draw_counter_kill_threshold)
6837             {
6838                 GL_ENTRYPOINT(glDrawElementsInstancedBaseVertex)(mode, count, type, pIndices, primcount, basevertex);
6839             }
6840
6841             break;
6842         }
6843         case VOGL_ENTRYPOINT_glMultiDrawArrays:
6844         case VOGL_ENTRYPOINT_glMultiDrawArraysEXT:
6845         {
6846             GLenum mode = trace_packet.get_param_value<GLenum>(0);
6847
6848             const GLint *pFirst = trace_packet.get_param_client_memory<const GLint>(1);
6849             uint first_size = trace_packet.get_param_client_memory_data_size(1);
6850
6851             const GLsizei *pCount = trace_packet.get_param_client_memory<const GLsizei>(2);
6852             uint count_size = trace_packet.get_param_client_memory_data_size(2);
6853
6854             GLsizei primcount = trace_packet.get_param_value<GLsizei>(3);
6855
6856             if ((first_size != primcount * sizeof(GLint)) || (count_size != primcount * sizeof(GLsizei)))
6857             {
6858                 process_entrypoint_error("%s: first and/or count params do not point to arrays of the expected size\n", VOGL_METHOD_NAME);
6859                 return cStatusSoftFailure;
6860             }
6861
6862             if (m_frame_draw_counter < m_frame_draw_counter_kill_threshold)
6863             {
6864                 //  Multi-draws with client side arrays are not supported for replay.
6865                 if (entrypoint_id == VOGL_ENTRYPOINT_glMultiDrawElements)
6866                     GL_ENTRYPOINT(glMultiDrawArrays)(mode, pFirst, pCount, primcount);
6867                 else
6868                     GL_ENTRYPOINT(glMultiDrawArraysEXT)(mode, pFirst, pCount, primcount);
6869             }
6870
6871             break;
6872         }
6873         case VOGL_ENTRYPOINT_glMultiDrawElements:
6874         case VOGL_ENTRYPOINT_glMultiDrawElementsEXT:
6875         {
6876             GLenum mode = trace_packet.get_param_value<GLenum>(0);
6877
6878             const GLsizei *pCount = trace_packet.get_param_client_memory<const GLsizei>(1);
6879             uint count_size = trace_packet.get_param_client_memory_data_size(1);
6880
6881             GLenum type = trace_packet.get_param_value<GLenum>(2);
6882
6883             const vogl_client_memory_array trace_indices_void_ptr_array = trace_packet.get_param_client_memory_array(3); // const GLvoid *
6884
6885             GLsizei primcount = trace_packet.get_param_value<GLsizei>(4);
6886
6887             if ((count_size != static_cast<uint>(primcount * sizeof(GLsizei))) || (trace_indices_void_ptr_array.size() != static_cast<uint>(primcount)))
6888             {
6889                 process_entrypoint_error("%s: count and/or indices params do not point to arrays of the expected size\n", VOGL_METHOD_NAME);
6890                 return cStatusSoftFailure;
6891             }
6892
6893             vogl::growable_array<GLvoid *, 256> replay_indices(trace_indices_void_ptr_array.size());
6894             for (uint i = 0; i < trace_indices_void_ptr_array.size(); i++)
6895                 replay_indices[i] = reinterpret_cast<GLvoid *>(trace_indices_void_ptr_array.get_element<vogl_trace_ptr_value>(i));
6896
6897             if (m_frame_draw_counter < m_frame_draw_counter_kill_threshold)
6898             {
6899                 //  Multi-draws with client side arrays are not supported for replay.
6900                 if (entrypoint_id == VOGL_ENTRYPOINT_glMultiDrawElements)
6901                     GL_ENTRYPOINT(glMultiDrawElements)(mode, pCount, type, replay_indices.get_ptr(), primcount);
6902                 else
6903                     GL_ENTRYPOINT(glMultiDrawElementsEXT)(mode, pCount, type, (const GLvoid **)replay_indices.get_ptr(), primcount);
6904             }
6905
6906             break;
6907         }
6908         case VOGL_ENTRYPOINT_glMultiDrawElementsBaseVertex:
6909         {
6910             GLenum mode = trace_packet.get_param_value<GLenum>(0);
6911
6912             const GLsizei *pCount = trace_packet.get_param_client_memory<const GLsizei>(1);
6913             uint count_size = trace_packet.get_param_client_memory_data_size(1);
6914
6915             GLenum type = trace_packet.get_param_value<GLenum>(2);
6916
6917             const vogl_client_memory_array trace_indices_void_ptr_array = trace_packet.get_param_client_memory_array(3); // const GLvoid *
6918             //GLvoid * const *ppIndices = trace_packet.get_param_client_memory<GLvoid *>(3);
6919             //uint index_size = trace_packet.get_param_client_memory_data_size(3);
6920
6921             GLsizei primcount = trace_packet.get_param_value<GLsizei>(4);
6922
6923             const GLint *pBase_vertex = trace_packet.get_param_client_memory<const GLint>(5);
6924             uint base_vertex_size = trace_packet.get_param_client_memory_data_size(5);
6925
6926             if ((count_size != primcount * sizeof(GLsizei)) ||
6927                 (trace_indices_void_ptr_array.size() != static_cast<uint>(primcount)) ||
6928                 (base_vertex_size != primcount * sizeof(GLint)))
6929             {
6930                 process_entrypoint_error("%s: count, indices, and/or base_vertex_size params do not point to arrays of the expected size\n", VOGL_METHOD_NAME);
6931                 return cStatusSoftFailure;
6932             }
6933
6934             vogl::growable_array<GLvoid *, 256> replay_indices(trace_indices_void_ptr_array.size());
6935             for (uint i = 0; i < trace_indices_void_ptr_array.size(); i++)
6936                 replay_indices[i] = reinterpret_cast<GLvoid *>(trace_indices_void_ptr_array.get_element<vogl_trace_ptr_value>(i));
6937
6938             if (m_frame_draw_counter < m_frame_draw_counter_kill_threshold)
6939             {
6940                 //  Multi-draws with client side arrays are not supported for replay.
6941                 GL_ENTRYPOINT(glMultiDrawElementsBaseVertex)(mode, pCount, type, replay_indices.get_ptr(), primcount, pBase_vertex);
6942             }
6943
6944             break;
6945         }
6946         case VOGL_ENTRYPOINT_glDrawElementsBaseVertex:
6947         {
6948             GLenum mode = trace_packet.get_param_value<GLenum>(0);
6949             GLsizei count = trace_packet.get_param_value<GLsizei>(1);
6950             GLenum type = trace_packet.get_param_value<GLenum>(2);
6951             vogl_trace_ptr_value trace_indices_ptr_value = trace_packet.get_param_ptr_value(3);
6952             GLint base_vertex = trace_packet.get_param_value<GLint>(4);
6953
6954             const GLvoid *pIndices;
6955             if (!draw_elements_client_side_array_setup(mode, 0, 0, count, type, trace_indices_ptr_value, pIndices, base_vertex, false, true))
6956                 return cStatusSoftFailure;
6957
6958             if (m_frame_draw_counter < m_frame_draw_counter_kill_threshold)
6959             {
6960                 GL_ENTRYPOINT(glDrawElementsBaseVertex)(mode, count, type, pIndices, base_vertex);
6961             }
6962
6963             break;
6964         }
6965         case VOGL_ENTRYPOINT_glGetBufferSubData:
6966         {
6967             if (!benchmark_mode())
6968             {
6969                 GLenum target = trace_packet.get_param_value<GLenum>(0);
6970                 vogl_trace_ptr_value offset = trace_packet.get_param_ptr_value(1);
6971                 vogl_trace_ptr_value size = trace_packet.get_param_ptr_value(2);
6972                 GLvoid *pTrace_ptr = trace_packet.get_param_client_memory<GLvoid>(3);
6973
6974                 if (offset != static_cast<uintptr_t>(offset))
6975                 {
6976                     process_entrypoint_error("%s: offset parameter is too large (%" PRIu64 ")\n", VOGL_METHOD_NAME, (uint64_t)offset);
6977                     return cStatusHardFailure;
6978                 }
6979
6980                 if ((size > cUINT32_MAX) || (size != static_cast<uintptr_t>(size)))
6981                 {
6982                     process_entrypoint_error("%s: size parameter is too large (%" PRIu64 ")\n", VOGL_METHOD_NAME, (uint64_t)size);
6983                     return cStatusHardFailure;
6984                 }
6985
6986                 vogl::growable_array<uint8, 1024> buf(pTrace_ptr ? static_cast<uint>(size) : 0);
6987
6988                 GL_ENTRYPOINT(glGetBufferSubData)(target, static_cast<GLintptr>(offset), static_cast<GLsizeiptr>(size), pTrace_ptr ? buf.get_ptr() : NULL);
6989
6990                 if ((buf.size()) && (pTrace_ptr))
6991                 {
6992                     if (memcmp(buf.get_ptr(), pTrace_ptr, static_cast<size_t>(size)) != 0)
6993                     {
6994                         process_entrypoint_warning("%s: Replay's returned data differed from trace's\n", VOGL_METHOD_NAME);
6995                     }
6996                 }
6997             }
6998
6999             break;
7000         }
7001         case VOGL_ENTRYPOINT_glGetClipPlane:
7002         {
7003             if (!benchmark_mode())
7004             {
7005                 GLenum plane = trace_packet.get_param_value<GLenum>(0);
7006                 const GLdouble *pTrace_equation = trace_packet.get_param_client_memory<GLdouble>(1);
7007
7008                 GLdouble equation[4];
7009                 GL_ENTRYPOINT(glGetClipPlane)(plane, pTrace_equation ? equation : NULL);
7010
7011                 if (pTrace_equation)
7012                 {
7013                     if (memcmp(equation, pTrace_equation, sizeof(GLdouble) * 4) != 0)
7014                     {
7015                         process_entrypoint_warning("%s: Replay's returned data differed from trace's\n", VOGL_METHOD_NAME);
7016                     }
7017                 }
7018             }
7019
7020             break;
7021         }
7022         case VOGL_ENTRYPOINT_glBufferData:
7023         case VOGL_ENTRYPOINT_glBufferDataARB:
7024         {
7025             GLenum target = trace_packet.get_param_value<GLenum>(0);
7026             vogl_trace_ptr_value size = trace_packet.get_param_value<vogl_trace_ptr_value>(1); // GLsizeiptrARB
7027             const GLvoid *data = trace_packet.get_param_client_memory_ptr(2);
7028             uint data_size = trace_packet.get_param_client_memory_data_size(2);
7029             GLenum usage = trace_packet.get_param_value<GLenum>(3);
7030
7031             if ((data) && (static_cast<vogl_trace_ptr_value>(data_size) < size))
7032             {
7033                 process_entrypoint_error("%s: trace's data array is too small\n", VOGL_METHOD_NAME);
7034                 return cStatusHardFailure;
7035             }
7036
7037             if (size != static_cast<uintptr_t>(size))
7038             {
7039                 process_entrypoint_error("%s: size parameter is too large (%" PRIu64 ")\n", VOGL_METHOD_NAME, static_cast<uint64_t>(size));
7040                 return cStatusHardFailure;
7041             }
7042
7043             if (entrypoint_id == VOGL_ENTRYPOINT_glBufferData)
7044                 g_vogl_actual_gl_entrypoints.m_glBufferData(target, static_cast<GLsizeiptr>(size), data, usage);
7045             else
7046                 g_vogl_actual_gl_entrypoints.m_glBufferDataARB(target, static_cast<GLsizeiptrARB>(size), data, usage);
7047
7048             GLuint buffer = vogl_get_bound_gl_buffer(target);
7049             if (buffer)
7050             {
7051                 uint i;
7052                 for (i = 0; i < get_shared_state()->m_mapped_buffers.size(); i++)
7053                 {
7054                     if (get_shared_state()->m_mapped_buffers[i].m_buffer == buffer)
7055                     {
7056                         process_entrypoint_warning("%s: glBufferData() called on already mapped GL buffer %u, assuming GL will be unmapping it\n", VOGL_METHOD_NAME, buffer);
7057
7058                         get_shared_state()->m_mapped_buffers.erase_unordered(i);
7059                         break;
7060                     }
7061                 }
7062             }
7063
7064             break;
7065         }
7066         case VOGL_ENTRYPOINT_glMapBufferARB:
7067         case VOGL_ENTRYPOINT_glMapBuffer:
7068         {
7069             GLenum target = trace_packet.get_param_value<GLenum>(0);
7070             GLenum access = trace_packet.get_param_value<GLenum>(1);
7071             vogl_trace_ptr_value trace_result_ptr_value = trace_packet.get_return_ptr_value();
7072
7073             // FIXME - must call GL even if !pTrace_result
7074             if (trace_result_ptr_value)
7075             {
7076                 void *pMap;
7077                 if (entrypoint_id == VOGL_ENTRYPOINT_glMapBuffer)
7078                     pMap = GL_ENTRYPOINT(glMapBuffer)(target, access);
7079                 else
7080                     pMap = GL_ENTRYPOINT(glMapBufferARB)(target, access);
7081
7082                 if (!pMap)
7083                 {
7084                     process_entrypoint_error("%s: glMapBuffer succeeded during trace, but failed during replay!\n", VOGL_METHOD_NAME);
7085                     return cStatusHardFailure;
7086                 }
7087
7088                 GLuint buffer = vogl_get_bound_gl_buffer(target);
7089
7090                 uint i;
7091                 for (i = 0; i < get_shared_state()->m_mapped_buffers.size(); i++)
7092                 {
7093                     if (get_shared_state()->m_mapped_buffers[i].m_buffer == buffer)
7094                     {
7095                         process_entrypoint_error("%s: Buffer %u is already mapped\n", VOGL_METHOD_NAME, buffer);
7096                         return cStatusHardFailure;
7097                     }
7098                 }
7099
7100                 if (i == get_shared_state()->m_mapped_buffers.size())
7101                 {
7102                     GLint length = 0;
7103                     GL_ENTRYPOINT(glGetBufferParameteriv)(target, GL_BUFFER_SIZE, &length);
7104
7105                     mapped_buffer_desc m;
7106                     m.m_buffer = buffer;
7107                     m.m_target = target;
7108                     m.m_offset = 0;
7109                     m.m_length = length;
7110                     m.m_access = access;
7111                     m.m_range = false;
7112                     m.m_pPtr = pMap;
7113                     get_shared_state()->m_mapped_buffers.push_back(m);
7114                 }
7115             }
7116
7117             break;
7118         }
7119         case VOGL_ENTRYPOINT_glMapBufferRange:
7120         {
7121             GLenum target = trace_packet.get_param_value<GLenum>(0);
7122             vogl_trace_ptr_value offset = trace_packet.get_param_value<vogl_trace_ptr_value>(1); // GLintptr
7123             vogl_trace_ptr_value length = trace_packet.get_param_value<vogl_trace_ptr_value>(2); // GLsizeiptr
7124             GLbitfield access = trace_packet.get_param_value<GLbitfield>(3);
7125             vogl_trace_ptr_value trace_result_ptr_value = trace_packet.get_return_ptr_value();
7126
7127             if (offset != static_cast<uintptr_t>(offset))
7128             {
7129                 process_entrypoint_error("%s: offset parameter is too large (%" PRIu64 ")\n", VOGL_METHOD_NAME, static_cast<uint64_t>(offset));
7130                 return cStatusHardFailure;
7131             }
7132             if (length != static_cast<uintptr_t>(length))
7133             {
7134                 process_entrypoint_error("%s: length parameter is too large (%" PRIu64 ")\n", VOGL_METHOD_NAME, static_cast<uint64_t>(length));
7135                 return cStatusHardFailure;
7136             }
7137
7138             // FIXME - must call GL even if !pTrace_result
7139             if (trace_result_ptr_value)
7140             {
7141                 void *pMap = GL_ENTRYPOINT(glMapBufferRange)(target, static_cast<GLintptr>(offset), static_cast<GLsizeiptr>(length), access);
7142                 if (!pMap)
7143                 {
7144                     process_entrypoint_error("%s: glMapBufferRange succeeded during trace, but failed during replay!\n", VOGL_METHOD_NAME);
7145                     return cStatusHardFailure;
7146                 }
7147
7148                 GLuint buffer = vogl_get_bound_gl_buffer(target);
7149                 uint i;
7150                 for (i = 0; i < get_shared_state()->m_mapped_buffers.size(); i++)
7151                 {
7152                     if (get_shared_state()->m_mapped_buffers[i].m_buffer == buffer)
7153                     {
7154                         process_entrypoint_error("%s: Buffer %u is already mapped\n", VOGL_METHOD_NAME, buffer);
7155                         return cStatusHardFailure;
7156                     }
7157                 }
7158
7159                 if (i == get_shared_state()->m_mapped_buffers.size())
7160                 {
7161                     mapped_buffer_desc m;
7162                     m.m_buffer = buffer;
7163                     m.m_target = target;
7164                     m.m_offset = offset;
7165                     m.m_length = length;
7166                     m.m_access = access;
7167                     m.m_range = true;
7168                     m.m_pPtr = pMap;
7169                     get_shared_state()->m_mapped_buffers.push_back(m);
7170                 }
7171             }
7172
7173             break;
7174         }
7175         case VOGL_ENTRYPOINT_glFlushMappedBufferRange:
7176         {
7177             // vogltrace queues up the flushes, will process them while handling the glUnmapBuffer() call
7178             break;
7179         }
7180         case VOGL_ENTRYPOINT_glUnmapBufferARB:
7181         case VOGL_ENTRYPOINT_glUnmapBuffer:
7182         {
7183             GLenum target = trace_packet.get_param_value<GLenum>(0);
7184             GLboolean trace_result = trace_packet.get_return_value<GLboolean>();
7185
7186             GLuint buffer = vogl_get_bound_gl_buffer(target);
7187
7188             // FIXME - must call GL even if !buffer
7189             if (buffer)
7190             {
7191                 uint mapped_buffers_index;
7192                 for (mapped_buffers_index = 0; mapped_buffers_index < get_shared_state()->m_mapped_buffers.size(); mapped_buffers_index++)
7193                     if (get_shared_state()->m_mapped_buffers[mapped_buffers_index].m_buffer == buffer)
7194                         break;
7195                 if (mapped_buffers_index == get_shared_state()->m_mapped_buffers.size())
7196                 {
7197                     process_entrypoint_error("%s: Unable to find mapped buffer during unmap\n", VOGL_METHOD_NAME);
7198                     return cStatusHardFailure;
7199                 }
7200
7201                 mapped_buffer_desc &map_desc = get_shared_state()->m_mapped_buffers[mapped_buffers_index];
7202
7203                 bool writable_map = false;
7204                 bool explicit_bit = false;
7205                 if (map_desc.m_range)
7206                 {
7207                     writable_map = ((map_desc.m_access & GL_MAP_WRITE_BIT) != 0);
7208                     explicit_bit = (map_desc.m_access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0;
7209                 }
7210                 else
7211                 {
7212                     writable_map = (map_desc.m_access != GL_READ_ONLY);
7213                 }
7214
7215                 if (writable_map)
7216                 {
7217                     const key_value_map &unmap_data = trace_packet.get_key_value_map();
7218
7219                     if (explicit_bit)
7220                     {
7221                         int num_flushed_ranges = unmap_data.get_int(string_hash("flushed_ranges"));
7222
7223                         for (int i = 0; i < num_flushed_ranges; i++)
7224                         {
7225                             int64_t ofs = unmap_data.get_int64(i * 4 + 0);
7226                             int64_t size = unmap_data.get_int64(i * 4 + 1);
7227                             VOGL_NOTE_UNUSED(size);
7228                             const uint8_vec *pData = unmap_data.get_blob(i * 4 + 2);
7229                             if (!pData)
7230                             {
7231                                 process_entrypoint_error("%s: Failed finding flushed range data in key value map\n", VOGL_METHOD_NAME);
7232                                 return cStatusHardFailure;
7233                             }
7234
7235                             if (ofs != static_cast<GLintptr>(ofs))
7236                             {
7237                                 process_entrypoint_error("%s: Flush offset is too large (%" PRIu64 ")\n", VOGL_METHOD_NAME, static_cast<uint64_t>(ofs));
7238                                 return cStatusHardFailure;
7239                             }
7240
7241                             VOGL_ASSERT(size == pData->size());
7242
7243                             memcpy(static_cast<uint8 *>(map_desc.m_pPtr) + ofs, pData->get_ptr(), pData->size());
7244
7245                             GL_ENTRYPOINT(glFlushMappedBufferRange)(target, static_cast<GLintptr>(ofs), pData->size());
7246                         }
7247                     }
7248                     else
7249                     {
7250                         int64_t ofs = unmap_data.get_int64(0);
7251                         VOGL_NOTE_UNUSED(ofs);
7252                         int64_t size = unmap_data.get_int64(1);
7253                         VOGL_NOTE_UNUSED(size);
7254                         const uint8_vec *pData = unmap_data.get_blob(2);
7255                         if (!pData)
7256                         {
7257                             process_entrypoint_error("%s: Failed finding mapped data in key value map\n", VOGL_METHOD_NAME);
7258                             return cStatusHardFailure;
7259                         }
7260                         else
7261                         {
7262                             memcpy(map_desc.m_pPtr, pData->get_ptr(), pData->size());
7263                         }
7264                     }
7265                 }
7266
7267                 get_shared_state()->m_mapped_buffers.erase_unordered(mapped_buffers_index);
7268             }
7269
7270             GLboolean replay_result;
7271             if (entrypoint_id == VOGL_ENTRYPOINT_glUnmapBuffer)
7272                 replay_result = GL_ENTRYPOINT(glUnmapBuffer)(target);
7273             else
7274                 replay_result = GL_ENTRYPOINT(glUnmapBufferARB)(target);
7275
7276             if (trace_result != replay_result)
7277                 process_entrypoint_warning("%s: Replay glUnmapBuffer's return value differs from trace's (replay: %u vs. trace: %u)\n", VOGL_METHOD_NAME, replay_result, trace_result);
7278
7279             break;
7280         }
7281         case VOGL_ENTRYPOINT_glGenVertexArrays:
7282         {
7283             if (!gen_handles(get_context_state()->m_vertex_array_objects, trace_packet.get_param_value<GLsizei>(0), static_cast<const GLuint *>(trace_packet.get_param_client_memory_ptr(1)), GL_ENTRYPOINT(glGenVertexArrays), NULL))
7284                 return cStatusHardFailure;
7285             break;
7286         }
7287         case VOGL_ENTRYPOINT_glBindVertexArray:
7288         {
7289             GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
7290             GLuint replay_handle = map_handle(get_context_state()->m_vertex_array_objects, trace_handle);
7291
7292             GL_ENTRYPOINT(glBindVertexArray)(replay_handle);
7293             break;
7294         }
7295         case VOGL_ENTRYPOINT_glDeleteVertexArrays:
7296         {
7297             delete_handles(get_context_state()->m_vertex_array_objects, trace_packet.get_param_value<GLsizei>(0), static_cast<const GLuint *>(trace_packet.get_param_client_memory_ptr(1)), GL_ENTRYPOINT(glDeleteVertexArrays));
7298             break;
7299         }
7300         case VOGL_ENTRYPOINT_glIsFramebuffer:
7301         case VOGL_ENTRYPOINT_glIsFramebufferEXT:
7302         {
7303             if (!benchmark_mode())
7304             {
7305                 GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
7306                 GLuint replay_handle = map_handle(get_context_state()->m_framebuffers, trace_handle);
7307                 GLboolean trace_result = trace_packet.get_return_value<GLboolean>();
7308
7309                 GLboolean replay_result;
7310                 if (entrypoint_id == VOGL_ENTRYPOINT_glIsFramebuffer)
7311                     replay_result = GL_ENTRYPOINT(glIsFramebuffer)(replay_handle);
7312                 else
7313                     replay_result = GL_ENTRYPOINT(glIsFramebufferEXT)(replay_handle);
7314
7315                 if (trace_result != replay_result)
7316                     process_entrypoint_error("%s: Replay's returned GLboolean differed from trace's! Replay: %u Trace: %u\n", VOGL_METHOD_NAME, static_cast<uint>(replay_result), static_cast<uint>(trace_result));
7317             }
7318
7319             break;
7320         }
7321         case VOGL_ENTRYPOINT_glIsBuffer:
7322         {
7323             if (!benchmark_mode())
7324             {
7325                 GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
7326                 GLuint replay_handle = map_handle(get_shared_state()->m_buffers, trace_handle);
7327                 GLboolean trace_result = trace_packet.get_return_value<GLboolean>();
7328
7329                 GLboolean replay_result = GL_ENTRYPOINT(glIsBuffer)(replay_handle);
7330                 if (trace_result != replay_result)
7331                     process_entrypoint_error("%s: Replay's returned GLboolean differed from trace's! Replay: %u Trace: %u\n", VOGL_METHOD_NAME, static_cast<uint>(replay_result), static_cast<uint>(trace_result));
7332             }
7333             break;
7334         }
7335         case VOGL_ENTRYPOINT_glIsEnabledi:
7336         {
7337             if (!benchmark_mode())
7338             {
7339                 GLenum cap = trace_packet.get_param_value<GLenum>(0);
7340                 GLuint index = trace_packet.get_param_value<GLuint>(1);
7341                 GLboolean trace_result = trace_packet.get_return_value<GLboolean>();
7342
7343                 GLboolean replay_result = GL_ENTRYPOINT(glIsEnabledi)(cap, index);
7344                 if (trace_result != replay_result)
7345                     process_entrypoint_error("%s: Replay's returned GLboolean differed from trace's! Replay: %u Trace: %u\n", VOGL_METHOD_NAME, static_cast<uint>(replay_result), static_cast<uint>(trace_result));
7346             }
7347             break;
7348         }
7349         case VOGL_ENTRYPOINT_glIsEnabled:
7350         {
7351             if (!benchmark_mode())
7352             {
7353                 GLenum cap = trace_packet.get_param_value<GLenum>(0);
7354                 GLboolean trace_result = trace_packet.get_return_value<GLboolean>();
7355
7356                 GLboolean replay_result = GL_ENTRYPOINT(glIsEnabled)(cap);
7357                 if (trace_result != replay_result)
7358                     process_entrypoint_error("%s: Replay's returned GLboolean differed from trace's! Replay: %u Trace: %u\n", VOGL_METHOD_NAME, static_cast<uint>(replay_result), static_cast<uint>(trace_result));
7359             }
7360             break;
7361         }
7362         case VOGL_ENTRYPOINT_glIsProgram:
7363         {
7364             if (!benchmark_mode())
7365             {
7366                 GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
7367                 GLuint replay_handle = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle);
7368                 GLboolean trace_result = trace_packet.get_return_value<GLboolean>();
7369
7370                 GLboolean replay_result = GL_ENTRYPOINT(glIsProgram)(replay_handle);
7371
7372                 if (trace_result != replay_result)
7373                     process_entrypoint_error("%s: Replay's returned GLboolean differed from trace's! Replay: %u Trace: %u\n", VOGL_METHOD_NAME, static_cast<uint>(replay_result), static_cast<uint>(trace_result));
7374             }
7375             break;
7376         }
7377         case VOGL_ENTRYPOINT_glIsQuery:
7378         {
7379             if (!benchmark_mode())
7380             {
7381                 GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
7382                 GLuint replay_handle = map_handle(get_shared_state()->m_queries, trace_handle);
7383                 GLboolean trace_result = trace_packet.get_return_value<GLboolean>();
7384
7385                 GLboolean replay_result = GL_ENTRYPOINT(glIsQuery)(replay_handle);
7386                 if (trace_result != replay_result)
7387                     process_entrypoint_error("%s: Replay's returned GLboolean differed from trace's! Replay: %u Trace: %u\n", VOGL_METHOD_NAME, static_cast<uint>(replay_result), static_cast<uint>(trace_result));
7388             }
7389             break;
7390         }
7391         case VOGL_ENTRYPOINT_glIsShader:
7392         {
7393             if (!benchmark_mode())
7394             {
7395                 GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
7396                 GLuint replay_handle = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle);
7397                 GLboolean trace_result = trace_packet.get_return_value<GLboolean>();
7398
7399                 GLboolean replay_result = GL_ENTRYPOINT(glIsShader)(replay_handle);
7400                 if (trace_result != replay_result)
7401                     process_entrypoint_error("%s: Replay's returned GLboolean differed from trace's! Replay: %u Trace: %u\n", VOGL_METHOD_NAME, static_cast<uint>(replay_result), static_cast<uint>(trace_result));
7402             }
7403             break;
7404         }
7405         case VOGL_ENTRYPOINT_glIsTexture:
7406         case VOGL_ENTRYPOINT_glIsTextureEXT:
7407         {
7408             if (!benchmark_mode())
7409             {
7410                 GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
7411                 GLuint replay_handle = trace_handle;
7412                 GLboolean trace_result = trace_packet.get_return_value<GLboolean>();
7413
7414                 map_handle(get_shared_state()->m_shadow_state.m_textures, trace_handle, replay_handle);
7415
7416                 GLboolean replay_result;
7417                 if (entrypoint_id == VOGL_ENTRYPOINT_glIsTexture)
7418                     replay_result = GL_ENTRYPOINT(glIsTexture)(replay_handle);
7419                 else
7420                     replay_result = GL_ENTRYPOINT(glIsTextureEXT)(replay_handle);
7421
7422                 if (trace_result != replay_result)
7423                     process_entrypoint_error("%s: Replay's returned GLboolean differed from trace's! Replay: %u Trace: %u\n", VOGL_METHOD_NAME, static_cast<uint>(replay_result), static_cast<uint>(trace_result));
7424             }
7425
7426             break;
7427         }
7428         case VOGL_ENTRYPOINT_glIsVertexArray:
7429         {
7430             if (!benchmark_mode())
7431             {
7432                 GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
7433                 GLuint replay_handle = map_handle(get_context_state()->m_vertex_array_objects, trace_handle);
7434                 GLboolean trace_result = trace_packet.get_return_value<GLboolean>();
7435
7436                 GLboolean replay_result = GL_ENTRYPOINT(glIsVertexArray)(replay_handle);
7437                 if (trace_result != replay_result)
7438                     process_entrypoint_error("%s: Replay's returned GLboolean differed from trace's! Replay: %u Trace: %u\n", VOGL_METHOD_NAME, static_cast<uint>(replay_result), static_cast<uint>(trace_result));
7439             }
7440
7441             break;
7442         }
7443         case VOGL_ENTRYPOINT_glReadPixels:
7444         {
7445 // TODO: This is causing huge stalls when replaying metro, not sure why. Also, the # of traced bytes is zero in metro.
7446 #if 0
7447                 if (!benchmark_mode())
7448                 {
7449             GLint x = trace_packet.get_param_value<GLint>(0);
7450             GLint y = trace_packet.get_param_value<GLint>(1);
7451             GLsizei width = trace_packet.get_param_value<GLsizei>(2);
7452             GLsizei height = trace_packet.get_param_value<GLsizei>(3);
7453             GLenum format = trace_packet.get_param_value<GLenum>(4);
7454             GLenum type = trace_packet.get_param_value<GLenum>(5);
7455             const GLvoid *trace_data = trace_packet.get_param_client_memory<const GLvoid>(6);
7456             uint trace_data_size = trace_packet.get_param_client_memory_data_size(6);
7457
7458                         size_t replay_data_size = vogl_get_image_size(format, type, width, height, 1);
7459                         if (replay_data_size != trace_data_size)
7460                         {
7461                                 process_entrypoint_warning("%s: Unexpected trace data size, got %u expected %" PRIu64 "\n", VOGL_METHOD_NAME, trace_data_size, (uint64_t)replay_data_size);
7462                         }
7463                         else if (!trace_data)
7464                         {
7465                                 process_entrypoint_warning("%s: Trace data is missing from packet\n", VOGL_METHOD_NAME);
7466                         }
7467
7468                         if (replay_data_size > cUINT32_MAX)
7469                         {
7470                                 process_entrypoint_error("%s: Replay data size is too large (%" PRIu64 ")!\n", VOGL_METHOD_NAME, (uint64_t)replay_data_size);
7471                                 return cStatusHardFailure;
7472                         }
7473
7474                         vogl::vector<uint8> data(static_cast<uint>(replay_data_size));
7475                         GL_ENTRYPOINT(glReadPixels)(x, y, width, height, format, type, data.get_ptr());
7476
7477                         if ((trace_data_size == replay_data_size) && (trace_data_size) && (trace_data))
7478                         {
7479                                 if (memcmp(data.get_ptr(), trace_data, trace_data_size) != 0)
7480                                 {
7481                                         process_entrypoint_error("%s: Replay's returned pixel data differed from trace's!\n", VOGL_METHOD_NAME);
7482                                 }
7483                         }
7484                 }
7485 #endif
7486             break;
7487         }
7488         case VOGL_ENTRYPOINT_glGetTexLevelParameterfv:
7489         {
7490             if (!benchmark_mode())
7491             {
7492                 GLenum target = trace_packet.get_param_value<GLenum>(0);
7493                 GLint level = trace_packet.get_param_value<GLint>(1);
7494                 GLenum pname = trace_packet.get_param_value<GLenum>(2);
7495                 const GLfloat *pTrace_params = trace_packet.get_param_client_memory<const GLfloat>(3);
7496                 uint trace_params_size = trace_packet.get_param_client_memory_data_size(3);
7497
7498                 int n = g_gl_enums.get_pname_count(pname);
7499                 if (n <= 0)
7500                 {
7501                     process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
7502                     return cStatusSoftFailure;
7503                 }
7504
7505                 vogl::growable_array<GLfloat, 17> replay_params(n + 1);
7506                 replay_params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_FLOAT_MAGIC;
7507
7508                 GL_ENTRYPOINT(glGetTexLevelParameterfv)(target, level, pname, replay_params.get_ptr());
7509
7510                 VOGL_VERIFY(replay_params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_FLOAT_MAGIC);
7511
7512                 if (!pTrace_params)
7513                     process_entrypoint_warning("%s: Trace param data is missing from packet\n", VOGL_METHOD_NAME);
7514                 else if (trace_params_size != sizeof(GLfloat) * n)
7515                     process_entrypoint_warning("%s: Invalid trace param data size\n", VOGL_METHOD_NAME);
7516                 else if (memcmp(pTrace_params, replay_params.get_ptr(), sizeof(GLfloat) * n) != 0)
7517                     process_entrypoint_error("%s: Trace's param data differs from replay's\n", VOGL_METHOD_NAME);
7518             }
7519
7520             break;
7521         }
7522         case VOGL_ENTRYPOINT_glGetTexLevelParameteriv:
7523         {
7524             if (!benchmark_mode())
7525             {
7526                 GLenum target = trace_packet.get_param_value<GLenum>(0);
7527                 GLint level = trace_packet.get_param_value<GLint>(1);
7528                 GLenum pname = trace_packet.get_param_value<GLenum>(2);
7529                 const GLint *pTrace_params = trace_packet.get_param_client_memory<const GLint>(3);
7530                 uint trace_params_size = trace_packet.get_param_client_memory_data_size(3);
7531
7532                 int n = g_gl_enums.get_pname_count(pname);
7533                 if (n <= 0)
7534                 {
7535                     process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
7536                     return cStatusSoftFailure;
7537                 }
7538
7539                 vogl::growable_array<GLint, 16> replay_params(n + 1);
7540                 replay_params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC;
7541
7542                 GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, level, pname, replay_params.get_ptr());
7543
7544                 VOGL_VERIFY(replay_params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC);
7545
7546                 if (!pTrace_params)
7547                     process_entrypoint_warning("%s: Trace param data is missing from packet\n", VOGL_METHOD_NAME);
7548                 else if (trace_params_size != sizeof(GLint) * n)
7549                     process_entrypoint_warning("%s: Invalid trace param data size\n", VOGL_METHOD_NAME);
7550                 else if (memcmp(pTrace_params, replay_params.get_ptr(), sizeof(GLint) * n) != 0)
7551                     process_entrypoint_error("%s: Trace's param data differs from replay's\n", VOGL_METHOD_NAME);
7552             }
7553
7554             break;
7555         }
7556         case VOGL_ENTRYPOINT_glGetTexParameterIiv:
7557         case VOGL_ENTRYPOINT_glGetTexParameteriv:
7558         {
7559             if (!benchmark_mode())
7560             {
7561                 GLenum target = trace_packet.get_param_value<GLenum>(0);
7562                 GLenum pname = trace_packet.get_param_value<GLenum>(1);
7563                 const GLint *pTrace_params = trace_packet.get_param_client_memory<const GLint>(2);
7564                 uint trace_params_size = trace_packet.get_param_client_memory_data_size(2);
7565
7566                 int n = g_gl_enums.get_pname_count(pname);
7567                 if (n <= 0)
7568                 {
7569                     process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
7570                     return cStatusSoftFailure;
7571                 }
7572
7573                 vogl::growable_array<GLint, 16> replay_params(n + 1);
7574                 replay_params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC;
7575
7576                 if (entrypoint_id == VOGL_ENTRYPOINT_glGetTexParameterIiv)
7577                     GL_ENTRYPOINT(glGetTexParameterIiv)(target, pname, replay_params.get_ptr());
7578                 else
7579                     GL_ENTRYPOINT(glGetTexParameteriv)(target, pname, replay_params.get_ptr());
7580
7581                 VOGL_VERIFY(replay_params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC);
7582
7583                 if (!pTrace_params)
7584                     process_entrypoint_warning("%s: Trace param data is missing from packet\n", VOGL_METHOD_NAME);
7585                 else if (trace_params_size != sizeof(GLint) * n)
7586                     process_entrypoint_warning("%s: Invalid trace param data size\n", VOGL_METHOD_NAME);
7587                 else if (memcmp(pTrace_params, replay_params.get_ptr(), sizeof(GLint) * n) != 0)
7588                     process_entrypoint_error("%s: Trace's param data differs from replay's\n", VOGL_METHOD_NAME);
7589             }
7590
7591             break;
7592         }
7593         case VOGL_ENTRYPOINT_glGetTexParameterIuiv:
7594         {
7595             if (!benchmark_mode())
7596             {
7597                 GLenum target = trace_packet.get_param_value<GLenum>(0);
7598                 GLenum pname = trace_packet.get_param_value<GLenum>(1);
7599                 const GLuint *pTrace_params = trace_packet.get_param_client_memory<const GLuint>(2);
7600                 uint trace_params_size = trace_packet.get_param_client_memory_data_size(2);
7601
7602                 int n = g_gl_enums.get_pname_count(pname);
7603                 if (n <= 0)
7604                 {
7605                     process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
7606                     return cStatusSoftFailure;
7607                 }
7608
7609                 vogl::growable_array<GLuint, 16> replay_params(n + 1);
7610                 replay_params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC;
7611
7612                 GL_ENTRYPOINT(glGetTexParameterIuiv)(target, pname, replay_params.get_ptr());
7613
7614                 VOGL_VERIFY(replay_params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC);
7615
7616                 if (!pTrace_params)
7617                     process_entrypoint_warning("%s: Trace param data is missing from packet\n", VOGL_METHOD_NAME);
7618                 else if (trace_params_size != sizeof(GLuint) * n)
7619                     process_entrypoint_warning("%s: Invalid trace param data size\n", VOGL_METHOD_NAME);
7620                 else if (memcmp(pTrace_params, replay_params.get_ptr(), sizeof(GLuint) * n) != 0)
7621                     process_entrypoint_error("%s: Trace's param data differs from replay's\n", VOGL_METHOD_NAME);
7622             }
7623
7624             break;
7625         }
7626         case VOGL_ENTRYPOINT_glGetTexParameterfv:
7627         {
7628             if (!benchmark_mode())
7629             {
7630                 GLenum target = trace_packet.get_param_value<GLenum>(0);
7631                 GLenum pname = trace_packet.get_param_value<GLenum>(1);
7632                 const GLfloat *pTrace_params = trace_packet.get_param_client_memory<const GLfloat>(2);
7633                 uint trace_params_size = trace_packet.get_param_client_memory_data_size(2);
7634
7635                 int n = g_gl_enums.get_pname_count(pname);
7636                 if (n <= 0)
7637                 {
7638                     process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
7639                     return cStatusSoftFailure;
7640                 }
7641
7642                 vogl::growable_array<GLfloat, 17> replay_params(n + 1);
7643                 replay_params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_FLOAT_MAGIC;
7644
7645                 GL_ENTRYPOINT(glGetTexParameterfv)(target, pname, replay_params.get_ptr());
7646
7647                 VOGL_VERIFY(replay_params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_FLOAT_MAGIC);
7648
7649                 if (!pTrace_params)
7650                     process_entrypoint_warning("%s: Trace param data is missing from packet\n", VOGL_METHOD_NAME);
7651                 else if (trace_params_size != sizeof(GLfloat) * n)
7652                     process_entrypoint_warning("%s: Invalid trace param data size\n", VOGL_METHOD_NAME);
7653                 else if (memcmp(pTrace_params, replay_params.get_ptr(), sizeof(GLfloat) * n) != 0)
7654                     process_entrypoint_error("%s: Trace's param data differs from replay's\n", VOGL_METHOD_NAME);
7655             }
7656
7657             break;
7658         }
7659
7660         case VOGL_ENTRYPOINT_glGetVertexAttribdv:
7661         {
7662             status = get_vertex_attrib_helper<GLdouble>(GL_ENTRYPOINT(glGetVertexAttribdv));
7663             if (status != cStatusOK)
7664                 return status;
7665             break;
7666         }
7667         case VOGL_ENTRYPOINT_glGetVertexAttribfv:
7668         {
7669             status = get_vertex_attrib_helper<GLfloat>(GL_ENTRYPOINT(glGetVertexAttribfv));
7670             if (status != cStatusOK)
7671                 return status;
7672             break;
7673         }
7674         case VOGL_ENTRYPOINT_glGetVertexAttribiv:
7675         {
7676             status = get_vertex_attrib_helper<GLint>(GL_ENTRYPOINT(glGetVertexAttribiv));
7677             if (status != cStatusOK)
7678                 return status;
7679             break;
7680         }
7681         case VOGL_ENTRYPOINT_glGetVertexAttribIiv:
7682         {
7683             status = get_vertex_attrib_helper<GLint>(GL_ENTRYPOINT(glGetVertexAttribIiv));
7684             if (status != cStatusOK)
7685                 return status;
7686             break;
7687         }
7688         case VOGL_ENTRYPOINT_glGetVertexAttribIivEXT:
7689         {
7690             status = get_vertex_attrib_helper<GLint>(GL_ENTRYPOINT(glGetVertexAttribIivEXT));
7691             if (status != cStatusOK)
7692                 return status;
7693             break;
7694         }
7695         case VOGL_ENTRYPOINT_glGetVertexAttribIuiv:
7696         {
7697             status = get_vertex_attrib_helper<GLuint>(GL_ENTRYPOINT(glGetVertexAttribIuiv));
7698             if (status != cStatusOK)
7699                 return status;
7700             break;
7701         }
7702         case VOGL_ENTRYPOINT_glGetVertexAttribIuivEXT:
7703         {
7704             status = get_vertex_attrib_helper<GLuint>(GL_ENTRYPOINT(glGetVertexAttribIuivEXT));
7705             if (status != cStatusOK)
7706                 return status;
7707             break;
7708         }
7709         case VOGL_ENTRYPOINT_glGenLists:
7710         {
7711             GLsizei range = trace_packet.get_param_value<GLsizei>(0);
7712             GLuint trace_base_handle = trace_packet.get_return_value<GLuint>();
7713
7714             if (trace_base_handle)
7715             {
7716                 check_gl_error();
7717
7718                 GLuint replay_base_handle = GL_ENTRYPOINT(glGenLists)(range);
7719
7720                 if ((check_gl_error()) || (!replay_base_handle))
7721                 {
7722                     process_entrypoint_error("%s: glGenLists() succeeded in the trace, but failed during replay!\n", VOGL_METHOD_NAME);
7723                     return cStatusHardFailure;
7724                 }
7725
7726                 for (GLsizei i = 0; i < range; i++)
7727                 {
7728                     GLuint trace_handle = trace_base_handle + i;
7729                     GLuint replay_handle = replay_base_handle + i;
7730
7731                     if (!gen_handle(get_shared_state()->m_lists, trace_handle, replay_handle))
7732                         return cStatusHardFailure;
7733
7734                     if (!get_shared_state()->m_shadow_state.m_display_lists.gen_lists(trace_handle, 1, &replay_handle))
7735                     {
7736                         process_entrypoint_warning("%s: Failed genning list into display list shadow, trace handle %u GL handle %u\n", VOGL_METHOD_NAME, trace_handle, replay_handle);
7737                     }
7738                 }
7739             }
7740             else
7741             {
7742                 GLuint replay_base_handle = GL_ENTRYPOINT(glGenLists)(range);
7743                 if (replay_base_handle)
7744                 {
7745                     process_entrypoint_warning("%s: glGenLists() failed in the trace, but succeeded during replay!\n", VOGL_METHOD_NAME);
7746
7747                     GL_ENTRYPOINT(glDeleteLists)(replay_base_handle, range);
7748                 }
7749             }
7750
7751             break;
7752         }
7753         case VOGL_ENTRYPOINT_glCallList:
7754         {
7755             GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
7756             GLuint replay_handle = map_handle(get_shared_state()->m_lists, trace_handle);
7757
7758             GL_ENTRYPOINT(glCallList)(replay_handle);
7759
7760             if (!get_shared_state()->m_shadow_state.m_display_lists.parse_list_and_update_shadows(trace_handle, display_list_bind_callback, this))
7761             {
7762                 process_entrypoint_warning("%s: Failed processing display list shadow for trace handle %u GL handle %u\n", VOGL_METHOD_NAME, trace_handle, replay_handle);
7763             }
7764
7765             if ((status = post_draw_call()) != cStatusOK)
7766                 return status;
7767
7768             break;
7769         }
7770         case VOGL_ENTRYPOINT_glCallLists:
7771         {
7772             GLsizei n = trace_packet.get_param_value<GLsizei>(0);
7773             GLenum type = trace_packet.get_param_value<GLenum>(1);
7774             const GLvoid *pTrace_lists = trace_packet.get_param_client_memory<const GLvoid>(2);
7775             uint trace_lists_size = trace_packet.get_param_client_memory_data_size(2);
7776
7777             uint type_size = vogl_get_gl_type_size(type);
7778             if (!type_size)
7779             {
7780                 process_entrypoint_error("%s: Unable to execute glCallLists, type is invalid\n", VOGL_METHOD_NAME);
7781                 return cStatusSoftFailure;
7782             }
7783
7784             if ((n) && (!pTrace_lists))
7785             {
7786                 process_entrypoint_error("%s: Unable to execute glCallLists, lists param is NULL\n", VOGL_METHOD_NAME);
7787                 return cStatusSoftFailure;
7788             }
7789
7790             if (trace_lists_size < (type_size * n))
7791             {
7792                 process_entrypoint_error("%s: Unable to execute glCallLists, lists param data size is too small in trace\n", VOGL_METHOD_NAME);
7793                 return cStatusSoftFailure;
7794             }
7795
7796             GLuint list_base = 0;
7797             GL_ENTRYPOINT(glGetIntegerv)(GL_LIST_BASE, reinterpret_cast<GLint *>(&list_base));
7798
7799             const uint8 *pTrace_lists_ptr = static_cast<const uint8 *>(pTrace_lists);
7800             for (GLsizei i = 0; i < n; i++)
7801             {
7802                 GLint trace_handle = list_base;
7803                 switch (type)
7804                 {
7805                     case GL_BYTE:
7806                     {
7807                         trace_handle += *reinterpret_cast<const signed char *>(pTrace_lists_ptr);
7808                         pTrace_lists_ptr++;
7809                         break;
7810                     }
7811                     case GL_UNSIGNED_BYTE:
7812                     {
7813                         trace_handle += *pTrace_lists_ptr;
7814                         pTrace_lists_ptr++;
7815                         break;
7816                     }
7817                     case GL_SHORT:
7818                     {
7819                         trace_handle += *reinterpret_cast<const int16 *>(pTrace_lists_ptr);
7820                         pTrace_lists_ptr += sizeof(int16);
7821                         break;
7822                     }
7823                     case GL_UNSIGNED_SHORT:
7824                     {
7825                         trace_handle += *reinterpret_cast<const uint16 *>(pTrace_lists_ptr);
7826                         pTrace_lists_ptr += sizeof(uint16);
7827                         break;
7828                     }
7829                     case GL_INT:
7830                     {
7831                         trace_handle += *reinterpret_cast<const int32 *>(pTrace_lists_ptr);
7832                         pTrace_lists_ptr += sizeof(int32);
7833                         break;
7834                     }
7835                     case GL_UNSIGNED_INT:
7836                     {
7837                         trace_handle += *reinterpret_cast<const uint32 *>(pTrace_lists_ptr);
7838                         pTrace_lists_ptr += sizeof(uint32);
7839                         break;
7840                     }
7841                     case GL_FLOAT:
7842                     {
7843                         trace_handle += static_cast<GLint>(*reinterpret_cast<const float *>(pTrace_lists_ptr));
7844                         pTrace_lists_ptr += sizeof(float);
7845                         break;
7846                     }
7847                     case GL_2_BYTES:
7848                     {
7849                         trace_handle += ((pTrace_lists_ptr[0] << 8U) + pTrace_lists_ptr[1]);
7850                         pTrace_lists_ptr += 2;
7851                         break;
7852                     }
7853                     case GL_3_BYTES:
7854                     {
7855                         trace_handle += ((pTrace_lists_ptr[0] << 16U) + (pTrace_lists_ptr[1] << 8U) + pTrace_lists_ptr[2]);
7856                         pTrace_lists_ptr += 3;
7857                         break;
7858                     }
7859                     case GL_4_BYTES:
7860                     {
7861                         trace_handle += ((pTrace_lists_ptr[0] << 24U) + (pTrace_lists_ptr[1] << 16U) + (pTrace_lists_ptr[2] << 8U) + pTrace_lists_ptr[3]);
7862                         pTrace_lists_ptr += 4;
7863                         break;
7864                     }
7865                     default:
7866                     {
7867                         process_entrypoint_error("%s: Invalid type parameter (0x%08X)\n", VOGL_METHOD_NAME, type);
7868                         return cStatusSoftFailure;
7869                     }
7870                 }
7871
7872                 if (trace_handle <= 0)
7873                 {
7874                     process_entrypoint_error("%s: Trace handle after adding list base is negative (%i), skipping this list index\n", VOGL_METHOD_NAME, trace_handle);
7875                 }
7876                 else
7877                 {
7878                     GLuint replay_handle = map_handle(get_shared_state()->m_lists, trace_handle);
7879                     GL_ENTRYPOINT(glCallList)(replay_handle);
7880
7881                     if (!get_shared_state()->m_shadow_state.m_display_lists.parse_list_and_update_shadows(trace_handle, display_list_bind_callback, this))
7882                     {
7883                         process_entrypoint_warning("%s: Failed processing display list shadow for trace handle %u GL handle %u\n", VOGL_METHOD_NAME, trace_handle, replay_handle);
7884                     }
7885                 }
7886             }
7887
7888             if ((status = post_draw_call()) != cStatusOK)
7889                 return status;
7890
7891             break;
7892         }
7893         case VOGL_ENTRYPOINT_glDeleteLists:
7894         {
7895             GLuint trace_list = trace_packet.get_param_value<GLuint>(0);
7896             GLsizei range = trace_packet.get_param_value<GLsizei>(1);
7897
7898             for (GLsizei i = 0; i < range; i++)
7899             {
7900                 GLuint trace_handle = trace_list + i;
7901                 delete_handles(get_shared_state()->m_lists, 1, &trace_handle, delete_list_helper);
7902
7903                 if (!get_shared_state()->m_shadow_state.m_display_lists.del_lists(trace_handle, 1))
7904                 {
7905                     process_entrypoint_warning("%s: Unable to delete list in display list shadow, trace handle %u\n", VOGL_METHOD_NAME, trace_handle);
7906                 }
7907             }
7908
7909             break;
7910         }
7911         case VOGL_ENTRYPOINT_glIsList:
7912         {
7913             if (!benchmark_mode())
7914             {
7915                 GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
7916                 GLuint replay_handle = map_handle(get_shared_state()->m_lists, trace_handle);
7917                 GLboolean trace_result = trace_packet.get_return_value<GLboolean>();
7918
7919                 GLboolean replay_result = GL_ENTRYPOINT(glIsList)(replay_handle);
7920                 if (trace_result != replay_result)
7921                     process_entrypoint_error("%s: Replay's returned GLboolean differed from trace's! Replay: %u Trace: %u\n", VOGL_METHOD_NAME, static_cast<uint>(replay_result), static_cast<uint>(trace_result));
7922             }
7923
7924             break;
7925         }
7926         case VOGL_ENTRYPOINT_glNewList:
7927         {
7928             GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
7929             GLuint replay_handle = map_handle(get_shared_state()->m_lists, trace_handle);
7930             GLenum mode = trace_packet.get_param_value<GLenum>(1);
7931
7932             check_gl_error();
7933
7934             GL_ENTRYPOINT(glNewList)(replay_handle, mode);
7935
7936             if (!check_gl_error())
7937             {
7938                 get_shared_state()->m_shadow_state.m_display_lists.new_list(trace_handle, replay_handle);
7939
7940                 get_context_state()->m_current_display_list_mode = mode;
7941                 get_context_state()->m_current_display_list_handle = trace_handle;
7942             }
7943
7944             // TODO: Check if glNewList() failed vs the replay.
7945             // This is important, because if the new failed during tracing but succeeded during replay then we've seriously diverged.
7946             // This is a bigger topic, we really should have the option of calling glGetError() during tracing after each GL call and recording the results to check for divergence.
7947             break;
7948         }
7949         case VOGL_ENTRYPOINT_glListBase:
7950         {
7951             GLuint base = trace_packet.get_param_value<GLuint>(0);
7952             GL_ENTRYPOINT(glListBase)(base);
7953             break;
7954         }
7955         case VOGL_ENTRYPOINT_glEndList:
7956         {
7957             GL_ENTRYPOINT(glEndList)();
7958
7959             if (!get_context_state()->is_composing_display_list())
7960             {
7961                 process_entrypoint_warning("%s: glEndList() called without calling glNewList()!\n", VOGL_METHOD_NAME);
7962             }
7963             else
7964             {
7965                 if (!get_shared_state()->m_shadow_state.m_display_lists.end_list(get_context_state()->m_current_display_list_handle))
7966                     process_entrypoint_warning("%s: Failed ending display list, trace handle %u\n", VOGL_METHOD_NAME, get_context_state()->m_current_display_list_handle);
7967
7968                 get_context_state()->m_current_display_list_mode = GL_NONE;
7969                 get_context_state()->m_current_display_list_handle = -1;
7970             }
7971
7972             break;
7973         }
7974         case VOGL_ENTRYPOINT_glFeedbackBuffer:
7975         {
7976             GLsizei size = trace_packet.get_param_value<GLsizei>(0);
7977             GLenum type = trace_packet.get_param_value<GLenum>(1);
7978
7979             if (static_cast<GLsizei>(m_pCur_context_state->m_feedback_buffer.size()) < size)
7980                 m_pCur_context_state->m_feedback_buffer.resize(size);
7981
7982             GL_ENTRYPOINT(glFeedbackBuffer)(size, type, m_pCur_context_state->m_feedback_buffer.get_ptr());
7983
7984             break;
7985         }
7986         case VOGL_ENTRYPOINT_glSeparableFilter2D:
7987         {
7988             GLenum target = trace_packet.get_param_value<GLenum>(0);
7989             GLenum internalformat = trace_packet.get_param_value<GLenum>(1);
7990             GLsizei width = trace_packet.get_param_value<GLsizei>(2);
7991             GLsizei height = trace_packet.get_param_value<GLsizei>(3);
7992             GLenum format = trace_packet.get_param_value<GLenum>(4);
7993             GLenum type = trace_packet.get_param_value<GLenum>(5);
7994
7995             const GLvoid *row = trace_packet.get_param_client_memory<const GLvoid>(6);
7996             uint row_size = trace_packet.get_param_client_memory_data_size(6);
7997             if (row_size < vogl_get_image_size(format, type, width, 1, 1))
7998             {
7999                 process_entrypoint_error("%s: row trace array is too small\n", VOGL_METHOD_NAME);
8000                 return cStatusSoftFailure;
8001             }
8002
8003             const GLvoid *column = trace_packet.get_param_client_memory<const GLvoid>(7);
8004             uint col_size = trace_packet.get_param_client_memory_data_size(7);
8005             if (col_size < vogl_get_image_size(format, type, width, 1, 1))
8006             {
8007                 process_entrypoint_error("%s: column trace array is too small\n", VOGL_METHOD_NAME);
8008                 return cStatusSoftFailure;
8009             }
8010
8011             GL_ENTRYPOINT(glSeparableFilter2D)(target, internalformat, width, height, format, type, row, column);
8012             break;
8013         }
8014
8015         case VOGL_ENTRYPOINT_glNamedProgramLocalParameters4fvEXT:
8016         {
8017             GLuint trace_program = trace_packet.get_param_value<GLuint>(0);
8018             GLuint replay_program = map_handle(get_shared_state()->m_arb_programs, trace_program);
8019
8020             GL_ENTRYPOINT(glNamedProgramLocalParameters4fvEXT)(replay_program, trace_packet.get_param_value<GLenum>(1), trace_packet.get_param_value<GLuint>(2), trace_packet.get_param_value<GLsizei>(3), trace_packet.get_param_client_memory<const GLfloat>(4));
8021             break;
8022         }
8023
8024         case VOGL_ENTRYPOINT_glNamedProgramLocalParameterI4iEXT:
8025         {
8026             GLuint trace_program = trace_packet.get_param_value<GLuint>(0);
8027             GLuint replay_program = map_handle(get_shared_state()->m_arb_programs, trace_program);
8028
8029             GL_ENTRYPOINT(glNamedProgramLocalParameterI4iEXT)(replay_program, trace_packet.get_param_value<GLenum>(1), trace_packet.get_param_value<GLuint>(2), trace_packet.get_param_value<GLint>(3), trace_packet.get_param_value<GLint>(4), trace_packet.get_param_value<GLint>(5), trace_packet.get_param_value<GLint>(6));
8030             break;
8031         }
8032         case VOGL_ENTRYPOINT_glNamedProgramLocalParameterI4ivEXT:
8033         {
8034             GLuint trace_program = trace_packet.get_param_value<GLuint>(0);
8035             GLuint replay_program = map_handle(get_shared_state()->m_arb_programs, trace_program);
8036
8037             GL_ENTRYPOINT(glNamedProgramLocalParameterI4ivEXT)(replay_program, trace_packet.get_param_value<GLenum>(1), trace_packet.get_param_value<GLuint>(2), trace_packet.get_param_client_memory<GLint>(3));
8038             break;
8039         }
8040
8041         case VOGL_ENTRYPOINT_glNamedProgramLocalParametersI4ivEXT:
8042         {
8043             GLuint trace_program = trace_packet.get_param_value<GLuint>(0);
8044             GLuint replay_program = map_handle(get_shared_state()->m_arb_programs, trace_program);
8045
8046             GL_ENTRYPOINT(glNamedProgramLocalParametersI4ivEXT)(replay_program, trace_packet.get_param_value<GLenum>(1), trace_packet.get_param_value<GLuint>(2), trace_packet.get_param_value<GLsizei>(3), trace_packet.get_param_client_memory<GLint>(4));
8047             break;
8048         }
8049         case VOGL_ENTRYPOINT_glNamedProgramLocalParameterI4uiEXT:
8050         {
8051             GLuint trace_program = trace_packet.get_param_value<GLuint>(0);
8052             GLuint replay_program = map_handle(get_shared_state()->m_arb_programs, trace_program);
8053
8054             GL_ENTRYPOINT(glNamedProgramLocalParameterI4uiEXT)(replay_program, trace_packet.get_param_value<GLenum>(1), trace_packet.get_param_value<GLuint>(2),
8055                                                                trace_packet.get_param_value<GLuint>(3), trace_packet.get_param_value<GLuint>(4),
8056                                                                trace_packet.get_param_value<GLuint>(5), trace_packet.get_param_value<GLuint>(6));
8057             break;
8058         }
8059         case VOGL_ENTRYPOINT_glNamedProgramLocalParameterI4uivEXT:
8060         {
8061             GLuint trace_program = trace_packet.get_param_value<GLuint>(0);
8062             GLuint replay_program = map_handle(get_shared_state()->m_arb_programs, trace_program);
8063
8064             GL_ENTRYPOINT(glNamedProgramLocalParameterI4uivEXT)(replay_program, trace_packet.get_param_value<GLenum>(1), trace_packet.get_param_value<GLuint>(2), trace_packet.get_param_client_memory<GLuint>(3));
8065             break;
8066         }
8067         case VOGL_ENTRYPOINT_glNamedProgramLocalParametersI4uivEXT:
8068         {
8069             GLuint trace_program = trace_packet.get_param_value<GLuint>(0);
8070             GLuint replay_program = map_handle(get_shared_state()->m_arb_programs, trace_program);
8071
8072             GL_ENTRYPOINT(glNamedProgramLocalParametersI4uivEXT)(replay_program, trace_packet.get_param_value<GLenum>(1), trace_packet.get_param_value<GLuint>(2), trace_packet.get_param_value<GLsizei>(3), trace_packet.get_param_client_memory<GLuint>(4));
8073             break;
8074         }
8075         case VOGL_ENTRYPOINT_glNamedProgramLocalParameter4fvEXT:
8076         {
8077             GLuint trace_program = trace_packet.get_param_value<GLuint>(0);
8078             GLuint replay_program = map_handle(get_shared_state()->m_arb_programs, trace_program);
8079
8080             GL_ENTRYPOINT(glNamedProgramLocalParameter4fvEXT)(replay_program, trace_packet.get_param_value<GLenum>(1), trace_packet.get_param_value<GLuint>(2), trace_packet.get_param_client_memory<const GLfloat>(3));
8081             break;
8082         }
8083         case VOGL_ENTRYPOINT_glGetTexEnvfv:
8084         {
8085             if (!benchmark_mode())
8086             {
8087                 GLenum target = trace_packet.get_param_value<GLenum>(0);
8088                 GLenum pname = trace_packet.get_param_value<GLenum>(1);
8089                 const GLfloat *pParams = trace_packet.get_param_client_memory<GLfloat>(2);
8090
8091                 GLfloat vals[4] = { 0, 0, 0, 0 };
8092
8093                 int n = g_gl_enums.get_pname_count(pname);
8094                 VOGL_ASSERT(n <= (int)VOGL_ARRAY_SIZE(vals));
8095
8096                 GL_ENTRYPOINT(glGetTexEnvfv)(target, pname, vals);
8097
8098                 if (n < 0)
8099                 {
8100                     process_entrypoint_error("%s: Unable to compute element count for pname 0x%08X\n", VOGL_METHOD_NAME, pname);
8101                 }
8102                 else if (memcmp(pParams, vals, n * sizeof(GLfloat)) != 0)
8103                 {
8104                     process_entrypoint_error("%s: Replay divergence detected\n", VOGL_METHOD_NAME);
8105                 }
8106             }
8107
8108             break;
8109         }
8110         case VOGL_ENTRYPOINT_glGetTexEnviv:
8111         {
8112             if (!benchmark_mode())
8113             {
8114                 GLenum target = trace_packet.get_param_value<GLenum>(0);
8115                 GLenum pname = trace_packet.get_param_value<GLenum>(1);
8116                 const GLint *pParams = trace_packet.get_param_client_memory<GLint>(2);
8117
8118                 GLint vals[4] = { 0, 0, 0, 0 };
8119
8120                 int n = g_gl_enums.get_pname_count(pname);
8121                 VOGL_ASSERT(n <= (int)VOGL_ARRAY_SIZE(vals));
8122
8123                 GL_ENTRYPOINT(glGetTexEnviv)(target, pname, vals);
8124
8125                 if (n < 0)
8126                 {
8127                     process_entrypoint_error("%s: Unable to compute element count for pname 0x%08X\n", VOGL_METHOD_NAME, pname);
8128                 }
8129                 else if (memcmp(pParams, vals, n * sizeof(GLint)) != 0)
8130                 {
8131                     process_entrypoint_error("%s: Replay divergence detected\n", VOGL_METHOD_NAME);
8132                 }
8133             }
8134
8135             break;
8136         }
8137         case VOGL_ENTRYPOINT_glGetTexGendv:
8138         {
8139             if (!benchmark_mode())
8140             {
8141                 GLenum coord = trace_packet.get_param_value<GLenum>(0);
8142                 GLenum pname = trace_packet.get_param_value<GLenum>(1);
8143                 const GLdouble *pParams = trace_packet.get_param_client_memory<GLdouble>(2);
8144
8145                 GLdouble vals[4] = { 0, 0, 0, 0 };
8146
8147                 int n = g_gl_enums.get_pname_count(pname);
8148                 VOGL_ASSERT(n <= (int)VOGL_ARRAY_SIZE(vals));
8149
8150                 GL_ENTRYPOINT(glGetTexGendv)(coord, pname, vals);
8151
8152                 if (n < 0)
8153                 {
8154                     process_entrypoint_error("%s: Unable to compute element count for pname 0x%08X\n", VOGL_METHOD_NAME, pname);
8155                 }
8156                 else if (memcmp(pParams, vals, n * sizeof(GLdouble)) != 0)
8157                 {
8158                     process_entrypoint_error("%s: Replay divergence detected\n", VOGL_METHOD_NAME);
8159                 }
8160             }
8161
8162             break;
8163         }
8164         case VOGL_ENTRYPOINT_glGetTexGenfv:
8165         {
8166             if (!benchmark_mode())
8167             {
8168                 GLenum coord = trace_packet.get_param_value<GLenum>(0);
8169                 GLenum pname = trace_packet.get_param_value<GLenum>(1);
8170                 const GLfloat *pParams = trace_packet.get_param_client_memory<GLfloat>(2);
8171
8172                 GLfloat vals[4] = { 0, 0, 0, 0 };
8173
8174                 int n = g_gl_enums.get_pname_count(pname);
8175                 VOGL_ASSERT(n <= (int)VOGL_ARRAY_SIZE(vals));
8176
8177                 GL_ENTRYPOINT(glGetTexGenfv)(coord, pname, vals);
8178
8179                 if (n < 0)
8180                 {
8181                     process_entrypoint_error("%s: Unable to compute element count for pname 0x%08X\n", VOGL_METHOD_NAME, pname);
8182                 }
8183                 else if (memcmp(pParams, vals, n * sizeof(GLfloat)) != 0)
8184                 {
8185                     process_entrypoint_error("%s: Replay divergence detected\n", VOGL_METHOD_NAME);
8186                 }
8187             }
8188
8189             break;
8190         }
8191         case VOGL_ENTRYPOINT_glGetTexGeniv:
8192         {
8193             if (!benchmark_mode())
8194             {
8195                 GLenum coord = trace_packet.get_param_value<GLenum>(0);
8196                 GLenum pname = trace_packet.get_param_value<GLenum>(1);
8197                 const GLint *pParams = trace_packet.get_param_client_memory<GLint>(2);
8198
8199                 GLint vals[4] = { 0, 0, 0, 0 };
8200
8201                 int n = g_gl_enums.get_pname_count(pname);
8202                 VOGL_ASSERT(n <= (int)VOGL_ARRAY_SIZE(vals));
8203
8204                 GL_ENTRYPOINT(glGetTexGeniv)(coord, pname, vals);
8205
8206                 if (n < 0)
8207                 {
8208                     process_entrypoint_error("%s: Unable to compute element count for pname 0x%08X\n", VOGL_METHOD_NAME, pname);
8209                 }
8210                 else if (memcmp(pParams, vals, n * sizeof(GLint)) != 0)
8211                 {
8212                     process_entrypoint_error("%s: Replay divergence detected\n", VOGL_METHOD_NAME);
8213                 }
8214             }
8215
8216             break;
8217         }
8218         case VOGL_ENTRYPOINT_glGetLightfv:
8219         {
8220             if (!benchmark_mode())
8221             {
8222                 GLenum light = trace_packet.get_param_value<GLenum>(0);
8223                 GLenum pname = trace_packet.get_param_value<GLenum>(1);
8224                 const GLfloat *pParams = trace_packet.get_param_client_memory<GLfloat>(2);
8225
8226                 GLfloat vals[4] = { 0, 0, 0, 0 };
8227
8228                 int n = g_gl_enums.get_pname_count(pname);
8229                 VOGL_ASSERT(n <= (int)VOGL_ARRAY_SIZE(vals));
8230
8231                 GL_ENTRYPOINT(glGetLightfv)(light, pname, vals);
8232
8233                 if (n < 0)
8234                 {
8235                     process_entrypoint_error("%s: Unable to compute element count for pname 0x%08X\n", VOGL_METHOD_NAME, pname);
8236                 }
8237                 else if (memcmp(pParams, vals, n * sizeof(GLfloat)) != 0)
8238                 {
8239                     process_entrypoint_error("%s: Replay divergence detected\n", VOGL_METHOD_NAME);
8240                 }
8241             }
8242
8243             break;
8244         }
8245         case VOGL_ENTRYPOINT_glGetLightiv:
8246         {
8247             if (!benchmark_mode())
8248             {
8249                 GLenum light = trace_packet.get_param_value<GLenum>(0);
8250                 GLenum pname = trace_packet.get_param_value<GLenum>(1);
8251                 const GLint *pParams = trace_packet.get_param_client_memory<GLint>(2);
8252
8253                 GLint vals[4] = { 0, 0, 0, 0 };
8254
8255                 int n = g_gl_enums.get_pname_count(pname);
8256                 VOGL_ASSERT(n <= (int)VOGL_ARRAY_SIZE(vals));
8257
8258                 GL_ENTRYPOINT(glGetLightiv)(light, pname, vals);
8259
8260                 if (n < 0)
8261                 {
8262                     process_entrypoint_error("%s: Unable to compute element count for pname 0x%08X\n", VOGL_METHOD_NAME, pname);
8263                 }
8264                 else if (memcmp(pParams, vals, n * sizeof(GLint)) != 0)
8265                 {
8266                     process_entrypoint_error("%s: Replay divergence detected\n", VOGL_METHOD_NAME);
8267                 }
8268             }
8269
8270             break;
8271         }
8272         case VOGL_ENTRYPOINT_glSelectBuffer:
8273         {
8274             GLsizei size = trace_packet.get_param_value<GLsizei>(0);
8275
8276             if (m_pCur_context_state->m_select_buffer.try_resize(size))
8277             {
8278                 GL_ENTRYPOINT(glSelectBuffer)(size, m_pCur_context_state->m_select_buffer.get_ptr());
8279             }
8280             else
8281             {
8282                 process_entrypoint_error("%s: Failed resizing context's select buffer\n", VOGL_METHOD_NAME);
8283             }
8284
8285             break;
8286         }
8287         case VOGL_ENTRYPOINT_glClearBufferfv:
8288         {
8289             VOGL_REPLAY_LOAD_PARAMS_HELPER_glClearBufferfv;
8290
8291             // TODO: Check params
8292
8293             VOGL_REPLAY_CALL_GL_HELPER_glClearBufferfv;
8294
8295             break;
8296         }
8297         case VOGL_ENTRYPOINT_glClearBufferiv:
8298         {
8299             VOGL_REPLAY_LOAD_PARAMS_HELPER_glClearBufferiv;
8300
8301             // TODO: Check params
8302
8303             VOGL_REPLAY_CALL_GL_HELPER_glClearBufferiv;
8304
8305             break;
8306         }
8307         case VOGL_ENTRYPOINT_glClearBufferuiv:
8308         {
8309             VOGL_REPLAY_LOAD_PARAMS_HELPER_glClearBufferuiv;
8310
8311             // TODO: Check params
8312
8313             VOGL_REPLAY_CALL_GL_HELPER_glClearBufferuiv;
8314
8315             break;
8316         }
8317         case VOGL_ENTRYPOINT_glTexBuffer:
8318         case VOGL_ENTRYPOINT_glTexBufferARB:
8319         case VOGL_ENTRYPOINT_glTexBufferEXT:
8320         {
8321             VOGL_REPLAY_LOAD_PARAMS_HELPER_glTexBuffer;
8322
8323             buffer = map_handle(get_shared_state()->m_buffers, buffer);
8324
8325             SWITCH_GL_ENTRYPOINT3_VOID(glTexBuffer, glTexBufferARB, glTexBufferEXT, target, internalformat, buffer);
8326             break;
8327         }
8328         case VOGL_ENTRYPOINT_glBeginConditionalRender:
8329         {
8330             VOGL_REPLAY_LOAD_PARAMS_HELPER_glBeginConditionalRender;
8331
8332             id = map_handle(get_shared_state()->m_queries, id);
8333
8334             VOGL_REPLAY_CALL_GL_HELPER_glBeginConditionalRender;
8335             break;
8336         }
8337         case VOGL_ENTRYPOINT_glEndConditionalRender:
8338         {
8339             VOGL_REPLAY_LOAD_PARAMS_HELPER_glEndConditionalRender;
8340
8341             VOGL_REPLAY_CALL_GL_HELPER_glEndConditionalRender;
8342             break;
8343         }
8344         case VOGL_ENTRYPOINT_glBeginTransformFeedback:
8345         {
8346             VOGL_REPLAY_LOAD_PARAMS_HELPER_glBeginTransformFeedback;
8347
8348             VOGL_REPLAY_CALL_GL_HELPER_glBeginTransformFeedback;
8349             break;
8350         }
8351         case VOGL_ENTRYPOINT_glEndTransformFeedback:
8352         {
8353             VOGL_REPLAY_LOAD_PARAMS_HELPER_glEndTransformFeedback;
8354
8355             VOGL_REPLAY_CALL_GL_HELPER_glEndTransformFeedback;
8356
8357             break;
8358         }
8359         case VOGL_ENTRYPOINT_glTransformFeedbackVaryings:
8360         {
8361             VOGL_REPLAY_LOAD_PARAMS_HELPER_glTransformFeedbackVaryings;
8362             VOGL_NOTE_UNUSED(pTrace_varyings);
8363
8364             program = map_handle(get_shared_state()->m_shadow_state.m_objs, program);
8365
8366             dynamic_string_array replay_varyings(count);
8367
8368             const key_value_map &key_value_map = trace_packet.get_key_value_map();
8369             const value_to_value_hash_map &hash_map = key_value_map.get_map();
8370
8371             for (value_to_value_hash_map::const_iterator it = hash_map.begin(); it != hash_map.end(); ++it)
8372             {
8373                 int key_index = it->first.get_int();
8374
8375                 if ((key_index >= 0) && (key_index < count))
8376                 {
8377                     const dynamic_string *pName = it->second.get_string_ptr();
8378                     VOGL_ASSERT(pName);
8379
8380                     replay_varyings[key_index] = pName ? *pName : "";
8381                 }
8382                 else
8383                 {
8384                     VOGL_ASSERT_ALWAYS;
8385                 }
8386             }
8387
8388             vogl::vector<const GLchar *> str_ptrs(count);
8389             for (int i = 0; i < count; i++)
8390                 str_ptrs[i] = reinterpret_cast<const GLchar *>(replay_varyings[i].get_ptr());
8391
8392             GLchar *const *pReplay_varyings = (GLchar *const *)(str_ptrs.get_ptr());
8393
8394             VOGL_REPLAY_CALL_GL_HELPER_glTransformFeedbackVaryings;
8395
8396             break;
8397         }
8398         case VOGL_ENTRYPOINT_glUniformBufferEXT:
8399         {
8400             VOGL_REPLAY_LOAD_PARAMS_HELPER_glUniformBufferEXT;
8401
8402             GLuint trace_program = program;
8403
8404             program = map_handle(get_shared_state()->m_shadow_state.m_objs, program);
8405             location = determine_uniform_replay_location(trace_program, location);
8406             buffer = map_handle(get_shared_state()->m_buffers, buffer);
8407
8408             VOGL_REPLAY_CALL_GL_HELPER_glUniformBufferEXT;
8409             break;
8410         }
8411         case VOGL_ENTRYPOINT_glUniformBlockBinding:
8412         {
8413             // TODO: Does any of this other stuff need to be remapped?
8414             VOGL_REPLAY_LOAD_PARAMS_HELPER_glUniformBlockBinding;
8415
8416             program = map_handle(get_shared_state()->m_shadow_state.m_objs, program);
8417
8418             VOGL_REPLAY_CALL_GL_HELPER_glUniformBlockBinding;
8419             break;
8420         }
8421         case VOGL_ENTRYPOINT_glFrameTerminatorGREMEDY:
8422         {
8423             // TODO - we need to hook up this extension to the tracer
8424             break;
8425         }
8426         case VOGL_ENTRYPOINT_glStringMarkerGREMEDY:
8427         {
8428             // TODO - we need to hook up this extension to the tracer
8429             break;
8430         }
8431         case VOGL_ENTRYPOINT_glDebugMessageCallbackARB:
8432         case VOGL_ENTRYPOINT_glGetDebugMessageLogARB:
8433         case VOGL_ENTRYPOINT_glDebugMessageControlARB:
8434         case VOGL_ENTRYPOINT_glDebugMessageInsertARB:
8435         {
8436             // TODO
8437             break;
8438         }
8439         case VOGL_ENTRYPOINT_glAreTexturesResident:
8440         case VOGL_ENTRYPOINT_glAreTexturesResidentEXT:
8441         case VOGL_ENTRYPOINT_glGetActiveAtomicCounterBufferiv:
8442         case VOGL_ENTRYPOINT_glGetActiveAttribARB:
8443         case VOGL_ENTRYPOINT_glGetActiveSubroutineName:
8444         case VOGL_ENTRYPOINT_glGetActiveSubroutineUniformName:
8445         case VOGL_ENTRYPOINT_glGetActiveSubroutineUniformiv:
8446         case VOGL_ENTRYPOINT_glGetActiveUniformARB:
8447         case VOGL_ENTRYPOINT_glGetActiveUniformBlockName:
8448         case VOGL_ENTRYPOINT_glGetActiveUniformBlockiv:
8449         case VOGL_ENTRYPOINT_glGetActiveUniformName:
8450         case VOGL_ENTRYPOINT_glGetActiveUniformsiv:
8451         case VOGL_ENTRYPOINT_glGetActiveVaryingNV:
8452         case VOGL_ENTRYPOINT_glGetArrayObjectfvATI:
8453         case VOGL_ENTRYPOINT_glGetArrayObjectivATI:
8454         case VOGL_ENTRYPOINT_glGetAttachedObjectsARB:
8455         case VOGL_ENTRYPOINT_glGetAttribLocationARB:
8456         case VOGL_ENTRYPOINT_glGetBooleanIndexedvEXT:
8457         case VOGL_ENTRYPOINT_glGetBooleani_v:
8458         case VOGL_ENTRYPOINT_glGetBufferParameteri64v:
8459         case VOGL_ENTRYPOINT_glGetBufferParameterivARB:
8460         case VOGL_ENTRYPOINT_glGetBufferParameterui64vNV:
8461         case VOGL_ENTRYPOINT_glGetBufferPointervARB:
8462         case VOGL_ENTRYPOINT_glGetBufferSubDataARB:
8463         case VOGL_ENTRYPOINT_glGetClipPlanefOES:
8464         case VOGL_ENTRYPOINT_glGetClipPlanexOES:
8465         case VOGL_ENTRYPOINT_glGetColorTable:
8466         case VOGL_ENTRYPOINT_glGetColorTableEXT:
8467         case VOGL_ENTRYPOINT_glGetColorTableParameterfv:
8468         case VOGL_ENTRYPOINT_glGetColorTableParameterfvEXT:
8469         case VOGL_ENTRYPOINT_glGetColorTableParameterfvSGI:
8470         case VOGL_ENTRYPOINT_glGetColorTableParameteriv:
8471         case VOGL_ENTRYPOINT_glGetColorTableParameterivEXT:
8472         case VOGL_ENTRYPOINT_glGetColorTableParameterivSGI:
8473         case VOGL_ENTRYPOINT_glGetColorTableSGI:
8474         case VOGL_ENTRYPOINT_glGetCombinerInputParameterfvNV:
8475         case VOGL_ENTRYPOINT_glGetCombinerInputParameterivNV:
8476         case VOGL_ENTRYPOINT_glGetCombinerOutputParameterfvNV:
8477         case VOGL_ENTRYPOINT_glGetCombinerOutputParameterivNV:
8478         case VOGL_ENTRYPOINT_glGetCombinerStageParameterfvNV:
8479         case VOGL_ENTRYPOINT_glGetCompressedMultiTexImageEXT:
8480         case VOGL_ENTRYPOINT_glGetCompressedTexImage:
8481         case VOGL_ENTRYPOINT_glGetCompressedTexImageARB:
8482         case VOGL_ENTRYPOINT_glGetCompressedTextureImageEXT:
8483         case VOGL_ENTRYPOINT_glGetConvolutionFilter:
8484         case VOGL_ENTRYPOINT_glGetConvolutionFilterEXT:
8485         case VOGL_ENTRYPOINT_glGetConvolutionParameterfv:
8486         case VOGL_ENTRYPOINT_glGetConvolutionParameterfvEXT:
8487         case VOGL_ENTRYPOINT_glGetConvolutionParameteriv:
8488         case VOGL_ENTRYPOINT_glGetConvolutionParameterivEXT:
8489         case VOGL_ENTRYPOINT_glGetConvolutionParameterxvOES:
8490         case VOGL_ENTRYPOINT_glGetDebugMessageLog:
8491         case VOGL_ENTRYPOINT_glGetDebugMessageLogAMD:
8492         case VOGL_ENTRYPOINT_glGetDetailTexFuncSGIS:
8493         case VOGL_ENTRYPOINT_glGetDoubleIndexedvEXT:
8494         case VOGL_ENTRYPOINT_glGetDoublei_v:
8495         case VOGL_ENTRYPOINT_glGetFenceivNV:
8496         case VOGL_ENTRYPOINT_glGetFinalCombinerInputParameterfvNV:
8497         case VOGL_ENTRYPOINT_glGetFinalCombinerInputParameterivNV:
8498         case VOGL_ENTRYPOINT_glGetFixedvOES:
8499         case VOGL_ENTRYPOINT_glGetFloatIndexedvEXT:
8500         case VOGL_ENTRYPOINT_glGetFloati_v:
8501         case VOGL_ENTRYPOINT_glGetFogFuncSGIS:
8502         case VOGL_ENTRYPOINT_glGetFragDataIndex:
8503         case VOGL_ENTRYPOINT_glGetFragDataLocation:
8504         case VOGL_ENTRYPOINT_glGetFragDataLocationEXT:
8505         case VOGL_ENTRYPOINT_glGetFragmentLightfvSGIX:
8506         case VOGL_ENTRYPOINT_glGetFragmentLightivSGIX:
8507         case VOGL_ENTRYPOINT_glGetFragmentMaterialfvSGIX:
8508         case VOGL_ENTRYPOINT_glGetFragmentMaterialivSGIX:
8509         case VOGL_ENTRYPOINT_glGetFramebufferAttachmentParameteriv:
8510         case VOGL_ENTRYPOINT_glGetFramebufferAttachmentParameterivEXT:
8511         case VOGL_ENTRYPOINT_glGetFramebufferParameteriv:
8512         case VOGL_ENTRYPOINT_glGetFramebufferParameterivEXT:
8513         case VOGL_ENTRYPOINT_glGetGraphicsResetStatusARB:
8514         case VOGL_ENTRYPOINT_glGetHandleARB:
8515         case VOGL_ENTRYPOINT_glGetHistogram:
8516         case VOGL_ENTRYPOINT_glGetHistogramEXT:
8517         case VOGL_ENTRYPOINT_glGetHistogramParameterfv:
8518         case VOGL_ENTRYPOINT_glGetHistogramParameterfvEXT:
8519         case VOGL_ENTRYPOINT_glGetHistogramParameteriv:
8520         case VOGL_ENTRYPOINT_glGetHistogramParameterivEXT:
8521         case VOGL_ENTRYPOINT_glGetHistogramParameterxvOES:
8522         case VOGL_ENTRYPOINT_glGetImageHandleNV:
8523         case VOGL_ENTRYPOINT_glGetImageTransformParameterfvHP:
8524         case VOGL_ENTRYPOINT_glGetImageTransformParameterivHP:
8525         case VOGL_ENTRYPOINT_glGetInstrumentsSGIX:
8526         case VOGL_ENTRYPOINT_glGetInteger64i_v:
8527         case VOGL_ENTRYPOINT_glGetInteger64v:
8528         case VOGL_ENTRYPOINT_glGetIntegerIndexedvEXT:
8529         case VOGL_ENTRYPOINT_glGetIntegeri_v:
8530         case VOGL_ENTRYPOINT_glGetIntegerui64i_vNV:
8531         case VOGL_ENTRYPOINT_glGetIntegerui64vNV:
8532         case VOGL_ENTRYPOINT_glGetInternalformati64v:
8533         case VOGL_ENTRYPOINT_glGetInternalformativ:
8534         case VOGL_ENTRYPOINT_glGetInvariantBooleanvEXT:
8535         case VOGL_ENTRYPOINT_glGetInvariantFloatvEXT:
8536         case VOGL_ENTRYPOINT_glGetInvariantIntegervEXT:
8537         case VOGL_ENTRYPOINT_glGetLightxOES:
8538         case VOGL_ENTRYPOINT_glGetListParameterfvSGIX:
8539         case VOGL_ENTRYPOINT_glGetListParameterivSGIX:
8540         case VOGL_ENTRYPOINT_glGetLocalConstantBooleanvEXT:
8541         case VOGL_ENTRYPOINT_glGetLocalConstantFloatvEXT:
8542         case VOGL_ENTRYPOINT_glGetLocalConstantIntegervEXT:
8543         case VOGL_ENTRYPOINT_glGetMapAttribParameterfvNV:
8544         case VOGL_ENTRYPOINT_glGetMapAttribParameterivNV:
8545         case VOGL_ENTRYPOINT_glGetMapControlPointsNV:
8546         case VOGL_ENTRYPOINT_glGetMapParameterfvNV:
8547         case VOGL_ENTRYPOINT_glGetMapParameterivNV:
8548         case VOGL_ENTRYPOINT_glGetMapdv:
8549         case VOGL_ENTRYPOINT_glGetMapfv:
8550         case VOGL_ENTRYPOINT_glGetMapiv:
8551         case VOGL_ENTRYPOINT_glGetMapxvOES:
8552         case VOGL_ENTRYPOINT_glGetMaterialfv:
8553         case VOGL_ENTRYPOINT_glGetMaterialiv:
8554         case VOGL_ENTRYPOINT_glGetMaterialxOES:
8555         case VOGL_ENTRYPOINT_glGetMinmax:
8556         case VOGL_ENTRYPOINT_glGetMinmaxEXT:
8557         case VOGL_ENTRYPOINT_glGetMinmaxParameterfv:
8558         case VOGL_ENTRYPOINT_glGetMinmaxParameterfvEXT:
8559         case VOGL_ENTRYPOINT_glGetMinmaxParameteriv:
8560         case VOGL_ENTRYPOINT_glGetMinmaxParameterivEXT:
8561         case VOGL_ENTRYPOINT_glGetMultiTexEnvfvEXT:
8562         case VOGL_ENTRYPOINT_glGetMultiTexEnvivEXT:
8563         case VOGL_ENTRYPOINT_glGetMultiTexGendvEXT:
8564         case VOGL_ENTRYPOINT_glGetMultiTexGenfvEXT:
8565         case VOGL_ENTRYPOINT_glGetMultiTexGenivEXT:
8566         case VOGL_ENTRYPOINT_glGetMultiTexImageEXT:
8567         case VOGL_ENTRYPOINT_glGetMultiTexLevelParameterfvEXT:
8568         case VOGL_ENTRYPOINT_glGetMultiTexLevelParameterivEXT:
8569         case VOGL_ENTRYPOINT_glGetMultiTexParameterIivEXT:
8570         case VOGL_ENTRYPOINT_glGetMultiTexParameterIuivEXT:
8571         case VOGL_ENTRYPOINT_glGetMultiTexParameterfvEXT:
8572         case VOGL_ENTRYPOINT_glGetMultiTexParameterivEXT:
8573         case VOGL_ENTRYPOINT_glGetMultisamplefv:
8574         case VOGL_ENTRYPOINT_glGetMultisamplefvNV:
8575         case VOGL_ENTRYPOINT_glGetNamedBufferParameterivEXT:
8576         case VOGL_ENTRYPOINT_glGetNamedBufferParameterui64vNV:
8577         case VOGL_ENTRYPOINT_glGetNamedBufferPointervEXT:
8578         case VOGL_ENTRYPOINT_glGetNamedBufferSubDataEXT:
8579         case VOGL_ENTRYPOINT_glGetNamedFramebufferAttachmentParameterivEXT:
8580         case VOGL_ENTRYPOINT_glGetNamedFramebufferParameterivEXT:
8581         case VOGL_ENTRYPOINT_glGetNamedProgramLocalParameterIivEXT:
8582         case VOGL_ENTRYPOINT_glGetNamedProgramLocalParameterIuivEXT:
8583         case VOGL_ENTRYPOINT_glGetNamedProgramLocalParameterdvEXT:
8584         case VOGL_ENTRYPOINT_glGetNamedProgramLocalParameterfvEXT:
8585         case VOGL_ENTRYPOINT_glGetNamedProgramStringEXT:
8586         case VOGL_ENTRYPOINT_glGetNamedProgramivEXT:
8587         case VOGL_ENTRYPOINT_glGetNamedRenderbufferParameterivEXT:
8588         case VOGL_ENTRYPOINT_glGetNamedStringARB:
8589         case VOGL_ENTRYPOINT_glGetNamedStringivARB:
8590         case VOGL_ENTRYPOINT_glGetObjectBufferfvATI:
8591         case VOGL_ENTRYPOINT_glGetObjectBufferivATI:
8592         case VOGL_ENTRYPOINT_glGetObjectLabel:
8593         case VOGL_ENTRYPOINT_glGetObjectParameterfvARB:
8594         case VOGL_ENTRYPOINT_glGetObjectParameterivAPPLE:
8595         case VOGL_ENTRYPOINT_glGetObjectPtrLabel:
8596         case VOGL_ENTRYPOINT_glGetOcclusionQueryivNV:
8597         case VOGL_ENTRYPOINT_glGetOcclusionQueryuivNV:
8598         case VOGL_ENTRYPOINT_glGetPathColorGenfvNV:
8599         case VOGL_ENTRYPOINT_glGetPathColorGenivNV:
8600         case VOGL_ENTRYPOINT_glGetPathCommandsNV:
8601         case VOGL_ENTRYPOINT_glGetPathCoordsNV:
8602         case VOGL_ENTRYPOINT_glGetPathDashArrayNV:
8603         case VOGL_ENTRYPOINT_glGetPathLengthNV:
8604         case VOGL_ENTRYPOINT_glGetPathMetricRangeNV:
8605         case VOGL_ENTRYPOINT_glGetPathMetricsNV:
8606         case VOGL_ENTRYPOINT_glGetPathParameterfvNV:
8607         case VOGL_ENTRYPOINT_glGetPathParameterivNV:
8608         case VOGL_ENTRYPOINT_glGetPathSpacingNV:
8609         case VOGL_ENTRYPOINT_glGetPathTexGenfvNV:
8610         case VOGL_ENTRYPOINT_glGetPathTexGenivNV:
8611         case VOGL_ENTRYPOINT_glGetPerfMonitorCounterDataAMD:
8612         case VOGL_ENTRYPOINT_glGetPerfMonitorCounterInfoAMD:
8613         case VOGL_ENTRYPOINT_glGetPerfMonitorCounterStringAMD:
8614         case VOGL_ENTRYPOINT_glGetPerfMonitorCountersAMD:
8615         case VOGL_ENTRYPOINT_glGetPerfMonitorGroupStringAMD:
8616         case VOGL_ENTRYPOINT_glGetPerfMonitorGroupsAMD:
8617         case VOGL_ENTRYPOINT_glGetPixelMapfv:
8618         case VOGL_ENTRYPOINT_glGetPixelMapuiv:
8619         case VOGL_ENTRYPOINT_glGetPixelMapusv:
8620         case VOGL_ENTRYPOINT_glGetPixelMapxv:
8621         case VOGL_ENTRYPOINT_glGetPixelTexGenParameterfvSGIS:
8622         case VOGL_ENTRYPOINT_glGetPixelTexGenParameterivSGIS:
8623         case VOGL_ENTRYPOINT_glGetPixelTransformParameterfvEXT:
8624         case VOGL_ENTRYPOINT_glGetPixelTransformParameterivEXT:
8625         case VOGL_ENTRYPOINT_glGetPointerIndexedvEXT:
8626         case VOGL_ENTRYPOINT_glGetPointervEXT:
8627         case VOGL_ENTRYPOINT_glGetPolygonStipple:
8628         case VOGL_ENTRYPOINT_glGetProgramBinary:
8629         case VOGL_ENTRYPOINT_glGetProgramEnvParameterIivNV:
8630         case VOGL_ENTRYPOINT_glGetProgramEnvParameterIuivNV:
8631         case VOGL_ENTRYPOINT_glGetProgramEnvParameterdvARB:
8632         case VOGL_ENTRYPOINT_glGetProgramEnvParameterfvARB:
8633         case VOGL_ENTRYPOINT_glGetProgramInterfaceiv:
8634         case VOGL_ENTRYPOINT_glGetProgramLocalParameterIivNV:
8635         case VOGL_ENTRYPOINT_glGetProgramLocalParameterIuivNV:
8636         case VOGL_ENTRYPOINT_glGetProgramLocalParameterdvARB:
8637         case VOGL_ENTRYPOINT_glGetProgramLocalParameterfvARB:
8638         case VOGL_ENTRYPOINT_glGetProgramNamedParameterdvNV:
8639         case VOGL_ENTRYPOINT_glGetProgramNamedParameterfvNV:
8640         case VOGL_ENTRYPOINT_glGetProgramParameterdvNV:
8641         case VOGL_ENTRYPOINT_glGetProgramParameterfvNV:
8642         case VOGL_ENTRYPOINT_glGetProgramPipelineInfoLog:
8643         case VOGL_ENTRYPOINT_glGetProgramPipelineiv:
8644         case VOGL_ENTRYPOINT_glGetProgramResourceIndex:
8645         case VOGL_ENTRYPOINT_glGetProgramResourceLocation:
8646         case VOGL_ENTRYPOINT_glGetProgramResourceLocationIndex:
8647         case VOGL_ENTRYPOINT_glGetProgramResourceName:
8648         case VOGL_ENTRYPOINT_glGetProgramResourceiv:
8649         case VOGL_ENTRYPOINT_glGetProgramStageiv:
8650         case VOGL_ENTRYPOINT_glGetProgramStringARB:
8651         case VOGL_ENTRYPOINT_glGetProgramStringNV:
8652         case VOGL_ENTRYPOINT_glGetProgramSubroutineParameteruivNV:
8653         case VOGL_ENTRYPOINT_glGetProgramivNV:
8654         case VOGL_ENTRYPOINT_glGetQueryIndexediv:
8655         case VOGL_ENTRYPOINT_glGetQueryObjecti64vEXT:
8656         case VOGL_ENTRYPOINT_glGetQueryObjectui64vEXT:
8657         case VOGL_ENTRYPOINT_glGetQueryiv:
8658         case VOGL_ENTRYPOINT_glGetQueryivARB:
8659         case VOGL_ENTRYPOINT_glGetSamplerParameterIiv:
8660         case VOGL_ENTRYPOINT_glGetSamplerParameterIuiv:
8661         case VOGL_ENTRYPOINT_glGetSamplerParameterfv:
8662         case VOGL_ENTRYPOINT_glGetSamplerParameteriv:
8663         case VOGL_ENTRYPOINT_glGetSeparableFilter:
8664         case VOGL_ENTRYPOINT_glGetSeparableFilterEXT:
8665         case VOGL_ENTRYPOINT_glGetShaderPrecisionFormat:
8666         case VOGL_ENTRYPOINT_glGetShaderSource:
8667         case VOGL_ENTRYPOINT_glGetShaderSourceARB:
8668         case VOGL_ENTRYPOINT_glGetSharpenTexFuncSGIS:
8669         case VOGL_ENTRYPOINT_glGetSubroutineIndex:
8670         case VOGL_ENTRYPOINT_glGetSubroutineUniformLocation:
8671         case VOGL_ENTRYPOINT_glGetSynciv:
8672         case VOGL_ENTRYPOINT_glGetTexBumpParameterfvATI:
8673         case VOGL_ENTRYPOINT_glGetTexBumpParameterivATI:
8674         case VOGL_ENTRYPOINT_glGetTexEnvxvOES:
8675         case VOGL_ENTRYPOINT_glGetTexFilterFuncSGIS:
8676         case VOGL_ENTRYPOINT_glGetTexGenxvOES:
8677         case VOGL_ENTRYPOINT_glGetTexImage:
8678         case VOGL_ENTRYPOINT_glGetTexLevelParameterxvOES:
8679         case VOGL_ENTRYPOINT_glGetTexParameterIivEXT:
8680         case VOGL_ENTRYPOINT_glGetTexParameterIuivEXT:
8681         case VOGL_ENTRYPOINT_glGetTexParameterPointervAPPLE:
8682         case VOGL_ENTRYPOINT_glGetTexParameterxvOES:
8683         case VOGL_ENTRYPOINT_glGetTextureHandleNV:
8684         case VOGL_ENTRYPOINT_glGetTextureImageEXT:
8685         case VOGL_ENTRYPOINT_glGetTextureLevelParameterfvEXT:
8686         case VOGL_ENTRYPOINT_glGetTextureLevelParameterivEXT:
8687         case VOGL_ENTRYPOINT_glGetTextureParameterIivEXT:
8688         case VOGL_ENTRYPOINT_glGetTextureParameterIuivEXT:
8689         case VOGL_ENTRYPOINT_glGetTextureParameterfvEXT:
8690         case VOGL_ENTRYPOINT_glGetTextureParameterivEXT:
8691         case VOGL_ENTRYPOINT_glGetTextureSamplerHandleNV:
8692         case VOGL_ENTRYPOINT_glGetTrackMatrixivNV:
8693         case VOGL_ENTRYPOINT_glGetTransformFeedbackVarying:
8694         case VOGL_ENTRYPOINT_glGetTransformFeedbackVaryingEXT:
8695         case VOGL_ENTRYPOINT_glGetTransformFeedbackVaryingNV:
8696         case VOGL_ENTRYPOINT_glGetUniformBlockIndex:
8697         case VOGL_ENTRYPOINT_glGetUniformBufferSizeEXT:
8698         case VOGL_ENTRYPOINT_glGetUniformIndices:
8699         case VOGL_ENTRYPOINT_glGetUniformOffsetEXT:
8700         case VOGL_ENTRYPOINT_glGetUniformSubroutineuiv:
8701         case VOGL_ENTRYPOINT_glGetUniformdv:
8702         case VOGL_ENTRYPOINT_glGetUniformfv:
8703         case VOGL_ENTRYPOINT_glGetUniformfvARB:
8704         case VOGL_ENTRYPOINT_glGetUniformi64vNV:
8705         case VOGL_ENTRYPOINT_glGetUniformiv:
8706         case VOGL_ENTRYPOINT_glGetUniformivARB:
8707         case VOGL_ENTRYPOINT_glGetUniformui64vNV:
8708         case VOGL_ENTRYPOINT_glGetUniformuiv:
8709         case VOGL_ENTRYPOINT_glGetUniformuivEXT:
8710         case VOGL_ENTRYPOINT_glGetVariantArrayObjectfvATI:
8711         case VOGL_ENTRYPOINT_glGetVariantArrayObjectivATI:
8712         case VOGL_ENTRYPOINT_glGetVariantBooleanvEXT:
8713         case VOGL_ENTRYPOINT_glGetVariantFloatvEXT:
8714         case VOGL_ENTRYPOINT_glGetVariantIntegervEXT:
8715         case VOGL_ENTRYPOINT_glGetVariantPointervEXT:
8716         case VOGL_ENTRYPOINT_glGetVaryingLocationNV:
8717         case VOGL_ENTRYPOINT_glGetVertexAttribArrayObjectfvATI:
8718         case VOGL_ENTRYPOINT_glGetVertexAttribArrayObjectivATI:
8719         case VOGL_ENTRYPOINT_glGetVertexAttribLdv:
8720         case VOGL_ENTRYPOINT_glGetVertexAttribLdvEXT:
8721         case VOGL_ENTRYPOINT_glGetVertexAttribLi64vNV:
8722         case VOGL_ENTRYPOINT_glGetVertexAttribLui64vNV:
8723         case VOGL_ENTRYPOINT_glGetVertexAttribPointerv:
8724         case VOGL_ENTRYPOINT_glGetVertexAttribPointervARB:
8725         case VOGL_ENTRYPOINT_glGetVertexAttribPointervNV:
8726         case VOGL_ENTRYPOINT_glGetVertexAttribdvARB:
8727         case VOGL_ENTRYPOINT_glGetVertexAttribdvNV:
8728         case VOGL_ENTRYPOINT_glGetVertexAttribfvARB:
8729         case VOGL_ENTRYPOINT_glGetVertexAttribfvNV:
8730         case VOGL_ENTRYPOINT_glGetVertexAttribivARB:
8731         case VOGL_ENTRYPOINT_glGetVertexAttribivNV:
8732         case VOGL_ENTRYPOINT_glGetVideoCaptureStreamdvNV:
8733         case VOGL_ENTRYPOINT_glGetVideoCaptureStreamfvNV:
8734         case VOGL_ENTRYPOINT_glGetVideoCaptureStreamivNV:
8735         case VOGL_ENTRYPOINT_glGetVideoCaptureivNV:
8736         case VOGL_ENTRYPOINT_glGetVideoi64vNV:
8737         case VOGL_ENTRYPOINT_glGetVideoivNV:
8738         case VOGL_ENTRYPOINT_glGetVideoui64vNV:
8739         case VOGL_ENTRYPOINT_glGetVideouivNV:
8740         case VOGL_ENTRYPOINT_glGetnColorTableARB:
8741         case VOGL_ENTRYPOINT_glGetnCompressedTexImageARB:
8742         case VOGL_ENTRYPOINT_glGetnConvolutionFilterARB:
8743         case VOGL_ENTRYPOINT_glGetnHistogramARB:
8744         case VOGL_ENTRYPOINT_glGetnMapdvARB:
8745         case VOGL_ENTRYPOINT_glGetnMapfvARB:
8746         case VOGL_ENTRYPOINT_glGetnMapivARB:
8747         case VOGL_ENTRYPOINT_glGetnMinmaxARB:
8748         case VOGL_ENTRYPOINT_glGetnPixelMapfvARB:
8749         case VOGL_ENTRYPOINT_glGetnPixelMapuivARB:
8750         case VOGL_ENTRYPOINT_glGetnPixelMapusvARB:
8751         case VOGL_ENTRYPOINT_glGetnPolygonStippleARB:
8752         case VOGL_ENTRYPOINT_glGetnSeparableFilterARB:
8753         case VOGL_ENTRYPOINT_glGetnTexImageARB:
8754         case VOGL_ENTRYPOINT_glGetnUniformdvARB:
8755         case VOGL_ENTRYPOINT_glGetnUniformfvARB:
8756         case VOGL_ENTRYPOINT_glGetnUniformivARB:
8757         case VOGL_ENTRYPOINT_glGetnUniformuivARB:
8758         case VOGL_ENTRYPOINT_glIsBufferARB:
8759         case VOGL_ENTRYPOINT_glIsEnabledIndexedEXT:
8760         case VOGL_ENTRYPOINT_glIsQueryARB:
8761         case VOGL_ENTRYPOINT_glIsSync:
8762         case VOGL_ENTRYPOINT_glPrioritizeTextures:
8763         case VOGL_ENTRYPOINT_glPrioritizeTexturesEXT:
8764         {
8765             if (!(g_vogl_entrypoint_descs[entrypoint_id].m_flags & cGLEFPrintedUnimplementedWarning))
8766             {
8767                 process_entrypoint_warning("%s: TODO: Implement glGet() function %s\n", VOGL_METHOD_NAME, g_vogl_entrypoint_descs[entrypoint_id].m_pName);
8768
8769                 g_vogl_entrypoint_descs[entrypoint_id].m_flags |= cGLEFPrintedUnimplementedWarning;
8770             }
8771             break;
8772         }
8773         default:
8774         {
8775             if (g_vogl_entrypoint_descs[entrypoint_id].m_is_whitelisted)
8776                 process_entrypoint_error("%s: Unhandled GL function %s. This function is marked as whitelisted but was not handled!\n", VOGL_METHOD_NAME, g_vogl_entrypoint_descs[entrypoint_id].m_pName);
8777             else
8778                 process_entrypoint_error("%s: Unhandled GL function %s. This function needs to be added to the whitelist!\n", VOGL_METHOD_NAME, g_vogl_entrypoint_descs[entrypoint_id].m_pName);
8779             return cStatusSoftFailure;
8780         }
8781     }
8782
8783     m_last_processed_call_counter = trace_packet.get_call_counter();
8784
8785     if (!m_pCur_context_state->m_inside_gl_begin)
8786     {
8787         if (check_gl_error())
8788             return cStatusGLError;
8789     }
8790
8791     if (vogl_is_draw_entrypoint(entrypoint_id) || vogl_is_clear_entrypoint(entrypoint_id) || (entrypoint_id == VOGL_ENTRYPOINT_glBitmap))
8792     {
8793         if ((status = post_draw_call()) != cStatusOK)
8794             return status;
8795     }
8796
8797     return cStatusOK;
8798 }
8799
8800 //----------------------------------------------------------------------------------------------------------------------
8801 // vogl_gl_replayer::snapshot_backbuffer
8802 //----------------------------------------------------------------------------------------------------------------------
8803 void vogl_gl_replayer::snapshot_backbuffer()
8804 {
8805     VOGL_FUNC_TRACER
8806
8807     if (!m_pCur_context_state)
8808     {
8809         vogl_warning_printf("%s: Can't take snapshot without an active context\n", VOGL_METHOD_NAME);
8810         return;
8811     }
8812
8813     uint recorded_width = m_pWindow->get_width();
8814     uint recorded_height = m_pWindow->get_height();
8815
8816     uint width = 0, height = 0;
8817     m_pWindow->get_actual_dimensions(width, height);
8818
8819     VOGL_ASSERT((recorded_width == width) && (recorded_height == height));
8820     VOGL_NOTE_UNUSED(recorded_width);
8821     VOGL_NOTE_UNUSED(recorded_height);
8822
8823     m_screenshot_buffer.resize(width * height * 3);
8824
8825     bool success = vogl_copy_buffer_to_image(m_screenshot_buffer.get_ptr(), m_screenshot_buffer.size(), width, height, GL_RGB, GL_UNSIGNED_BYTE, false, 0, GL_BACK);
8826     if (!success)
8827     {
8828         process_entrypoint_error("%s: Failed calling glReadPixels() to take screenshot\n", VOGL_METHOD_NAME);
8829     }
8830
8831     if (m_flags & cGLReplayerDumpScreenshots)
8832     {
8833         size_t png_size = 0;
8834         void *pPNG_data = tdefl_write_image_to_png_file_in_memory_ex(m_screenshot_buffer.get_ptr(), width, height, 3, &png_size, 1, true);
8835
8836         dynamic_string screenshot_filename(cVarArg, "%s_%07u.png", m_screenshot_prefix.get_ptr(), m_total_swaps);
8837         if (!file_utils::write_buf_to_file(screenshot_filename.get_ptr(), pPNG_data, png_size))
8838         {
8839             process_entrypoint_error("Failed writing PNG screenshot to file %s\n", screenshot_filename.get_ptr());
8840         }
8841         else
8842         {
8843             vogl_message_printf("Wrote screenshot to file %s\n", screenshot_filename.get_ptr());
8844         }
8845
8846         mz_free(pPNG_data);
8847     }
8848
8849     if ((m_flags & cGLReplayerDumpBackbufferHashes) || (m_flags & cGLReplayerHashBackbuffer))
8850     {
8851         uint64_t backbuffer_crc64;
8852
8853         if (m_flags & cGLReplayerSumHashing)
8854         {
8855             backbuffer_crc64 = calc_sum64(m_screenshot_buffer.get_ptr(), m_screenshot_buffer.size());
8856         }
8857         else
8858         {
8859             backbuffer_crc64 = calc_crc64(CRC64_INIT, m_screenshot_buffer.get_ptr(), m_screenshot_buffer.size());
8860         }
8861
8862         vogl_printf("Frame %u hash: 0x%016" PRIX64 "\n", m_frame_index, backbuffer_crc64);
8863
8864         if (m_backbuffer_hash_filename.has_content())
8865         {
8866             FILE *pFile = vogl_fopen(m_backbuffer_hash_filename.get_ptr(), "a");
8867             if (!pFile)
8868                 vogl_error_printf("Failed writing to backbuffer hash file %s\n", m_backbuffer_hash_filename.get_ptr());
8869             else
8870             {
8871                 vogl_fprintf(pFile, "0x%016" PRIX64 "\n", cast_val_to_uint64(backbuffer_crc64));
8872                 vogl_fclose(pFile);
8873             }
8874         }
8875     }
8876 }
8877
8878 //----------------------------------------------------------------------------------------------------------------------
8879 // vogl_gl_replayer::is_valid_handle
8880 //----------------------------------------------------------------------------------------------------------------------
8881 bool vogl_gl_replayer::replay_to_trace_handle_remapper::is_valid_handle(vogl_namespace_t handle_namespace, uint64_t replay_handle)
8882 {
8883     VOGL_FUNC_TRACER
8884
8885     if (!replay_handle)
8886         return 0;
8887
8888     uint32 replay_handle32 = static_cast<uint32>(replay_handle);
8889
8890     switch (handle_namespace)
8891     {
8892         case VOGL_NAMESPACE_VERTEX_ARRAYS:
8893         {
8894             VOGL_ASSERT(replay_handle32 == replay_handle);
8895             return (m_replayer.get_context_state()->m_vertex_array_objects.search_table_for_value_get_count(replay_handle32) != 0);
8896         }
8897         case VOGL_NAMESPACE_FRAMEBUFFERS:
8898         {
8899             VOGL_ASSERT(replay_handle32 == replay_handle);
8900             return (m_replayer.get_context_state()->m_framebuffers.search_table_for_value_get_count(replay_handle32) != 0);
8901         }
8902         case VOGL_NAMESPACE_TEXTURES:
8903         {
8904             VOGL_ASSERT(replay_handle32 == replay_handle);
8905             return (m_replayer.get_shared_state()->m_shadow_state.m_textures.contains_inv(replay_handle32) != 0);
8906         }
8907         case VOGL_NAMESPACE_RENDER_BUFFERS:
8908         {
8909             VOGL_ASSERT(replay_handle32 == replay_handle);
8910             return (m_replayer.get_shared_state()->m_shadow_state.m_rbos.contains_inv(replay_handle32) != 0);
8911         }
8912         case VOGL_NAMESPACE_QUERIES:
8913         {
8914             VOGL_ASSERT(replay_handle32 == replay_handle);
8915             return (m_replayer.get_shared_state()->m_queries.search_table_for_value_get_count(replay_handle32) != 0);
8916         }
8917         case VOGL_NAMESPACE_SAMPLERS:
8918         {
8919             VOGL_ASSERT(replay_handle32 == replay_handle);
8920             return (m_replayer.get_shared_state()->m_sampler_objects.search_table_for_value_get_count(replay_handle32) != 0);
8921         }
8922         case VOGL_NAMESPACE_PROGRAMS:
8923         {
8924             VOGL_ASSERT(replay_handle32 == replay_handle);
8925             return m_replayer.get_shared_state()->m_shadow_state.m_objs.get_target_inv(replay_handle32) == VOGL_PROGRAM_OBJECT;
8926         }
8927         case VOGL_NAMESPACE_SHADERS:
8928         {
8929             VOGL_ASSERT(replay_handle32 == replay_handle);
8930             return m_replayer.get_shared_state()->m_shadow_state.m_objs.get_target_inv(replay_handle32) == VOGL_SHADER_OBJECT;
8931         }
8932         case VOGL_NAMESPACE_BUFFERS:
8933         {
8934             VOGL_ASSERT(replay_handle32 == replay_handle);
8935             return m_replayer.get_shared_state()->m_buffers.search_table_for_value_get_count(replay_handle32);
8936         }
8937         case VOGL_NAMESPACE_SYNCS:
8938         {
8939             GLsync replay_sync = vogl_handle_to_sync(replay_handle);
8940             return m_replayer.get_shared_state()->m_syncs.search_table_for_value_get_count(replay_sync) != 0;
8941         }
8942         case VOGL_NAMESPACE_PROGRAM_ARB:
8943         {
8944             VOGL_ASSERT(replay_handle32 == replay_handle);
8945             return m_replayer.get_shared_state()->m_arb_programs.search_table_for_value_get_count(replay_handle32) != 0;
8946         }
8947         default:
8948             break;
8949     }
8950
8951     VOGL_VERIFY(0);
8952
8953     return false;
8954 }
8955
8956 //----------------------------------------------------------------------------------------------------------------------
8957 // vogl_gl_replayer::remap_handle
8958 //----------------------------------------------------------------------------------------------------------------------
8959 uint64_t vogl_gl_replayer::replay_to_trace_handle_remapper::remap_handle(vogl_namespace_t handle_namespace, uint64_t replay_handle)
8960 {
8961     VOGL_FUNC_TRACER
8962
8963     if (!replay_handle)
8964         return 0;
8965
8966     uint32 replay_handle32 = static_cast<uint32>(replay_handle);
8967
8968     switch (handle_namespace)
8969     {
8970         case VOGL_NAMESPACE_VERTEX_ARRAYS:
8971         {
8972             VOGL_ASSERT(replay_handle32 == replay_handle);
8973             if (remap_replay_to_trace_handle(m_replayer.get_context_state()->m_vertex_array_objects, replay_handle32))
8974                 return replay_handle32;
8975             break;
8976         }
8977         case VOGL_NAMESPACE_FRAMEBUFFERS:
8978         {
8979             VOGL_ASSERT(replay_handle32 == replay_handle);
8980             if (remap_replay_to_trace_handle(m_replayer.get_context_state()->m_framebuffers, replay_handle32))
8981                 return replay_handle32;
8982             break;
8983         }
8984         case VOGL_NAMESPACE_TEXTURES:
8985         {
8986             VOGL_ASSERT(replay_handle32 == replay_handle);
8987
8988             uint32 trace_handle = replay_handle32;
8989             if (m_replayer.get_shared_state()->m_shadow_state.m_textures.map_inv_handle_to_handle(replay_handle32, trace_handle))
8990                 return trace_handle;
8991
8992             break;
8993         }
8994         case VOGL_NAMESPACE_RENDER_BUFFERS:
8995         {
8996             VOGL_ASSERT(replay_handle32 == replay_handle);
8997             GLuint trace_handle = replay_handle32;
8998             if (m_replayer.get_shared_state()->m_shadow_state.m_rbos.map_inv_handle_to_handle(replay_handle32, trace_handle))
8999                 return trace_handle;
9000
9001             break;
9002         }
9003         case VOGL_NAMESPACE_QUERIES:
9004         {
9005             VOGL_ASSERT(replay_handle32 == replay_handle);
9006             if (remap_replay_to_trace_handle(m_replayer.get_shared_state()->m_queries, replay_handle32))
9007                 return replay_handle32;
9008             break;
9009         }
9010         case VOGL_NAMESPACE_SAMPLERS:
9011         {
9012             VOGL_ASSERT(replay_handle32 == replay_handle);
9013             if (remap_replay_to_trace_handle(m_replayer.get_shared_state()->m_sampler_objects, replay_handle32))
9014                 return replay_handle32;
9015             break;
9016         }
9017         case VOGL_NAMESPACE_PROGRAMS:
9018         {
9019             VOGL_ASSERT(replay_handle32 == replay_handle);
9020             VOGL_ASSERT(m_replayer.get_shared_state()->m_shadow_state.m_objs.get_target_inv(replay_handle32) == VOGL_PROGRAM_OBJECT);
9021             GLuint trace_handle = replay_handle32;
9022             if (m_replayer.get_shared_state()->m_shadow_state.m_objs.map_inv_handle_to_handle(replay_handle32, trace_handle))
9023                 return trace_handle;
9024             break;
9025         }
9026         case VOGL_NAMESPACE_SHADERS:
9027         {
9028             VOGL_ASSERT(replay_handle32 == replay_handle);
9029             VOGL_ASSERT(m_replayer.get_shared_state()->m_shadow_state.m_objs.get_target_inv(replay_handle32) == VOGL_SHADER_OBJECT);
9030             GLuint trace_handle = replay_handle32;
9031             if (m_replayer.get_shared_state()->m_shadow_state.m_objs.map_inv_handle_to_handle(replay_handle32, trace_handle))
9032                 return trace_handle;
9033             break;
9034         }
9035         case VOGL_NAMESPACE_BUFFERS:
9036         {
9037             VOGL_ASSERT(replay_handle32 == replay_handle);
9038             if (remap_replay_to_trace_handle(m_replayer.get_shared_state()->m_buffers, replay_handle32))
9039                 return replay_handle32;
9040             break;
9041         }
9042         case VOGL_NAMESPACE_SYNCS:
9043         {
9044             GLsync replay_sync = vogl_handle_to_sync(replay_handle);
9045
9046             gl_sync_hash_map::const_iterator it(m_replayer.get_shared_state()->m_syncs.search_table_for_value(replay_sync));
9047             if (it != m_replayer.get_shared_state()->m_syncs.end())
9048             {
9049                 VOGL_ASSERT(it->second == replay_sync);
9050                 return it->first;
9051             }
9052
9053             break;
9054         }
9055         case VOGL_NAMESPACE_PROGRAM_ARB:
9056         {
9057             VOGL_ASSERT(replay_handle32 == replay_handle);
9058             if (remap_replay_to_trace_handle(m_replayer.get_shared_state()->m_arb_programs, replay_handle32))
9059                 return replay_handle32;
9060             break;
9061         }
9062         default:
9063         {
9064             break;
9065         }
9066     }
9067
9068     VOGL_ASSERT_ALWAYS;
9069
9070     vogl_error_printf("%s: Failed remapping handle %" PRIu64 " in namespace %s. This is either a handle shadowing bug, or this object was deleted while it was still bound on another context or attached to an object.\n", VOGL_METHOD_NAME, replay_handle, vogl_get_namespace_name(handle_namespace));
9071
9072     return replay_handle;
9073 }
9074
9075 //----------------------------------------------------------------------------------------------------------------------
9076 // vogl_gl_replayer::replay_to_trace_handle_remapper::remap_location
9077 //----------------------------------------------------------------------------------------------------------------------
9078 int32 vogl_gl_replayer::replay_to_trace_handle_remapper::remap_location(uint32 replay_program, int32 replay_location)
9079 {
9080     VOGL_FUNC_TRACER
9081
9082     if ((!replay_program) || (replay_location < 0))
9083         return replay_location;
9084
9085     GLuint trace_program = static_cast<GLuint>(remap_handle(VOGL_NAMESPACE_PROGRAMS, replay_program));
9086
9087     glsl_program_hash_map::const_iterator it(m_replayer.get_shared_state()->m_glsl_program_hash_map.find(trace_program));
9088     if (it != m_replayer.get_shared_state()->m_glsl_program_hash_map.end())
9089     {
9090         const glsl_program_state &state = it->second;
9091
9092         uniform_location_hash_map::const_iterator loc_it(state.m_uniform_locations.search_table_for_value(replay_location));
9093         if (loc_it != state.m_uniform_locations.end())
9094             return loc_it->first;
9095     }
9096
9097     vogl_warning_printf("%s: Failed remapping location %i of program %u\n", VOGL_METHOD_NAME, replay_location, replay_program);
9098
9099     return replay_location;
9100 }
9101
9102 //----------------------------------------------------------------------------------------------------------------------
9103 // vogl_gl_replayer::replay_to_trace_handle_remapper::determine_from_object_target
9104 //----------------------------------------------------------------------------------------------------------------------
9105 bool vogl_gl_replayer::replay_to_trace_handle_remapper::determine_from_object_target(vogl_namespace_t handle_namespace, uint64_t replay_handle, GLenum &target)
9106 {
9107     VOGL_FUNC_TRACER
9108
9109     target = GL_NONE;
9110
9111     uint32 handle32 = static_cast<uint32>(replay_handle);
9112
9113     switch (handle_namespace)
9114     {
9115         case VOGL_NAMESPACE_TEXTURES:
9116         {
9117             VOGL_ASSERT(handle32 == replay_handle);
9118             if (!m_replayer.get_shared_state()->m_shadow_state.m_textures.contains_inv(handle32))
9119                 return false;
9120
9121             target = m_replayer.get_shared_state()->m_shadow_state.m_textures.get_target_inv(handle32);
9122             return true;
9123         }
9124         default:
9125             break;
9126     }
9127
9128     VOGL_VERIFY(0);
9129     return false;
9130 }
9131
9132 //----------------------------------------------------------------------------------------------------------------------
9133 // vogl_gl_replayer::replay_to_trace_handle_remapper::determine_to_object_target
9134 //----------------------------------------------------------------------------------------------------------------------
9135 bool vogl_gl_replayer::replay_to_trace_handle_remapper::determine_to_object_target(vogl_namespace_t handle_namespace, uint64_t trace_handle, GLenum &target)
9136 {
9137     VOGL_FUNC_TRACER
9138
9139     target = GL_NONE;
9140
9141     uint32 handle32 = static_cast<uint32>(trace_handle);
9142
9143     switch (handle_namespace)
9144     {
9145         case VOGL_NAMESPACE_TEXTURES:
9146         {
9147             VOGL_ASSERT(handle32 == trace_handle);
9148             if (!m_replayer.get_shared_state()->m_shadow_state.m_textures.contains(handle32))
9149                 return false;
9150
9151             target = m_replayer.get_shared_state()->m_shadow_state.m_textures.get_target(handle32);
9152             return true;
9153         }
9154         default:
9155             break;
9156     }
9157
9158     VOGL_VERIFY(0);
9159     return false;
9160 }
9161
9162 //----------------------------------------------------------------------------------------------------------------------
9163 // vogl_replayer::determine_used_program_handles
9164 //----------------------------------------------------------------------------------------------------------------------
9165 bool vogl_gl_replayer::determine_used_program_handles(const vogl_trace_packet_array &trim_packets, vogl_handle_hash_set &replay_program_handles)
9166 {
9167     VOGL_FUNC_TRACER
9168
9169     trace_to_replay_handle_remapper trace_to_replay_remapper(*this);
9170
9171 #if 0
9172         GLint cur_program_handle = 0;
9173         GL_ENTRYPOINT(glGetIntegerv)(GL_CURRENT_PROGRAM, &cur_program_handle);
9174         check_gl_error();
9175
9176         if (cur_program_handle)
9177                 replay_program_handles.insert(cur_program_handle);
9178 #endif
9179
9180     // Scan for bound programs on all contexts in this sharegroup
9181     context_state *pContext_shareroot = m_pCur_context_state->m_pShared_state;
9182     for (context_hash_map::iterator it = m_contexts.begin(); it != m_contexts.end(); ++it)
9183     {
9184         context_state *pContext = it->second;
9185         if (pContext->m_pShared_state == pContext_shareroot)
9186         {
9187             if (pContext->m_cur_replay_program)
9188                 replay_program_handles.insert(pContext->m_cur_replay_program);
9189         }
9190     }
9191
9192     for (uint packet_index = 0; packet_index < trim_packets.size(); packet_index++)
9193     {
9194         if (trim_packets.get_packet_type(packet_index) != cTSPTGLEntrypoint)
9195             continue;
9196
9197         const uint8_vec &packet_buf = trim_packets.get_packet_buf(packet_index);
9198
9199         // Important note: This purposesly doesn't process ctype packets, because they don't really do anything and I'm going to be redesigning the ctype/entrypoint stuff anyway so they are always processed after SOF.
9200         if (!m_temp2_gl_packet.deserialize(packet_buf.get_ptr(), packet_buf.size(), true))
9201             return false;
9202
9203         GLuint trace_handle = 0;
9204         bool refers_to_program = vogl_does_packet_refer_to_program(m_temp2_gl_packet, trace_handle);
9205         if (!refers_to_program)
9206             continue;
9207         if (!trace_handle)
9208             continue;
9209
9210         // trace_handle is conservative, and it's fine if it can't be actually mapped into the replay space because as we process packets it's possible for the trace to create/delete program handles
9211         // All that matters is that we're conservative (i.e. we can't filter out any programs that are actually referenced in this trace packet array).
9212         if (!trace_to_replay_remapper.is_valid_handle(VOGL_NAMESPACE_PROGRAMS, trace_handle))
9213             continue;
9214
9215         uint64_t replay_handle = trace_to_replay_remapper.remap_handle(VOGL_NAMESPACE_PROGRAMS, trace_handle);
9216         if (!replay_handle)
9217             continue;
9218
9219         VOGL_ASSERT(utils::is_32bit(replay_handle));
9220
9221         replay_program_handles.insert(static_cast<uint32>(replay_handle));
9222     }
9223
9224     vogl_message_printf("%s: Found %u actually referenced program handles\n", VOGL_METHOD_NAME, replay_program_handles.size());
9225
9226     return true;
9227 }
9228
9229 //----------------------------------------------------------------------------------------------------------------------
9230 // vogl_replayer::fill_replay_handle_hash_set
9231 //----------------------------------------------------------------------------------------------------------------------
9232 void vogl_gl_replayer::fill_replay_handle_hash_set(vogl_handle_hash_set &replay_handle_hash, const gl_handle_hash_map &trace_to_replay_hash)
9233 {
9234     VOGL_FUNC_TRACER
9235
9236     replay_handle_hash.reset();
9237     replay_handle_hash.reserve(trace_to_replay_hash.size());
9238     for (gl_handle_hash_map::const_iterator it = trace_to_replay_hash.begin(); it != trace_to_replay_hash.end(); ++it)
9239     {
9240         // Insert replay handles into destination hash table
9241         bool success = replay_handle_hash.insert(it->second).second;
9242         VOGL_ASSERT(success);
9243         VOGL_NOTE_UNUSED(success);
9244     }
9245 }
9246
9247 //----------------------------------------------------------------------------------------------------------------------
9248 // vogl_replayer::snapshot_state
9249 //----------------------------------------------------------------------------------------------------------------------
9250 vogl_gl_state_snapshot *vogl_gl_replayer::snapshot_state(const vogl_trace_packet_array *pTrim_packets, bool optimize_snapshot)
9251 {
9252     VOGL_FUNC_TRACER
9253
9254     timed_scope ts(VOGL_METHOD_NAME);
9255
9256     vogl_gl_state_snapshot *pSnapshot = vogl_new(vogl_gl_state_snapshot);
9257
9258     vogl_message_printf("%s: Beginning capture: width %u, height %u, trace context 0x%" PRIx64 ", frame index %u, last call counter %" PRIu64 ", at frame boundary: %u\n", VOGL_METHOD_NAME,
9259                        m_pWindow->get_width(), m_pWindow->get_height(), m_cur_trace_context, m_frame_index, m_last_parsed_call_counter, m_at_frame_boundary);
9260
9261     if (!pSnapshot->begin_capture(m_pWindow->get_width(), m_pWindow->get_height(), m_cur_trace_context, m_frame_index, m_last_parsed_call_counter, m_at_frame_boundary))
9262     {
9263         vogl_error_printf("%s: Failed beginning capture\n", VOGL_METHOD_NAME);
9264
9265         vogl_delete(pSnapshot);
9266         pSnapshot = NULL;
9267
9268         return NULL;
9269     }
9270
9271     vogl_client_side_array_desc_vec client_side_vertex_attrib_ptrs;
9272     for (uint i = 0; i < VOGL_ARRAY_SIZE(m_client_side_vertex_attrib_data); i++)
9273         client_side_vertex_attrib_ptrs.push_back(vogl_client_side_array_desc(reinterpret_cast<vogl_trace_ptr_value>(m_client_side_vertex_attrib_data[i].get_ptr()), m_client_side_vertex_attrib_data[i].size()));
9274
9275     vogl_client_side_array_desc_vec client_side_array_ptrs;
9276     for (uint i = 0; i < VOGL_ARRAY_SIZE(m_client_side_array_data); i++)
9277         client_side_array_ptrs.push_back(vogl_client_side_array_desc(reinterpret_cast<vogl_trace_ptr_value>(m_client_side_array_data[i].get_ptr()), m_client_side_array_data[i].size()));
9278
9279     vogl_client_side_array_desc_vec client_side_texcoord_ptrs;
9280     for (uint i = 0; i < VOGL_ARRAY_SIZE(m_client_side_texcoord_data); i++)
9281         client_side_texcoord_ptrs.push_back(vogl_client_side_array_desc(reinterpret_cast<vogl_trace_ptr_value>(m_client_side_texcoord_data[i].get_ptr()), m_client_side_texcoord_data[i].size()));
9282
9283     pSnapshot->add_client_side_array_ptrs(client_side_vertex_attrib_ptrs, client_side_array_ptrs, client_side_texcoord_ptrs);
9284
9285     vogl_printf("%s: Capturing %u context(s)\n", VOGL_METHOD_NAME, m_contexts.size());
9286
9287     context_hash_map::iterator it;
9288     for (it = m_contexts.begin(); it != m_contexts.end(); ++it)
9289     {
9290         context_state *pContext_state = it->second;
9291
9292         if (pContext_state->m_deleted)
9293         {
9294             vogl_error_printf("%s: Sharelist root context 0x%" PRIx64 " was destroyed - this scenario is not yet supported for state snapshotting.\n", VOGL_METHOD_NAME, cast_val_to_uint64(it->first));
9295             break;
9296         }
9297
9298         vogl_capture_context_params temp_shadow_state;
9299         vogl_capture_context_params *pShadow_state = &temp_shadow_state;
9300
9301         if (pContext_state->m_has_been_made_current)
9302         {
9303             status_t status = switch_contexts(it->first);
9304             if (status != cStatusOK)
9305             {
9306                 vogl_error_printf("%s: Failed switching to trace context 0x%" PRIX64 ", capture failed\n", VOGL_METHOD_NAME, cast_val_to_uint64(it->first));
9307                 break;
9308             }
9309
9310             VOGL_ASSERT(m_pCur_context_state == pContext_state);
9311
9312             if (m_pCur_context_state->m_inside_gl_begin)
9313             {
9314                 vogl_warning_printf("%s: Trace context 0x%" PRIX64 " is inside a glBegin, which is not fully supported for state capturing. Capture will continue but will not be replayable.\n", VOGL_METHOD_NAME, cast_val_to_uint64(it->first));
9315                 pSnapshot->set_is_restorable(false);
9316             }
9317
9318             if (get_shared_state()->m_mapped_buffers.size())
9319             {
9320                 vogl_warning_printf("%s: Trace context 0x%" PRIX64 " has %u currently mapped GL buffers, this scenario is not currently unsupported for state capturing. Capture will continue but will not be replayable.\n", VOGL_METHOD_NAME, cast_val_to_uint64(it->first), get_shared_state()->m_mapped_buffers.size());
9321                 pSnapshot->set_is_restorable(false);
9322             }
9323
9324             // Init the shadow state needed by the snapshot code.
9325             if (!m_pCur_context_state->is_root_context())
9326             {
9327                 // Only fill in non-shared state.
9328                 fill_replay_handle_hash_set(pShadow_state->m_framebuffers, get_context_state()->m_framebuffers);
9329                 fill_replay_handle_hash_set(pShadow_state->m_vaos, get_context_state()->m_vertex_array_objects);
9330             }
9331             else
9332             {
9333                 pShadow_state = &m_pCur_context_state->m_shadow_state;
9334
9335                 pShadow_state->m_query_targets = get_shared_state()->m_query_targets;
9336
9337                 fill_replay_handle_hash_set(pShadow_state->m_samplers, get_shared_state()->m_sampler_objects);
9338                 fill_replay_handle_hash_set(pShadow_state->m_framebuffers, get_context_state()->m_framebuffers);
9339                 fill_replay_handle_hash_set(pShadow_state->m_vaos, get_context_state()->m_vertex_array_objects);
9340
9341                 // Buffer targets
9342                 pShadow_state->m_buffer_targets.reset();
9343                 for (gl_handle_hash_map::const_iterator buf_it = get_shared_state()->m_buffers.begin(); buf_it != get_shared_state()->m_buffers.end(); ++buf_it)
9344                 {
9345                     GLuint trace_handle = buf_it->first;
9346                     GLuint replay_handle = buf_it->second;
9347
9348                     gl_handle_hash_map::const_iterator target_it = get_shared_state()->m_buffer_targets.find(trace_handle);
9349                     if (target_it == get_shared_state()->m_buffer_targets.end())
9350                     {
9351                         vogl_error_printf("%s: Unable to find buffer trace handle 0x%X GL handle 0x%X in buffer target map! This should not happen!\n", VOGL_METHOD_NAME, trace_handle, replay_handle);
9352                         continue;
9353                     }
9354                     GLenum target = target_it->second;
9355
9356                     pShadow_state->m_buffer_targets.insert(replay_handle, target);
9357                 }
9358
9359                 // Syncs
9360                 pShadow_state->m_syncs.reset();
9361                 pShadow_state->m_syncs.reserve(get_shared_state()->m_syncs.size());
9362                 for (gl_sync_hash_map::const_iterator sync_it = get_shared_state()->m_syncs.begin(); sync_it != get_shared_state()->m_syncs.end(); ++sync_it)
9363                 {
9364                     bool success = pShadow_state->m_syncs.insert(vogl_sync_to_handle(sync_it->second)).second;
9365                     VOGL_ASSERT(success);
9366                     VOGL_NOTE_UNUSED(success);
9367                 }
9368
9369                 // Program handles filter
9370                 pShadow_state->m_filter_program_handles = false;
9371                 pShadow_state->m_program_handles_filter.reset();
9372
9373 #if 0
9374                                 // TODO: The program optimization code works, but we also need to delete any unused shaders (or shaders that have been marked as deleted but are referred to by optimized out programs).
9375                                 // This is an optimization issue, and we're concentrating on correctness right now so let's figure this out later.
9376                                 if ((pTrim_packets) && (optimize_snapshot))
9377                                 {
9378                     if (!determine_used_program_handles(*pTrim_packets, pShadow_state->m_program_handles_filter))
9379                                         {
9380                                                 vogl_warning_printf("%s: Failed determining used program handles\n", VOGL_METHOD_NAME);
9381                                                 pShadow_state->m_program_handles_filter.clear();
9382                                         }
9383                                         else
9384                                         {
9385                                                 pShadow_state->m_filter_program_handles = true;
9386                                         }
9387                                 }
9388 #else
9389                 VOGL_NOTE_UNUSED(optimize_snapshot);
9390                 VOGL_NOTE_UNUSED(pTrim_packets);
9391 #endif
9392
9393                 // ARB program targets
9394                 pShadow_state->m_arb_program_targets.reset();
9395                 for (gl_handle_hash_map::const_iterator arb_prog_it = get_shared_state()->m_arb_program_targets.begin(); arb_prog_it != get_shared_state()->m_arb_program_targets.end(); ++arb_prog_it)
9396                 {
9397                     GLuint trace_handle = arb_prog_it->first;
9398                     GLuint replay_handle = get_shared_state()->m_arb_programs.value(trace_handle);
9399                     if ((!trace_handle) || (!replay_handle))
9400                     {
9401                         VOGL_ASSERT_ALWAYS;
9402                         continue;
9403                     }
9404
9405                     GLenum target = arb_prog_it->second;
9406                     pShadow_state->m_arb_program_targets.insert(replay_handle, target);
9407                 }
9408             }
9409         }
9410
9411         if (!pSnapshot->capture_context(pContext_state->m_context_desc, pContext_state->m_context_info, m_replay_to_trace_remapper, *pShadow_state))
9412         {
9413             vogl_error_printf("%s: Failed capturing trace context 0x%" PRIX64 ", capture failed\n", VOGL_METHOD_NAME, static_cast<uint64_t>(it->first));
9414             break;
9415         }
9416     }
9417
9418     if ((it == m_contexts.end()) && (pSnapshot->end_capture()))
9419     {
9420         vogl_printf("%s: Capture succeeded\n", VOGL_METHOD_NAME);
9421     }
9422     else
9423     {
9424         vogl_printf("%s: Capture failed\n", VOGL_METHOD_NAME);
9425
9426         vogl_delete(pSnapshot);
9427         pSnapshot = NULL;
9428     }
9429
9430     return pSnapshot;
9431 }
9432
9433 //----------------------------------------------------------------------------------------------------------------------
9434 // vogl_replayer::reset_state
9435 //----------------------------------------------------------------------------------------------------------------------
9436 void vogl_gl_replayer::reset_state()
9437 {
9438     VOGL_FUNC_TRACER
9439
9440     // Purposely does NOT destroy the cached snapshots
9441
9442     destroy_pending_snapshot();
9443     destroy_contexts();
9444
9445     m_pending_make_current_packet.clear();
9446     m_pending_window_resize_width = 0;
9447     m_pending_window_resize_height = 0;
9448     m_pending_window_resize_attempt_counter = 0;
9449
9450     m_frame_index = 0;
9451     m_last_parsed_call_counter = -1;
9452     m_last_processed_call_counter = -1;
9453     m_at_frame_boundary = true;
9454
9455     m_cur_trace_context = 0;
9456     m_cur_replay_context = 0;
9457     m_pCur_context_state = NULL;
9458
9459     // Testing
9460     //if (m_pWindow->is_opened())
9461     //   m_pWindow->clear_window();
9462 }
9463
9464 //----------------------------------------------------------------------------------------------------------------------
9465 // trace_to_replay_handle_remapper::is_valid_handle
9466 //----------------------------------------------------------------------------------------------------------------------
9467 bool vogl_gl_replayer::trace_to_replay_handle_remapper::is_valid_handle(vogl_namespace_t handle_namespace, uint64_t from_handle)
9468 {
9469     VOGL_FUNC_TRACER
9470
9471     if (!from_handle)
9472         return false;
9473
9474     uint32 from_handle32 = static_cast<uint32>(from_handle);
9475
9476     switch (handle_namespace)
9477     {
9478         case VOGL_NAMESPACE_VERTEX_ARRAYS:
9479         {
9480             VOGL_ASSERT(from_handle32 == from_handle);
9481             return m_replayer.get_context_state()->m_vertex_array_objects.contains(from_handle32);
9482         }
9483         case VOGL_NAMESPACE_TEXTURES:
9484         {
9485             VOGL_ASSERT(from_handle32 == from_handle);
9486             return m_replayer.get_shared_state()->m_shadow_state.m_textures.contains(from_handle32);
9487         }
9488         case VOGL_NAMESPACE_SAMPLERS:
9489         {
9490             VOGL_ASSERT(from_handle32 == from_handle);
9491             return m_replayer.get_shared_state()->m_sampler_objects.contains(from_handle32);
9492         }
9493         case VOGL_NAMESPACE_BUFFERS:
9494         {
9495             VOGL_ASSERT(from_handle32 == from_handle);
9496             return m_replayer.get_shared_state()->m_buffers.contains(from_handle32);
9497         }
9498         case VOGL_NAMESPACE_SHADERS:
9499         case VOGL_NAMESPACE_PROGRAMS:
9500         {
9501             VOGL_ASSERT(from_handle32 == from_handle);
9502             return m_replayer.get_shared_state()->m_shadow_state.m_objs.contains(from_handle32);
9503         }
9504         case VOGL_NAMESPACE_FRAMEBUFFERS:
9505         {
9506             VOGL_ASSERT(from_handle32 == from_handle);
9507             return m_replayer.get_context_state()->m_framebuffers.contains(from_handle32);
9508         }
9509         case VOGL_NAMESPACE_RENDER_BUFFERS:
9510         {
9511             VOGL_ASSERT(from_handle32 == from_handle);
9512             return m_replayer.get_shared_state()->m_shadow_state.m_rbos.contains(from_handle32);
9513         }
9514         case VOGL_NAMESPACE_QUERIES:
9515         {
9516             VOGL_ASSERT(from_handle32 == from_handle);
9517             return m_replayer.get_shared_state()->m_queries.contains(from_handle32);
9518         }
9519         case VOGL_NAMESPACE_SYNCS:
9520         {
9521             return m_replayer.get_shared_state()->m_syncs.contains(from_handle);
9522         }
9523         case VOGL_NAMESPACE_PROGRAM_ARB:
9524         {
9525             return m_replayer.get_shared_state()->m_arb_programs.contains(from_handle32);
9526         }
9527         default:
9528             break;
9529     }
9530
9531     VOGL_VERIFY(0);
9532
9533     return false;
9534 }
9535
9536 //----------------------------------------------------------------------------------------------------------------------
9537 // trace_to_replay_handle_remapper::remap_handle
9538 //----------------------------------------------------------------------------------------------------------------------
9539 uint64_t vogl_gl_replayer::trace_to_replay_handle_remapper::remap_handle(vogl_namespace_t handle_namespace, uint64_t from_handle)
9540 {
9541     VOGL_FUNC_TRACER
9542
9543     if (!from_handle)
9544         return from_handle;
9545
9546     uint32 from_handle32 = static_cast<uint32>(from_handle);
9547
9548     switch (handle_namespace)
9549     {
9550         case VOGL_NAMESPACE_VERTEX_ARRAYS:
9551         {
9552             VOGL_ASSERT(from_handle32 == from_handle);
9553             return m_replayer.get_context_state()->m_vertex_array_objects.value(from_handle32, from_handle32);
9554         }
9555         case VOGL_NAMESPACE_TEXTURES:
9556         {
9557             VOGL_ASSERT(from_handle32 == from_handle);
9558
9559             uint32 replay_handle = from_handle32;
9560             if (m_replayer.get_shared_state()->m_shadow_state.m_textures.map_handle_to_inv_handle(from_handle32, replay_handle))
9561                 return replay_handle;
9562             break;
9563         }
9564         case VOGL_NAMESPACE_SAMPLERS:
9565         {
9566             VOGL_ASSERT(from_handle32 == from_handle);
9567             return m_replayer.get_shared_state()->m_sampler_objects.value(from_handle32, from_handle32);
9568         }
9569         case VOGL_NAMESPACE_BUFFERS:
9570         {
9571             VOGL_ASSERT(from_handle32 == from_handle);
9572             return m_replayer.get_shared_state()->m_buffers.value(from_handle32, from_handle32);
9573         }
9574         case VOGL_NAMESPACE_SHADERS:
9575         case VOGL_NAMESPACE_PROGRAMS:
9576         {
9577             VOGL_ASSERT(from_handle32 == from_handle);
9578
9579             GLuint replay_handle = from_handle32;
9580             if (m_replayer.get_shared_state()->m_shadow_state.m_objs.map_handle_to_inv_handle(from_handle32, replay_handle))
9581                 return replay_handle;
9582             break;
9583         }
9584         case VOGL_NAMESPACE_FRAMEBUFFERS:
9585         {
9586             VOGL_ASSERT(from_handle32 == from_handle);
9587             return m_replayer.get_context_state()->m_framebuffers.value(from_handle32, from_handle32);
9588         }
9589         case VOGL_NAMESPACE_RENDER_BUFFERS:
9590         {
9591             VOGL_ASSERT(from_handle32 == from_handle);
9592
9593             GLuint replay_handle = from_handle32;
9594             if (m_replayer.get_shared_state()->m_shadow_state.m_rbos.map_handle_to_inv_handle(from_handle32, replay_handle))
9595                 return replay_handle;
9596
9597             break;
9598         }
9599         case VOGL_NAMESPACE_QUERIES:
9600         {
9601             VOGL_ASSERT(from_handle32 == from_handle);
9602             return m_replayer.get_shared_state()->m_queries.value(from_handle32, from_handle32);
9603         }
9604         case VOGL_NAMESPACE_SYNCS:
9605         {
9606             return vogl_sync_to_handle(m_replayer.get_shared_state()->m_syncs.value(from_handle, vogl_handle_to_sync(from_handle)));
9607         }
9608         case VOGL_NAMESPACE_PROGRAM_ARB:
9609         {
9610             return m_replayer.get_shared_state()->m_arb_programs.value(from_handle32, from_handle32);
9611         }
9612         default:
9613         {
9614             break;
9615         }
9616     }
9617
9618     VOGL_ASSERT_ALWAYS;
9619
9620     vogl_error_printf("%s: Failed remapping handle %" PRIu64 " in namespace %s.\n", VOGL_METHOD_NAME, from_handle, vogl_get_namespace_name(handle_namespace));
9621
9622     return from_handle;
9623 }
9624
9625 //----------------------------------------------------------------------------------------------------------------------
9626 // trace_to_replay_handle_remapper::remap_location
9627 //----------------------------------------------------------------------------------------------------------------------
9628 int32 vogl_gl_replayer::trace_to_replay_handle_remapper::remap_location(uint32 trace_program, int32 from_location)
9629 {
9630     VOGL_FUNC_TRACER
9631
9632     VOGL_NOTE_UNUSED(trace_program);
9633
9634     // restoring declares, but doesn't need to remap
9635     VOGL_ASSERT_ALWAYS;
9636
9637     return from_location;
9638 }
9639
9640 //----------------------------------------------------------------------------------------------------------------------
9641 // trace_to_replay_handle_remapper::remap_vertex_attrib_ptr
9642 //----------------------------------------------------------------------------------------------------------------------
9643 vogl_trace_ptr_value vogl_gl_replayer::trace_to_replay_handle_remapper::remap_vertex_attrib_ptr(uint index, vogl_trace_ptr_value ptr_val)
9644 {
9645     VOGL_FUNC_TRACER
9646
9647     if (!ptr_val)
9648         return ptr_val;
9649
9650     VOGL_ASSERT(index < VOGL_ARRAY_SIZE(m_replayer.m_client_side_vertex_attrib_data));
9651     if (!m_replayer.m_client_side_vertex_attrib_data[index].size())
9652     {
9653         m_replayer.m_client_side_vertex_attrib_data[index].resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
9654     }
9655
9656     return reinterpret_cast<vogl_trace_ptr_value>(m_replayer.m_client_side_vertex_attrib_data[index].get_ptr());
9657 }
9658
9659 //----------------------------------------------------------------------------------------------------------------------
9660 // trace_to_replay_handle_remapper::remap_vertex_array_ptr
9661 //----------------------------------------------------------------------------------------------------------------------
9662 vogl_trace_ptr_value vogl_gl_replayer::trace_to_replay_handle_remapper::remap_vertex_array_ptr(vogl_client_side_array_desc_id_t id, uint index, vogl_trace_ptr_value ptr_val)
9663 {
9664     VOGL_FUNC_TRACER
9665
9666     VOGL_ASSERT(id < VOGL_NUM_CLIENT_SIDE_ARRAY_DESCS);
9667
9668     if (!ptr_val)
9669         return ptr_val;
9670
9671     if (id == vogl_texcoord_pointer_array_id)
9672     {
9673         VOGL_ASSERT(index < VOGL_ARRAY_SIZE(m_replayer.m_client_side_texcoord_data));
9674
9675         if (!m_replayer.m_client_side_texcoord_data[index].size())
9676         {
9677             m_replayer.m_client_side_texcoord_data[index].resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
9678         }
9679
9680         return reinterpret_cast<vogl_trace_ptr_value>(m_replayer.m_client_side_texcoord_data[index].get_ptr());
9681     }
9682     else
9683     {
9684         VOGL_ASSERT(index < VOGL_ARRAY_SIZE(m_replayer.m_client_side_array_data));
9685
9686         if (!m_replayer.m_client_side_array_data[id].size())
9687         {
9688             m_replayer.m_client_side_array_data[id].resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
9689         }
9690
9691         return reinterpret_cast<vogl_trace_ptr_value>(m_replayer.m_client_side_array_data[id].get_ptr());
9692     }
9693 }
9694
9695 //----------------------------------------------------------------------------------------------------------------------
9696 // trace_to_replay_handle_remapper::declare_handle
9697 //----------------------------------------------------------------------------------------------------------------------
9698 void vogl_gl_replayer::trace_to_replay_handle_remapper::declare_handle(vogl_namespace_t handle_namespace, uint64_t from_handle, uint64_t to_handle, GLenum target)
9699 {
9700     VOGL_FUNC_TRACER
9701
9702     if ((!from_handle) || (!to_handle))
9703     {
9704         VOGL_ASSERT_ALWAYS;
9705         return;
9706     }
9707
9708     uint32 from_handle32 = static_cast<uint32>(from_handle);
9709     uint32 to_handle32 = static_cast<uint32>(to_handle);
9710
9711     switch (handle_namespace)
9712     {
9713         case VOGL_NAMESPACE_VERTEX_ARRAYS:
9714         {
9715             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
9716             m_replayer.get_context_state()->m_vertex_array_objects.insert(from_handle32, to_handle32);
9717             break;
9718         }
9719         case VOGL_NAMESPACE_TEXTURES:
9720         {
9721             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
9722             if (!m_replayer.get_shared_state()->m_shadow_state.m_textures.update(from_handle32, to_handle32, target))
9723                 vogl_warning_printf("%s: Failed inserting trace texture %u GL texture %u handle into texture handle tracker!\n", VOGL_METHOD_NAME, from_handle32, to_handle32);
9724             break;
9725         }
9726         case VOGL_NAMESPACE_SAMPLERS:
9727         {
9728             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
9729             m_replayer.get_shared_state()->m_sampler_objects.insert(from_handle32, to_handle32);
9730             break;
9731         }
9732         case VOGL_NAMESPACE_BUFFERS:
9733         {
9734             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
9735             m_replayer.get_shared_state()->m_buffers.insert(from_handle32, to_handle32);
9736             m_replayer.get_shared_state()->m_buffer_targets.insert(from_handle32, target);
9737             break;
9738         }
9739         case VOGL_NAMESPACE_SHADERS:
9740         {
9741             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
9742             if (!m_replayer.get_shared_state()->m_shadow_state.m_objs.insert(from_handle32, to_handle32, VOGL_SHADER_OBJECT))
9743                 vogl_warning_printf("%s: Failed inserting trace shader handle %u GL handle %u into object handle tracker!\n", VOGL_METHOD_NAME, from_handle32, to_handle32);
9744             break;
9745         }
9746         case VOGL_NAMESPACE_PROGRAMS:
9747         {
9748             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
9749             if (!m_replayer.get_shared_state()->m_shadow_state.m_objs.insert(from_handle32, to_handle32, VOGL_PROGRAM_OBJECT))
9750                 vogl_warning_printf("%s: Failed inserting trace program handle %u GL handle %u into object handle tracker!\n", VOGL_METHOD_NAME, from_handle32, to_handle32);
9751             break;
9752         }
9753         case VOGL_NAMESPACE_FRAMEBUFFERS:
9754         {
9755             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
9756             m_replayer.get_context_state()->m_framebuffers.insert(from_handle32, to_handle32);
9757             break;
9758         }
9759         case VOGL_NAMESPACE_RENDER_BUFFERS:
9760         {
9761             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
9762             if (!m_replayer.get_shared_state()->m_shadow_state.m_rbos.insert(from_handle32, to_handle32, GL_NONE))
9763                 vogl_warning_printf("%s: Failed inserting trace RBO handle %u GL handle %u into RBO handle tracker!\n", VOGL_METHOD_NAME, from_handle32, to_handle32);
9764             break;
9765         }
9766         case VOGL_NAMESPACE_QUERIES:
9767         {
9768             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
9769             m_replayer.get_shared_state()->m_queries.insert(from_handle32, to_handle32);
9770             m_replayer.get_shared_state()->m_query_targets[to_handle32] = target;
9771             break;
9772         }
9773         case VOGL_NAMESPACE_SYNCS:
9774         {
9775             m_replayer.get_shared_state()->m_syncs.insert(from_handle, vogl_handle_to_sync(to_handle));
9776             break;
9777         }
9778         case VOGL_NAMESPACE_PROGRAM_ARB:
9779         {
9780             m_replayer.get_shared_state()->m_arb_programs.insert(from_handle32, to_handle32);
9781             m_replayer.get_shared_state()->m_arb_program_targets.insert(from_handle32, target);
9782             break;
9783         }
9784         default:
9785         {
9786             VOGL_VERIFY(0);
9787             break;
9788         }
9789     }
9790 }
9791
9792 //----------------------------------------------------------------------------------------------------------------------
9793 // trace_to_replay_handle_remapper::delete_handle_and_object
9794 //----------------------------------------------------------------------------------------------------------------------
9795 void vogl_gl_replayer::trace_to_replay_handle_remapper::delete_handle_and_object(vogl_namespace_t handle_namespace, uint64_t from_handle, uint64_t to_handle)
9796 {
9797     VOGL_FUNC_TRACER
9798
9799     if ((!from_handle) || (!to_handle))
9800     {
9801         VOGL_ASSERT_ALWAYS;
9802         return;
9803     }
9804
9805     uint32 from_handle32 = static_cast<uint32>(from_handle);
9806     uint32 to_handle32 = static_cast<uint32>(to_handle);
9807     VOGL_NOTE_UNUSED(to_handle32);
9808
9809     switch (handle_namespace)
9810     {
9811         case VOGL_NAMESPACE_VERTEX_ARRAYS:
9812         {
9813             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
9814             m_replayer.get_context_state()->m_vertex_array_objects.erase(from_handle32);
9815             vogl_destroy_gl_object(handle_namespace, to_handle);
9816             break;
9817         }
9818         case VOGL_NAMESPACE_TEXTURES:
9819         {
9820             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
9821             if (!m_replayer.get_shared_state()->m_shadow_state.m_textures.erase(from_handle32))
9822                 vogl_warning_printf("%s: Failed deleting trace texture handle %u GL handle %u from texture handle tracker!\n", VOGL_METHOD_NAME, from_handle32, to_handle32);
9823
9824             vogl_destroy_gl_object(handle_namespace, to_handle);
9825             break;
9826         }
9827         case VOGL_NAMESPACE_SAMPLERS:
9828         {
9829             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
9830             m_replayer.get_shared_state()->m_sampler_objects.erase(from_handle32);
9831             vogl_destroy_gl_object(handle_namespace, to_handle);
9832             break;
9833         }
9834         case VOGL_NAMESPACE_BUFFERS:
9835         {
9836             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
9837             m_replayer.get_shared_state()->m_buffers.erase(from_handle32);
9838             m_replayer.get_shared_state()->m_buffer_targets.erase(from_handle32);
9839             vogl_destroy_gl_object(handle_namespace, to_handle);
9840             break;
9841         }
9842         case VOGL_NAMESPACE_SHADERS:
9843         {
9844             m_replayer.handle_delete_shader(from_handle32);
9845             break;
9846         }
9847         case VOGL_NAMESPACE_PROGRAMS:
9848         {
9849             m_replayer.handle_delete_program(from_handle32);
9850             break;
9851         }
9852         case VOGL_NAMESPACE_FRAMEBUFFERS:
9853         {
9854             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
9855             m_replayer.get_context_state()->m_framebuffers.erase(from_handle32);
9856             vogl_destroy_gl_object(handle_namespace, to_handle);
9857             break;
9858         }
9859         case VOGL_NAMESPACE_RENDER_BUFFERS:
9860         {
9861             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
9862
9863             if (!m_replayer.get_shared_state()->m_shadow_state.m_rbos.erase(from_handle32))
9864                 vogl_warning_printf("%s: Failed deleting trace texture handle %u GL handle %u from RBO handle tracker!\n", VOGL_METHOD_NAME, from_handle32, to_handle32);
9865
9866             vogl_destroy_gl_object(handle_namespace, to_handle);
9867             break;
9868         }
9869         case VOGL_NAMESPACE_QUERIES:
9870         {
9871             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
9872             m_replayer.get_shared_state()->m_queries.erase(from_handle32);
9873             vogl_destroy_gl_object(handle_namespace, to_handle);
9874             break;
9875         }
9876         case VOGL_NAMESPACE_SYNCS:
9877         {
9878             m_replayer.get_shared_state()->m_syncs.erase(from_handle);
9879             vogl_destroy_gl_object(handle_namespace, to_handle);
9880             break;
9881         }
9882         case VOGL_NAMESPACE_PROGRAM_ARB:
9883         {
9884             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
9885             m_replayer.get_shared_state()->m_arb_programs.erase(from_handle32);
9886             m_replayer.get_shared_state()->m_arb_program_targets.erase(from_handle32);
9887             vogl_destroy_gl_object(handle_namespace, to_handle);
9888             break;
9889         }
9890         default:
9891         {
9892             VOGL_VERIFY(0);
9893             break;
9894         }
9895     }
9896 }
9897
9898 //----------------------------------------------------------------------------------------------------------------------
9899 // vogl_replayer::trace_to_replay_handle_remapper::declare_location
9900 //----------------------------------------------------------------------------------------------------------------------
9901 void vogl_gl_replayer::trace_to_replay_handle_remapper::declare_location(uint32 from_program_handle, uint32 to_program_handle, int32 from_location, int32 to_location)
9902 {
9903     VOGL_FUNC_TRACER
9904
9905     GLuint check_replay_handle = 0;
9906     VOGL_ASSERT(m_replayer.get_shared_state()->m_shadow_state.m_objs.map_handle_to_inv_handle(from_program_handle, check_replay_handle));
9907     VOGL_ASSERT(check_replay_handle == to_program_handle);
9908     VOGL_NOTE_UNUSED(check_replay_handle);
9909
9910     VOGL_NOTE_UNUSED(to_program_handle);
9911
9912     glsl_program_hash_map::iterator it(m_replayer.get_shared_state()->m_glsl_program_hash_map.insert(from_program_handle).first);
9913
9914     glsl_program_state &prog_state = it->second;
9915
9916     VOGL_ASSERT(!prog_state.m_uniform_locations.contains(from_location));
9917
9918     prog_state.m_uniform_locations.insert(from_location, to_location);
9919 }
9920
9921 //----------------------------------------------------------------------------------------------------------------------
9922 // vogl_gl_replayer::trace_to_replay_handle_remapper::determine_from_object_target
9923 //----------------------------------------------------------------------------------------------------------------------
9924 bool vogl_gl_replayer::trace_to_replay_handle_remapper::determine_from_object_target(vogl_namespace_t handle_namespace, uint64_t trace_handle, GLenum &target)
9925 {
9926     VOGL_FUNC_TRACER
9927
9928     target = GL_NONE;
9929
9930     uint32 handle32 = static_cast<uint32>(trace_handle);
9931
9932     switch (handle_namespace)
9933     {
9934         case VOGL_NAMESPACE_TEXTURES:
9935         {
9936             VOGL_ASSERT(handle32 == trace_handle);
9937             if (!m_replayer.get_shared_state()->m_shadow_state.m_textures.contains(handle32))
9938                 return false;
9939
9940             target = m_replayer.get_shared_state()->m_shadow_state.m_textures.get_target(handle32);
9941             return true;
9942         }
9943         default:
9944             break;
9945     }
9946
9947     VOGL_VERIFY(0);
9948     return false;
9949 }
9950
9951 //----------------------------------------------------------------------------------------------------------------------
9952 // vogl_gl_replayer::trace_to_replay_handle_remapper::determine_to_object_target
9953 //----------------------------------------------------------------------------------------------------------------------
9954 bool vogl_gl_replayer::trace_to_replay_handle_remapper::determine_to_object_target(vogl_namespace_t handle_namespace, uint64_t replay_handle, GLenum &target)
9955 {
9956     VOGL_FUNC_TRACER
9957
9958     target = GL_NONE;
9959
9960     uint32 handle32 = static_cast<uint32>(replay_handle);
9961
9962     switch (handle_namespace)
9963     {
9964         case VOGL_NAMESPACE_TEXTURES:
9965         {
9966             VOGL_ASSERT(handle32 == replay_handle);
9967             if (!m_replayer.get_shared_state()->m_shadow_state.m_textures.contains_inv(handle32))
9968                 return false;
9969
9970             target = m_replayer.get_shared_state()->m_shadow_state.m_textures.get_target_inv(handle32);
9971             return true;
9972         }
9973         default:
9974             break;
9975     }
9976
9977     VOGL_VERIFY(0);
9978     return false;
9979 }
9980
9981 //----------------------------------------------------------------------------------------------------------------------
9982 // vogl_replayer::restore_objects
9983 //----------------------------------------------------------------------------------------------------------------------
9984 vogl_gl_replayer::status_t vogl_gl_replayer::restore_objects(
9985     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,
9986     vogl_const_gl_object_state_ptr_vec &objects_to_delete)
9987 {
9988     VOGL_FUNC_TRACER
9989
9990     VOGL_NOTE_UNUSED(snapshot);
9991
9992     if (m_flags & cGLReplayerVerboseMode)
9993         vogl_printf("%s: Restoring %s objects\n", VOGL_METHOD_NAME, get_gl_object_state_type_str(state_type));
9994
9995     vogl::timer tm;
9996     if (m_flags & cGLReplayerVerboseMode)
9997         tm.start();
9998
9999     const vogl_gl_object_state_ptr_vec &object_ptrs = context_state.get_objects();
10000
10001     uint n = 0;
10002
10003     for (uint i = 0; i < object_ptrs.size(); i++)
10004     {
10005         const vogl_gl_object_state *pState_obj = object_ptrs[i];
10006
10007         if (pState_obj->get_type() != state_type)
10008             continue;
10009
10010         GLuint64 restore_handle = 0;
10011         if (!pState_obj->restore(m_pCur_context_state->m_context_info, trace_to_replay_remapper, restore_handle))
10012         {
10013             vogl_error_printf("%s: Failed restoring object type %s object index %u trace handle 0x%" PRIX64 " restore handle 0x%" PRIX64 "\n", VOGL_METHOD_NAME, get_gl_object_state_type_str(state_type), i, (uint64_t)pState_obj->get_snapshot_handle(), (uint64_t)restore_handle);
10014             return cStatusHardFailure;
10015         }
10016         n++;
10017
10018         if (pState_obj->get_marked_for_deletion())
10019         {
10020             objects_to_delete.push_back(pState_obj);
10021         }
10022
10023         VOGL_ASSERT(trace_to_replay_remapper.remap_handle(pState_obj->get_handle_namespace(), pState_obj->get_snapshot_handle()) == restore_handle);
10024
10025         switch (pState_obj->get_type())
10026         {
10027             case cGLSTQuery:
10028             {
10029                 const vogl_query_state *pQuery = static_cast<const vogl_query_state *>(pState_obj);
10030
10031                 VOGL_ASSERT(restore_handle <= cUINT32_MAX);
10032                 get_shared_state()->m_query_targets[static_cast<GLuint>(restore_handle)] = pQuery->get_target();
10033
10034                 break;
10035             }
10036             case cGLSTProgram:
10037             {
10038                 const vogl_program_state *pProg = static_cast<const vogl_program_state *>(pState_obj);
10039
10040                 if (pProg->has_link_time_snapshot())
10041                 {
10042                     vogl_program_state link_snapshot(*pProg->get_link_time_snapshot());
10043                     if (!link_snapshot.remap_handles(trace_to_replay_remapper))
10044                     {
10045                         vogl_error_printf("%s: Failed remapping handles in program link time snapshot, object index %u trace handle 0x%" PRIX64 " restore handle 0x%" PRIX64 "\n", VOGL_METHOD_NAME, i, (uint64_t)pState_obj->get_snapshot_handle(), (uint64_t)restore_handle);
10046                     }
10047                     else
10048                     {
10049                         get_shared_state()->m_shadow_state.m_linked_programs.add_snapshot(static_cast<uint32>(restore_handle), link_snapshot);
10050                     }
10051                 }
10052
10053                 if (m_flags & cGLReplayerVerboseMode)
10054                 {
10055                     if ((n & 255) == 255)
10056                         vogl_printf("%s: Restored %u programs\n", VOGL_METHOD_NAME, n);
10057                 }
10058
10059                 break;
10060             }
10061             default:
10062                 break;
10063         }
10064     }
10065
10066     if (m_flags & cGLReplayerVerboseMode)
10067     {
10068         tm.stop();
10069         vogl_printf("%s: Restore took %f secs\n", VOGL_METHOD_NAME, tm.get_elapsed_secs());
10070
10071         vogl_printf("%s: Finished restoring %u %s objects\n", VOGL_METHOD_NAME, n, get_gl_object_state_type_str(state_type));
10072     }
10073
10074     return cStatusOK;
10075 }
10076
10077 //----------------------------------------------------------------------------------------------------------------------
10078 // vogl_xfont_cache
10079 //----------------------------------------------------------------------------------------------------------------------
10080 class vogl_xfont_cache
10081 {
10082     VOGL_NO_COPY_OR_ASSIGNMENT_OP(vogl_xfont_cache);
10083
10084 public:
10085     vogl_xfont_cache(Display *dpy)
10086         : m_dpy(dpy)
10087     {
10088         VOGL_FUNC_TRACER
10089     }
10090
10091     ~vogl_xfont_cache()
10092     {
10093         VOGL_FUNC_TRACER
10094
10095         clear();
10096     }
10097
10098     void clear()
10099     {
10100         VOGL_FUNC_TRACER
10101
10102         for (xfont_map::iterator it = m_xfonts.begin(); it != m_xfonts.end(); ++it)
10103             XFreeFont(m_dpy, it->second);
10104         m_xfonts.clear();
10105     }
10106
10107     XFontStruct *get_or_create(const char *pName)
10108     {
10109         VOGL_FUNC_TRACER
10110
10111         XFontStruct **ppXFont = m_xfonts.find_value(pName);
10112         if (ppXFont)
10113             return *ppXFont;
10114
10115         XFontStruct *pXFont = XLoadQueryFont(m_dpy, pName);
10116         if (pXFont)
10117             m_xfonts.insert(pName, pXFont);
10118
10119         return pXFont;
10120     }
10121
10122 private:
10123     Display *m_dpy;
10124
10125     typedef vogl::map<dynamic_string, XFontStruct *> xfont_map;
10126     xfont_map m_xfonts;
10127 };
10128
10129 //----------------------------------------------------------------------------------------------------------------------
10130 // vogl_replayer::restore_display_lists
10131 //----------------------------------------------------------------------------------------------------------------------
10132 vogl_gl_replayer::status_t vogl_gl_replayer::restore_display_lists(vogl_handle_remapper &trace_to_replay_remapper, const vogl_gl_state_snapshot &snapshot, const vogl_context_snapshot &context_snapshot)
10133 {
10134     VOGL_FUNC_TRACER
10135
10136     VOGL_NOTE_UNUSED(trace_to_replay_remapper);
10137     VOGL_NOTE_UNUSED(snapshot);
10138
10139     VOGL_ASSERT(m_cur_trace_context);
10140
10141     check_gl_error();
10142
10143     const vogl_display_list_state &disp_lists = context_snapshot.get_display_list_state();
10144
10145     if (!disp_lists.size())
10146         return cStatusOK;
10147
10148     vogl_message_printf("%s: Recreating %u display lists\n", VOGL_METHOD_NAME, disp_lists.get_display_list_map().size());
10149
10150     vogl_xfont_cache xfont_cache(m_pWindow->get_display());
10151
10152     const vogl_display_list_map &disp_list_map = disp_lists.get_display_list_map();
10153
10154     for (vogl_display_list_map::const_iterator it = disp_list_map.begin(); it != disp_list_map.end(); ++it)
10155     {
10156         GLuint trace_handle = it->first;
10157         const vogl_display_list &disp_list = it->second;
10158
10159         if (!trace_handle)
10160         {
10161             VOGL_ASSERT_ALWAYS;
10162             continue;
10163         }
10164
10165         if (!disp_list.is_valid())
10166         {
10167             VOGL_ASSERT_ALWAYS;
10168             continue;
10169         }
10170
10171         GLuint replay_handle = GL_ENTRYPOINT(glGenLists)(1);
10172         if (check_gl_error() || !replay_handle)
10173             goto handle_failure;
10174
10175         if (disp_list.is_xfont())
10176         {
10177             XFontStruct *pXFont = xfont_cache.get_or_create(disp_list.get_xfont_name().get_ptr());
10178             if (!pXFont)
10179             {
10180                 vogl_error_printf("%s: Unable to load XFont \"%s\", can't recreate trace display list %u!\n", VOGL_METHOD_NAME, disp_list.get_xfont_name().get_ptr(), trace_handle);
10181             }
10182             else
10183             {
10184                 GL_ENTRYPOINT(glXUseXFont)(pXFont->fid, disp_list.get_xfont_glyph(), 1, replay_handle);
10185             }
10186         }
10187         else
10188         {
10189             GL_ENTRYPOINT(glNewList)(replay_handle, GL_COMPILE);
10190
10191             if (check_gl_error() || !replay_handle)
10192             {
10193                 GL_ENTRYPOINT(glDeleteLists)(replay_handle, 1);
10194                 check_gl_error();
10195
10196                 goto handle_failure;
10197             }
10198
10199             const vogl_trace_packet_array &packets = disp_list.get_packets();
10200
10201             for (uint packet_index = 0; packet_index < packets.size(); packet_index++)
10202             {
10203                 if (packets.get_packet_type(packet_index) != cTSPTGLEntrypoint)
10204                 {
10205                     vogl_error_printf("%s: Unexpected display list packet type %u, packet index %u, can't fully recreate trace display list %u!\n", VOGL_METHOD_NAME, packets.get_packet_type(packet_index), packet_index, trace_handle);
10206                     continue;
10207                 }
10208
10209                 const uint8_vec &packet_buf = packets.get_packet_buf(packet_index);
10210
10211                 if (!m_temp2_gl_packet.deserialize(packet_buf, true))
10212                 {
10213                     vogl_error_printf("%s: Failed deserializing display list at packet index %u, can't fully recreate trace display list %u!\n", VOGL_METHOD_NAME, packet_index, trace_handle);
10214                     continue;
10215                 }
10216
10217                 vogl_trace_gl_entrypoint_packet &gl_entrypoint_packet = m_temp2_gl_packet.get_entrypoint_packet();
10218
10219                 gl_entrypoint_packet.m_context_handle = m_cur_trace_context;
10220
10221                 if (m_flags & cGLReplayerDebugMode)
10222                     dump_trace_gl_packet_debug_info(gl_entrypoint_packet);
10223
10224                 int64_t prev_parsed_call_counter = m_last_parsed_call_counter;
10225                 int64_t prev_processed_call_counter = m_last_processed_call_counter;
10226                 m_last_parsed_call_counter = gl_entrypoint_packet.m_call_counter;
10227                 m_last_processed_call_counter = gl_entrypoint_packet.m_call_counter;
10228                 bool prev_at_frame_boundary = m_at_frame_boundary;
10229
10230                 const vogl_trace_packet *pPrev_gl_packet = m_pCur_gl_packet;
10231
10232                 vogl_gl_replayer::status_t status = process_gl_entrypoint_packet_internal(m_temp2_gl_packet);
10233
10234                 m_pCur_gl_packet = pPrev_gl_packet;
10235
10236                 m_last_parsed_call_counter = prev_parsed_call_counter;
10237                 m_last_processed_call_counter = prev_processed_call_counter;
10238                 m_at_frame_boundary = prev_at_frame_boundary;
10239
10240                 if (status != cStatusOK)
10241                 {
10242                     vogl_error_printf("%s: Failed recreating display list at packet index %u, can't fully recreate trace display list %u!\n", VOGL_METHOD_NAME, packet_index, trace_handle);
10243                     continue;
10244                 }
10245             }
10246
10247             // TODO: Set context state because we're currently generating a display list!
10248             if (disp_list.is_generating())
10249             {
10250                 VOGL_ASSERT_ALWAYS;
10251             }
10252
10253             GL_ENTRYPOINT(glEndList)();
10254             check_gl_error();
10255         }
10256
10257         get_shared_state()->m_lists.insert(trace_handle, replay_handle);
10258
10259         if (!get_shared_state()->m_shadow_state.m_display_lists.define_list(trace_handle, replay_handle, disp_list))
10260         {
10261             vogl_error_printf("%s: Failed adding display list trace handle %u GL handle %u into display list shadow!\n", VOGL_METHOD_NAME, trace_handle, replay_handle);
10262         }
10263     }
10264
10265     check_gl_error();
10266
10267     vogl_message_printf("%s: Done recreating display lists\n", VOGL_METHOD_NAME);
10268
10269     return cStatusOK;
10270
10271 handle_failure:
10272     return cStatusHardFailure;
10273 }
10274
10275 //----------------------------------------------------------------------------------------------------------------------
10276 // vogl_replayer::restore_general_state
10277 //----------------------------------------------------------------------------------------------------------------------
10278 vogl_gl_replayer::status_t vogl_gl_replayer::restore_general_state(vogl_handle_remapper &trace_to_replay_remapper, const vogl_gl_state_snapshot &snapshot, const vogl_context_snapshot &context_snapshot)
10279 {
10280     VOGL_FUNC_TRACER
10281
10282     VOGL_NOTE_UNUSED(snapshot);
10283
10284     vogl_general_context_state::vogl_persistent_restore_state persistent_restore_state;
10285     persistent_restore_state.m_pSelect_buffer = &m_pCur_context_state->m_select_buffer;
10286
10287     if (!context_snapshot.get_general_state().restore(m_pCur_context_state->m_context_info, trace_to_replay_remapper, persistent_restore_state))
10288         return cStatusHardFailure;
10289
10290     if (!m_pCur_context_state->m_context_info.is_core_profile())
10291     {
10292         if (context_snapshot.get_texenv_state().is_valid())
10293         {
10294             if (!context_snapshot.get_texenv_state().restore(m_pCur_context_state->m_context_info))
10295                 return cStatusHardFailure;
10296         }
10297
10298         if (context_snapshot.get_material_state().is_valid())
10299         {
10300             if (!context_snapshot.get_material_state().restore(m_pCur_context_state->m_context_info))
10301                 return cStatusHardFailure;
10302         }
10303
10304         if (context_snapshot.get_light_state().is_valid())
10305         {
10306             if (!context_snapshot.get_light_state().restore(m_pCur_context_state->m_context_info))
10307                 return cStatusHardFailure;
10308         }
10309
10310         if (context_snapshot.get_matrix_state().is_valid())
10311         {
10312             if (!context_snapshot.get_matrix_state().restore(m_pCur_context_state->m_context_info))
10313                 return cStatusHardFailure;
10314         }
10315
10316         if (context_snapshot.get_polygon_stipple_state().is_valid())
10317         {
10318             if (!context_snapshot.get_polygon_stipple_state().restore(m_pCur_context_state->m_context_info))
10319                 return cStatusHardFailure;
10320         }
10321
10322         if (context_snapshot.get_arb_program_environment_state().is_valid())
10323         {
10324             if (m_pCur_context_state->m_context_info.supports_extension("GL_ARB_vertex_program"))
10325             {
10326                 if (!context_snapshot.get_arb_program_environment_state().restore(m_pCur_context_state->m_context_info, trace_to_replay_remapper))
10327                     return cStatusHardFailure;
10328             }
10329             else
10330             {
10331                 vogl_error_printf("%s: Unable to restore ARB program environment state to context because it does not support the \"GL_ARB_vertex_program\" extension\n", VOGL_METHOD_NAME);
10332             }
10333         }
10334     }
10335
10336     if (context_snapshot.get_current_vertex_attrib_state().is_valid())
10337     {
10338         if (!context_snapshot.get_current_vertex_attrib_state().restore(m_pCur_context_state->m_context_info))
10339             return cStatusHardFailure;
10340     }
10341
10342     return cStatusOK;
10343 }
10344
10345 //----------------------------------------------------------------------------------------------------------------------
10346 // vogl_replayer::validate_program_and_shader_handle_tables
10347 //----------------------------------------------------------------------------------------------------------------------
10348 bool vogl_gl_replayer::validate_program_and_shader_handle_tables()
10349 {
10350     VOGL_FUNC_TRACER
10351
10352     if (!m_pCur_context_state)
10353         return true;
10354
10355     if (!get_shared_state()->m_shadow_state.m_objs.check())
10356         vogl_error_printf("%s: Object handle tracker failed validation!\n", VOGL_METHOD_NAME);
10357
10358     uint_vec replay_handles;
10359     get_shared_state()->m_shadow_state.m_objs.get_inv_handles(replay_handles);
10360
10361     for (uint i = 0; i < replay_handles.size(); i++)
10362     {
10363         GLuint replay_handle = replay_handles[i];
10364         GLuint trace_handle = replay_handle;
10365         bool map_succeeded = get_shared_state()->m_shadow_state.m_objs.map_inv_handle_to_handle(replay_handle, trace_handle);
10366         VOGL_ASSERT(map_succeeded);
10367         VOGL_NOTE_UNUSED(map_succeeded);
10368
10369         GLenum target = get_shared_state()->m_shadow_state.m_objs.get_target_inv(replay_handle);
10370         VOGL_ASSERT(target == get_shared_state()->m_shadow_state.m_objs.get_target(trace_handle));
10371
10372         if (target == VOGL_PROGRAM_OBJECT)
10373         {
10374             if (!GL_ENTRYPOINT(glIsProgram)(replay_handle))
10375             {
10376                 vogl_error_printf("%s: GL handle %u is being tracked, but glIsProgram() reports the handle is not a program\n", VOGL_METHOD_NAME, replay_handle);
10377             }
10378
10379             if (!get_shared_state()->m_glsl_program_hash_map.contains(trace_handle))
10380             {
10381                 vogl_error_printf("%s: Found program at trace handle %u GL handle %u, but the GLSL program hash map doesn't contain an entry for this object!\n", VOGL_METHOD_NAME, trace_handle, replay_handle);
10382             }
10383         }
10384         else if (target == VOGL_SHADER_OBJECT)
10385         {
10386             if (!GL_ENTRYPOINT(glIsShader)(replay_handle))
10387             {
10388                 vogl_error_printf("%s: GL handle %u is being tracked, but glIsShader() reports the handle is not a program\n", VOGL_METHOD_NAME, replay_handle);
10389             }
10390         }
10391         else
10392         {
10393             VOGL_ASSERT_ALWAYS;
10394         }
10395     }
10396
10397     return true;
10398 }
10399
10400 //----------------------------------------------------------------------------------------------------------------------
10401 // vogl_replayer::validate_textures
10402 //----------------------------------------------------------------------------------------------------------------------
10403 bool vogl_gl_replayer::validate_textures()
10404 {
10405     VOGL_FUNC_TRACER
10406
10407     if (!m_pCur_context_state)
10408         return true;
10409
10410     if (!get_shared_state()->m_shadow_state.m_textures.check())
10411         vogl_error_printf("%s: Texture handle tracker failed validation!\n", VOGL_METHOD_NAME);
10412
10413     for (uint replay_handle = 1; replay_handle <= 0xFFFFU; replay_handle++)
10414     {
10415         bool is_tex = GL_ENTRYPOINT(glIsTexture)(replay_handle) != 0;
10416
10417         bool found_in_shadow = get_shared_state()->m_shadow_state.m_textures.contains_inv(replay_handle);
10418
10419         if (!is_tex)
10420         {
10421             if (found_in_shadow)
10422             {
10423                 GLuint trace_handle = 0;
10424                 get_shared_state()->m_shadow_state.m_textures.map_inv_handle_to_handle(replay_handle, trace_handle);
10425                 vogl_debug_printf("%s: Texture %u is not a name, but it has a valid mapping to trace handle %u\n", VOGL_METHOD_NAME, replay_handle, trace_handle);
10426             }
10427         }
10428         else
10429         {
10430             if (!found_in_shadow)
10431             {
10432                 vogl_debug_printf("%s: Texture %u is a valid name, but it does have a mapping to a trace handle!\n", VOGL_METHOD_NAME, replay_handle);
10433             }
10434         }
10435     }
10436
10437     return true;
10438 }
10439
10440 //----------------------------------------------------------------------------------------------------------------------
10441 // vogl_replayer::update_context_shadows
10442 //----------------------------------------------------------------------------------------------------------------------
10443 vogl_gl_replayer::status_t vogl_gl_replayer::update_context_shadows(vogl_handle_remapper &trace_to_replay_remapper, const vogl_gl_state_snapshot &snapshot, const vogl_context_snapshot &context_snapshot)
10444 {
10445     VOGL_FUNC_TRACER
10446
10447     VOGL_NOTE_UNUSED(snapshot);
10448     VOGL_NOTE_UNUSED(context_snapshot);
10449     VOGL_NOTE_UNUSED(trace_to_replay_remapper);
10450
10451     check_gl_error();
10452
10453     // Make sure shadow is good
10454     GLint actual_current_replay_program = 0;
10455     GL_ENTRYPOINT(glGetIntegerv)(GL_CURRENT_PROGRAM, &actual_current_replay_program);
10456     check_gl_error();
10457
10458     m_pCur_context_state->m_cur_replay_program = actual_current_replay_program;
10459     if (!actual_current_replay_program)
10460         m_pCur_context_state->m_cur_trace_program = 0;
10461     else
10462     {
10463         GLuint trace_handle = actual_current_replay_program;
10464         if (!get_shared_state()->m_shadow_state.m_objs.map_inv_handle_to_handle(actual_current_replay_program, trace_handle))
10465         {
10466             process_entrypoint_error("%s: Failed finding restored GL shader %u in program/shader object handle hashmap\n", VOGL_METHOD_NAME, actual_current_replay_program);
10467
10468             m_pCur_context_state->m_cur_replay_program = 0;
10469             m_pCur_context_state->m_cur_trace_program = 0;
10470         }
10471         else
10472         {
10473             m_pCur_context_state->m_cur_trace_program = trace_handle;
10474         }
10475     }
10476
10477     check_program_binding_shadow();
10478
10479     return cStatusOK;
10480 }
10481
10482 //----------------------------------------------------------------------------------------------------------------------
10483 // vogl_replayer::handle_marked_for_deleted_objects
10484 //----------------------------------------------------------------------------------------------------------------------
10485 void vogl_gl_replayer::handle_marked_for_deleted_objects(vogl_const_gl_object_state_ptr_vec &objects_to_delete, trace_to_replay_handle_remapper &trace_to_replay_remapper)
10486 {
10487     VOGL_FUNC_TRACER
10488
10489     if (m_flags & cGLReplayerVerboseMode)
10490     {
10491         vogl_debug_printf("%s: %u program/shader objects where marked as deleted\n", VOGL_METHOD_NAME, objects_to_delete.size());
10492     }
10493
10494     for (uint i = 0; i < objects_to_delete.size(); i++)
10495     {
10496         const vogl_gl_object_state *pState_obj = objects_to_delete[i];
10497
10498         GLuint64 trace_handle = pState_obj->get_snapshot_handle();
10499         GLuint64 restore_handle = trace_to_replay_remapper.remap_handle(pState_obj->get_handle_namespace(), pState_obj->get_snapshot_handle());
10500
10501         if (m_flags & cGLReplayerVerboseMode)
10502         {
10503             // This should be a rare/exception case so let's try to be a little paranoid.
10504             vogl_debug_printf("%s: Snapshot object type %s trace handle 0x%" PRIX64 " restore handle 0x%" PRIX64 ", was marked as deleted, deleting object after restoring (object should still be referenced by state in the GL context)\n", VOGL_METHOD_NAME,
10505                              get_gl_object_state_type_str(pState_obj->get_type()), (uint64_t)trace_handle, (uint64_t)restore_handle);
10506         }
10507
10508         GLboolean object_is_still_a_name = true;
10509
10510         switch (pState_obj->get_type())
10511         {
10512             case cGLSTProgram:
10513             {
10514                 handle_delete_program(static_cast<GLuint>(trace_handle));
10515
10516                 object_is_still_a_name = GL_ENTRYPOINT(glIsProgram)(static_cast<GLuint>(restore_handle));
10517
10518                 break;
10519             }
10520             case cGLSTShader:
10521             {
10522                 handle_delete_shader(static_cast<GLuint>(trace_handle));
10523
10524                 object_is_still_a_name = GL_ENTRYPOINT(glIsShader)(static_cast<GLuint>(restore_handle));
10525
10526                 break;
10527             }
10528             default:
10529             {
10530                 VOGL_ASSERT_ALWAYS;
10531                 break;
10532             }
10533         }
10534
10535         // "A program object marked for deletion with glDeleteProgram but still in use as part of current rendering state is still considered a program object and glIsProgram will return GL_TRUE."
10536         // Same for shaders.
10537         if (!object_is_still_a_name)
10538         {
10539             vogl_debug_printf("%s: Snapshot object type %s trace handle 0x%" PRIX64 " restore handle 0x%" PRIX64 ", was marked as deleted, then deleted after a full state restore, but the object which should still be referenced by state in the GL context fails the glIsProgram()/glIsShader()/etc. test\n", VOGL_METHOD_NAME,
10540                              get_gl_object_state_type_str(pState_obj->get_type()), (uint64_t)trace_handle, (uint64_t)restore_handle);
10541         }
10542     }
10543 }
10544
10545 //----------------------------------------------------------------------------------------------------------------------
10546 // vogl_replayer::begin_applying_snapshot
10547 // Takes ownership (even on errors) when delete_snapshot_after_applying is true.
10548 //----------------------------------------------------------------------------------------------------------------------
10549 vogl_gl_replayer::status_t vogl_gl_replayer::begin_applying_snapshot(const vogl_gl_state_snapshot *pSnapshot, bool delete_snapshot_after_applying)
10550 {
10551     VOGL_FUNC_TRACER
10552
10553     if (!pSnapshot->is_valid())
10554     {
10555         if (delete_snapshot_after_applying)
10556             vogl_delete(const_cast<vogl_gl_state_snapshot *>(pSnapshot));
10557
10558         return cStatusHardFailure;
10559     }
10560
10561     reset_state();
10562
10563     m_pPending_snapshot = pSnapshot;
10564     m_delete_pending_snapshot_after_applying = delete_snapshot_after_applying;
10565
10566     m_frame_index = pSnapshot->get_frame_index();
10567     m_last_parsed_call_counter = pSnapshot->get_gl_call_counter();
10568     m_last_processed_call_counter = pSnapshot->get_gl_call_counter();
10569     m_at_frame_boundary = false;
10570
10571     if (!(m_flags & cGLReplayerLockWindowDimensions))
10572     {
10573         return trigger_pending_window_resize(pSnapshot->get_window_width(), pSnapshot->get_window_height());
10574     }
10575
10576     return process_applying_pending_snapshot();
10577 }
10578
10579 //----------------------------------------------------------------------------------------------------------------------
10580 // vogl_replayer::restore_context
10581 //----------------------------------------------------------------------------------------------------------------------
10582 vogl_gl_replayer::status_t vogl_gl_replayer::restore_context(vogl_handle_remapper &trace_to_replay_remapper, const vogl_gl_state_snapshot &snapshot, const vogl_context_snapshot &context_snapshot)
10583 {
10584     VOGL_FUNC_TRACER
10585
10586     VOGL_NOTE_UNUSED(trace_to_replay_remapper);
10587     VOGL_NOTE_UNUSED(snapshot);
10588
10589     // TODO: This always creates with attribs, also need to support plain glXCreateContext()
10590
10591     Display *dpy = m_pWindow->get_display();
10592     GLXFBConfig fb_config = m_pWindow->get_fb_configs()[0];
10593
10594     vogl_trace_context_ptr_value trace_share_context = context_snapshot.get_context_desc().get_trace_share_context();
10595
10596     GLXContext replay_share_context = remap_context(trace_share_context);
10597     if ((trace_share_context) && (!replay_share_context))
10598     {
10599         vogl_error_printf("%s: Failed remapping trace share context handle 0x%" PRIx64 " to replay context!\n", VOGL_METHOD_NAME, cast_val_to_uint64(trace_share_context));
10600         return cStatusHardFailure;
10601     }
10602
10603     GLboolean direct = context_snapshot.get_context_desc().get_direct();
10604
10605     vogl_trace_context_ptr_value trace_context = context_snapshot.get_context_desc().get_trace_context();
10606
10607     status_t status = create_context_attribs(trace_context, dpy, fb_config, trace_share_context, replay_share_context, direct,
10608                                              context_snapshot.get_context_desc().get_attribs().get_vec().get_ptr(),
10609                                              context_snapshot.get_context_desc().get_attribs().get_vec().size(), true);
10610     if (status != cStatusOK)
10611     {
10612         vogl_error_printf("%s: Failed creating new context\n", VOGL_METHOD_NAME);
10613         return status;
10614     }
10615
10616     // Has this context ever been made current?
10617     if (context_snapshot.get_context_info().is_valid())
10618     {
10619         context_state *pContext_state = get_trace_context_state(trace_context);
10620         if (!pContext_state)
10621         {
10622             vogl_error_printf("%s: Failed finding replay context current\n", VOGL_METHOD_NAME);
10623             return cStatusHardFailure;
10624         }
10625
10626         GLXContext replay_context = pContext_state->m_replay_context;
10627         if (!replay_context)
10628         {
10629             vogl_error_printf("%s: Failed finding replay context current\n", VOGL_METHOD_NAME);
10630             return cStatusHardFailure;
10631         }
10632
10633         GLXDrawable drawable = m_pWindow->get_xwindow();
10634
10635         Bool result = GL_ENTRYPOINT(glXMakeCurrent)(dpy, drawable, replay_context);
10636         if (!result)
10637         {
10638             vogl_error_printf("%s: Failed making context current\n", VOGL_METHOD_NAME);
10639             return cStatusHardFailure;
10640         }
10641
10642         m_cur_trace_context = trace_context;
10643         m_cur_replay_context = replay_context;
10644         m_pCur_context_state = pContext_state;
10645
10646         if (!handle_context_made_current())
10647             return cStatusHardFailure;
10648     }
10649
10650     return cStatusOK;
10651 }
10652
10653 //----------------------------------------------------------------------------------------------------------------------
10654 // vogl_replayer::process_applying_pending_snapshot
10655 //----------------------------------------------------------------------------------------------------------------------
10656 vogl_gl_replayer::status_t vogl_gl_replayer::process_applying_pending_snapshot()
10657 {
10658     VOGL_FUNC_TRACER
10659
10660     if (!m_pPending_snapshot)
10661         return cStatusOK;
10662
10663     timed_scope ts(VOGL_METHOD_NAME);
10664
10665     const vogl_gl_state_snapshot &snapshot = *m_pPending_snapshot;
10666
10667     trace_to_replay_handle_remapper trace_to_replay_remapper(*this);
10668
10669     m_frame_index = snapshot.get_frame_index();
10670     m_last_parsed_call_counter = snapshot.get_gl_call_counter();
10671     m_last_processed_call_counter = snapshot.get_gl_call_counter();
10672     m_at_frame_boundary = snapshot.get_at_frame_boundary();
10673
10674     // Ensure the client side array bufs are large enough (we don't care about the actual ptr values).
10675     for (uint i = 0; i < snapshot.get_client_side_vertex_attrib_ptrs().size(); i++)
10676         m_client_side_vertex_attrib_data[i].resize(snapshot.get_client_side_vertex_attrib_ptrs()[i].m_size);
10677
10678     for (uint i = 0; i < snapshot.get_client_side_array_ptrs().size(); i++)
10679         m_client_side_array_data[i].resize(snapshot.get_client_side_array_ptrs()[i].m_size);
10680
10681     for (uint i = 0; i < snapshot.get_client_side_texcoord_ptrs().size(); i++)
10682         m_client_side_texcoord_data[i].resize(snapshot.get_client_side_texcoord_ptrs()[i].m_size);
10683
10684     const vogl_context_snapshot_ptr_vec &context_ptrs = snapshot.get_contexts();
10685
10686     vogl_context_snapshot_ptr_vec restore_context_ptrs(snapshot.get_contexts());
10687     vogl::vector<vogl_const_gl_object_state_ptr_vec> objects_to_delete_vec(context_ptrs.size());
10688
10689     status_t status = cStatusOK;
10690     uint total_contexts_restored = 0;
10691     bool restored_default_framebuffer = false;
10692
10693     for (;;)
10694     {
10695         uint num_contexts_restored_in_this_pass = 0;
10696
10697         for (uint context_index = 0; context_index < restore_context_ptrs.size(); context_index++)
10698         {
10699             if (!restore_context_ptrs[context_index])
10700                 continue;
10701
10702             const vogl_context_snapshot &context_state = *restore_context_ptrs[context_index];
10703
10704             if (context_state.get_context_desc().get_trace_share_context())
10705             {
10706                 // Don't restore this context if its sharelist context hasn't been restored yet
10707                 if (!remap_context(context_state.get_context_desc().get_trace_share_context()))
10708                     continue;
10709             }
10710
10711             status = restore_context(trace_to_replay_remapper, snapshot, context_state);
10712             if (status != cStatusOK)
10713                 goto handle_error;
10714
10715             // Has this context ever been made current?
10716             if (context_state.get_context_info().is_valid())
10717             {
10718                 // Keep this in sync with vogl_gl_object_state_type (the order doesn't need to match the enum, but be sure to restore leaf GL objects first!)
10719                 const vogl_gl_object_state_type s_object_type_restore_order[] = { cGLSTBuffer, cGLSTSampler, cGLSTQuery, cGLSTRenderbuffer, cGLSTTexture, cGLSTFramebuffer, cGLSTVertexArray, cGLSTShader, cGLSTProgram, cGLSTSync, cGLSTARBProgram };
10720                 VOGL_ASSUME(VOGL_ARRAY_SIZE(s_object_type_restore_order) == (cGLSTTotalTypes - 1));
10721
10722                 if (m_flags & cGLReplayerLowLevelDebugMode)
10723                 {
10724                     if (!validate_textures())
10725                         vogl_warning_printf("%s: Failed validating texture handles against handle mapping tables\n", VOGL_METHOD_NAME);
10726                 }
10727
10728                 vogl_const_gl_object_state_ptr_vec &objects_to_delete = objects_to_delete_vec[context_index];
10729
10730                 for (uint i = 0; i < VOGL_ARRAY_SIZE(s_object_type_restore_order); i++)
10731                 {
10732                     status = restore_objects(trace_to_replay_remapper, snapshot, context_state, s_object_type_restore_order[i], objects_to_delete);
10733                     if (status != cStatusOK)
10734                         goto handle_error;
10735
10736                     if (m_flags & cGLReplayerLowLevelDebugMode)
10737                     {
10738                         if (!validate_program_and_shader_handle_tables())
10739                             vogl_error_printf("%s: Program/shader handle table validation failed!\n", VOGL_METHOD_NAME);
10740
10741                         if (!validate_textures())
10742                             vogl_warning_printf("%s: Failed validating texture handles against handle mapping tables\n", VOGL_METHOD_NAME);
10743                     }
10744                 }
10745
10746                 if (m_flags & cGLReplayerLowLevelDebugMode)
10747                 {
10748                     if (!validate_textures())
10749                         vogl_warning_printf("%s: Failed validating texture handles against handle mapping tables\n", VOGL_METHOD_NAME);
10750                 }
10751
10752                 status = restore_display_lists(trace_to_replay_remapper, snapshot, context_state);
10753                 if (status != cStatusOK)
10754                     goto handle_error;
10755
10756                 // Restore default framebuffer
10757                 if ((!restored_default_framebuffer) && (snapshot.get_default_framebuffer().is_valid()))
10758                 {
10759                     restored_default_framebuffer = true;
10760
10761                     if (!snapshot.get_default_framebuffer().restore(m_pCur_context_state->m_context_info))
10762                     {
10763                         vogl_warning_printf("%s: Failed restoring default framebuffer!\n", VOGL_METHOD_NAME);
10764                     }
10765                 }
10766
10767                 // Beware: restore_general_state() will bind a bunch of stuff from the trace!
10768                 status = restore_general_state(trace_to_replay_remapper, snapshot, context_state);
10769                 if (status != cStatusOK)
10770                     goto handle_error;
10771
10772                 status = update_context_shadows(trace_to_replay_remapper, snapshot, context_state);
10773                 if (status != cStatusOK)
10774                     goto handle_error;
10775
10776                 if (m_flags & cGLReplayerLowLevelDebugMode)
10777                 {
10778                     if (!validate_program_and_shader_handle_tables())
10779                         vogl_error_printf("%s: Program/shader handle table validation failed!\n", VOGL_METHOD_NAME);
10780
10781                     if (!validate_textures())
10782                         vogl_warning_printf("%s: Failed validating texture handles against handle mapping tables\n", VOGL_METHOD_NAME);
10783                 }
10784             }
10785
10786             num_contexts_restored_in_this_pass++;
10787
10788             total_contexts_restored++;
10789
10790             restore_context_ptrs[context_index] = NULL;
10791         }
10792
10793         if (!num_contexts_restored_in_this_pass)
10794             break;
10795     }
10796
10797     if (total_contexts_restored != snapshot.get_contexts().size())
10798     {
10799         vogl_error_printf("%s: Failed satisfying sharelist dependency during context restoration\n", VOGL_METHOD_NAME);
10800         goto handle_error;
10801     }
10802
10803     for (uint context_index = 0; context_index < context_ptrs.size(); context_index++)
10804     {
10805         const vogl_context_snapshot &context_state = *context_ptrs[context_index];
10806
10807         if (!context_state.get_context_info().is_valid())
10808             continue;
10809
10810         status_t status = switch_contexts(context_state.get_context_desc().get_trace_context());
10811         if (status != cStatusOK)
10812         {
10813             vogl_error_printf("%s: Failed switching to trace context 0x%" PRIX64 ", capture failed\n", VOGL_METHOD_NAME, cast_val_to_uint64(context_state.get_context_desc().get_trace_context()));
10814             goto handle_error;
10815         }
10816
10817         vogl_const_gl_object_state_ptr_vec &objects_to_delete = objects_to_delete_vec[context_index];
10818
10819         handle_marked_for_deleted_objects(objects_to_delete, trace_to_replay_remapper);
10820     }
10821
10822     destroy_pending_snapshot();
10823
10824     return cStatusOK;
10825
10826 handle_error:
10827
10828     reset_state();
10829
10830     return status;
10831 }
10832
10833 //----------------------------------------------------------------------------------------------------------------------
10834 // vogl_gl_replayer::write_trim_file_internal
10835 //----------------------------------------------------------------------------------------------------------------------
10836 bool vogl_gl_replayer::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)
10837 {
10838     // Open the output trace
10839     // TODO: This pretty much ignores the ctypes packet, and uses the one based off the ptr size in the header. The ctypes stuff needs to be refactored, storing it in an explicit packet is bad.
10840     const vogl_ctypes &trace_gl_ctypes = get_trace_gl_ctypes();
10841
10842     vogl_trace_packet trace_packet(&trace_gl_ctypes);
10843
10844     // TODO: This seems like WAY too much work! Move the snapshot to the beginning of the trace, in the header!
10845     bool found_state_snapshot = false;
10846     dynamic_string binary_snapshot_id, text_snapshot_id;
10847
10848     bool is_at_start_of_trace = false;
10849     VOGL_NOTE_UNUSED(is_at_start_of_trace);
10850
10851     int demarcation_packet_index = -1;
10852     for (uint packet_index = 0; packet_index < trim_packets.size(); packet_index++)
10853     {
10854         const vogl_trace_stream_packet_types_t packet_type = trim_packets.get_packet_type(packet_index);
10855         if (packet_type != cTSPTGLEntrypoint)
10856             continue;
10857
10858         const uint8_vec &packet_buf = trim_packets.get_packet_buf(packet_index);
10859
10860         const vogl_trace_gl_entrypoint_packet *pGL_packet = &trim_packets.get_packet<vogl_trace_gl_entrypoint_packet>(packet_index);
10861         if (pGL_packet->m_entrypoint_id != VOGL_ENTRYPOINT_glInternalTraceCommandRAD)
10862             continue;
10863
10864         if (!trace_packet.deserialize(packet_buf.get_ptr(), packet_buf.size(), true))
10865         {
10866             console::error("%s: Failed parsing glInternalTraceCommandRAD packet\n", VOGL_FUNCTION_NAME);
10867             return false;
10868         }
10869
10870         GLuint cmd = trace_packet.get_param_value<GLuint>(0);
10871         if (cmd == cITCRDemarcation)
10872         {
10873             is_at_start_of_trace = true;
10874             demarcation_packet_index = packet_index;
10875         }
10876         else if (cmd == cITCRKeyValueMap)
10877         {
10878             key_value_map &kvm = trace_packet.get_key_value_map();
10879
10880             dynamic_string cmd_type(kvm.get_string("command_type"));
10881
10882             if (cmd_type == "state_snapshot")
10883             {
10884                 found_state_snapshot = true;
10885
10886                 text_snapshot_id = kvm.get_string("id");
10887                 binary_snapshot_id = kvm.get_string("binary_id");
10888             }
10889         }
10890     }
10891
10892     vogl_trace_file_writer trace_writer(&trace_gl_ctypes);
10893     if (!trace_writer.open(trim_filename.get_ptr(), NULL, true, false, m_trace_pointer_size_in_bytes))
10894     {
10895         console::error("%s: Failed creating trimmed trace file \"%s\"!\n", VOGL_FUNCTION_NAME, trim_filename.get_ptr());
10896         return false;
10897     }
10898
10899     if (found_state_snapshot)
10900     {
10901         // Copy over the source trace's archive (it contains the snapshot, along with any files it refers to).
10902         if (trace_reader.get_archive_blob_manager().is_initialized())
10903         {
10904             dynamic_string_array blob_files(trace_reader.get_archive_blob_manager().enumerate());
10905             for (uint i = 0; i < blob_files.size(); i++)
10906             {
10907                 if ((blob_files[i].is_empty()) || (blob_files[i] == VOGL_TRACE_ARCHIVE_FRAME_FILE_OFFSETS_FILENAME))
10908                     continue;
10909
10910                 vogl_message_printf("Adding blob file %s to output trace archive\n", blob_files[i].get_ptr());
10911
10912                 if (!trace_writer.get_trace_archive()->copy_file(trace_reader.get_archive_blob_manager(), blob_files[i], blob_files[i]).has_content())
10913                 {
10914                     vogl_error_printf("%s: Failed copying blob data for file \"%s\" to output trace archive!\n", VOGL_FUNCTION_NAME, blob_files[i].get_ptr());
10915                     return false;
10916                 }
10917             }
10918         }
10919     }
10920     else
10921     {
10922         // Copy over the source trace's backtrace map, machine info, etc. files.
10923         if (trace_reader.get_archive_blob_manager().is_initialized())
10924         {
10925             // compiler_info.json
10926             trace_writer.get_trace_archive()->copy_file(trace_reader.get_archive_blob_manager(), VOGL_TRACE_ARCHIVE_COMPILER_INFO_FILENAME, VOGL_TRACE_ARCHIVE_COMPILER_INFO_FILENAME);
10927             // machine_info.json
10928             trace_writer.get_trace_archive()->copy_file(trace_reader.get_archive_blob_manager(), VOGL_TRACE_ARCHIVE_MACHINE_INFO_FILENAME, VOGL_TRACE_ARCHIVE_MACHINE_INFO_FILENAME);
10929             // backtrace_map_syms.json
10930             trace_writer.get_trace_archive()->copy_file(trace_reader.get_archive_blob_manager(), VOGL_TRACE_ARCHIVE_BACKTRACE_MAP_SYMS_FILENAME, VOGL_TRACE_ARCHIVE_BACKTRACE_MAP_SYMS_FILENAME);
10931             // backtrace_map_addrs.json
10932             trace_writer.get_trace_archive()->copy_file(trace_reader.get_archive_blob_manager(), VOGL_TRACE_ARCHIVE_BACKTRACE_MAP_ADDRS_FILENAME, VOGL_TRACE_ARCHIVE_BACKTRACE_MAP_ADDRS_FILENAME);
10933         }
10934
10935         vogl_unique_ptr<vogl_gl_state_snapshot> pTrim_snapshot(snapshot_state(&trim_packets, optimize_snapshot));
10936
10937         if (!pTrim_snapshot.get())
10938         {
10939             console::error("%s: Failed creating replayer GL snapshot!\n", VOGL_FUNCTION_NAME);
10940             return false;
10941         }
10942
10943         pTrim_snapshot->set_frame_index(0);
10944
10945         json_document doc;
10946         if (!pTrim_snapshot->serialize(*doc.get_root(), *trace_writer.get_trace_archive(), &trace_gl_ctypes))
10947         {
10948             console::error("%s: Failed serializing GL state snapshot!\n", VOGL_FUNCTION_NAME);
10949             trace_writer.close();
10950             file_utils::delete_file(trim_filename.get_ptr());
10951             return false;
10952         }
10953
10954         vogl::vector<char> snapshot_data;
10955         doc.serialize(snapshot_data, true, 0, false);
10956
10957         uint8_vec binary_snapshot_data;
10958         doc.binary_serialize(binary_snapshot_data);
10959
10960         pTrim_snapshot.reset();
10961
10962         // Write the state_snapshot file to the trace archive
10963         dynamic_string snapshot_id(trace_writer.get_trace_archive()->add_buf_compute_unique_id(snapshot_data.get_ptr(), snapshot_data.size(), "state_snapshot", VOGL_TEXT_JSON_EXTENSION));
10964         if (snapshot_id.is_empty())
10965         {
10966             console::error("%s: Failed adding GL snapshot file to output blob manager!\n", VOGL_FUNCTION_NAME);
10967             trace_writer.close();
10968             file_utils::delete_file(trim_filename.get_ptr());
10969             return false;
10970         }
10971
10972         if (pSnapshot_id)
10973             *pSnapshot_id = snapshot_id;
10974
10975         snapshot_data.clear();
10976
10977         // Write the binary_state_snapshot file to the trace archive
10978         dynamic_string binary_snapshot_id(trace_writer.get_trace_archive()->add_buf_compute_unique_id(binary_snapshot_data.get_ptr(), binary_snapshot_data.size(), "binary_state_snapshot", VOGL_BINARY_JSON_EXTENSION));
10979         if (binary_snapshot_id.is_empty())
10980         {
10981             console::error("%s: Failed adding binary GL snapshot file to output blob manager!\n", VOGL_FUNCTION_NAME);
10982             trace_writer.close();
10983             file_utils::delete_file(trim_filename.get_ptr());
10984             return false;
10985         }
10986
10987         binary_snapshot_data.clear();
10988
10989         key_value_map snapshot_key_value_map;
10990         snapshot_key_value_map.insert("command_type", "state_snapshot");
10991         snapshot_key_value_map.insert("id", snapshot_id);
10992         snapshot_key_value_map.insert("binary_id", binary_snapshot_id);
10993
10994         dynamic_stream snapshot_stream(0);
10995         if (!vogl_write_glInternalTraceCommandRAD(snapshot_stream, &trace_gl_ctypes, cITCRKeyValueMap, sizeof(snapshot_key_value_map), reinterpret_cast<const GLubyte *>(&snapshot_key_value_map)))
10996         {
10997             console::error("%s: Failed serializing snapshot packet!\n", VOGL_FUNCTION_NAME);
10998             trace_writer.close();
10999             file_utils::delete_file(trim_filename.get_ptr());
11000             return false;
11001         }
11002
11003         if (demarcation_packet_index >= 0)
11004         {
11005             trim_packets.insert(demarcation_packet_index, snapshot_stream.get_buf());
11006             demarcation_packet_index++;
11007         }
11008         else
11009         {
11010             dynamic_stream demarcation_stream(0);
11011             vogl_write_glInternalTraceCommandRAD(demarcation_stream, &trace_gl_ctypes, cITCRDemarcation, 0, NULL);
11012
11013             // Screw the ctypes packet, it's only used for debugging right now anyway.
11014             trim_packets.insert(0, snapshot_stream.get_buf());
11015             trim_packets.insert(1, demarcation_stream.get_buf());
11016         }
11017     }
11018
11019     for (uint packet_index = 0; packet_index < trim_packets.size(); packet_index++)
11020     {
11021         const uint8_vec &packet_buf = trim_packets.get_packet_buf(packet_index);
11022
11023         const bool is_swap = trim_packets.is_swap_buffers_packet(packet_index);
11024
11025         const vogl_trace_stream_packet_types_t packet_type = trim_packets.get_packet_type(packet_index);
11026         if (packet_type == cTSPTEOF)
11027             break;
11028         else if (packet_type != cTSPTGLEntrypoint)
11029         {
11030             VOGL_ASSERT_ALWAYS;
11031         }
11032
11033         if (!trace_writer.write_packet(packet_buf.get_ptr(), packet_buf.size(), is_swap))
11034         {
11035             console::error("%s: Failed writing trace packet to output trace file \"%s\"!\n", VOGL_FUNCTION_NAME, trim_filename.get_ptr());
11036             trace_writer.close();
11037             file_utils::delete_file(trim_filename.get_ptr());
11038             return false;
11039         }
11040     }
11041
11042     bool success = trace_writer.close();
11043     if (!success)
11044         console::error("%s: Failed closing wrote trim trace file \"%s\"\n", VOGL_FUNCTION_NAME, trim_filename.get_ptr());
11045     else
11046         console::message("%s: Successfully wrote trim trace file \"%s\"\n", VOGL_FUNCTION_NAME, trim_filename.get_ptr());
11047
11048     return success;
11049 }
11050
11051 //----------------------------------------------------------------------------------------------------------------------
11052 // vogl_gl_replayer::write_trim_file
11053 //----------------------------------------------------------------------------------------------------------------------
11054 bool vogl_gl_replayer::write_trim_file(uint flags, const dynamic_string &trim_filename, uint trim_len, vogl_trace_file_reader &trace_reader, dynamic_string *pSnapshot_id)
11055 {
11056     VOGL_FUNC_TRACER
11057
11058     if (!m_is_valid)
11059     {
11060         console::error("%s: Trace is not open\n", VOGL_METHOD_NAME);
11061         return false;
11062     }
11063
11064     bool from_start_of_frame = (flags & cWriteTrimFileFromStartOfFrame) != 0;
11065
11066     if ((!from_start_of_frame) || (!trim_len))
11067         flags &= ~cWriteTrimFileOptimizeSnapshot;
11068
11069     const uint trim_frame = static_cast<uint>(get_frame_index());
11070     const int64_t trim_call_counter = get_last_parsed_call_counter();
11071
11072     // Read the desired packets from the source trace file
11073     vogl_trace_packet_array trim_packets;
11074
11075     if ((trim_len) || (!trim_frame))
11076     {
11077         console::message("%s: Reading trim packets from source trace file\n", VOGL_FUNCTION_NAME);
11078
11079         uint frames_to_read = trim_len;
11080         if ((from_start_of_frame) && (!trim_frame) && (!trim_len))
11081             frames_to_read = 1;
11082
11083         uint actual_trim_len = 0;
11084         vogl_trace_file_reader::trace_file_reader_status_t read_packets_status = trace_reader.read_frame_packets(trim_frame, frames_to_read, trim_packets, actual_trim_len);
11085         if (read_packets_status == vogl_trace_file_reader::cFailed)
11086         {
11087             console::error("%s: Failed reading source trace file packets beginning at frame %u!\n", VOGL_FUNCTION_NAME, trim_frame);
11088             return false;
11089         }
11090
11091         if (actual_trim_len != frames_to_read)
11092         {
11093             console::warning("%s: Only able to read %u frames from trim file beginning at frame %u, not the requested %u\n", VOGL_FUNCTION_NAME, actual_trim_len, trim_frame, frames_to_read);
11094         }
11095
11096         if (from_start_of_frame)
11097         {
11098             console::message("%s: Read %u trim packets beginning at frame %u actual len %u from source trace file\n", VOGL_FUNCTION_NAME, trim_packets.size(), trim_frame, actual_trim_len);
11099
11100             if ((!trim_frame) && (!trim_len))
11101             {
11102                 // Special case: They want frame 0 with no packets, so be sure to copy any internal trace commands at the very beginning of the trace.
11103                 // TODO: Most of this will go away once we move the state snapshot into the trace archive.
11104
11105                 vogl_trace_packet_array new_trim_packets;
11106
11107                 vogl_trace_packet trace_packet(&get_trace_gl_ctypes());
11108
11109                 for (uint packet_index = 0; packet_index < trim_packets.size(); packet_index++)
11110                 {
11111                     const vogl_trace_stream_packet_types_t packet_type = trim_packets.get_packet_type(packet_index);
11112                     if (packet_type != cTSPTGLEntrypoint)
11113                         break;
11114
11115                     const uint8_vec &packet_buf = trim_packets.get_packet_buf(packet_index);
11116
11117                     const vogl_trace_gl_entrypoint_packet *pGL_packet = &trim_packets.get_packet<vogl_trace_gl_entrypoint_packet>(packet_index);
11118                     if (pGL_packet->m_entrypoint_id != VOGL_ENTRYPOINT_glInternalTraceCommandRAD)
11119                         break;
11120
11121                     if (!trace_packet.deserialize(packet_buf.get_ptr(), packet_buf.size(), true))
11122                     {
11123                         console::error("%s: Failed parsing glInternalTraceCommandRAD packet\n", VOGL_FUNCTION_NAME);
11124                         return false;
11125                     }
11126
11127                     GLuint cmd = trace_packet.get_param_value<GLuint>(0);
11128
11129                     new_trim_packets.push_back(packet_buf);
11130
11131                     if (cmd == cITCRDemarcation)
11132                         break;
11133                 }
11134
11135                 trim_packets.swap(new_trim_packets);
11136             }
11137         }
11138         else if (trim_call_counter >= 0)
11139         {
11140             uint orig_num_packets = trim_packets.size();
11141             uint total_erased_packets = 0;
11142
11143             // Remove any calls before the current one.
11144             for (int64_t packet_index = 0; packet_index < trim_packets.size(); packet_index++)
11145             {
11146                 if (trim_packets.get_packet_type(static_cast<uint>(packet_index)) != cTSPTGLEntrypoint)
11147                     continue;
11148
11149                 const vogl_trace_gl_entrypoint_packet *pGL_packet = &trim_packets.get_packet<vogl_trace_gl_entrypoint_packet>(static_cast<uint>(packet_index));
11150
11151                 if (static_cast<int64_t>(pGL_packet->m_call_counter) <= trim_call_counter)
11152                 {
11153                     trim_packets.erase(static_cast<uint>(packet_index));
11154                     packet_index--;
11155
11156                     total_erased_packets++;
11157                 }
11158             }
11159
11160             console::message("%s: Read %u packets from frame %u, erased %u packets before call counter %" PRIu64 ", storing %u trim packets from source trace file\n", VOGL_FUNCTION_NAME, orig_num_packets, trim_frame, total_erased_packets, trim_call_counter, trim_packets.size());
11161         }
11162     }
11163
11164     return write_trim_file_internal(trim_packets, trim_filename, trace_reader, (flags & cWriteTrimFileOptimizeSnapshot) != 0, pSnapshot_id);
11165 }