]> git.cworth.org Git - vogl/blob - src/voglcommon/vogl_gl_replayer.cpp
- Adding support for pixel pack buffers used with glReadPixels(), glGetTexImage(...
[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     // Seems better to return -1 when we can't find the uniform (which can happen if the driver optimizes the program differently vs. tracing).
1270     // Otherwise, we can pass an invalid handle down to the driver and this will crash AMD's fglrx.
1271     //GLint replay_location = trace_location;
1272     GLint replay_location = -1;
1273
1274     glsl_program_hash_map::iterator it = get_shared_state()->m_glsl_program_hash_map.find(trace_program);
1275     if (it == get_shared_state()->m_glsl_program_hash_map.end())
1276     {
1277         process_entrypoint_warning("%s: Failed looking up current trace program in GLSL program hash map\n", VOGL_METHOD_NAME);
1278     }
1279     else
1280     {
1281         glsl_program_state &state = it->second;
1282
1283         uniform_location_hash_map::const_iterator loc_it = state.m_uniform_locations.find(trace_location);
1284         if (loc_it == state.m_uniform_locations.end())
1285         {
1286             process_entrypoint_warning("%s: Failed looking up uniform location index\n", VOGL_METHOD_NAME);
1287         }
1288         else
1289         {
1290             replay_location = loc_it->second;
1291         }
1292     }
1293     return replay_location;
1294 }
1295
1296 //----------------------------------------------------------------------------------------------------------------------
1297 // vogl_replayer::process_entrypoint_print_summary_context
1298 //----------------------------------------------------------------------------------------------------------------------
1299 void vogl_gl_replayer::process_entrypoint_print_summary_context(eConsoleMessageType msg_type)
1300 {
1301     VOGL_FUNC_TRACER
1302
1303     if (!m_pCur_gl_packet)
1304         return;
1305
1306     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",
1307                     g_vogl_entrypoint_descs[m_pCur_gl_packet->get_entrypoint_id()].m_pName,
1308                     m_frame_index, m_total_swaps,
1309                     m_pCur_gl_packet->get_entrypoint_packet().m_call_counter,
1310                     m_pCur_gl_packet->get_entrypoint_packet().m_context_handle,
1311                     m_cur_trace_context,
1312                     m_pCur_gl_packet->get_entrypoint_packet().m_thread_id);
1313
1314 #if 0
1315         dynamic_string_array backtrace;
1316         if (get_printable_backtrace(backtrace))
1317         {
1318                 console::printf("Backtrace:\n");
1319                 for (uint i = 0; i < backtrace.size(); i++)
1320                         console::printf("%s\n", backtrace[i].get_ptr());
1321         }
1322 #endif
1323 }
1324
1325 //----------------------------------------------------------------------------------------------------------------------
1326 // vogl_replayer::print_detailed_context
1327 //----------------------------------------------------------------------------------------------------------------------
1328 void vogl_gl_replayer::print_detailed_context(eConsoleMessageType msg_type)
1329 {
1330     VOGL_FUNC_TRACER
1331
1332     json_node node;
1333
1334     vogl_loose_file_blob_manager blob_file_manager;
1335     blob_file_manager.init(cBMFWritable);
1336
1337     vogl_trace_packet::json_serialize_params serialize_params;
1338     serialize_params.m_output_basename = "replay_error";
1339     serialize_params.m_cur_frame = m_frame_index;
1340     serialize_params.m_blob_file_size_threshold = 1024;
1341     serialize_params.m_pBlob_manager = (m_flags & cGLReplayerDumpPacketBlobFilesOnError) ? &blob_file_manager : NULL;
1342     m_pCur_gl_packet->json_serialize(node, serialize_params);
1343
1344     dynamic_string node_str;
1345     node.serialize(node_str, true, 0);
1346     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());
1347 }
1348
1349 //----------------------------------------------------------------------------------------------------------------------
1350 // vogl_replayer::process_entrypoint_msg_print_detailed_context
1351 //----------------------------------------------------------------------------------------------------------------------
1352 void vogl_gl_replayer::process_entrypoint_msg_print_detailed_context(eConsoleMessageType msg_type)
1353 {
1354     VOGL_FUNC_TRACER
1355
1356     if (!m_pCur_gl_packet)
1357         return;
1358
1359     dump_packet_as_func_call(*m_pCur_gl_packet);
1360
1361     if (!(m_flags & cGLReplayerDumpPacketsOnError))
1362         return;
1363
1364     print_detailed_context(msg_type);
1365 }
1366
1367 //----------------------------------------------------------------------------------------------------------------------
1368 // vogl_replayer::process_entrypoint_info
1369 //----------------------------------------------------------------------------------------------------------------------
1370 void vogl_gl_replayer::process_entrypoint_info(const char *pFmt, ...)
1371 {
1372     VOGL_FUNC_TRACER
1373
1374     process_entrypoint_print_summary_context(cInfoConsoleMessage);
1375
1376     va_list args;
1377     va_start(args, pFmt);
1378     console::vprintf(cInfoConsoleMessage, pFmt, args);
1379     va_end(args);
1380
1381     process_entrypoint_msg_print_detailed_context(cInfoConsoleMessage);
1382 }
1383
1384 //----------------------------------------------------------------------------------------------------------------------
1385 // vogl_replayer::process_entrypoint_message
1386 //----------------------------------------------------------------------------------------------------------------------
1387 void vogl_gl_replayer::process_entrypoint_message(const char *pFmt, ...)
1388 {
1389     VOGL_FUNC_TRACER
1390
1391     process_entrypoint_print_summary_context(cMessageConsoleMessage);
1392
1393     va_list args;
1394     va_start(args, pFmt);
1395     console::vprintf(cMessageConsoleMessage, pFmt, args);
1396     va_end(args);
1397
1398     process_entrypoint_msg_print_detailed_context(cInfoConsoleMessage);
1399 }
1400
1401 //----------------------------------------------------------------------------------------------------------------------
1402 // vogl_replayer::process_entrypoint_warning
1403 //----------------------------------------------------------------------------------------------------------------------
1404 void vogl_gl_replayer::process_entrypoint_warning(const char *pFmt, ...)
1405 {
1406     VOGL_FUNC_TRACER
1407
1408     process_entrypoint_print_summary_context(cWarningConsoleMessage);
1409
1410     va_list args;
1411     va_start(args, pFmt);
1412     console::vprintf(cWarningConsoleMessage, pFmt, args);
1413     va_end(args);
1414
1415     process_entrypoint_msg_print_detailed_context(cInfoConsoleMessage);
1416 }
1417
1418 //----------------------------------------------------------------------------------------------------------------------
1419 // vogl_replayer::process_entrypoint_error
1420 //----------------------------------------------------------------------------------------------------------------------
1421 void vogl_gl_replayer::process_entrypoint_error(const char *pFmt, ...)
1422 {
1423     VOGL_FUNC_TRACER
1424
1425     process_entrypoint_print_summary_context(cErrorConsoleMessage);
1426
1427     va_list args;
1428     va_start(args, pFmt);
1429     console::vprintf(cErrorConsoleMessage, pFmt, args);
1430     va_end(args);
1431
1432     process_entrypoint_msg_print_detailed_context(cInfoConsoleMessage);
1433 }
1434
1435 //----------------------------------------------------------------------------------------------------------------------
1436 // vogl_replayer::switch_contexts
1437 //----------------------------------------------------------------------------------------------------------------------
1438 vogl_gl_replayer::status_t vogl_gl_replayer::switch_contexts(vogl_trace_context_ptr_value trace_context)
1439 {
1440     VOGL_FUNC_TRACER
1441
1442     // HACK HACK
1443     //if (m_pCur_gl_packet->get_call_counter() == 25583)
1444     //    vogl_debug_break();
1445
1446     //vogl_trace_context_ptr_value trace_context = gl_packet.m_context_handle;
1447     if (trace_context == m_cur_trace_context)
1448         return cStatusOK;
1449
1450     if (m_flags & cGLReplayerDebugMode)
1451     {
1452         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));
1453     }
1454
1455     // pContext_state will be NULL if they are unmapping!
1456     context_state *pContext_state = get_trace_context_state(trace_context);
1457     GLXContext replay_context = pContext_state ? pContext_state->m_replay_context : 0;
1458
1459     const Display *dpy = m_pWindow->get_display();
1460     GLXDrawable drawable = replay_context ? m_pWindow->get_xwindow() : (GLXDrawable)NULL;
1461
1462     Bool result = GL_ENTRYPOINT(glXMakeCurrent)(dpy, drawable, replay_context);
1463     if (!result)
1464     {
1465         process_entrypoint_error("%s: Failed switching current trace context to 0x%" PRIX64 "\n", VOGL_METHOD_NAME, trace_context);
1466         return cStatusHardFailure;
1467     }
1468
1469     m_cur_trace_context = trace_context;
1470     m_cur_replay_context = replay_context;
1471     m_pCur_context_state = pContext_state;
1472
1473     return cStatusOK;
1474 }
1475
1476 //----------------------------------------------------------------------------------------------------------------------
1477 // vogl_replayer::debug_callback_arb
1478 //----------------------------------------------------------------------------------------------------------------------
1479 void vogl_gl_replayer::debug_callback_arb(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, GLvoid *pUser_param)
1480 {
1481     VOGL_FUNC_TRACER
1482
1483     VOGL_NOTE_UNUSED(length);
1484
1485     char final_message[4096];
1486
1487     context_state *pContext_state = (context_state *)(pUser_param);
1488
1489     vogl_format_debug_output_arb(final_message, sizeof(final_message), source, type, id, severity, reinterpret_cast<const char *>(message));
1490
1491     if (pContext_state)
1492     {
1493         vogl_warning_printf("%s: Trace context: 0x%" PRIX64 ", Replay context 0x%" PRIX64 ", Last trace call counter: %" PRIu64 "\n%s\n", VOGL_FUNCTION_NAME,
1494                            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);
1495     }
1496     else
1497     {
1498         vogl_warning_printf("%s: %s\n", VOGL_FUNCTION_NAME, final_message);
1499     }
1500 }
1501
1502 //----------------------------------------------------------------------------------------------------------------------
1503 // vogl_replayer::debug_callback
1504 //----------------------------------------------------------------------------------------------------------------------
1505 void vogl_gl_replayer::debug_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, GLvoid *pUser_param)
1506 {
1507     VOGL_FUNC_TRACER
1508
1509     VOGL_NOTE_UNUSED(length);
1510
1511     char final_message[4096];
1512
1513     context_state *pContext_state = (context_state *)(pUser_param);
1514
1515     vogl_format_debug_output_arb(final_message, sizeof(final_message), source, type, id, severity, reinterpret_cast<const char *>(message));
1516
1517     if (pContext_state)
1518     {
1519         vogl_warning_printf("%s: Trace context: 0x%" PRIX64 ", Replay context 0x%" PRIX64 ", Last trace call counter: %" PRIu64 "\n%s\n", VOGL_FUNCTION_NAME,
1520                            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);
1521     }
1522     else
1523     {
1524         vogl_warning_printf("%s: %s\n", VOGL_FUNCTION_NAME, final_message);
1525     }
1526 }
1527
1528 //----------------------------------------------------------------------------------------------------------------------
1529 // vogl_replayer::is_extension_supported
1530 //----------------------------------------------------------------------------------------------------------------------
1531 bool vogl_gl_replayer::is_extension_supported(const char *pExt)
1532 {
1533     VOGL_FUNC_TRACER
1534
1535     if ((m_pCur_context_state) && (m_pCur_context_state->m_context_info.is_valid()))
1536     {
1537         return m_pCur_context_state->m_context_info.supports_extension(pExt);
1538     }
1539
1540     VOGL_ASSERT_ALWAYS;
1541
1542     return true;
1543 }
1544
1545 //----------------------------------------------------------------------------------------------------------------------
1546 // vogl_replayer::context_state::handle_context_made_current
1547 //----------------------------------------------------------------------------------------------------------------------
1548 bool vogl_gl_replayer::context_state::handle_context_made_current()
1549 {
1550     VOGL_FUNC_TRACER
1551
1552     if (m_has_been_made_current)
1553         return true;
1554
1555     VOGL_CHECK_GL_ERROR;
1556
1557     m_has_been_made_current = true;
1558
1559     if (!m_context_info.init(m_context_desc))
1560     {
1561         vogl_error_printf("%s: vogl_context_info::init() failed!\n", VOGL_METHOD_NAME);
1562         return false;
1563     }
1564
1565     if (!m_context_info.get_max_vertex_attribs())
1566     {
1567         vogl_warning_printf("%s: GL_MAX_VERTEX_ATTRIBS is 0\n", VOGL_METHOD_NAME);
1568     }
1569     else if (m_context_info.get_max_vertex_attribs() >= VOGL_MAX_SUPPORTED_GL_VERTEX_ATTRIBUTES)
1570     {
1571         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);
1572         return false;
1573     }
1574
1575     if (m_replayer.m_flags & cGLReplayerLowLevelDebugMode)
1576     {
1577         vogl_debug_printf("%s: Creating dummy handles\n", VOGL_METHOD_NAME);
1578
1579         // HACK HACK
1580         // Generate a bunch of replay handles, so the trace and replay namespaces are totally different to shake out handle or target remapping bugs
1581         // TODO: All more object types
1582         vogl::vector<GLuint> dummy_handles(65536);
1583
1584         GL_ENTRYPOINT(glGenTextures)(4000, dummy_handles.get_ptr());
1585         GL_ENTRYPOINT(glGenBuffers)(6000, dummy_handles.get_ptr());
1586         GL_ENTRYPOINT(glGenLists)(8000);
1587         GL_ENTRYPOINT(glGenQueries)(10000, dummy_handles.get_ptr());
1588
1589         GL_ENTRYPOINT(glGenVertexArrays)(12000, dummy_handles.get_ptr());
1590         GL_ENTRYPOINT(glGenProgramsARB)(14000, dummy_handles.get_ptr());
1591         GL_ENTRYPOINT(glGenFramebuffers)(16000, dummy_handles.get_ptr());
1592         GL_ENTRYPOINT(glGenSamplers)(18000, dummy_handles.get_ptr());
1593         GL_ENTRYPOINT(glGenRenderbuffers)(20000, dummy_handles.get_ptr());
1594
1595         for (uint i = 0; i < 22000; i++)
1596             GL_ENTRYPOINT(glCreateProgram)();
1597
1598         vogl_debug_printf("%s: Finished creating dummy handles\n", VOGL_METHOD_NAME);
1599     }
1600
1601     VOGL_CHECK_GL_ERROR;
1602
1603     return true;
1604 }
1605
1606 //----------------------------------------------------------------------------------------------------------------------
1607 // vogl_replayer::handle_context_made_current
1608 //----------------------------------------------------------------------------------------------------------------------
1609 bool vogl_gl_replayer::handle_context_made_current()
1610 {
1611     VOGL_FUNC_TRACER
1612
1613     if (!m_pCur_context_state->handle_context_made_current())
1614         return false;
1615
1616     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")))
1617     {
1618         GL_ENTRYPOINT(glDebugMessageCallbackARB)(debug_callback_arb, (GLvoid *)m_pCur_context_state);
1619         GL_ENTRYPOINT(glEnable)(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
1620         check_gl_error();
1621     }
1622
1623     if (m_flags & cGLReplayerVerboseMode)
1624     {
1625         vogl_debug_printf("%s: Trace context: 0x%" PRIX64 ", replay context 0x%" PRIX64 ", GL_VERSION: %s\n",
1626                          VOGL_METHOD_NAME,
1627                          (uint64_t)m_cur_trace_context,
1628                          (uint64_t)m_cur_replay_context,
1629                          m_pCur_context_state->m_context_info.get_version_str().get_ptr());
1630     }
1631
1632     return true;
1633 }
1634
1635 //----------------------------------------------------------------------------------------------------------------------
1636 // vogl_replayer::dump_context_attrib_list
1637 //----------------------------------------------------------------------------------------------------------------------
1638 void vogl_gl_replayer::dump_context_attrib_list(const int *pAttrib_list, uint size)
1639 {
1640     VOGL_FUNC_TRACER
1641
1642     if (!pAttrib_list)
1643     {
1644         vogl_debug_printf("Attrib list is NULL\n");
1645         return;
1646     }
1647     vogl_debug_printf("Context attribs:\n");
1648
1649     uint ofs = 0;
1650     for (;;)
1651     {
1652         if (ofs >= size)
1653         {
1654             vogl_error_printf("%s: Attrib list ended prematurely (must end in a 0 key)\n", VOGL_METHOD_NAME);
1655             break;
1656         }
1657
1658         uint key = pAttrib_list[ofs];
1659         if (!key)
1660             break;
1661         ofs++;
1662
1663         if (ofs >= size)
1664         {
1665             vogl_error_printf("%s: Attrib list ended prematurely (must end in a 0 key)\n", VOGL_METHOD_NAME);
1666             break;
1667         }
1668
1669         uint value = pAttrib_list[ofs];
1670         ofs++;
1671
1672         vogl_debug_printf("Key: %s (0x%08X), Value: 0x%08X\n", g_gl_enums.find_name(key, "GLX"), key, value);
1673     }
1674     vogl_debug_printf("End of context attribs\n");
1675 }
1676
1677 //----------------------------------------------------------------------------------------------------------------------
1678 // vogl_replayer::find_attrib_key
1679 //----------------------------------------------------------------------------------------------------------------------
1680 int vogl_gl_replayer::find_attrib_key(const vogl::vector<int> &attrib_list, int key_to_find)
1681 {
1682     VOGL_FUNC_TRACER
1683
1684     uint ofs = 0;
1685     while (ofs < attrib_list.size())
1686     {
1687         int key = attrib_list[ofs];
1688         if (!key)
1689             break;
1690
1691         if (++ofs >= attrib_list.size())
1692         {
1693             process_entrypoint_warning("%s: Failed parsing attrib list, this call is probably going to fail\n", VOGL_METHOD_NAME);
1694             break;
1695         }
1696
1697         if (key == key_to_find)
1698             return ofs;
1699         ofs++;
1700     }
1701
1702     return -1;
1703 }
1704
1705 //----------------------------------------------------------------------------------------------------------------------
1706 // vogl_replayer::create_context_attribs
1707 //----------------------------------------------------------------------------------------------------------------------
1708 vogl_gl_replayer::status_t vogl_gl_replayer::create_context_attribs(
1709     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,
1710     const int *pTrace_attrib_list, int trace_attrib_list_size, bool expecting_attribs)
1711 {
1712     VOGL_FUNC_TRACER
1713
1714     vogl::vector<int> temp_attrib_list;
1715
1716     if ((pTrace_attrib_list) && (trace_attrib_list_size))
1717     {
1718         temp_attrib_list.append(pTrace_attrib_list, trace_attrib_list_size);
1719         if (temp_attrib_list.back() != 0)
1720         {
1721             process_entrypoint_warning("%s: attrib list does not end with 0\n", VOGL_METHOD_NAME);
1722         }
1723     }
1724     else
1725     {
1726         if (expecting_attribs)
1727         {
1728             if (m_flags & cGLReplayerVerboseMode)
1729                 process_entrypoint_message("%s: No attrib list found in trace, assuming an attrib list ending with 0\n", VOGL_METHOD_NAME);
1730         }
1731
1732         temp_attrib_list.push_back(0);
1733     }
1734
1735     if (m_flags & cGLReplayerForceDebugContexts)
1736     {
1737         // See http://www.opengl.org/registry/specs/ARB/glx_create_context.txt
1738         int context_flags_ofs = find_attrib_key(temp_attrib_list, GLX_CONTEXT_FLAGS_ARB);
1739         if (context_flags_ofs < 0)
1740         {
1741             temp_attrib_list.back() = GLX_CONTEXT_FLAGS_ARB;
1742             temp_attrib_list.push_back(GLX_CONTEXT_DEBUG_BIT_ARB);
1743             temp_attrib_list.push_back(0);
1744
1745             if (m_flags & cGLReplayerVerboseMode)
1746                 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);
1747         }
1748         else
1749         {
1750             temp_attrib_list[context_flags_ofs] |= GLX_CONTEXT_DEBUG_BIT_ARB;
1751
1752             if (m_flags & cGLReplayerVerboseMode)
1753                 process_entrypoint_warning("%s: Slamming on GLX_CONTEXT_DEBUG_BIT_ARB bit to enable debug context\n", VOGL_METHOD_NAME);
1754         }
1755
1756         int context_major_version_ofs = find_attrib_key(temp_attrib_list, GLX_CONTEXT_MAJOR_VERSION_ARB);
1757         int context_minor_version_ofs = find_attrib_key(temp_attrib_list, GLX_CONTEXT_MINOR_VERSION_ARB);
1758
1759         bool slammed_up_to_3_0 = false;
1760         if (context_major_version_ofs < 0)
1761         {
1762 // 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).
1763 #if 0
1764                         temp_attrib_list.back() = GLX_CONTEXT_MAJOR_VERSION_ARB;
1765                         temp_attrib_list.push_back(3);
1766                         temp_attrib_list.push_back(0);
1767
1768                         slammed_up_to_3_0 = true;
1769 #endif
1770         }
1771         else if (temp_attrib_list[context_major_version_ofs] < 3)
1772         {
1773             temp_attrib_list[context_major_version_ofs] = 3;
1774
1775             slammed_up_to_3_0 = true;
1776         }
1777
1778         if (slammed_up_to_3_0)
1779         {
1780             if (context_minor_version_ofs < 0)
1781             {
1782                 temp_attrib_list.back() = GLX_CONTEXT_MINOR_VERSION_ARB;
1783                 temp_attrib_list.push_back(0);
1784                 temp_attrib_list.push_back(0);
1785             }
1786             else
1787             {
1788                 temp_attrib_list[context_minor_version_ofs] = 0;
1789             }
1790
1791             process_entrypoint_warning("%s: Forcing GL context version up to 3.0 due to debug context usage\n", VOGL_METHOD_NAME);
1792         }
1793     }
1794
1795     const int *pAttrib_list = temp_attrib_list.get_ptr();
1796     const uint attrib_list_size = temp_attrib_list.size();
1797
1798     if (m_flags & cGLReplayerVerboseMode)
1799         dump_context_attrib_list(pAttrib_list, attrib_list_size);
1800
1801     GLXContext replay_context = GL_ENTRYPOINT(glXCreateContextAttribsARB)(dpy, config, replay_share_context, direct, pAttrib_list);
1802     if (!replay_context)
1803     {
1804         if (trace_context)
1805         {
1806             process_entrypoint_error("%s: Failed creating new GL context!\n", VOGL_METHOD_NAME);
1807             return cStatusHardFailure;
1808         }
1809         else
1810         {
1811             process_entrypoint_warning("%s: Successfully created a new GL context where the traced app failed!\n", VOGL_METHOD_NAME);
1812         }
1813     }
1814
1815     if (replay_context)
1816     {
1817         if (trace_context)
1818         {
1819             context_state *pContext_state = define_new_context(trace_context, replay_context, trace_share_context, direct, VOGL_ENTRYPOINT_glXCreateContextAttribsARB, pAttrib_list, attrib_list_size);
1820             VOGL_NOTE_UNUSED(pContext_state);
1821         }
1822         else
1823         {
1824             GL_ENTRYPOINT(glXDestroyContext)(m_pWindow->get_display(), replay_context);
1825         }
1826     }
1827
1828     return cStatusOK;
1829 }
1830
1831 //----------------------------------------------------------------------------------------------------------------------
1832 // vogl_replayer::process_pending_make_current
1833 //----------------------------------------------------------------------------------------------------------------------
1834 vogl_gl_replayer::status_t vogl_gl_replayer::process_pending_make_current()
1835 {
1836     VOGL_FUNC_TRACER
1837
1838     if (!m_pending_make_current_packet.is_valid())
1839         return cStatusOK;
1840
1841     vogl_trace_packet &gl_packet = m_pending_make_current_packet;
1842
1843     Bool trace_result = gl_packet.get_return_value<Bool>();
1844
1845     gl_entrypoint_id_t entrypoint_id = gl_packet.get_entrypoint_id();
1846     VOGL_ASSERT((entrypoint_id == VOGL_ENTRYPOINT_glXMakeCurrent) || (entrypoint_id == VOGL_ENTRYPOINT_glXMakeContextCurrent));
1847
1848     // pContext_state will be NULL if they are unmapping!
1849     vogl_trace_ptr_value trace_context = gl_packet.get_param_ptr_value((entrypoint_id == VOGL_ENTRYPOINT_glXMakeCurrent) ? 2 : 3);
1850     context_state *pContext_state = get_trace_context_state(trace_context);
1851     GLXContext replay_context = pContext_state ? pContext_state->m_replay_context : 0;
1852
1853     if ((trace_context) && (!replay_context))
1854     {
1855         process_entrypoint_error("%s, Failed remapping GL context\n", VOGL_METHOD_NAME);
1856         m_pending_make_current_packet.clear();
1857         return cStatusHardFailure;
1858     }
1859
1860     const Display *dpy = m_pWindow->get_display();
1861     GLXDrawable drawable = replay_context ? m_pWindow->get_xwindow() : (GLXDrawable)NULL;
1862
1863     Bool result = GL_ENTRYPOINT(glXMakeCurrent)(dpy, drawable, replay_context);
1864     if (!result)
1865     {
1866         if (trace_result)
1867         {
1868             process_entrypoint_error("%s: Failed making context current, but in the trace this call succeeded!\n", VOGL_METHOD_NAME);
1869             m_pending_make_current_packet.clear();
1870             return cStatusHardFailure;
1871         }
1872         else
1873         {
1874             process_entrypoint_warning("%s: Failed making context current, in the trace this call also failed\n", VOGL_METHOD_NAME);
1875         }
1876     }
1877     else
1878     {
1879         m_cur_trace_context = trace_context;
1880         m_cur_replay_context = replay_context;
1881         m_pCur_context_state = pContext_state;
1882
1883         if (!trace_result)
1884         {
1885             process_entrypoint_warning("%s: Context was successfuly made current, but this operation failed in the trace\n", VOGL_METHOD_NAME);
1886         }
1887
1888         if (m_cur_replay_context)
1889         {
1890             int viewport_x = gl_packet.get_key_value_map().get_int(string_hash("viewport_x"));
1891             int viewport_y = gl_packet.get_key_value_map().get_int(string_hash("viewport_y"));
1892             int viewport_width = gl_packet.get_key_value_map().get_int(string_hash("viewport_width"));
1893             int viewport_height = gl_packet.get_key_value_map().get_int(string_hash("viewport_height"));
1894             int win_width = gl_packet.get_key_value_map().get_int(string_hash("win_width"));
1895             int win_height = gl_packet.get_key_value_map().get_int(string_hash("win_height"));
1896
1897             if (!m_pCur_context_state->m_has_been_made_current)
1898             {
1899                 vogl_printf("glXMakeCurrent(): Trace Viewport: [%u,%u,%u,%u], Window: [%u %u]\n",
1900                            viewport_x, viewport_y,
1901                            viewport_width, viewport_height,
1902                            win_width, win_height);
1903             }
1904
1905             GLint cur_viewport[4];
1906             GL_ENTRYPOINT(glGetIntegerv)(GL_VIEWPORT, cur_viewport);
1907
1908             uint cur_win_width = 0, cur_win_height = 0;
1909             m_pWindow->get_actual_dimensions(cur_win_width, cur_win_height);
1910
1911             if (!m_pCur_context_state->m_has_been_made_current)
1912             {
1913                 vogl_printf("glXMakeCurrent(): Replay Viewport: [%u,%u,%u,%u], Window: [%u %u]\n",
1914                            cur_viewport[0], cur_viewport[1],
1915                            cur_viewport[2], cur_viewport[3],
1916                            cur_win_width, cur_win_height);
1917             }
1918
1919             if ((cur_viewport[0] != viewport_x) || (cur_viewport[1] != viewport_y) || (cur_viewport[2] != viewport_width) || (cur_viewport[3] != viewport_height))
1920             {
1921                 process_entrypoint_warning("%s: Replay viewport differs from traces!\n", VOGL_METHOD_NAME);
1922             }
1923
1924             if (!handle_context_made_current())
1925                 return cStatusHardFailure;
1926         }
1927     }
1928
1929     m_last_processed_call_counter = gl_packet.get_call_counter();
1930
1931     m_pending_make_current_packet.clear();
1932
1933     return cStatusOK;
1934 }
1935
1936 //----------------------------------------------------------------------------------------------------------------------
1937 // vogl_process_internal_trace_command_ctypes_packet
1938 //----------------------------------------------------------------------------------------------------------------------
1939 bool vogl_process_internal_trace_command_ctypes_packet(const key_value_map &kvm, const vogl_ctypes &ctypes)
1940 {
1941     VOGL_FUNC_TRACER
1942
1943     // TODO: Implement the code to map trace ctypes to replay ctypes. That's going to be fun.
1944     int num_trace_ctypes = kvm.get_int("num_ctypes");
1945     VOGL_VERIFY(num_trace_ctypes == VOGL_NUM_CTYPES);
1946
1947     // TODO: This just verifies that the replayer's idea of each ctype matches the tracer's.
1948     // This will need to be revisited once we port to other OS's.
1949     // TODO: Move the ctypes crap into the SOF packet or something, it's not easy to deal with this packet on the fly.
1950     for (int ctype_iter = 0; ctype_iter < num_trace_ctypes; ctype_iter++)
1951     {
1952         const vogl_ctype_desc_t &desc = ctypes[static_cast<vogl_ctype_t>(ctype_iter)];
1953
1954         uint base_index = ctype_iter << 8;
1955         dynamic_string name(kvm.get_string(base_index++));
1956         dynamic_string ctype(kvm.get_string(base_index++));
1957         int size = kvm.get_int(base_index++);
1958         uint loki_type_flags = kvm.get_uint(base_index++);
1959         bool is_pointer = kvm.get_bool(base_index++);
1960         bool is_opaque_pointer = kvm.get_bool(base_index++);
1961         bool is_pointer_diff = kvm.get_bool(base_index++);
1962         bool is_opaque_type = kvm.get_bool(base_index++);
1963
1964         VOGL_VERIFY(name.compare(desc.m_pName, true) == 0);
1965         VOGL_VERIFY(ctype.compare(desc.m_pCType, true) == 0);
1966         if (!desc.m_is_opaque_type)
1967         {
1968             VOGL_VERIFY(size == desc.m_size);
1969         }
1970
1971         const uint loki_type_check_mask = ~(LOKI_TYPE_BITMASK(LOKI_IS_SIGNED_LONG) | LOKI_TYPE_BITMASK(LOKI_IS_UNSIGNED_LONG));
1972         VOGL_VERIFY((loki_type_flags & loki_type_check_mask) == (desc.m_loki_type_flags & loki_type_check_mask));
1973
1974         VOGL_VERIFY(is_pointer == desc.m_is_pointer);
1975         VOGL_VERIFY(is_opaque_pointer == desc.m_is_opaque_pointer);
1976         VOGL_VERIFY(is_pointer_diff == desc.m_is_pointer_diff);
1977         VOGL_VERIFY(is_opaque_type == desc.m_is_opaque_type);
1978     }
1979
1980     return true;
1981 }
1982
1983 //----------------------------------------------------------------------------------------------------------------------
1984 // vogl_replayer::process_internal_trace_command
1985 //----------------------------------------------------------------------------------------------------------------------
1986 vogl_gl_replayer::status_t vogl_gl_replayer::process_internal_trace_command(const vogl_trace_gl_entrypoint_packet &gl_packet)
1987 {
1988     VOGL_FUNC_TRACER
1989
1990     VOGL_NOTE_UNUSED(gl_packet);
1991
1992     GLuint cmd = m_pCur_gl_packet->get_param_value<GLuint>(0);
1993     GLuint size = m_pCur_gl_packet->get_param_value<GLuint>(1);
1994     VOGL_NOTE_UNUSED(size);
1995     vogl_trace_ptr_value trace_data_ptr_value = m_pCur_gl_packet->get_param_ptr_value(2);
1996     VOGL_NOTE_UNUSED(trace_data_ptr_value);
1997
1998     vogl_gl_replayer::status_t status = cStatusOK;
1999
2000     switch (cmd)
2001     {
2002         case cITCRDemarcation:
2003         {
2004             break;
2005         }
2006         case cITCRKeyValueMap:
2007         {
2008             const key_value_map &kvm = m_pCur_gl_packet->get_key_value_map();
2009
2010             dynamic_string cmd_type(kvm.get_string("command_type"));
2011             if (cmd_type == "state_snapshot")
2012             {
2013                 dynamic_string text_id(kvm.get_string("id"));
2014                 dynamic_string binary_id(kvm.get_string("binary_id"));
2015                 if (text_id.is_empty() && binary_id.is_empty())
2016                 {
2017                     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());
2018                     return cStatusHardFailure;
2019                 }
2020
2021                 dynamic_string id_to_use(text_id.is_empty() ? binary_id : text_id);
2022
2023                 // TODO: Make a 1st class snapshot cache class
2024                 // TODO: This could fail if the user hand modifies the snapshot in some way - add an option to disable caching.
2025                 vogl_gl_state_snapshot *pSnapshot = NULL;
2026                 if (m_flags & cGLReplayerSnapshotCaching)
2027                 {
2028                     for (uint snapshot_index = 0; snapshot_index < m_snapshots.size(); snapshot_index++)
2029                     {
2030                         if (!m_snapshots[snapshot_index].m_name.compare(id_to_use, false))
2031                         {
2032                             pSnapshot = m_snapshots[snapshot_index].m_pSnapshot;
2033                             if (snapshot_index)
2034                             {
2035                                 snapshot_cache_entry cache_entry(m_snapshots[snapshot_index]);
2036                                 m_snapshots.erase(snapshot_index);
2037                                 m_snapshots.insert(0, cache_entry);
2038                             }
2039                             break;
2040                         }
2041                     }
2042                 }
2043
2044                 if (!pSnapshot)
2045                 {
2046                     timed_scope ts("Deserialize snapshot time");
2047
2048                     if (!m_pBlob_manager)
2049                     {
2050                         process_entrypoint_error("%s: Failed reading snapshot blob data \"%s\"!\n", VOGL_METHOD_NAME, id_to_use.get_ptr());
2051                         return cStatusHardFailure;
2052                     }
2053
2054                     uint8_vec snapshot_data;
2055
2056                     if (!m_pBlob_manager->get(id_to_use, snapshot_data) || (snapshot_data.is_empty()))
2057                     {
2058                         process_entrypoint_error("%s: Failed reading snapshot blob data \"%s\"!\n", VOGL_METHOD_NAME, id_to_use.get_ptr());
2059                         return cStatusHardFailure;
2060                     }
2061
2062                     vogl_message_printf("%s: Deserializing state snapshot \"%s\", %u bytes\n", VOGL_METHOD_NAME, id_to_use.get_ptr(), snapshot_data.size());
2063
2064                     json_document doc;
2065
2066                     bool success;
2067                     if (id_to_use == text_id)
2068                         success = doc.deserialize(reinterpret_cast<const char *>(snapshot_data.get_ptr()), snapshot_data.size());
2069                     else
2070                         success = doc.binary_deserialize(snapshot_data);
2071                     if (!success || (!doc.get_root()))
2072                     {
2073                         process_entrypoint_error("%s: Failed deserializing JSON snapshot blob data \"%s\"!\n", VOGL_METHOD_NAME, id_to_use.get_ptr());
2074                         return cStatusHardFailure;
2075                     }
2076
2077                     pSnapshot = vogl_new(vogl_gl_state_snapshot);
2078                     if (!pSnapshot->deserialize(*doc.get_root(), *m_pBlob_manager, &m_trace_gl_ctypes))
2079                     {
2080                         vogl_delete(pSnapshot);
2081                         pSnapshot = NULL;
2082
2083                         process_entrypoint_error("%s: Failed deserializing snapshot blob data \"%s\"!\n", VOGL_METHOD_NAME, id_to_use.get_ptr());
2084                         return cStatusHardFailure;
2085                     }
2086
2087                     if (m_flags & cGLReplayerSnapshotCaching)
2088                     {
2089                         snapshot_cache_entry new_cache_entry;
2090                         new_cache_entry.m_name = id_to_use;
2091                         new_cache_entry.m_pSnapshot = pSnapshot;
2092                         m_snapshots.insert(0, new_cache_entry);
2093
2094                         // FIXME: Even 3-4 snapshots in memory may be too much in 32-bit mode for some large apps.
2095                         while (m_snapshots.size() > 3)
2096                         {
2097                             vogl_delete(m_snapshots.back().m_pSnapshot);
2098                             m_snapshots.resize(m_snapshots.size() - 1);
2099                         }
2100                     }
2101                 }
2102
2103                 status = begin_applying_snapshot(pSnapshot, (m_flags & cGLReplayerSnapshotCaching) ? false : true);
2104
2105                 if ((status != cStatusOK) && (status != cStatusResizeWindow))
2106                 {
2107                     if (m_flags & cGLReplayerSnapshotCaching)
2108                     {
2109                         VOGL_ASSERT(m_snapshots[0].m_pSnapshot == pSnapshot);
2110
2111                         vogl_delete(m_snapshots[0].m_pSnapshot);
2112                         m_snapshots.erase(0U);
2113                     }
2114
2115                     if (m_flags & cGLReplayerSnapshotCaching)
2116                     {
2117                         vogl_delete(pSnapshot);
2118                         pSnapshot = NULL;
2119                     }
2120
2121                     process_entrypoint_error("%s: Failed applying GL snapshot from blob data \"%s\"!\n", VOGL_METHOD_NAME, id_to_use.get_ptr());
2122                     return status;
2123                 }
2124
2125                 vogl_message_printf("%s: Successfully applied GL state snapshot from blob \"%s\"\n", VOGL_METHOD_NAME, id_to_use.get_ptr());
2126             }
2127             else if (cmd_type == "ctypes")
2128             {
2129                 m_ctypes_packet = *m_pCur_gl_packet;
2130
2131                 if (!vogl_process_internal_trace_command_ctypes_packet(kvm, m_trace_gl_ctypes))
2132                     return cStatusHardFailure;
2133             }
2134             else if (cmd_type == "entrypoints")
2135             {
2136                 // TODO
2137             }
2138             else
2139             {
2140                 process_entrypoint_warning("%s: Unknown glInternalTraceCommandRAD key_value_map command type: \"%s\"\n", VOGL_METHOD_NAME, cmd_type.get_ptr());
2141             }
2142             break;
2143         }
2144         default:
2145         {
2146             process_entrypoint_warning("%s: Unknown glInternalTraceCommandRAD command type: %u\n", VOGL_METHOD_NAME, cmd);
2147             break;
2148         }
2149     }
2150
2151     return status;
2152 }
2153
2154 //----------------------------------------------------------------------------------------------------------------------
2155 // vogl_replayer::check_program_binding_shadow
2156 //----------------------------------------------------------------------------------------------------------------------
2157 bool vogl_gl_replayer::check_program_binding_shadow()
2158 {
2159     VOGL_FUNC_TRACER
2160
2161     if (!m_pCur_context_state)
2162         return true;
2163
2164     // Make sure shadow is good
2165     GLint actual_current_replay_program = 0;
2166     GL_ENTRYPOINT(glGetIntegerv)(GL_CURRENT_PROGRAM, &actual_current_replay_program);
2167     check_gl_error();
2168
2169     if (m_pCur_context_state->m_cur_replay_program == static_cast<GLuint>(actual_current_replay_program))
2170         return true;
2171
2172     // OK, on AMD it plays games with GL_CURRENT_PROGRAM when the currently bound program is deleted. Check for this scenario.
2173     bool is_still_program = GL_ENTRYPOINT(glIsProgram)(m_pCur_context_state->m_cur_replay_program) != 0;
2174     if ((!check_gl_error()) && (is_still_program))
2175     {
2176         GLint marked_for_deletion = GL_FALSE;
2177         GL_ENTRYPOINT(glGetProgramiv)(m_pCur_context_state->m_cur_replay_program, GL_DELETE_STATUS, &marked_for_deletion);
2178
2179         if ((!check_gl_error()) && (marked_for_deletion))
2180             return true;
2181     }
2182
2183     VOGL_VERIFY(0);
2184     return false;
2185 }
2186
2187 //----------------------------------------------------------------------------------------------------------------------
2188 // vogl_replayer::handle_use_program
2189 //----------------------------------------------------------------------------------------------------------------------
2190 void vogl_gl_replayer::handle_use_program(GLuint trace_handle, gl_entrypoint_id_t entrypoint_id)
2191 {
2192     VOGL_FUNC_TRACER
2193
2194     // 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.
2195     check_program_binding_shadow();
2196
2197     GLuint replay_handle = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle);
2198     VOGL_ASSERT(!trace_handle || get_shared_state()->m_shadow_state.m_objs.get_target(trace_handle) == VOGL_PROGRAM_OBJECT);
2199     VOGL_ASSERT(!trace_handle || get_shared_state()->m_shadow_state.m_objs.get_target_inv(replay_handle) == VOGL_PROGRAM_OBJECT);
2200
2201     // For safety, absorb any previous error.
2202     check_gl_error();
2203
2204     GLuint prev_replay_program = m_pCur_context_state->m_cur_replay_program;
2205     GLuint prev_trace_program = m_pCur_context_state->m_cur_trace_program;
2206
2207     bool prev_is_program = false;
2208     GLint prev_link_status = false;
2209     GLint prev_is_marked_for_deletion = false;
2210     vogl::growable_array<GLuint, 8> prev_attached_replay_shaders;
2211
2212     if ((prev_replay_program) && (replay_handle != prev_replay_program))
2213     {
2214         prev_is_program = GL_ENTRYPOINT(glIsProgram)(prev_replay_program);
2215         check_gl_error_quietly();
2216
2217         if (prev_is_program)
2218         {
2219             GL_ENTRYPOINT(glGetProgramiv)(prev_replay_program, GL_DELETE_STATUS, &prev_is_marked_for_deletion);
2220             check_gl_error_quietly();
2221
2222             GL_ENTRYPOINT(glGetProgramiv)(prev_replay_program, GL_LINK_STATUS, &prev_link_status);
2223             check_gl_error_quietly();
2224
2225             if (prev_is_marked_for_deletion)
2226             {
2227                 // 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.
2228                 GLint num_attached_shaders = 0;
2229                 GL_ENTRYPOINT(glGetProgramiv)(prev_replay_program, GL_ATTACHED_SHADERS, &num_attached_shaders);
2230                 check_gl_error_quietly();
2231
2232                 if (num_attached_shaders)
2233                 {
2234                     prev_attached_replay_shaders.resize(num_attached_shaders);
2235
2236                     GLsizei actual_count = 0;
2237                     GL_ENTRYPOINT(glGetAttachedShaders)(prev_replay_program, num_attached_shaders, &actual_count, prev_attached_replay_shaders.get_ptr());
2238                     check_gl_error_quietly();
2239
2240                     VOGL_ASSERT(actual_count == num_attached_shaders);
2241                 }
2242             }
2243         }
2244     }
2245
2246     if (entrypoint_id == VOGL_ENTRYPOINT_glUseProgram)
2247         GL_ENTRYPOINT(glUseProgram)(replay_handle);
2248     else
2249         GL_ENTRYPOINT(glUseProgramObjectARB)(replay_handle);
2250
2251     // Can't shadow if glUseProgram failed.
2252     if (check_gl_error())
2253         return;
2254
2255     if ((prev_replay_program) && (prev_replay_program != replay_handle))
2256     {
2257         bool is_prev_still_program = GL_ENTRYPOINT(glIsProgram)(prev_replay_program);
2258         if (!is_prev_still_program)
2259         {
2260             VOGL_ASSERT(prev_is_program);
2261             VOGL_ASSERT(prev_is_marked_for_deletion);
2262
2263             // The previously bound program is really dead now, kill it from our tables and also check up on any shaders it was attached to.
2264             bool was_deleted = get_shared_state()->m_shadow_state.m_objs.erase(prev_trace_program);
2265             VOGL_ASSERT(was_deleted);
2266             VOGL_NOTE_UNUSED(was_deleted);
2267
2268             was_deleted = get_shared_state()->m_glsl_program_hash_map.erase(prev_trace_program);
2269             VOGL_ASSERT(was_deleted);
2270
2271             was_deleted = get_shared_state()->m_shadow_state.m_linked_programs.remove_snapshot(prev_replay_program);
2272             if ((prev_link_status) && (!was_deleted))
2273             {
2274                 VOGL_ASSERT_ALWAYS;
2275             }
2276
2277             for (uint i = 0; i < prev_attached_replay_shaders.size(); i++)
2278             {
2279                 GLuint replay_shader_handle = prev_attached_replay_shaders[i];
2280
2281                 bool is_still_shader = GL_ENTRYPOINT(glIsShader)(replay_shader_handle);
2282                 check_gl_error_quietly();
2283
2284                 if (is_still_shader)
2285                     continue;
2286
2287                 if (!get_shared_state()->m_shadow_state.m_objs.contains_inv(replay_shader_handle))
2288                 {
2289                     // We didn't create this shader handle, the AMD driver did on a program binary link, so ignore it.
2290                     continue;
2291                 }
2292
2293                 // The attached shader is now really dead.
2294                 VOGL_ASSERT(get_shared_state()->m_shadow_state.m_objs.get_target_inv(replay_shader_handle) == VOGL_SHADER_OBJECT);
2295                 if (!get_shared_state()->m_shadow_state.m_objs.erase_inv(replay_shader_handle))
2296                 {
2297                     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);
2298                 }
2299             }
2300         }
2301     }
2302
2303     m_pCur_context_state->m_cur_replay_program = replay_handle;
2304     m_pCur_context_state->m_cur_trace_program = trace_handle;
2305 }
2306
2307 //----------------------------------------------------------------------------------------------------------------------
2308 // vogl_replayer::handle_delete_program
2309 //----------------------------------------------------------------------------------------------------------------------
2310 void vogl_gl_replayer::handle_delete_program(GLuint trace_handle)
2311 {
2312     VOGL_FUNC_TRACER
2313
2314     check_program_binding_shadow();
2315
2316     // Note: This mixes ARB and non-ARB funcs. to probe around, which is evil.
2317
2318     GLuint replay_handle = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle);
2319     VOGL_ASSERT(get_shared_state()->m_shadow_state.m_objs.get_target(trace_handle) == VOGL_PROGRAM_OBJECT);
2320     VOGL_ASSERT(get_shared_state()->m_shadow_state.m_objs.get_target_inv(replay_handle) == VOGL_PROGRAM_OBJECT);
2321
2322     context_state *pContext_shareroot = m_pCur_context_state->m_pShared_state;
2323     for (context_hash_map::iterator it = m_contexts.begin(); it != m_contexts.end(); ++it)
2324     {
2325         if (it->first == m_pCur_context_state->m_context_desc.get_trace_context())
2326             continue;
2327
2328         context_state *pContext = it->second;
2329         if (pContext->m_pShared_state == pContext_shareroot)
2330         {
2331             if (pContext->m_cur_trace_program == trace_handle)
2332             {
2333                 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",
2334                                          VOGL_METHOD_NAME, trace_handle, replay_handle,
2335                                          cast_val_to_uint64(m_pCur_context_state->m_context_desc.get_trace_context()),
2336                                          cast_val_to_uint64(it->first));
2337             }
2338         }
2339     }
2340
2341     bool is_program = GL_ENTRYPOINT(glIsProgram)(replay_handle) != 0;
2342     check_gl_error_quietly();
2343
2344     vogl::growable_array<GLuint, 8> attached_replay_shaders;
2345
2346     if ((is_program) && (replay_handle))
2347     {
2348         GLint num_attached_shaders = 0;
2349         GL_ENTRYPOINT(glGetProgramiv)(replay_handle, GL_ATTACHED_SHADERS, &num_attached_shaders);
2350         check_gl_error_quietly();
2351
2352         if (num_attached_shaders)
2353         {
2354             attached_replay_shaders.resize(num_attached_shaders);
2355
2356             GLsizei actual_count = 0;
2357             GL_ENTRYPOINT(glGetAttachedShaders)(replay_handle, num_attached_shaders, &actual_count, attached_replay_shaders.get_ptr());
2358             check_gl_error_quietly();
2359
2360             VOGL_ASSERT(actual_count == num_attached_shaders);
2361         }
2362     }
2363
2364     GL_ENTRYPOINT(glDeleteProgram)(replay_handle);
2365
2366     bool deletion_succeeded = !check_gl_error();
2367     if (!deletion_succeeded)
2368     {
2369         VOGL_ASSERT(!is_program);
2370
2371         process_entrypoint_warning("%s: Failed deleting program, trace handle %u GL handle %u\n", VOGL_METHOD_NAME, trace_handle, replay_handle);
2372         return;
2373     }
2374
2375     if (!replay_handle)
2376         return;
2377
2378     bool is_still_program = GL_ENTRYPOINT(glIsProgram)(replay_handle) != 0;
2379     check_gl_error_quietly();
2380
2381     GLint marked_for_deletion = 0;
2382     if (is_still_program)
2383     {
2384         // It must still be bound to the context, or referred to in some other way that we don't know about.
2385         GL_ENTRYPOINT(glGetProgramiv)(replay_handle, GL_DELETE_STATUS, &marked_for_deletion);
2386         bool delete_status_check_succeeded = !check_gl_error_quietly();
2387
2388         VOGL_VERIFY(delete_status_check_succeeded);
2389         VOGL_VERIFY(marked_for_deletion);
2390     }
2391     else if (!is_still_program)
2392     {
2393         VOGL_ASSERT(is_program);
2394
2395         // The program is really gone now.
2396         bool was_deleted = get_shared_state()->m_shadow_state.m_objs.erase(trace_handle);
2397         VOGL_ASSERT(was_deleted);
2398         VOGL_NOTE_UNUSED(was_deleted);
2399
2400         was_deleted = get_shared_state()->m_glsl_program_hash_map.erase(trace_handle);
2401         VOGL_ASSERT(was_deleted);
2402
2403         get_shared_state()->m_shadow_state.m_linked_programs.remove_snapshot(replay_handle);
2404
2405         if (m_pCur_context_state->m_cur_replay_program == replay_handle)
2406         {
2407             // This shouldn't happen - if the program is still bound to the context then it should still be a program.
2408             VOGL_ASSERT_ALWAYS;
2409             m_pCur_context_state->m_cur_replay_program = 0;
2410             m_pCur_context_state->m_cur_trace_program = 0;
2411         }
2412
2413         for (uint i = 0; i < attached_replay_shaders.size(); i++)
2414         {
2415             GLuint replay_shader_handle = attached_replay_shaders[i];
2416
2417             bool is_still_shader = GL_ENTRYPOINT(glIsShader)(replay_shader_handle) != 0;
2418             check_gl_error_quietly();
2419
2420             if (is_still_shader)
2421                 continue;
2422
2423             if (!get_shared_state()->m_shadow_state.m_objs.contains_inv(replay_shader_handle))
2424             {
2425                 // We didn't create this shader handle, the AMD driver did on a program binary link, so ignore it.
2426                 continue;
2427             }
2428
2429             // The attached shader is now really dead.
2430             VOGL_ASSERT(get_shared_state()->m_shadow_state.m_objs.get_target_inv(replay_shader_handle) == VOGL_SHADER_OBJECT);
2431             if (!get_shared_state()->m_shadow_state.m_objs.erase_inv(replay_shader_handle))
2432             {
2433                 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);
2434             }
2435         }
2436     }
2437 }
2438
2439 //----------------------------------------------------------------------------------------------------------------------
2440 // vogl_replayer::handle_delete_shader
2441 //----------------------------------------------------------------------------------------------------------------------
2442 void vogl_gl_replayer::handle_delete_shader(GLuint trace_handle)
2443 {
2444     VOGL_FUNC_TRACER
2445
2446     check_program_binding_shadow();
2447
2448     check_gl_error();
2449
2450     // Note: This mixes ARB and non-ARB funcs. to probe around, which is evil.
2451
2452     GLuint replay_handle = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle);
2453     VOGL_ASSERT(get_shared_state()->m_shadow_state.m_objs.get_target(trace_handle) == VOGL_SHADER_OBJECT);
2454     VOGL_ASSERT(get_shared_state()->m_shadow_state.m_objs.get_target_inv(replay_handle) == VOGL_SHADER_OBJECT);
2455
2456     GL_ENTRYPOINT(glDeleteShader)(replay_handle);
2457
2458     bool deletion_succeeded = !check_gl_error();
2459     if (!deletion_succeeded)
2460     {
2461         process_entrypoint_warning("%s: Failed deleting shader, trace handle %u GL handle %u\n", VOGL_METHOD_NAME, trace_handle, replay_handle);
2462         return;
2463     }
2464
2465     if (!replay_handle)
2466         return;
2467
2468     bool is_still_shader = GL_ENTRYPOINT(glIsShader)(replay_handle);
2469     check_gl_error_quietly();
2470
2471     if (!is_still_shader)
2472     {
2473         // The shader is really gone.
2474         bool was_deleted = get_shared_state()->m_shadow_state.m_objs.erase(trace_handle);
2475         VOGL_ASSERT(was_deleted);
2476         VOGL_NOTE_UNUSED(was_deleted);
2477     }
2478     else
2479     {
2480         GLint marked_for_deletion = 0;
2481         GL_ENTRYPOINT(glGetShaderiv)(replay_handle, GL_DELETE_STATUS, &marked_for_deletion);
2482         check_gl_error_quietly();
2483
2484         VOGL_VERIFY(marked_for_deletion);
2485
2486         // The shader is attached to a live program object (which may or may not be actually in the marked_as_deleted state)
2487         // we'll get around to it when the program object is deleted, or when they remove the program object from the current state.
2488     }
2489 }
2490
2491 //----------------------------------------------------------------------------------------------------------------------
2492 // vogl_replayer::handle_detach_shader
2493 //----------------------------------------------------------------------------------------------------------------------
2494 void vogl_gl_replayer::handle_detach_shader(gl_entrypoint_id_t entrypoint_id)
2495 {
2496     GLuint trace_program = m_pCur_gl_packet->get_param_value<GLuint>(0);
2497     GLuint replay_program = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_program);
2498
2499     GLuint trace_shader = m_pCur_gl_packet->get_param_value<GLuint>(1);
2500     GLuint replay_shader = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_shader);
2501
2502     check_gl_error();
2503
2504     // Note: This mixes ARB and non-ARB funcs. to probe around, which is evil.
2505
2506     GLboolean was_shader = GL_ENTRYPOINT(glIsShader)(replay_shader);
2507     check_gl_error_quietly();
2508
2509     GLint marked_for_deletion = 0;
2510     GL_ENTRYPOINT(glGetShaderiv)(replay_shader, GL_DELETE_STATUS, &marked_for_deletion);
2511     check_gl_error_quietly();
2512
2513     if (entrypoint_id == VOGL_ENTRYPOINT_glDetachObjectARB)
2514         GL_ENTRYPOINT(glDetachObjectARB)(replay_program, replay_shader);
2515     else
2516     {
2517         VOGL_ASSERT(entrypoint_id == VOGL_ENTRYPOINT_glDetachShader);
2518         GL_ENTRYPOINT(glDetachShader)(replay_program, replay_shader);
2519     }
2520
2521     bool detach_failed = check_gl_error();
2522
2523     GLboolean is_shader = GL_ENTRYPOINT(glIsShader)(replay_shader);
2524     check_gl_error_quietly();
2525
2526     if (!detach_failed)
2527     {
2528         if ((marked_for_deletion) && (was_shader) && (!is_shader))
2529         {
2530             // The shader is really gone now.
2531             bool was_deleted = get_shared_state()->m_shadow_state.m_objs.erase(trace_shader);
2532             VOGL_ASSERT(was_deleted);
2533             VOGL_NOTE_UNUSED(was_deleted);
2534         }
2535     }
2536 }
2537
2538 //----------------------------------------------------------------------------------------------------------------------
2539 // vogl_gl_replayer::handle_link_program
2540 //----------------------------------------------------------------------------------------------------------------------
2541 void vogl_gl_replayer::handle_link_program(gl_entrypoint_id_t entrypoint_id)
2542 {
2543     check_gl_error();
2544
2545     GLuint trace_handle = m_pCur_gl_packet->get_param_value<GLuint>(0);
2546     GLuint replay_handle = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle);
2547
2548     GLboolean is_program = GL_ENTRYPOINT(glIsProgram)(replay_handle);
2549     check_gl_error();
2550     if (!is_program)
2551     {
2552         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);
2553     }
2554
2555     const json_document *pDoc = m_pCur_gl_packet->get_key_value_map().get_json_document("metadata");
2556
2557     if (!pDoc)
2558     {
2559         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);
2560     }
2561     else if ((pDoc) && (!pDoc->is_object()))
2562     {
2563         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);
2564         pDoc = NULL;
2565     }
2566
2567     int trace_active_attributes = 0;
2568     int trace_active_uniforms = 0;
2569     int trace_active_uniform_blocks = 0;
2570     int trace_link_status = 1;
2571
2572     VOGL_NOTE_UNUSED(trace_active_uniforms);
2573     VOGL_NOTE_UNUSED(trace_active_uniform_blocks);
2574
2575     if (pDoc)
2576     {
2577         const json_node &doc_root = *pDoc->get_root();
2578
2579         trace_link_status = doc_root.value_as_int("link_status");
2580         trace_active_attributes = doc_root.value_as_int("total_active_attributes");
2581         trace_active_uniforms = doc_root.value_as_int("total_active_uniforms");
2582         trace_active_uniform_blocks = doc_root.value_as_int("active_uniform_blocks");
2583
2584         const json_node *pAttrib_node = doc_root.find_child_array("active_attribs");
2585         if (pAttrib_node)
2586         {
2587             for (uint i = 0; i < pAttrib_node->size(); i++)
2588             {
2589                 const json_node *pAttrib = pAttrib_node->get_child(i);
2590                 if (!pAttrib)
2591                 {
2592                     VOGL_ASSERT_ALWAYS;
2593                     continue;
2594                 }
2595
2596                 const char *pName = pAttrib->value_as_string_ptr("name");
2597                 int attrib_loc = pAttrib->value_as_int("location", -1);
2598
2599                 if ((pName) && (pName[0]) && (attrib_loc >= 0))
2600                 {
2601                     if (entrypoint_id == VOGL_ENTRYPOINT_glLinkProgramARB)
2602                         GL_ENTRYPOINT(glBindAttribLocationARB)(replay_handle, attrib_loc, pName);
2603                     else
2604                         GL_ENTRYPOINT(glBindAttribLocation)(replay_handle, attrib_loc, reinterpret_cast<const GLchar *>(pName));
2605
2606                     check_gl_error();
2607                 }
2608             }
2609         }
2610
2611         const json_node *pOutputs_object = doc_root.find_child_array("active_outputs");
2612         if (pOutputs_object)
2613         {
2614             for (uint i = 0; i < pOutputs_object->size(); i++)
2615             {
2616                 const json_node *pOutput_node = pOutputs_object->get_child(i);
2617                 if (!pOutput_node)
2618                     continue;
2619
2620                 dynamic_string name(pOutput_node->value_as_string("name"));
2621                 if ((name.is_empty()) || (name.begins_with("gl_", true)))
2622                     continue;
2623
2624                 int location = pOutput_node->value_as_int("location");
2625                 int location_index = pOutput_node->value_as_int("location_index");
2626
2627                 if (m_pCur_context_state->m_context_info.supports_extension("GL_ARB_blend_func_extended") && GL_ENTRYPOINT(glBindFragDataLocationIndexed))
2628                 {
2629                     GL_ENTRYPOINT(glBindFragDataLocationIndexed)(replay_handle, location, location_index, reinterpret_cast<const GLchar *>(name.get_ptr()));
2630                 }
2631                 else
2632                 {
2633                     if (location_index)
2634                         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);
2635
2636                     GL_ENTRYPOINT(glBindFragDataLocation)(replay_handle, location, reinterpret_cast<const GLchar *>(name.get_ptr()));
2637                 }
2638
2639                 check_gl_error();
2640             }
2641         }
2642
2643         GLenum transform_feedback_mode = vogl_get_json_value_as_enum(doc_root, "transform_feedback_mode");
2644         GLint num_varyings = doc_root.value_as_int("transform_feedback_num_varyings");
2645         if (num_varyings)
2646         {
2647             const json_node *pTransform_feedback_varyings = doc_root.find_child_array("transform_feedback_varyings");
2648             if (pTransform_feedback_varyings)
2649             {
2650                 dynamic_string_array names;
2651
2652                 for (uint i = 0; i < pTransform_feedback_varyings->size(); i++)
2653                 {
2654                     const json_node *pVarying_node = pTransform_feedback_varyings->get_child(i);
2655                     if (!pVarying_node)
2656                         continue;
2657
2658                     GLint index = pVarying_node->value_as_int("index");
2659                     if (index < 0)
2660                         continue;
2661
2662                     dynamic_string name(pVarying_node->value_as_string("name"));
2663
2664                     //GLsizei size(pVarying_node->value_as_int("size"));
2665                     //GLenum type(vogl_get_json_value_as_enum(*pVarying_node, "type"));
2666
2667                     names.ensure_element_is_valid(index);
2668                     names[index] = name;
2669                 }
2670
2671                 vogl::vector<GLchar *> varyings(names.size());
2672                 for (uint i = 0; i < names.size(); i++)
2673                     varyings[i] = (GLchar *)(names[i].get_ptr());
2674
2675                 GL_ENTRYPOINT(glTransformFeedbackVaryings)(replay_handle, varyings.size(), varyings.get_ptr(), transform_feedback_mode);
2676                 check_gl_error();
2677             }
2678         }
2679     }
2680
2681     switch (entrypoint_id)
2682     {
2683         case VOGL_ENTRYPOINT_glLinkProgram:
2684         {
2685             GL_ENTRYPOINT(glLinkProgram)(replay_handle);
2686             break;
2687         }
2688         case VOGL_ENTRYPOINT_glLinkProgramARB:
2689         {
2690             GL_ENTRYPOINT(glLinkProgramARB)(replay_handle);
2691             break;
2692         }
2693         case VOGL_ENTRYPOINT_glProgramBinary:
2694         {
2695             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));
2696             break;
2697         }
2698         default:
2699         {
2700             VOGL_ASSERT_ALWAYS;
2701             return;
2702         }
2703     }
2704
2705     check_gl_error();
2706
2707     GLint replay_link_status = 0;
2708     GLint replay_active_attributes = 0;
2709     if (entrypoint_id == VOGL_ENTRYPOINT_glLinkProgramARB)
2710     {
2711         GL_ENTRYPOINT(glGetObjectParameterivARB)(replay_handle, GL_OBJECT_LINK_STATUS_ARB, &replay_link_status);
2712         check_gl_error();
2713
2714         GL_ENTRYPOINT(glGetObjectParameterivARB)(replay_handle, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &replay_active_attributes);
2715         check_gl_error();
2716     }
2717     else
2718     {
2719         GL_ENTRYPOINT(glGetProgramiv)(replay_handle, GL_LINK_STATUS, &replay_link_status);
2720         check_gl_error();
2721
2722         GL_ENTRYPOINT(glGetProgramiv)(replay_handle, GL_ACTIVE_ATTRIBUTES, &replay_active_attributes);
2723         check_gl_error();
2724     }
2725
2726     if ((replay_link_status) || (!get_shared_state()->m_shadow_state.m_linked_programs.find_snapshot(replay_handle)))
2727     {
2728         bool success;
2729         if (entrypoint_id == VOGL_ENTRYPOINT_glProgramBinary)
2730             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));
2731         else
2732             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);
2733
2734         if (!success)
2735             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);
2736     }
2737
2738     if ((pDoc) && (replay_link_status != trace_link_status))
2739     {
2740         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);
2741     }
2742
2743     if (!replay_link_status)
2744     {
2745         vogl::vector<GLchar> log;
2746
2747         if (entrypoint_id == VOGL_ENTRYPOINT_glLinkProgramARB)
2748         {
2749             GLsizei length = 0;
2750             GL_ENTRYPOINT(glGetObjectParameterivARB)(replay_handle, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
2751             check_gl_error();
2752
2753             if (length)
2754             {
2755                 log.resize(length);
2756
2757                 GLint actual_length = 0;
2758                 GL_ENTRYPOINT(glGetInfoLogARB)(replay_handle, log.size(), &actual_length, reinterpret_cast<GLcharARB *>(log.get_ptr()));
2759                 check_gl_error();
2760             }
2761         }
2762         else
2763         {
2764             GLint length = 0;
2765             GL_ENTRYPOINT(glGetProgramiv)(replay_handle, GL_INFO_LOG_LENGTH, &length);
2766             check_gl_error();
2767
2768             if (length)
2769             {
2770                 log.resize(length);
2771
2772                 GL_ENTRYPOINT(glGetShaderInfoLog)(replay_handle, log.size(), &length, log.get_ptr());
2773                 check_gl_error();
2774             }
2775         }
2776
2777         if ((log.size()) && (log[0]))
2778         {
2779             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());
2780         }
2781     }
2782
2783     if ((pDoc) && (replay_active_attributes != trace_active_attributes))
2784     {
2785         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);
2786     }
2787
2788     const json_node *pUniforms_node = pDoc ? pDoc->get_root()->find_child_array("active_uniforms") : NULL;
2789
2790     if (pUniforms_node)
2791     {
2792         glsl_program_hash_map::iterator it = get_shared_state()->m_glsl_program_hash_map.find(trace_handle);
2793         if (it == get_shared_state()->m_glsl_program_hash_map.end())
2794             it = get_shared_state()->m_glsl_program_hash_map.insert(trace_handle).first;
2795         glsl_program_state &prog_state = it->second;
2796
2797         for (uint i = 0; i < pUniforms_node->size(); i++)
2798         {
2799             const json_node *pUniform = pUniforms_node->get_child(i);
2800             if (!pUniform)
2801             {
2802                 VOGL_ASSERT_ALWAYS;
2803                 continue;
2804             }
2805
2806             const char *pName = pUniform->value_as_string_ptr("name");
2807             if (!pName)
2808             {
2809                 VOGL_ASSERT_ALWAYS;
2810                 continue;
2811             }
2812             int trace_loc = pUniform->value_as_int("location");
2813             int trace_array_size = pUniform->value_as_int("size");
2814             //int trace_type = pUniform->value_as_int("type");
2815
2816             VOGL_ASSERT(trace_array_size >= 1);
2817
2818             if ((trace_loc < 0) || (trace_array_size <= 0))
2819                 continue;
2820
2821             if (trace_array_size > 1)
2822             {
2823                 dynamic_string element_name;
2824                 for (int i = 0; i < trace_array_size; i++)
2825                 {
2826                     element_name = pName;
2827                     int start_bracket_ofs = element_name.find_right('[');
2828                     if (start_bracket_ofs >= 0)
2829                         element_name.left(start_bracket_ofs);
2830                     element_name.format_append("[%u]", i);
2831
2832                     GLint element_trace_loc = trace_loc + i;
2833                     GLint element_replay_loc;
2834                     if (entrypoint_id == VOGL_ENTRYPOINT_glLinkProgramARB)
2835                         element_replay_loc = GL_ENTRYPOINT(glGetUniformLocationARB)(replay_handle, reinterpret_cast<const GLcharARB *>(element_name.get_ptr()));
2836                     else
2837                         element_replay_loc = GL_ENTRYPOINT(glGetUniformLocation)(replay_handle, reinterpret_cast<const GLchar *>(element_name.get_ptr()));
2838                     check_gl_error();
2839
2840                     if (element_replay_loc < 0)
2841                     {
2842                         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);
2843                     }
2844                     else
2845                     {
2846                         prog_state.m_uniform_locations.erase(element_trace_loc);
2847                         prog_state.m_uniform_locations.insert(element_trace_loc, element_replay_loc);
2848                     }
2849                 }
2850             }
2851             else if (trace_array_size == 1)
2852             {
2853                 GLint replay_loc;
2854                 if (entrypoint_id == VOGL_ENTRYPOINT_glLinkProgramARB)
2855                     replay_loc = GL_ENTRYPOINT(glGetUniformLocationARB)(replay_handle, reinterpret_cast<const GLcharARB *>(pName));
2856                 else
2857                     replay_loc = GL_ENTRYPOINT(glGetUniformLocation)(replay_handle, reinterpret_cast<const GLchar *>(pName));
2858                 check_gl_error();
2859
2860                 if (replay_loc < 0)
2861                 {
2862                     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);
2863                 }
2864                 else
2865                 {
2866                     prog_state.m_uniform_locations.erase(trace_loc);
2867                     prog_state.m_uniform_locations.insert(trace_loc, replay_loc);
2868                 }
2869             }
2870         } // i
2871     }
2872 }
2873
2874 //----------------------------------------------------------------------------------------------------------------------
2875 // vogl_gl_replayer::post_draw_call
2876 // Called after each draw call or blit.
2877 //----------------------------------------------------------------------------------------------------------------------
2878 vogl_gl_replayer::status_t vogl_gl_replayer::post_draw_call()
2879 {
2880     VOGL_FUNC_TRACER
2881
2882     if (m_pCur_context_state->m_inside_gl_begin)
2883         return cStatusOK;
2884
2885     if (check_gl_error())
2886         return cStatusGLError;
2887
2888     bool is_draw = vogl_is_draw_entrypoint(m_pCur_gl_packet->get_entrypoint_id());
2889
2890     if ((m_flags & cGLReplayerDumpShadersOnDraw) && (is_draw))
2891     {
2892         dump_current_shaders();
2893     }
2894
2895     if (m_flags & cGLReplayerDumpFramebufferOnDraws)
2896     {
2897         bool should_dump = false;
2898
2899         if (m_dump_framebuffer_on_draw_frame_index != -1)
2900         {
2901             if (m_frame_index == m_dump_framebuffer_on_draw_frame_index)
2902                 should_dump = true;
2903         }
2904         else if ((m_dump_framebuffer_on_draw_first_gl_call_index >= 0) && (m_dump_framebuffer_on_draw_last_gl_call_index >= 0))
2905         {
2906             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);
2907         }
2908         else
2909         {
2910             should_dump = true;
2911         }
2912
2913         if (should_dump)
2914         {
2915             dump_current_framebuffer();
2916         }
2917     }
2918
2919     m_frame_draw_counter += is_draw;
2920
2921     return cStatusOK;
2922 }
2923
2924 //----------------------------------------------------------------------------------------------------------------------
2925 // vogl_gl_replayer::dump_framebuffer
2926 //----------------------------------------------------------------------------------------------------------------------
2927 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)
2928 {
2929     VOGL_FUNC_TRACER
2930
2931     uint trace_read_framebuffer = 0;
2932     if (read_framebuffer)
2933     {
2934         gl_handle_hash_map::const_iterator it = get_context_state()->m_framebuffers.search_table_for_value(read_framebuffer);
2935         if (it != get_context_state()->m_framebuffers.end())
2936             trace_read_framebuffer = it->second;
2937     }
2938
2939     uint trace_texture = replay_texture;
2940     if (replay_texture)
2941     {
2942         if (!get_shared_state()->m_shadow_state.m_textures.map_inv_handle_to_handle(replay_texture, trace_texture))
2943             vogl_warning_printf("%s: Failed finding GL handle %u in texture handle shadow!\n", VOGL_METHOD_NAME, replay_texture);
2944     }
2945
2946     uint trace_rbo = 0;
2947     if (replay_rbo)
2948     {
2949         if (!get_shared_state()->m_shadow_state.m_rbos.map_inv_handle_to_handle(replay_rbo, trace_rbo))
2950             vogl_error_printf("%s: Failed finding GL handle %u in RBO handle shadow!\n", VOGL_METHOD_NAME, replay_rbo);
2951     }
2952
2953     m_screenshot_buffer.resize(width * height * 3);
2954
2955     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);
2956
2957     if (!success)
2958     {
2959         process_entrypoint_warning("%s: vogl_copy_buffer_to_image() failed!\n", VOGL_METHOD_NAME);
2960         return false;
2961     }
2962
2963     size_t png_size = 0;
2964     void *pPNG_data = tdefl_write_image_to_png_file_in_memory_ex(m_screenshot_buffer.get_ptr(), width, height, 3, &png_size, 1, true);
2965
2966     dynamic_string screenshot_filename(cVarArg, "%s_GLCTR%08llu_%s_FR%06u_DCTR%05llu_W%04i_H%04i_FBO%04u_%s",
2967                                        m_dump_framebuffer_on_draw_prefix.get_ptr(),
2968                                        (unsigned long long)m_pCur_gl_packet->get_call_counter(),
2969                                        g_vogl_entrypoint_descs[m_pCur_gl_packet->get_entrypoint_id()].m_pName,
2970                                        m_frame_index,
2971                                        (unsigned long long)m_frame_draw_counter,
2972                                        width, height,
2973                                        trace_read_framebuffer,
2974                                        g_gl_enums.find_gl_name(read_buffer));
2975
2976     if (internal_format != GL_NONE)
2977     {
2978         screenshot_filename += "_";
2979         screenshot_filename += g_gl_enums.find_gl_image_format_name(internal_format);
2980     }
2981
2982     if (orig_samples != 0)
2983         screenshot_filename += dynamic_string(cVarArg, "_MSAA%u", orig_samples);
2984     if (replay_texture)
2985         screenshot_filename += dynamic_string(cVarArg, "_TEX%04u", replay_texture);
2986     if (replay_rbo)
2987         screenshot_filename += dynamic_string(cVarArg, "_RBO%04u", replay_rbo);
2988
2989     screenshot_filename += ".png";
2990
2991     file_utils::create_directories(file_utils::get_pathname(screenshot_filename.get_ptr()), false);
2992
2993     if (!file_utils::write_buf_to_file(screenshot_filename.get_ptr(), pPNG_data, png_size))
2994     {
2995         process_entrypoint_error("%s: Failed writing framebuffer screenshot to file \"%s\"\n", VOGL_METHOD_NAME, screenshot_filename.get_ptr());
2996         success = false;
2997     }
2998     else
2999     {
3000         vogl_printf("%s: Wrote framebuffer screenshot to file \"%s\"\n", VOGL_METHOD_NAME, screenshot_filename.get_ptr());
3001     }
3002
3003     mz_free(pPNG_data);
3004
3005     return success;
3006 }
3007
3008 //----------------------------------------------------------------------------------------------------------------------
3009 // vogl_gl_replayer::dump_current_framebuffer
3010 //----------------------------------------------------------------------------------------------------------------------
3011 void vogl_gl_replayer::dump_current_framebuffer()
3012 {
3013     VOGL_FUNC_TRACER
3014
3015     uint draw_framebuffer_binding = vogl_get_gl_integer(GL_DRAW_FRAMEBUFFER_BINDING);
3016
3017     uint max_draw_buffers = vogl_get_gl_integer(GL_MAX_DRAW_BUFFERS);
3018     if (!max_draw_buffers)
3019     {
3020         process_entrypoint_warning("%s: GL_MAX_DRAW_BUFFERS is 0\n", VOGL_METHOD_NAME);
3021         return;
3022     }
3023
3024     //GL_COLOR_ATTACHMENT0-GL_COLOR_ATTACHMENT15, GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT
3025
3026     vogl::vector<GLenum> draw_buffers(max_draw_buffers);
3027     for (uint i = 0; i < max_draw_buffers; i++)
3028         draw_buffers[i] = vogl_get_gl_integer(GL_DRAW_BUFFER0 + i);
3029
3030     if (!draw_framebuffer_binding)
3031     {
3032         for (uint i = 0; i < max_draw_buffers; i++)
3033             if (draw_buffers[i] != GL_NONE)
3034                 dump_framebuffer(m_pWindow->get_width(), m_pWindow->get_height(), 0, draw_buffers[i], GL_NONE, 0, 0, 0);
3035         return;
3036     }
3037
3038     // TODO: We should probably keep around a persistent set of per-context (or sharelist) remappers
3039     vogl_framebuffer_state fbo_state;
3040     if (!fbo_state.snapshot(m_pCur_context_state->m_context_info, m_replay_to_trace_remapper, draw_framebuffer_binding, GL_NONE))
3041     {
3042         process_entrypoint_warning("%s: Unable to snapshot current FBO %u\n", VOGL_METHOD_NAME, draw_framebuffer_binding);
3043         return;
3044     }
3045
3046     for (uint i = 0; i < draw_buffers.size(); i++)
3047     {
3048         if (draw_buffers[i] == GL_NONE)
3049             continue;
3050
3051         const vogl_framebuffer_attachment *pAttachment = fbo_state.get_attachments().find_value(draw_buffers[i]);
3052         if (!pAttachment)
3053         {
3054             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);
3055             continue;
3056         }
3057
3058         if (pAttachment->get_type() == GL_FRAMEBUFFER_DEFAULT)
3059             continue;
3060         else if (pAttachment->get_type() == GL_RENDERBUFFER)
3061         {
3062             GLuint rbo_handle = pAttachment->get_param(GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
3063             if (!rbo_handle)
3064                 continue;
3065
3066             vogl_renderbuffer_state rbo_state;
3067             if (!rbo_state.snapshot(m_pCur_context_state->m_context_info, m_replay_to_trace_remapper, rbo_handle, GL_NONE))
3068             {
3069                 process_entrypoint_warning("%s: Failed getting RBO %u's' state!\n", VOGL_METHOD_NAME, rbo_handle);
3070                 continue;
3071             }
3072
3073             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))
3074                 continue;
3075
3076             uint width = rbo_state.get_desc().get_int_or_default(GL_RENDERBUFFER_WIDTH);
3077             uint height = rbo_state.get_desc().get_int_or_default(GL_RENDERBUFFER_HEIGHT);
3078             uint samples = rbo_state.get_desc().get_int_or_default(GL_RENDERBUFFER_SAMPLES);
3079             GLenum internal_format = rbo_state.get_desc().get_int_or_default(GL_RENDERBUFFER_INTERNAL_FORMAT);
3080
3081             if ((!width) || (!height) || (!internal_format))
3082             {
3083                 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);
3084                 continue;
3085             }
3086
3087             if (samples > 1)
3088             {
3089                 vogl_scoped_binding_state orig_framebuffers(GL_DRAW_FRAMEBUFFER, GL_READ_FRAMEBUFFER, GL_RENDERBUFFER);
3090
3091                 GLuint temp_rbo = 0;
3092                 GL_ENTRYPOINT(glGenRenderbuffers)(1, &temp_rbo);
3093                 check_gl_error();
3094
3095                 if (!temp_rbo)
3096                     continue;
3097
3098                 GL_ENTRYPOINT(glBindRenderbuffer)(GL_RENDERBUFFER, temp_rbo);
3099                 check_gl_error();
3100
3101                 GL_ENTRYPOINT(glRenderbufferStorage)(GL_RENDERBUFFER, internal_format, width, height);
3102                 check_gl_error();
3103
3104                 GLuint temp_fbo = 0;
3105                 GL_ENTRYPOINT(glGenFramebuffers)(1, &temp_fbo);
3106                 check_gl_error();
3107
3108                 GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, temp_fbo);
3109                 check_gl_error();
3110
3111                 GL_ENTRYPOINT(glFramebufferRenderbuffer)(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, temp_rbo);
3112                 check_gl_error();
3113
3114                 GLenum draw_buf = GL_COLOR_ATTACHMENT0;
3115                 GL_ENTRYPOINT(glDrawBuffers)(1, &draw_buf);
3116                 check_gl_error();
3117
3118                 GL_ENTRYPOINT(glReadBuffer)(GL_NONE);
3119                 check_gl_error();
3120
3121                 GLenum cur_status = GL_ENTRYPOINT(glCheckFramebufferStatus)(GL_DRAW_FRAMEBUFFER);
3122                 check_gl_error();
3123
3124                 if (cur_status == GL_FRAMEBUFFER_COMPLETE)
3125                 {
3126                     GL_ENTRYPOINT(glBindFramebuffer)(GL_READ_FRAMEBUFFER, draw_framebuffer_binding);
3127                     check_gl_error();
3128
3129                     // Save the framebuffer's readbuffer (it's per-framebuffer state, not context state).
3130                     vogl_scoped_state_saver state_saver(cGSTReadBuffer);
3131
3132                     GL_ENTRYPOINT(glReadBuffer)(draw_buffers[i]);
3133                     check_gl_error();
3134
3135                     GL_ENTRYPOINT(glBlitFramebuffer)(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
3136
3137                     if (!check_gl_error())
3138                         dump_framebuffer(width, height, temp_fbo, GL_COLOR_ATTACHMENT0, internal_format, samples, 0, rbo_handle);
3139                     else
3140                     {
3141                         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);
3142                     }
3143                 }
3144
3145                 GL_ENTRYPOINT(glBindRenderbuffer)(GL_RENDERBUFFER, 0);
3146                 check_gl_error();
3147
3148                 GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, 0);
3149                 check_gl_error();
3150
3151                 GL_ENTRYPOINT(glDeleteFramebuffers)(1, &temp_fbo);
3152                 check_gl_error();
3153
3154                 GL_ENTRYPOINT(glDeleteRenderbuffers)(1, &temp_rbo);
3155                 check_gl_error();
3156             }
3157             else
3158             {
3159                 dump_framebuffer(width, height, draw_framebuffer_binding, draw_buffers[i], internal_format, 0, 0, rbo_handle);
3160             }
3161         }
3162         else if (pAttachment->get_type() == GL_TEXTURE)
3163         {
3164             GLuint tex_handle = pAttachment->get_param(GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
3165             if (!tex_handle)
3166             {
3167                 process_entrypoint_warning("%s: Current FBO %u has a invalid object name\n", VOGL_METHOD_NAME, draw_framebuffer_binding);
3168                 continue;
3169             }
3170
3171             GLenum target = get_shared_state()->m_shadow_state.m_textures.get_target_inv(tex_handle);
3172             if (target == GL_NONE)
3173             {
3174                 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);
3175                 continue;
3176             }
3177
3178             if ((target == GL_TEXTURE_CUBE_MAP) || (target == GL_TEXTURE_CUBE_MAP_ARRAY))
3179                 target = pAttachment->get_param(GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE);
3180
3181             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))
3182             {
3183                 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);
3184                 continue;
3185             }
3186
3187             uint level = pAttachment->get_param(GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL);
3188             uint layer = pAttachment->get_param(GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER);
3189             VOGL_NOTE_UNUSED(layer);
3190
3191             GLint width = 0, height = 0, samples = 0;
3192             GLenum internal_format = GL_NONE;
3193
3194             {
3195                 vogl_scoped_binding_state binding_saver;
3196                 binding_saver.save_textures();
3197
3198                 GL_ENTRYPOINT(glBindTexture)(target, tex_handle);
3199                 check_gl_error();
3200
3201                 GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, level, GL_TEXTURE_WIDTH, &width);
3202                 check_gl_error();
3203
3204                 GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, level, GL_TEXTURE_HEIGHT, &height);
3205                 check_gl_error();
3206
3207                 GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, level, GL_TEXTURE_INTERNAL_FORMAT, reinterpret_cast<GLint *>(&internal_format));
3208                 check_gl_error();
3209
3210                 if (m_pCur_context_state->m_context_info.supports_extension("GL_ARB_texture_multisample"))
3211                 {
3212                     GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, level, GL_TEXTURE_SAMPLES, &samples);
3213                     check_gl_error();
3214                 }
3215             }
3216
3217             if ((!width) || (!height))
3218             {
3219                 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);
3220                 continue;
3221             }
3222
3223             if (samples > 1)
3224             {
3225                 process_entrypoint_warning("%s: Can't dump multisample texture FBO attachments yet\n", VOGL_METHOD_NAME);
3226                 continue;
3227             }
3228
3229             dump_framebuffer(width, height, draw_framebuffer_binding, draw_buffers[i], internal_format, 0, tex_handle, 0);
3230         }
3231     }
3232 }
3233
3234 //----------------------------------------------------------------------------------------------------------------------
3235 // vogl_gl_replayer::dump_current_shaders
3236 //----------------------------------------------------------------------------------------------------------------------
3237 void vogl_gl_replayer::dump_current_shaders()
3238 {
3239     VOGL_FUNC_TRACER
3240
3241     if (!m_pCur_context_state)
3242         return;
3243
3244     check_gl_error();
3245
3246     const GLuint replay_program = m_pCur_context_state->m_cur_replay_program;
3247
3248     // Get the current program.
3249     GLuint current_program = 0;
3250     GL_ENTRYPOINT(glGetIntegerv)(GL_CURRENT_PROGRAM, (GLint *)(&current_program));
3251     check_gl_error();
3252
3253     VOGL_ASSERT(replay_program == current_program);
3254
3255     if (!current_program)
3256         return;
3257
3258     // Get the attached shaders.
3259     GLsizei attached_shader_count = -1;
3260     GL_ENTRYPOINT(glGetProgramiv)(replay_program, GL_ATTACHED_SHADERS, &attached_shader_count);
3261     check_gl_error();
3262
3263     if (!attached_shader_count)
3264         return;
3265
3266     vogl::vector<GLuint> shaders(attached_shader_count);
3267     GLsizei actual_shader_count = 0;
3268     GL_ENTRYPOINT(glGetAttachedShaders)(replay_program,
3269                                         attached_shader_count,
3270                                         &actual_shader_count,
3271                                         shaders.get_ptr());
3272     check_gl_error();
3273
3274     VOGL_ASSERT(attached_shader_count == actual_shader_count); // Sanity check.
3275
3276     vogl_printf("Trace context 0x%" PRIx64 ", GL draw counter %" PRIu64 ", frame %u, replay program %u trace program %u has %d attached shaders:\n",
3277                cast_val_to_uint64(m_cur_trace_context), m_last_parsed_call_counter, m_frame_index,
3278                replay_program, m_pCur_context_state->m_cur_trace_program,
3279                attached_shader_count);
3280
3281     // Get source from shaders.
3282     vogl::vector<GLchar> source; // Shared buffer for each iteration.
3283     for (GLsizei i = 0; i < attached_shader_count; ++i)
3284     {
3285         const GLuint shader = shaders[i];
3286         GLint shader_type = 0;
3287         GL_ENTRYPOINT(glGetShaderiv)(shader, GL_SHADER_TYPE, &shader_type);
3288         check_gl_error();
3289
3290         vogl_printf("\n%s: %u\n", g_gl_enums.find_gl_name(shader_type), shader);
3291
3292         GLint source_length = -1; // Includes NUL terminator.
3293         GL_ENTRYPOINT(glGetShaderiv)(shader, GL_SHADER_SOURCE_LENGTH, &source_length);
3294         check_gl_error();
3295
3296         VOGL_ASSERT(source_length > 0);
3297
3298         source.resize(source_length);
3299         GLint actual_length = 0; // Excludes NUL terminator!
3300         GL_ENTRYPOINT(glGetShaderSource)(shader, source_length, &actual_length, source.get_ptr());
3301         check_gl_error();
3302
3303         VOGL_ASSERT(source_length == actual_length + 1); // Sanity check.
3304         vogl_printf("%.*s\n", source_length, source.get_const_ptr());
3305     }
3306     vogl_printf("========\n");
3307 }
3308
3309 //----------------------------------------------------------------------------------------------------------------------
3310 // vogl_gl_replayer::handle_ShaderSource
3311 // Handle ShaderSource and ShaderSourceARB.
3312 //----------------------------------------------------------------------------------------------------------------------
3313 vogl_gl_replayer::status_t vogl_gl_replayer::handle_ShaderSource(GLhandleARB trace_object,
3314                                                                GLsizei count,
3315                                                                const vogl_client_memory_array trace_strings_glchar_ptr_array,
3316                                                                const GLint *pTrace_lengths)
3317 {
3318     VOGL_FUNC_TRACER
3319
3320     GLhandleARB replay_object = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_object);
3321
3322     // m_pCur_gl_packet->get_param_client_memory_data_size(2) / sizeof(const GLchar *);
3323     const uint trace_strings_count = trace_strings_glchar_ptr_array.size();
3324     const uint trace_lengths_count = m_pCur_gl_packet->get_param_client_memory_data_size(3) / sizeof(const GLint);
3325
3326     if ((trace_strings_glchar_ptr_array.get_ptr()) &&
3327         (trace_strings_count != static_cast<uint>(count)))
3328     {
3329         process_entrypoint_error("%s: Trace strings array has an invalid count (expected %u, got %u)\n",
3330                                  VOGL_METHOD_NAME, count, trace_strings_count);
3331         return cStatusHardFailure;
3332     }
3333
3334     if ((pTrace_lengths) && (trace_lengths_count != static_cast<uint>(count)))
3335     {
3336         process_entrypoint_error("%s: Trace lengths array has an invalid count (expected %u, got %u)\n",
3337                                  VOGL_METHOD_NAME, count, trace_lengths_count);
3338         return cStatusHardFailure;
3339     }
3340
3341     vogl::vector<const GLcharARB *> strings(count);
3342     vogl::vector<GLint> lengths(count);
3343
3344     const key_value_map &map = m_pCur_gl_packet->get_key_value_map();
3345
3346     vogl::vector<uint8_vec> blobs(count);
3347
3348     for (GLsizei i = 0; i < count; i++)
3349     {
3350         strings[i] = NULL;
3351         if ((trace_strings_glchar_ptr_array.get_ptr()) &&
3352             (trace_strings_glchar_ptr_array.get_element<vogl_trace_ptr_value>(i) != 0))
3353         {
3354             strings[i] = "";
3355         }
3356
3357         lengths[i] = pTrace_lengths ? pTrace_lengths[i] : 0;
3358
3359         key_value_map::const_iterator it = map.find(i);
3360         if (it == map.end())
3361         {
3362             if (lengths[i] > 0)
3363             {
3364                 process_entrypoint_error("%s: Failed finding blob for non-empty string %i in packet's key value map\n",
3365                                          VOGL_METHOD_NAME, i);
3366                 return cStatusHardFailure;
3367             }
3368             continue;
3369         }
3370
3371         const uint8_vec *pBlob = it->second.get_blob();
3372         if (!pBlob)
3373         {
3374             process_entrypoint_error("%s: Can't convert string %i to a blob\n", VOGL_METHOD_NAME, i);
3375             return cStatusHardFailure;
3376         }
3377
3378         blobs[i] = *pBlob;
3379         uint8_vec &blob = blobs[i];
3380
3381         if ((pTrace_lengths) && (pTrace_lengths[i] >= 0))
3382         {
3383             if (static_cast<uint>(pTrace_lengths[i]) != blob.size())
3384             {
3385                 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());
3386                 lengths[i] = blob.size();
3387             }
3388         }
3389         else
3390         {
3391             if ((blob.size()) && (blob.back() != '\0'))
3392             {
3393                 process_entrypoint_warning("%s: String %u doesn't end in 0 terminator - appending terminator\n", VOGL_METHOD_NAME, i);
3394
3395                 blob.push_back('\0');
3396             }
3397
3398             VOGL_ASSERT(blob.size() &&
3399                           (blob.back() == '\0') &&
3400                           (blob.size() == (1 + vogl_strlen(reinterpret_cast<const char *>(blob.get_ptr())))));
3401         }
3402
3403         strings[i] = reinterpret_cast<const GLcharARB *>(blob.get_ptr());
3404     }
3405
3406     if (m_pCur_gl_packet->get_entrypoint_id() == VOGL_ENTRYPOINT_glShaderSource)
3407     {
3408         GL_ENTRYPOINT(glShaderSource)(replay_object,
3409                                       count,
3410                                       trace_strings_glchar_ptr_array.get_ptr() ? (GLchar * const *)strings.get_ptr() : NULL,
3411                                       pTrace_lengths ? lengths.get_ptr() : NULL);
3412     }
3413     else
3414     {
3415         GL_ENTRYPOINT(glShaderSourceARB)(replay_object,
3416                                          count,
3417                                          trace_strings_glchar_ptr_array.get_ptr() ? strings.get_ptr() : NULL,
3418                                          pTrace_lengths ? lengths.get_ptr() : NULL);
3419     }
3420     return cStatusOK;
3421 }
3422
3423 //----------------------------------------------------------------------------------------------------------------------
3424 // vogl_gl_replayer::display_list_bind_callback
3425 // handle is in the trace namespace
3426 //----------------------------------------------------------------------------------------------------------------------
3427 void vogl_gl_replayer::display_list_bind_callback(vogl_namespace_t handle_namespace, GLenum target, GLuint handle, void *pOpaque)
3428 {
3429     VOGL_FUNC_TRACER
3430
3431     vogl_gl_replayer *pReplayer = static_cast<vogl_gl_replayer *>(pOpaque);
3432
3433     if (handle_namespace == VOGL_NAMESPACE_TEXTURES)
3434     {
3435         if ((handle) && (target != GL_NONE))
3436         {
3437             // A conditional update because we can't really test to see if the bind inside the display list really succeeded.
3438             pReplayer->get_shared_state()->m_shadow_state.m_textures.conditional_update(handle, GL_NONE, target);
3439         }
3440     }
3441     else
3442     {
3443         // TODO - right now the display list whitelist doens't let anything else get bound.
3444         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);
3445     }
3446 }
3447
3448 //----------------------------------------------------------------------------------------------------------------------
3449 // Helper macros - slightly simplifies hand-generating entrypoints with EXT/ARB/etc. variants
3450 //----------------------------------------------------------------------------------------------------------------------
3451 #define SWITCH_GL_ENTRYPOINT2(e0, e1, ...)                 \
3452     if (entrypoint_id == VOGL_JOIN(VOGL_ENTRYPOINT_, e0)) \
3453         result = GL_ENTRYPOINT(e0)(__VA_ARGS__);           \
3454     else                                                   \
3455         result = GL_ENTRYPOINT(e1)(__VA_ARGS__);
3456
3457 #define SWITCH_GL_ENTRYPOINT3(e0, e1, e2, ...)                  \
3458     if (entrypoint_id == VOGL_JOIN(VOGL_ENTRYPOINT_, e0))      \
3459         result = GL_ENTRYPOINT(e0)(__VA_ARGS__);                \
3460     else if (entrypoint_id == VOGL_JOIN(VOGL_ENTRYPOINT_, e1)) \
3461         result = GL_ENTRYPOINT(e1)(__VA_ARGS__);                \
3462     else                                                        \
3463         result = GL_ENTRYPOINT(e2)(__VA_ARGS__);
3464
3465 #define SWITCH_GL_ENTRYPOINT2_VOID(e0, e1, ...)            \
3466     if (entrypoint_id == VOGL_JOIN(VOGL_ENTRYPOINT_, e0)) \
3467         GL_ENTRYPOINT(e0)(__VA_ARGS__);                    \
3468     else                                                   \
3469         GL_ENTRYPOINT(e1)(__VA_ARGS__);
3470
3471 #define SWITCH_GL_ENTRYPOINT3_VOID(e0, e1, e2, ...)             \
3472     if (entrypoint_id == VOGL_JOIN(VOGL_ENTRYPOINT_, e0))      \
3473         GL_ENTRYPOINT(e0)(__VA_ARGS__);                         \
3474     else if (entrypoint_id == VOGL_JOIN(VOGL_ENTRYPOINT_, e1)) \
3475         GL_ENTRYPOINT(e1)(__VA_ARGS__);                         \
3476     else                                                        \
3477         GL_ENTRYPOINT(e2)(__VA_ARGS__);
3478
3479 //----------------------------------------------------------------------------------------------------------------------
3480 // vogl_replayer::process_gl_entrypoint_packet
3481 // This will be called during replaying, or when building display lists during state restoring.
3482 //----------------------------------------------------------------------------------------------------------------------
3483 vogl_gl_replayer::status_t vogl_gl_replayer::process_gl_entrypoint_packet(vogl_trace_packet& trace_packet)
3484 {
3485     m_pCur_gl_packet = &trace_packet;
3486
3487     status_t status = cStatusOK;
3488
3489     if (m_pPending_snapshot)
3490     {
3491         status = process_applying_pending_snapshot();
3492         if (status != cStatusOK)
3493             return status;
3494     }
3495
3496     if (m_pending_make_current_packet.is_valid())
3497     {
3498         status = process_pending_make_current();
3499         if (status != cStatusOK)
3500             return status;
3501     }
3502
3503     const vogl_trace_gl_entrypoint_packet &entrypoint_packet = trace_packet.get_entrypoint_packet();
3504
3505     m_last_parsed_call_counter = entrypoint_packet.m_call_counter;
3506
3507     status = process_gl_entrypoint_packet_internal(trace_packet);
3508
3509     if (status != cStatusResizeWindow)
3510         m_last_processed_call_counter = entrypoint_packet.m_call_counter;
3511
3512     m_pCur_gl_packet = NULL;
3513
3514     return status;
3515 }
3516
3517 //----------------------------------------------------------------------------------------------------------------------
3518 // vogl_replayer::process_gl_entrypoint_packet_internal
3519 // This will be called during replaying, or when building display lists during state restoring.
3520 //----------------------------------------------------------------------------------------------------------------------
3521 vogl_gl_replayer::status_t vogl_gl_replayer::process_gl_entrypoint_packet_internal(vogl_trace_packet& trace_packet)
3522 {
3523     VOGL_FUNC_TRACER
3524
3525     m_at_frame_boundary = false;
3526
3527     const vogl_trace_gl_entrypoint_packet &gl_entrypoint_packet = trace_packet.get_entrypoint_packet();
3528     const gl_entrypoint_id_t entrypoint_id = trace_packet.get_entrypoint_id();
3529
3530     if (m_flags & cGLReplayerDebugMode)
3531         dump_trace_gl_packet_debug_info(gl_entrypoint_packet);
3532
3533     if (m_flags & cGLReplayerDebugMode)
3534         dump_packet_as_func_call(trace_packet);
3535
3536     if (m_flags & cGLReplayerDumpAllPackets)
3537         print_detailed_context(cDebugConsoleMessage);
3538
3539     if (entrypoint_id == VOGL_ENTRYPOINT_glInternalTraceCommandRAD)
3540         return process_internal_trace_command(gl_entrypoint_packet);
3541
3542     status_t status = cStatusOK;
3543
3544     if (gl_entrypoint_packet.m_context_handle != m_cur_trace_context)
3545     {
3546         status = switch_contexts(gl_entrypoint_packet.m_context_handle);
3547         if (status != cStatusOK)
3548             return status;
3549     }
3550
3551     bool processed_glx_packet = true;
3552     switch (entrypoint_id)
3553     {
3554         case VOGL_ENTRYPOINT_glXDestroyContext:
3555         {
3556             const Display *dpy = m_pWindow->get_display();
3557
3558             vogl_trace_context_ptr_value trace_context = trace_packet.get_param_ptr_value(1);
3559             GLXContext replay_context = remap_context(trace_context);
3560
3561             if ((trace_context) && (!replay_context))
3562             {
3563                 process_entrypoint_error("%s: Failed remapping GL trace context 0x%" PRIx64 "\n", VOGL_METHOD_NAME, (uint64_t)trace_context);
3564                 return cStatusHardFailure;
3565             }
3566
3567             if (trace_context == m_cur_trace_context)
3568             {
3569                 process_entrypoint_warning("%s: glXDestroyContext() called while trace context 0x%" PRIx64 " is still current, forcing it to not be current\n",
3570                                            VOGL_METHOD_NAME, (uint64_t)trace_context);
3571
3572                 m_cur_trace_context = 0;
3573                 m_cur_replay_context = 0;
3574                 m_pCur_context_state = NULL;
3575             }
3576
3577             GL_ENTRYPOINT(glXDestroyContext)(dpy, replay_context);
3578
3579             destroy_context(trace_context);
3580
3581             break;
3582         }
3583         case VOGL_ENTRYPOINT_glXMakeCurrent:
3584         case VOGL_ENTRYPOINT_glXMakeContextCurrent:
3585         {
3586             Bool trace_result = trace_packet.get_return_value<Bool>();
3587
3588             vogl_trace_context_ptr_value trace_context = trace_packet.get_param_ptr_value((entrypoint_id == VOGL_ENTRYPOINT_glXMakeCurrent) ? 2 : 3);
3589
3590             // pContext_state can be NULL!
3591             context_state *pContext_state = get_trace_context_state(trace_context);
3592             GLXContext replay_context = pContext_state ? pContext_state->m_replay_context : 0;
3593
3594             if ((trace_context) && (!replay_context))
3595             {
3596                 process_entrypoint_error("%s, Failed remapping GL context\n", VOGL_METHOD_NAME);
3597                 return cStatusHardFailure;
3598             }
3599
3600             int viewport_x = trace_packet.get_key_value_map().get_int(string_hash("viewport_x"));
3601             VOGL_NOTE_UNUSED(viewport_x);
3602             int viewport_y = trace_packet.get_key_value_map().get_int(string_hash("viewport_y"));
3603             VOGL_NOTE_UNUSED(viewport_y);
3604             int viewport_width = trace_packet.get_key_value_map().get_int(string_hash("viewport_width"));
3605             VOGL_NOTE_UNUSED(viewport_width);
3606             int viewport_height = trace_packet.get_key_value_map().get_int(string_hash("viewport_height"));
3607             VOGL_NOTE_UNUSED(viewport_height);
3608             int win_width = trace_packet.get_key_value_map().get_int(string_hash("win_width"));
3609             int win_height = trace_packet.get_key_value_map().get_int(string_hash("win_height"));
3610
3611             // 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.
3612             if ((trace_context) && (trace_result))
3613             {
3614                 if ((win_width) && (win_height))
3615                 {
3616                     if (!(m_flags & cGLReplayerLockWindowDimensions))
3617                     {
3618                         if ((m_pWindow->get_width() != win_width) || (m_pWindow->get_height() != win_height))
3619                         {
3620                             m_pending_make_current_packet = *m_pCur_gl_packet;
3621
3622                             status = trigger_pending_window_resize(win_width, win_height);
3623
3624                             vogl_printf("%s: Deferring glXMakeCurrent() until window resizes to %ux%u\n", VOGL_METHOD_NAME, win_width, win_height);
3625                         }
3626                     }
3627                 }
3628             }
3629
3630             if (status != cStatusResizeWindow)
3631             {
3632                 const Display *dpy = m_pWindow->get_display();
3633                 GLXDrawable drawable = replay_context ? m_pWindow->get_xwindow() : (GLXDrawable)NULL;
3634
3635                 Bool result = GL_ENTRYPOINT(glXMakeCurrent)(dpy, drawable, replay_context);
3636                 if (!result)
3637                 {
3638                     if (trace_result)
3639                     {
3640                         process_entrypoint_error("%s: Failed making context current, but in the trace this call succeeded!\n", VOGL_METHOD_NAME);
3641                         return cStatusHardFailure;
3642                     }
3643                     else
3644                     {
3645                         process_entrypoint_warning("%s: Failed making context current, in the trace this call also failed\n", VOGL_METHOD_NAME);
3646                     }
3647                 }
3648                 else
3649                 {
3650                     m_cur_trace_context = trace_context;
3651                     m_cur_replay_context = replay_context;
3652                     m_pCur_context_state = pContext_state;
3653
3654                     if (!trace_result)
3655                     {
3656                         process_entrypoint_warning("%s: Context was successfuly made current, but this operation failed in the trace\n", VOGL_METHOD_NAME);
3657                     }
3658
3659 #if 0
3660                                 vogl_printf("glXMakeCurrent(): Trace Viewport: [%u,%u,%u,%u], Window: [%u %u]\n",
3661                                            viewport_x, viewport_y,
3662                                            viewport_width, viewport_height,
3663                                            win_width, win_height);
3664 #endif
3665
3666                     if (m_cur_replay_context)
3667                     {
3668                         if (!handle_context_made_current())
3669                             return cStatusHardFailure;
3670                     }
3671                 }
3672             }
3673
3674             break;
3675         }
3676         case VOGL_ENTRYPOINT_glXQueryVersion:
3677         {
3678             int major = 0, minor = 0;
3679             Bool status = GL_ENTRYPOINT(glXQueryVersion)(m_pWindow->get_display(), &major, &minor);
3680             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,
3681                                        *trace_packet.get_param_client_memory<int>(1),
3682                                        *trace_packet.get_param_client_memory<int>(2),
3683                                        trace_packet.get_return_value<Bool>());
3684
3685             break;
3686         }
3687         case VOGL_ENTRYPOINT_glXChooseFBConfig:
3688         {
3689             // TODO
3690             break;
3691         }
3692         case VOGL_ENTRYPOINT_glXGetFBConfigAttrib:
3693         {
3694             // TODO
3695             break;
3696         }
3697         case VOGL_ENTRYPOINT_glXGetVisualFromFBConfig:
3698         {
3699             // TODO
3700             break;
3701         }
3702         case VOGL_ENTRYPOINT_glXGetProcAddress:
3703         case VOGL_ENTRYPOINT_glXGetProcAddressARB:
3704         {
3705             const GLubyte *procName = trace_packet.get_param_client_memory<GLubyte>(0);
3706             vogl_trace_ptr_value trace_func_ptr_value = trace_packet.get_return_ptr_value();
3707
3708             void *pFunc = (void *)GL_ENTRYPOINT(glXGetProcAddress)(procName);
3709
3710             if ((pFunc != NULL) != (trace_func_ptr_value != 0))
3711             {
3712                 process_entrypoint_warning("%s: glXGetProcAddress of function %s %s in the replay, but %s in the trace\n", VOGL_METHOD_NAME,
3713                                            (const char *)procName,
3714                                            (pFunc != NULL) ? "succeeded" : "failed",
3715                                            (trace_func_ptr_value != 0) ? "succeeded" : "failed");
3716             }
3717
3718             break;
3719         }
3720         case VOGL_ENTRYPOINT_glXCreateNewContext:
3721         {
3722             Display *dpy = m_pWindow->get_display();
3723             GLXFBConfig fb_config = m_pWindow->get_fb_configs()[0];
3724             int render_type = trace_packet.get_param_value<GLint>(2);
3725
3726             vogl_trace_context_ptr_value trace_share_context = trace_packet.get_param_ptr_value(3);
3727             GLXContext replay_share_context = remap_context(trace_share_context);
3728
3729             if ((trace_share_context) && (!replay_share_context))
3730             {
3731                 process_entrypoint_warning("%s: Failed remapping trace sharelist context 0x%" PRIx64 "!\n", VOGL_METHOD_NAME, cast_val_to_uint64(trace_share_context));
3732             }
3733
3734             Bool direct = trace_packet.get_param_value<Bool>(4);
3735             vogl_trace_context_ptr_value trace_context = trace_packet.get_return_ptr_value();
3736
3737             if (m_flags & cGLReplayerForceDebugContexts)
3738             {
3739                 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);
3740
3741                 status = create_context_attribs(trace_context, dpy, fb_config, trace_share_context, replay_share_context, direct, NULL, 0, false);
3742                 if (status != cStatusOK)
3743                     return status;
3744             }
3745             else
3746             {
3747                 GLXContext replay_context = GL_ENTRYPOINT(glXCreateNewContext)(dpy, fb_config, render_type, replay_share_context, direct);
3748
3749                 if (!replay_context)
3750                 {
3751                     if (trace_context)
3752                     {
3753                         process_entrypoint_error("%s: Failed creating new GL context!\n", VOGL_METHOD_NAME);
3754                         return cStatusHardFailure;
3755                     }
3756                     else
3757                     {
3758                         process_entrypoint_warning("%s: Successfully created a new GL context where the traced app failed!\n", VOGL_METHOD_NAME);
3759                     }
3760                 }
3761
3762                 if (replay_context)
3763                 {
3764                     if (trace_context)
3765                     {
3766                         context_state *pContext_state = define_new_context(trace_context, replay_context, trace_share_context, direct, VOGL_ENTRYPOINT_glXCreateNewContext, NULL, 0);
3767                         VOGL_NOTE_UNUSED(pContext_state);
3768                     }
3769                     else
3770                     {
3771                         GL_ENTRYPOINT(glXDestroyContext)(m_pWindow->get_display(), replay_context);
3772                     }
3773                 }
3774             }
3775
3776             break;
3777         }
3778         case VOGL_ENTRYPOINT_glXCreateContext:
3779         {
3780             Display *dpy = m_pWindow->get_display();
3781
3782             vogl_trace_context_ptr_value trace_share_context = trace_packet.get_param_ptr_value(2);
3783             GLXContext replay_share_context = remap_context(trace_share_context);
3784
3785             if ((trace_share_context) && (!replay_share_context))
3786             {
3787                 process_entrypoint_warning("%s: Failed remapping trace sharelist context 0x%" PRIx64 "!\n", VOGL_METHOD_NAME, cast_val_to_uint64(trace_share_context));
3788             }
3789
3790             GLXFBConfig fb_config = m_pWindow->get_fb_configs()[0];
3791             Bool direct = trace_packet.get_param_value<Bool>(3);
3792             vogl_trace_context_ptr_value trace_context = trace_packet.get_return_ptr_value();
3793
3794             if (m_flags & cGLReplayerForceDebugContexts)
3795             {
3796                 status = create_context_attribs(trace_context, dpy, fb_config, trace_share_context, replay_share_context, direct, NULL, 0, false);
3797                 if (status != cStatusOK)
3798                     return status;
3799             }
3800             else
3801             {
3802                 XVisualInfo *pVisual_info = GL_ENTRYPOINT(glXGetVisualFromFBConfig)(dpy, fb_config);
3803
3804                 GLXContext replay_context = GL_ENTRYPOINT(glXCreateContext)(dpy, pVisual_info, replay_share_context, direct);
3805
3806                 if (!replay_context)
3807                 {
3808                     if (trace_context)
3809                     {
3810                         process_entrypoint_error("%s: Failed creating new GL context!\n", VOGL_METHOD_NAME);
3811                         return cStatusHardFailure;
3812                     }
3813                     else
3814                     {
3815                         process_entrypoint_warning("%s: Successfully created a new GL context where the traced app failed!\n", VOGL_METHOD_NAME);
3816                     }
3817                 }
3818
3819                 if (replay_context)
3820                 {
3821                     if (trace_context)
3822                     {
3823                         context_state *pContext_state = define_new_context(trace_context, replay_context, trace_share_context, direct, VOGL_ENTRYPOINT_glXCreateContext, NULL, 0);
3824                         VOGL_NOTE_UNUSED(pContext_state);
3825                     }
3826                     else
3827                     {
3828                         GL_ENTRYPOINT(glXDestroyContext)(m_pWindow->get_display(), replay_context);
3829                     }
3830                 }
3831             }
3832
3833             break;
3834         }
3835         case VOGL_ENTRYPOINT_glXCreateContextAttribsARB:
3836         {
3837             Display *dpy = m_pWindow->get_display();
3838             GLXFBConfig fb_config = m_pWindow->get_fb_configs()[0];
3839
3840             vogl_trace_ptr_value trace_share_context = trace_packet.get_param_ptr_value(2);
3841             GLXContext replay_share_context = remap_context(trace_share_context);
3842
3843             if ((trace_share_context) && (!replay_share_context))
3844             {
3845                 process_entrypoint_warning("%s: Failed remapping trace sharelist context 0x%" PRIx64 "!\n", VOGL_METHOD_NAME, cast_val_to_uint64(trace_share_context));
3846             }
3847
3848             Bool direct = trace_packet.get_param_value<Bool>(3);
3849             const int *pTrace_attrib_list = static_cast<const int *>(trace_packet.get_param_client_memory_ptr(4));
3850             const uint trace_attrib_list_size = trace_packet.get_param_client_memory_data_size(4) / sizeof(int);
3851
3852             vogl_trace_ptr_value trace_context = trace_packet.get_return_ptr_value();
3853
3854             status = create_context_attribs(trace_context, dpy, fb_config, trace_share_context, replay_share_context, direct, pTrace_attrib_list, trace_attrib_list_size, true);
3855             if (status != cStatusOK)
3856                 return status;
3857
3858             break;
3859         }
3860         case VOGL_ENTRYPOINT_glXSwapBuffers:
3861         {
3862             check_program_binding_shadow();
3863
3864             if (m_flags & cGLReplayerLowLevelDebugMode)
3865             {
3866                 if (!validate_program_and_shader_handle_tables())
3867                     vogl_warning_printf("%s: Failed validating program/shaders against handle mapping tables\n", VOGL_METHOD_NAME);
3868                 if (!validate_textures())
3869                     vogl_warning_printf("%s: Failed validating texture handles against handle mapping tables\n", VOGL_METHOD_NAME);
3870             }
3871
3872             const Display *dpy = m_pWindow->get_display();
3873             GLXDrawable drawable = m_pWindow->get_xwindow();
3874
3875             if ((m_flags & cGLReplayerHashBackbuffer) || (m_flags & cGLReplayerDumpScreenshots) || (m_flags & cGLReplayerDumpBackbufferHashes))
3876             {
3877                 snapshot_backbuffer();
3878             }
3879
3880             if (m_dump_frontbuffer_filename.has_content())
3881             {
3882                 dump_frontbuffer_to_file(m_dump_frontbuffer_filename);
3883                 m_dump_frontbuffer_filename.clear();
3884             }
3885
3886             GL_ENTRYPOINT(glXSwapBuffers)(dpy, drawable);
3887
3888             if (m_swap_sleep_time)
3889                 vogl_sleep(m_swap_sleep_time);
3890
3891             status = cStatusNextFrame;
3892
3893             m_at_frame_boundary = true;
3894
3895             if (m_flags & cGLReplayerDebugMode)
3896             {
3897                 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);
3898             }
3899
3900             m_frame_index++;
3901             m_total_swaps++;
3902
3903             m_frame_draw_counter = 0;
3904
3905             int win_width = trace_packet.get_key_value_map().get_int(string_hash("win_width"));
3906             int win_height = trace_packet.get_key_value_map().get_int(string_hash("win_height"));
3907             if ((win_width) && (win_height))
3908             {
3909                 if (!(m_flags & cGLReplayerLockWindowDimensions))
3910                 {
3911                     if ((win_width != m_pWindow->get_width()) || (win_height != m_pWindow->get_height()))
3912                     {
3913                         // TODO: This resize might need to be deferred until the window system actually resizes the window.
3914                         //m_pWindow->resize(win_width, win_height);
3915                         trigger_pending_window_resize(win_width, win_height);
3916
3917                         vogl_printf("%s: Resizing window after swap to %ux%u\n", VOGL_METHOD_NAME, win_width, win_height);
3918                     }
3919                 }
3920             }
3921
3922             break;
3923         }
3924         case VOGL_ENTRYPOINT_glXWaitX:
3925         {
3926             VOGL_REPLAY_LOAD_PARAMS_HELPER_glXWaitX;
3927
3928             VOGL_REPLAY_CALL_GL_HELPER_glXWaitX;
3929
3930             break;
3931         }
3932         case VOGL_ENTRYPOINT_glXWaitGL:
3933         {
3934             VOGL_REPLAY_LOAD_PARAMS_HELPER_glXWaitGL;
3935
3936             VOGL_REPLAY_CALL_GL_HELPER_glXWaitGL;
3937
3938             break;
3939         }
3940         case VOGL_ENTRYPOINT_glXIsDirect:
3941         {
3942             const Display *dpy = m_pWindow->get_display();
3943
3944             vogl_trace_ptr_value trace_context = trace_packet.get_param_ptr_value(1);
3945             GLXContext replay_context = remap_context(trace_context);
3946
3947             Bool replay_is_direct = GL_ENTRYPOINT(glXIsDirect)(dpy, replay_context);
3948             Bool trace_is_direct = trace_packet.get_return_value<Bool>();
3949
3950             if (replay_is_direct != trace_is_direct)
3951             {
3952                 process_entrypoint_warning("%s: glXIsDirect() returned different results while replaying (%u) vs tracing (%u)!\n", VOGL_METHOD_NAME, replay_is_direct, trace_is_direct);
3953             }
3954
3955             break;
3956         }
3957         case VOGL_ENTRYPOINT_glXGetCurrentContext:
3958         {
3959             GLXContext replay_context = GL_ENTRYPOINT(glXGetCurrentContext)();
3960             vogl_trace_ptr_value trace_context = trace_packet.get_return_ptr_value();
3961
3962             if ((replay_context != 0) != (trace_context != 0))
3963             {
3964                 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);
3965             }
3966
3967             break;
3968         }
3969         case VOGL_ENTRYPOINT_glXCreateWindow:
3970         case VOGL_ENTRYPOINT_glXDestroyWindow:
3971         case VOGL_ENTRYPOINT_glXChooseVisual:
3972         case VOGL_ENTRYPOINT_glXGetCurrentDisplay:
3973         case VOGL_ENTRYPOINT_glXQueryDrawable:
3974         case VOGL_ENTRYPOINT_glXQueryExtension:
3975         case VOGL_ENTRYPOINT_glXQueryExtensionsString:
3976         case VOGL_ENTRYPOINT_glXSwapIntervalEXT:
3977         case VOGL_ENTRYPOINT_glXSwapIntervalSGI:
3978         case VOGL_ENTRYPOINT_glXGetCurrentDrawable:
3979         case VOGL_ENTRYPOINT_glXGetCurrentReadDrawable:
3980         case VOGL_ENTRYPOINT_glXQueryContext:
3981         case VOGL_ENTRYPOINT_glXGetClientString:
3982         case VOGL_ENTRYPOINT_glXGetConfig:
3983         case VOGL_ENTRYPOINT_glXGetFBConfigs:
3984         {
3985             // TODO
3986             break;
3987         }
3988         default:
3989         {
3990             processed_glx_packet = false;
3991             break;
3992         }
3993     }
3994
3995     if (processed_glx_packet)
3996     {
3997         // TODO: Check for GLX errors?
3998         return status;
3999     }
4000
4001     if (!m_cur_replay_context)
4002     {
4003         process_entrypoint_error("%s: Trace contains a GL call with no current context! Skipping call.\n", VOGL_METHOD_NAME);
4004         return cStatusSoftFailure;
4005     }
4006
4007     VOGL_ASSERT(m_pCur_context_state);
4008     m_pCur_context_state->m_last_call_counter = m_last_parsed_call_counter;
4009
4010 #ifdef VOGL_BUILD_DEBUG
4011     VOGL_ASSERT(get_trace_context_state(m_cur_trace_context) == m_pCur_context_state);
4012 #endif
4013
4014     // Add call to current display list
4015     if ((get_context_state()->is_composing_display_list()) && (g_vogl_entrypoint_descs[entrypoint_id].m_is_listable))
4016     {
4017         if (!vogl_display_list_state::is_call_listable(entrypoint_id, trace_packet))
4018         {
4019             if (!g_vogl_entrypoint_descs[entrypoint_id].m_whitelisted_for_displaylists)
4020                 process_entrypoint_error("%s: Failed serializing trace packet into display list shadow! Call is not whitelisted for display list usage by vogl.\n", VOGL_FUNCTION_NAME);
4021             else
4022                 process_entrypoint_warning("%s: Failed serializing trace packet into display list shadow! Call with these parameters is not listable.\n", VOGL_FUNCTION_NAME);
4023         }
4024         else
4025         {
4026             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))
4027             {
4028                 process_entrypoint_warning("%s: Failed adding current packet to display list shadow!\n", VOGL_METHOD_NAME);
4029             }
4030         }
4031     }
4032
4033     switch (entrypoint_id)
4034     {
4035 // ----- Create simple auto-generated replay funcs - voglgen creates this inc file from the funcs in gl_glx_simple_replay_funcs.txt
4036 // These simple GL entrypoints only take value params that don't require handle remapping, or simple pointers to client memory
4037 // (typically pointers to fixed size buffers, or params directly controlling the size of buffers).
4038 #define VOGL_SIMPLE_REPLAY_FUNC_BEGIN(name, num_params) \
4039     case VOGL_ENTRYPOINT_##name:                        \
4040     { if (!GL_ENTRYPOINT(name)) { process_entrypoint_error("vogl_gl_replayer::process_gl_entrypoint_packet_internal: Can't call NULL GL entrypoint %s (maybe a missing extension?)\n", #name); } else \
4041     GL_ENTRYPOINT(name)(
4042 #define VOGL_SIMPLE_REPLAY_FUNC_PARAM_VALUE(type, index) trace_packet.get_param_value<type>(index)
4043 #define VOGL_SIMPLE_REPLAY_FUNC_PARAM_SEPERATOR ,
4044 #define VOGL_SIMPLE_REPLAY_FUNC_PARAM_CLIENT_MEMORY(type, index) trace_packet.get_param_client_memory<type>(index)
4045 #define VOGL_SIMPLE_REPLAY_FUNC_END(name) ); \
4046     break;                                  \
4047     }
4048 #include "gl_glx_simple_replay_funcs.inc"
4049 #undef VOGL_SIMPLE_REPLAY_FUNC_BEGIN
4050 #undef VOGL_SIMPLE_REPLAY_FUNC_PARAM_VALUE
4051 #undef VOGL_SIMPLE_REPLAY_FUNC_PARAM_SEPERATOR
4052 #undef VOGL_SIMPLE_REPLAY_FUNC_PARAM_CLIENT_MEMORY
4053 #undef VOGL_SIMPLE_REPLAY_FUNC_PARAM_END
4054         // -----
4055         case VOGL_ENTRYPOINT_glXUseXFont:
4056         {
4057             const key_value_map &key_value_map = trace_packet.get_key_value_map();
4058
4059             const dynamic_string *pFont_name = key_value_map.get_string_ptr("font_name");
4060             if ((!pFont_name) || (pFont_name->is_empty()))
4061             {
4062                 process_entrypoint_warning("%s: Couldn't find font_name key, or key was empty - unable to call glXUseXFont()!\n", VOGL_METHOD_NAME);
4063             }
4064             else
4065             {
4066                 XFontStruct *pFont = XLoadQueryFont(m_pWindow->get_display(), pFont_name->get_ptr());
4067                 if (!pFont)
4068                 {
4069                     process_entrypoint_warning("%s: Couldn't load X font %s  - unable to call glXUseXFont()!\n", VOGL_METHOD_NAME, pFont_name->get_ptr());
4070                 }
4071                 else
4072                 {
4073                     GLint first = trace_packet.get_param_value<int>(1);
4074                     GLint count = trace_packet.get_param_value<int>(2);
4075                     int trace_list_base = trace_packet.get_param_value<int>(3);
4076                     GLuint replay_list_base = map_handle(get_shared_state()->m_lists, trace_list_base);
4077
4078                     GL_ENTRYPOINT(glXUseXFont)(pFont->fid, first, count, replay_list_base);
4079
4080                     XFreeFont(m_pWindow->get_display(), pFont);
4081
4082                     if (get_context_state()->is_composing_display_list())
4083                     {
4084                         process_entrypoint_warning("%s: glXUseXFont() called while composing a display list!\n", VOGL_METHOD_NAME);
4085                     }
4086                     else
4087                     {
4088                         if (!get_shared_state()->m_shadow_state.m_display_lists.glx_font(pFont_name->get_ptr(), first, count, trace_list_base))
4089                         {
4090                             process_entrypoint_warning("%s: Failed updating display list shadow\n", VOGL_METHOD_NAME);
4091                         }
4092                     }
4093                 }
4094             }
4095
4096             break;
4097         }
4098         case VOGL_ENTRYPOINT_glBlitFramebufferEXT:
4099         {
4100             VOGL_REPLAY_LOAD_PARAMS_HELPER_glBlitFramebufferEXT;
4101
4102             VOGL_REPLAY_CALL_GL_HELPER_glBlitFramebufferEXT;
4103
4104             if ((status = post_draw_call()) != cStatusOK)
4105                 return status;
4106
4107             break;
4108         }
4109         case VOGL_ENTRYPOINT_glBlitFramebuffer:
4110         {
4111             VOGL_REPLAY_LOAD_PARAMS_HELPER_glBlitFramebuffer;
4112
4113             VOGL_REPLAY_CALL_GL_HELPER_glBlitFramebuffer;
4114
4115             if ((status = post_draw_call()) != cStatusOK)
4116                 return status;
4117
4118             break;
4119         }
4120         case VOGL_ENTRYPOINT_glBegin:
4121         {
4122             if (m_pCur_context_state->m_inside_gl_begin)
4123             {
4124                 process_entrypoint_warning("%s: Got a glBegin while already inside a glBegin\n", VOGL_METHOD_NAME);
4125             }
4126             m_pCur_context_state->m_inside_gl_begin = true;
4127
4128             g_vogl_actual_gl_entrypoints.m_glBegin(trace_packet.get_param_value<GLenum>(0));
4129
4130             break;
4131         }
4132         case VOGL_ENTRYPOINT_glEnd:
4133         {
4134             if (!m_pCur_context_state->m_inside_gl_begin)
4135             {
4136                 process_entrypoint_warning("%s: Got glEnd without a matching glBegin\n", VOGL_METHOD_NAME);
4137             }
4138             m_pCur_context_state->m_inside_gl_begin = false;
4139
4140             g_vogl_actual_gl_entrypoints.m_glEnd();
4141
4142             if ((status = post_draw_call()) != cStatusOK)
4143                 return status;
4144
4145             break;
4146         }
4147         case VOGL_ENTRYPOINT_glGetError:
4148         {
4149             // TODO: Compare trace error vs. replay error
4150
4151             break;
4152         }
4153         case VOGL_ENTRYPOINT_glGetStringi:
4154         {
4155             if (!benchmark_mode())
4156             {
4157                 const GLubyte *pStr = GL_ENTRYPOINT(glGetStringi)(
4158                     trace_packet.get_param_value<GLenum>(0),
4159                     trace_packet.get_param_value<GLuint>(1));
4160                 VOGL_NOTE_UNUSED(pStr);
4161
4162                 // TODO: Compare vs. trace's?
4163             }
4164
4165             break;
4166         }
4167         case VOGL_ENTRYPOINT_glGetString:
4168         {
4169             if (!benchmark_mode())
4170             {
4171                 const GLubyte *pStr = GL_ENTRYPOINT(glGetString)(
4172                     trace_packet.get_param_value<GLenum>(0));
4173                 VOGL_NOTE_UNUSED(pStr);
4174
4175                 // TODO: Compare vs. trace's?
4176             }
4177
4178             break;
4179         }
4180         case VOGL_ENTRYPOINT_glGenFramebuffers:
4181         case VOGL_ENTRYPOINT_glGenFramebuffersEXT:
4182         {
4183             if (!gen_handles(get_context_state()->m_framebuffers,
4184                              trace_packet.get_param_value<GLsizei>(0),
4185                              static_cast<const GLuint *>(trace_packet.get_param_client_memory_ptr(1)),
4186                              (entrypoint_id == VOGL_ENTRYPOINT_glGenFramebuffers) ? GL_ENTRYPOINT(glGenFramebuffers) : GL_ENTRYPOINT(glGenFramebuffersEXT), NULL))
4187                 return cStatusHardFailure;
4188
4189             break;
4190         }
4191         case VOGL_ENTRYPOINT_glBindFramebuffer:
4192         case VOGL_ENTRYPOINT_glBindFramebufferEXT:
4193         {
4194             GLenum target = trace_packet.get_param_value<GLenum>(0);
4195             GLuint trace_handle = trace_packet.get_param_value<GLuint>(1);
4196
4197             GLuint replay_handle = map_handle(get_context_state()->m_framebuffers, trace_handle);
4198
4199             SWITCH_GL_ENTRYPOINT2_VOID(glBindFramebuffer, glBindFramebufferEXT, target, replay_handle);
4200
4201             break;
4202         }
4203         case VOGL_ENTRYPOINT_glGetRenderbufferParameterivEXT:
4204         case VOGL_ENTRYPOINT_glGetRenderbufferParameteriv:
4205         {
4206             if (!benchmark_mode())
4207             {
4208                 GLenum target = trace_packet.get_param_value<GLenum>(0);
4209                 GLenum pname = trace_packet.get_param_value<GLenum>(1);
4210                 GLint *pTrace_params = trace_packet.get_param_client_memory<GLint>(2);
4211                 uint trace_params_size = trace_packet.get_param_client_memory_data_size(2);
4212                 uint trace_params_count = trace_params_size / sizeof(GLint);
4213
4214                 int n = g_gl_enums.get_pname_count(pname);
4215                 if (n <= 0)
4216                 {
4217                     process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
4218                     return cStatusSoftFailure;
4219                 }
4220                 else if (n < static_cast<int>(trace_params_count))
4221                 {
4222                     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);
4223                     return cStatusSoftFailure;
4224                 }
4225                 else
4226                 {
4227                     vogl::growable_array<GLint, 16> params(n + 1);
4228                     params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC;
4229
4230                     SWITCH_GL_ENTRYPOINT2_VOID(glGetRenderbufferParameteriv, glGetRenderbufferParameterivEXT, target, pname, params.get_ptr());
4231
4232                     VOGL_VERIFY(params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC);
4233
4234                     if (memcmp(pTrace_params, params.get_ptr(), n * sizeof(GLint)) != 0)
4235                     {
4236                         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));
4237                     }
4238                 }
4239             }
4240
4241             break;
4242         }
4243         case VOGL_ENTRYPOINT_glCheckFramebufferStatus:
4244         case VOGL_ENTRYPOINT_glCheckFramebufferStatusEXT:
4245         {
4246             GLenum result;
4247             SWITCH_GL_ENTRYPOINT2(glCheckFramebufferStatus, glCheckFramebufferStatusEXT, trace_packet.get_param_value<GLenum>(0));
4248
4249             GLenum trace_status = trace_packet.get_return_value<GLenum>();
4250             if (result != trace_status)
4251             {
4252                 process_entrypoint_warning("%s: glCheckFramebufferStatus returned status 0x%08X during trace, but status 0x%08X during replay\n", VOGL_METHOD_NAME, trace_status, result);
4253             }
4254             break;
4255         }
4256         case VOGL_ENTRYPOINT_glDeleteFramebuffers:
4257         {
4258             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));
4259             break;
4260         }
4261         case VOGL_ENTRYPOINT_glDeleteFramebuffersEXT:
4262         {
4263             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));
4264             break;
4265         }
4266         case VOGL_ENTRYPOINT_glFramebufferTexture:
4267         {
4268             GLenum target = trace_packet.get_param_value<GLenum>(0);
4269             GLenum attachment = trace_packet.get_param_value<GLenum>(1);
4270             GLuint trace_texture = trace_packet.get_param_value<GLuint>(2);
4271             GLuint replay_texture = trace_texture;
4272             GLint level = trace_packet.get_param_value<GLint>(3);
4273
4274             if (!get_shared_state()->m_shadow_state.m_textures.map_handle_to_inv_handle(trace_texture, replay_texture))
4275             {
4276                 if (trace_texture)
4277                     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);
4278             }
4279
4280             GL_ENTRYPOINT(glFramebufferTexture)(target, attachment, replay_texture, level);
4281
4282             break;
4283         }
4284         case VOGL_ENTRYPOINT_glFramebufferTextureLayer:
4285         case VOGL_ENTRYPOINT_glFramebufferTextureLayerEXT:
4286         {
4287             GLenum target = trace_packet.get_param_value<GLenum>(0);
4288             GLenum attachment = trace_packet.get_param_value<GLenum>(1);
4289             GLuint trace_texture = trace_packet.get_param_value<GLuint>(2);
4290             GLuint replay_texture = trace_texture;
4291             GLint level = trace_packet.get_param_value<GLint>(3);
4292             GLint layer = trace_packet.get_param_value<GLint>(4);
4293
4294             if (!get_shared_state()->m_shadow_state.m_textures.map_handle_to_inv_handle(trace_texture, replay_texture))
4295             {
4296                 if (trace_texture)
4297                     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);
4298             }
4299
4300             SWITCH_GL_ENTRYPOINT2_VOID(glFramebufferTextureLayer, glFramebufferTextureLayerEXT, target, attachment, replay_texture, level, layer);
4301
4302             break;
4303         }
4304         case VOGL_ENTRYPOINT_glFramebufferTexture1DEXT:
4305         case VOGL_ENTRYPOINT_glFramebufferTexture1D:
4306         case VOGL_ENTRYPOINT_glFramebufferTexture2DEXT:
4307         case VOGL_ENTRYPOINT_glFramebufferTexture2D:
4308         case VOGL_ENTRYPOINT_glFramebufferTexture3DEXT:
4309         case VOGL_ENTRYPOINT_glFramebufferTexture3D:
4310         {
4311             GLenum target = trace_packet.get_param_value<GLenum>(0);
4312             GLenum attachment = trace_packet.get_param_value<GLenum>(1);
4313             GLenum textarget = trace_packet.get_param_value<GLenum>(2);
4314             GLuint trace_texture = trace_packet.get_param_value<GLuint>(3);
4315             GLuint replay_texture = trace_texture;
4316             GLint level = trace_packet.get_param_value<GLint>(4);
4317
4318             if (!get_shared_state()->m_shadow_state.m_textures.map_handle_to_inv_handle(trace_texture, replay_texture))
4319             {
4320                 if (trace_texture)
4321                     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);
4322             }
4323
4324             switch (entrypoint_id)
4325             {
4326                 case VOGL_ENTRYPOINT_glFramebufferTexture1DEXT:
4327                     GL_ENTRYPOINT(glFramebufferTexture1DEXT)(target, attachment, textarget, replay_texture, level);
4328                     break;
4329                 case VOGL_ENTRYPOINT_glFramebufferTexture1D:
4330                     GL_ENTRYPOINT(glFramebufferTexture1D)(target, attachment, textarget, replay_texture, level);
4331                     break;
4332                 case VOGL_ENTRYPOINT_glFramebufferTexture2DEXT:
4333                     GL_ENTRYPOINT(glFramebufferTexture2DEXT)(target, attachment, textarget, replay_texture, level);
4334                     break;
4335                 case VOGL_ENTRYPOINT_glFramebufferTexture2D:
4336                     GL_ENTRYPOINT(glFramebufferTexture2D)(target, attachment, textarget, replay_texture, level);
4337                     break;
4338                 case VOGL_ENTRYPOINT_glFramebufferTexture3DEXT:
4339                     GL_ENTRYPOINT(glFramebufferTexture3DEXT)(target, attachment, textarget, replay_texture, level, trace_packet.get_param_value<GLint>(5));
4340                     break;
4341                 case VOGL_ENTRYPOINT_glFramebufferTexture3D:
4342                     GL_ENTRYPOINT(glFramebufferTexture3D)(target, attachment, textarget, replay_texture, level, trace_packet.get_param_value<GLint>(5));
4343                     break;
4344                 default:
4345                     break;
4346             }
4347
4348             break;
4349         }
4350         case VOGL_ENTRYPOINT_glGenTextures:
4351         {
4352             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))
4353                 return cStatusHardFailure;
4354             break;
4355         }
4356         case VOGL_ENTRYPOINT_glGenTexturesEXT:
4357         {
4358             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))
4359                 return cStatusHardFailure;
4360             break;
4361         }
4362         case VOGL_ENTRYPOINT_glDeleteTextures:
4363         {
4364             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));
4365             break;
4366         }
4367         case VOGL_ENTRYPOINT_glDeleteTexturesEXT:
4368         {
4369             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));
4370             break;
4371         }
4372         case VOGL_ENTRYPOINT_glBindMultiTextureEXT:
4373         {
4374             VOGL_REPLAY_LOAD_PARAMS_HELPER_glBindMultiTextureEXT;
4375
4376             GLuint trace_texture = texture;
4377             map_handle(get_shared_state()->m_shadow_state.m_textures, trace_texture, texture);
4378
4379             if ((texture) && (get_context_state()->m_current_display_list_mode != GL_COMPILE))
4380                 check_gl_error();
4381
4382             VOGL_REPLAY_CALL_GL_HELPER_glBindMultiTextureEXT;
4383
4384             if ((texture) && (get_context_state()->m_current_display_list_mode != GL_COMPILE))
4385             {
4386                 if (!check_gl_error())
4387                     get_shared_state()->m_shadow_state.m_textures.update(trace_texture, texture, target);
4388             }
4389
4390             break;
4391         }
4392         case VOGL_ENTRYPOINT_glBindTexture:
4393         case VOGL_ENTRYPOINT_glBindTextureEXT:
4394         {
4395             VOGL_REPLAY_LOAD_PARAMS_HELPER_glBindTexture;
4396
4397             GLuint trace_texture = texture;
4398             map_handle(get_shared_state()->m_shadow_state.m_textures, trace_texture, texture);
4399
4400             if ((texture) && (get_context_state()->m_current_display_list_mode != GL_COMPILE))
4401                 check_gl_error();
4402
4403             SWITCH_GL_ENTRYPOINT2_VOID(glBindTexture, glBindTextureEXT, target, texture);
4404
4405             if ((texture) && (get_context_state()->m_current_display_list_mode != GL_COMPILE))
4406             {
4407                 if (!check_gl_error())
4408                     get_shared_state()->m_shadow_state.m_textures.update(trace_texture, texture, target);
4409             }
4410
4411             break;
4412         }
4413         case VOGL_ENTRYPOINT_glBindSampler:
4414         {
4415             GLuint replay_handle = map_handle(get_shared_state()->m_sampler_objects, trace_packet.get_param_value<GLuint>(1));
4416             GL_ENTRYPOINT(glBindSampler)(trace_packet.get_param_value<GLuint>(0), replay_handle);
4417             break;
4418         }
4419         case VOGL_ENTRYPOINT_glDeleteSamplers:
4420         {
4421             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));
4422             break;
4423         }
4424         case VOGL_ENTRYPOINT_glGenSamplers:
4425         {
4426             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))
4427                 return cStatusHardFailure;
4428             break;
4429         }
4430
4431         case VOGL_ENTRYPOINT_glSamplerParameterf:
4432         {
4433             VOGL_REPLAY_LOAD_PARAMS_HELPER_glSamplerParameterf;
4434             sampler = map_handle(get_shared_state()->m_sampler_objects, sampler);
4435             VOGL_REPLAY_CALL_GL_HELPER_glSamplerParameterf;
4436             break;
4437         }
4438         case VOGL_ENTRYPOINT_glSamplerParameteri:
4439         {
4440             VOGL_REPLAY_LOAD_PARAMS_HELPER_glSamplerParameteri;
4441             sampler = map_handle(get_shared_state()->m_sampler_objects, sampler);
4442             VOGL_REPLAY_CALL_GL_HELPER_glSamplerParameteri;
4443             break;
4444         }
4445         case VOGL_ENTRYPOINT_glSamplerParameterfv:
4446         {
4447             VOGL_REPLAY_LOAD_PARAMS_HELPER_glSamplerParameterfv;
4448             sampler = map_handle(get_shared_state()->m_sampler_objects, sampler);
4449             VOGL_REPLAY_CALL_GL_HELPER_glSamplerParameterfv;
4450             break;
4451         }
4452         case VOGL_ENTRYPOINT_glSamplerParameteriv:
4453         {
4454             VOGL_REPLAY_LOAD_PARAMS_HELPER_glSamplerParameteriv;
4455             sampler = map_handle(get_shared_state()->m_sampler_objects, sampler);
4456             VOGL_REPLAY_CALL_GL_HELPER_glSamplerParameteriv;
4457             break;
4458         }
4459         case VOGL_ENTRYPOINT_glSamplerParameterIiv:
4460         {
4461             VOGL_REPLAY_LOAD_PARAMS_HELPER_glSamplerParameterIiv;
4462             sampler = map_handle(get_shared_state()->m_sampler_objects, sampler);
4463             VOGL_REPLAY_CALL_GL_HELPER_glSamplerParameterIiv;
4464             break;
4465         }
4466         case VOGL_ENTRYPOINT_glSamplerParameterIuiv:
4467         {
4468             VOGL_REPLAY_LOAD_PARAMS_HELPER_glSamplerParameterIuiv;
4469             sampler = map_handle(get_shared_state()->m_sampler_objects, sampler);
4470             VOGL_REPLAY_CALL_GL_HELPER_glSamplerParameterIuiv;
4471             break;
4472         }
4473         case VOGL_ENTRYPOINT_glGenBuffers:
4474         case VOGL_ENTRYPOINT_glGenBuffersARB:
4475         {
4476             uint n = trace_packet.get_param_value<GLsizei>(0);
4477             const GLuint *pTrace_handles = static_cast<const GLuint *>(trace_packet.get_param_client_memory_ptr(1));
4478
4479             if (entrypoint_id == VOGL_ENTRYPOINT_glGenBuffers)
4480             {
4481                 if (!gen_handles(get_shared_state()->m_buffers, n, pTrace_handles, GL_ENTRYPOINT(glGenBuffers), NULL))
4482                     return cStatusHardFailure;
4483             }
4484             else
4485             {
4486                 if (!gen_handles(get_shared_state()->m_buffers, n, pTrace_handles, GL_ENTRYPOINT(glGenBuffersARB), NULL))
4487                     return cStatusHardFailure;
4488             }
4489
4490             if (pTrace_handles)
4491             {
4492                 for (uint i = 0; i < n; i++)
4493                 {
4494                     if (pTrace_handles[i])
4495                         get_shared_state()->m_buffer_targets.insert(pTrace_handles[i], GL_NONE);
4496                 }
4497             }
4498
4499             break;
4500         }
4501         case VOGL_ENTRYPOINT_glDeleteBuffers:
4502         case VOGL_ENTRYPOINT_glDeleteBuffersARB:
4503         {
4504             GLsizei trace_n = trace_packet.get_param_value<GLsizei>(0);
4505             const GLuint *pTrace_ids = static_cast<const GLuint *>(trace_packet.get_param_client_memory_ptr(1));
4506             uint trace_ids_count = trace_packet.get_param_client_memory_data_size(1);
4507
4508             if ((pTrace_ids) && (static_cast<GLsizei>(trace_ids_count) < trace_n))
4509             {
4510                 process_entrypoint_warning("%s: trace_ids trace array is too small\n", VOGL_METHOD_NAME);
4511                 return cStatusHardFailure;
4512             }
4513
4514             for (GLsizei iter = 0; iter < trace_n; iter++)
4515             {
4516                 GLuint trace_id = pTrace_ids[iter];
4517                 if (!trace_id)
4518                     continue;
4519
4520                 if (!get_shared_state()->m_buffer_targets.erase(trace_id))
4521                 {
4522                     process_entrypoint_warning("%s: Couldn't find trace buffer id %u in buffer target map!\n", VOGL_METHOD_NAME, trace_id);
4523                 }
4524
4525                 gl_handle_hash_map::const_iterator it = get_shared_state()->m_buffers.find(trace_id);
4526                 if (it == get_shared_state()->m_buffers.end())
4527                 {
4528                     process_entrypoint_warning("%s: Couldn't map trace buffer id %u to GL buffer id\n", VOGL_METHOD_NAME, trace_id);
4529                     continue;
4530                 }
4531
4532                 GLuint replay_id = it->second;
4533
4534                 vogl_mapped_buffer_desc_vec &mapped_bufs = get_shared_state()->m_shadow_state.m_mapped_buffers;
4535
4536                 for (uint i = 0; i < mapped_bufs.size(); i++)
4537                 {
4538                     if (mapped_bufs[i].m_buffer == replay_id)
4539                     {
4540                         process_entrypoint_warning("%s: glDeleteBuffers() called on mapped trace buffer %u GL buffer %u\n", VOGL_METHOD_NAME, trace_id, replay_id);
4541
4542                         mapped_bufs.erase_unordered(i);
4543                         break;
4544                     }
4545                 }
4546             }
4547
4548             if (entrypoint_id == VOGL_ENTRYPOINT_glDeleteBuffers)
4549                 delete_handles(get_shared_state()->m_buffers, trace_n, pTrace_ids, GL_ENTRYPOINT(glDeleteBuffers));
4550             else
4551                 delete_handles(get_shared_state()->m_buffers, trace_n, pTrace_ids, GL_ENTRYPOINT(glDeleteBuffersARB));
4552
4553             break;
4554         }
4555         case VOGL_ENTRYPOINT_glGenProgramsARB:
4556         {
4557             // arb program objects
4558             VOGL_REPLAY_LOAD_PARAMS_HELPER_glGenProgramsARB;
4559
4560             if (!gen_handles(get_shared_state()->m_arb_programs, n, pTrace_programs, GL_ENTRYPOINT(glGenProgramsARB), NULL))
4561                 return cStatusHardFailure;
4562
4563             for (GLsizei i = 0; (pTrace_programs) && (i < n); i++)
4564                 if (pTrace_programs[i])
4565                     get_shared_state()->m_arb_program_targets.insert(pTrace_programs[i], GL_NONE);
4566
4567             break;
4568         }
4569         case VOGL_ENTRYPOINT_glDeleteProgramsARB:
4570         {
4571             // arb program objects
4572             VOGL_REPLAY_LOAD_PARAMS_HELPER_glDeleteProgramsARB;
4573
4574             for (GLsizei i = 0; (pTrace_programs) && (i < n); i++)
4575                 get_shared_state()->m_arb_program_targets.erase(pTrace_programs[i]);
4576
4577             delete_handles(get_shared_state()->m_arb_programs, n, pTrace_programs, GL_ENTRYPOINT(glDeleteProgramsARB));
4578             break;
4579         }
4580         case VOGL_ENTRYPOINT_glBindProgramARB:
4581         {
4582             // arb program objects
4583             VOGL_REPLAY_LOAD_PARAMS_HELPER_glBindProgramARB;
4584
4585             GLuint trace_program = program;
4586             gl_handle_hash_map::const_iterator it;
4587             if (program)
4588             {
4589                 it = get_shared_state()->m_arb_programs.find(program);
4590                 if (it != get_shared_state()->m_arb_programs.end())
4591                     program = it->second;
4592                 else
4593                     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);
4594             }
4595
4596             check_gl_error();
4597
4598             VOGL_REPLAY_CALL_GL_HELPER_glBindProgramARB;
4599
4600             if (!check_gl_error() && (get_context_state()->m_current_display_list_mode != GL_COMPILE))
4601             {
4602                 if (trace_program)
4603                 {
4604                     if (it == get_shared_state()->m_arb_programs.end())
4605                         get_shared_state()->m_arb_programs.insert(trace_program, program);
4606
4607                     get_shared_state()->m_arb_program_targets[trace_program] = target;
4608                 }
4609             }
4610             else
4611             {
4612                 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));
4613                 return cStatusGLError;
4614             }
4615
4616             break;
4617         }
4618         case VOGL_ENTRYPOINT_glIsProgramARB:
4619         {
4620             if (!benchmark_mode())
4621             {
4622                 VOGL_REPLAY_LOAD_PARAMS_HELPER_glIsProgramARB;
4623
4624                 GLuint trace_program = program;
4625                 program = map_handle(get_shared_state()->m_arb_programs, program);
4626
4627                 GLboolean replay_result = VOGL_REPLAY_CALL_GL_HELPER_glIsProgramARB;
4628                 GLboolean trace_result = trace_packet.get_return_value<GLboolean>();
4629
4630                 if (trace_result != replay_result)
4631                     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);
4632             }
4633
4634             break;
4635         }
4636         case VOGL_ENTRYPOINT_glGenQueries:
4637         case VOGL_ENTRYPOINT_glGenQueriesARB:
4638         {
4639             GLsizei n = trace_packet.get_param_value<GLsizei>(0);
4640             vogl::growable_array<GLuint, 16> replay_handles(n);
4641
4642             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()))
4643                 return cStatusHardFailure;
4644
4645             for (GLsizei i = 0; i < n; i++)
4646                 get_shared_state()->m_query_targets[replay_handles[i]] = GL_NONE;
4647
4648             break;
4649         }
4650         case VOGL_ENTRYPOINT_glDeleteQueries:
4651         case VOGL_ENTRYPOINT_glDeleteQueriesARB:
4652         {
4653             GLsizei n = trace_packet.get_param_value<GLsizei>(0);
4654             const GLuint *pTrace_ids = static_cast<const GLuint *>(trace_packet.get_param_client_memory_ptr(1));
4655
4656             if (pTrace_ids)
4657             {
4658                 for (GLsizei i = 0; i < n; i++)
4659                 {
4660                     GLuint trace_id = pTrace_ids[i];
4661                     if (!trace_id)
4662                         continue;
4663                     gl_handle_hash_map::const_iterator it(get_shared_state()->m_queries.find(trace_id));
4664                     if (it != get_shared_state()->m_queries.end())
4665                         get_shared_state()->m_query_targets.erase(it->second);
4666                 }
4667             }
4668
4669             if (entrypoint_id == VOGL_ENTRYPOINT_glDeleteQueries)
4670                 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));
4671             else
4672                 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));
4673
4674             break;
4675         }
4676         case VOGL_ENTRYPOINT_glGenRenderbuffersEXT:
4677         {
4678             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))
4679                 return cStatusHardFailure;
4680             break;
4681         }
4682         case VOGL_ENTRYPOINT_glGenRenderbuffers:
4683         {
4684             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))
4685                 return cStatusHardFailure;
4686             break;
4687         }
4688         case VOGL_ENTRYPOINT_glDeleteRenderbuffersEXT:
4689         {
4690             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));
4691             break;
4692         }
4693         case VOGL_ENTRYPOINT_glDeleteRenderbuffers:
4694         {
4695             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));
4696             break;
4697         }
4698         case VOGL_ENTRYPOINT_glIsRenderbuffer:
4699         {
4700             if (!benchmark_mode())
4701             {
4702                 GLboolean replay_result = GL_ENTRYPOINT(glIsRenderbuffer)(map_handle(get_shared_state()->m_shadow_state.m_rbos, trace_packet.get_param_value<GLuint>(0)));
4703                 GLboolean trace_result = trace_packet.get_return_value<GLboolean>();
4704                 if (replay_result != trace_result)
4705                 {
4706                     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);
4707                 }
4708             }
4709             break;
4710         }
4711         case VOGL_ENTRYPOINT_glIsRenderbufferEXT:
4712         {
4713             if (!benchmark_mode())
4714             {
4715                 GLboolean replay_result = GL_ENTRYPOINT(glIsRenderbufferEXT)(map_handle(get_shared_state()->m_shadow_state.m_rbos, trace_packet.get_param_value<GLuint>(0)));
4716                 GLboolean trace_result = trace_packet.get_return_value<GLboolean>();
4717                 if (replay_result != trace_result)
4718                 {
4719                     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);
4720                 }
4721             }
4722             break;
4723         }
4724         case VOGL_ENTRYPOINT_glBindRenderbufferEXT:
4725         {
4726             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)));
4727             break;
4728         }
4729         case VOGL_ENTRYPOINT_glBindRenderbuffer:
4730         {
4731             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)));
4732             break;
4733         }
4734         case VOGL_ENTRYPOINT_glFramebufferRenderbufferEXT:
4735         {
4736             GL_ENTRYPOINT(glFramebufferRenderbufferEXT)(
4737                 trace_packet.get_param_value<GLenum>(0),
4738                 trace_packet.get_param_value<GLenum>(1),
4739                 trace_packet.get_param_value<GLenum>(2),
4740                 map_handle(get_shared_state()->m_shadow_state.m_rbos, trace_packet.get_param_value<GLuint>(3)));
4741             break;
4742         }
4743         case VOGL_ENTRYPOINT_glFramebufferRenderbuffer:
4744         {
4745             GL_ENTRYPOINT(glFramebufferRenderbuffer)(
4746                 trace_packet.get_param_value<GLenum>(0),
4747                 trace_packet.get_param_value<GLenum>(1),
4748                 trace_packet.get_param_value<GLenum>(2),
4749                 map_handle(get_shared_state()->m_shadow_state.m_rbos, trace_packet.get_param_value<GLuint>(3)));
4750             break;
4751         }
4752         case VOGL_ENTRYPOINT_glUseProgramObjectARB:
4753         case VOGL_ENTRYPOINT_glUseProgram:
4754         {
4755             GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
4756             handle_use_program(trace_handle, entrypoint_id);
4757             break;
4758         }
4759         case VOGL_ENTRYPOINT_glProgramParameteri:
4760         case VOGL_ENTRYPOINT_glProgramParameteriARB:
4761         case VOGL_ENTRYPOINT_glProgramParameteriEXT:
4762         {
4763             VOGL_REPLAY_LOAD_PARAMS_HELPER_glProgramParameteri;
4764
4765             program = map_handle(get_shared_state()->m_shadow_state.m_objs, program);
4766
4767             if (entrypoint_id == VOGL_ENTRYPOINT_glProgramParameteriARB)
4768                 VOGL_REPLAY_CALL_GL_HELPER_glProgramParameteriARB;
4769             else if (entrypoint_id == VOGL_ENTRYPOINT_glProgramParameteriEXT)
4770                 VOGL_REPLAY_CALL_GL_HELPER_glProgramParameteriEXT;
4771             else
4772                 VOGL_REPLAY_CALL_GL_HELPER_glProgramParameteri;
4773
4774             break;
4775         }
4776         case VOGL_ENTRYPOINT_glBindFragDataLocation:
4777         case VOGL_ENTRYPOINT_glBindFragDataLocationEXT:
4778         {
4779             VOGL_REPLAY_LOAD_PARAMS_HELPER_glBindFragDataLocation;
4780
4781             program = map_handle(get_shared_state()->m_shadow_state.m_objs, program);
4782
4783             if (entrypoint_id == VOGL_ENTRYPOINT_glBindFragDataLocation)
4784                 VOGL_REPLAY_CALL_GL_HELPER_glBindFragDataLocation;
4785             else
4786                 VOGL_REPLAY_CALL_GL_HELPER_glBindFragDataLocationEXT;
4787
4788             break;
4789         }
4790         case VOGL_ENTRYPOINT_glBindFragDataLocationIndexed:
4791         {
4792             VOGL_REPLAY_LOAD_PARAMS_HELPER_glBindFragDataLocationIndexed;
4793
4794             program = map_handle(get_shared_state()->m_shadow_state.m_objs, program);
4795
4796             VOGL_REPLAY_CALL_GL_HELPER_glBindFragDataLocationIndexed;
4797
4798             break;
4799         }
4800         case VOGL_ENTRYPOINT_glValidateProgramARB:
4801         {
4802             VOGL_REPLAY_LOAD_PARAMS_HELPER_glValidateProgramARB;
4803
4804             programObj = map_handle(get_shared_state()->m_shadow_state.m_objs, programObj);
4805
4806             VOGL_REPLAY_CALL_GL_HELPER_glValidateProgramARB;
4807
4808             break;
4809         }
4810         case VOGL_ENTRYPOINT_glValidateProgram:
4811         {
4812             VOGL_REPLAY_LOAD_PARAMS_HELPER_glValidateProgram;
4813
4814             program = map_handle(get_shared_state()->m_shadow_state.m_objs, program);
4815
4816             VOGL_REPLAY_CALL_GL_HELPER_glValidateProgram;
4817
4818             break;
4819         }
4820         case VOGL_ENTRYPOINT_glCreateProgram:
4821         case VOGL_ENTRYPOINT_glCreateProgramObjectARB:
4822         {
4823             GLuint trace_handle = trace_packet.get_return_value<GLuint>();
4824             if (trace_handle)
4825             {
4826                 GLuint replay_handle;
4827
4828                 if (entrypoint_id == VOGL_ENTRYPOINT_glCreateProgram)
4829                     replay_handle = GL_ENTRYPOINT(glCreateProgram)();
4830                 else
4831                     replay_handle = GL_ENTRYPOINT(glCreateProgramObjectARB)();
4832
4833                 VOGL_ASSERT(!replay_handle || (GL_ENTRYPOINT(glIsProgram)(replay_handle) != 0));
4834
4835                 if (!gen_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle, replay_handle, VOGL_PROGRAM_OBJECT))
4836                     return cStatusHardFailure;
4837             }
4838             break;
4839         }
4840         case VOGL_ENTRYPOINT_glDeleteProgram:
4841         {
4842             GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
4843             handle_delete_program(trace_handle);
4844
4845             break;
4846         }
4847         case VOGL_ENTRYPOINT_glDeleteObjectARB:
4848         {
4849             GLuint trace_handle = trace_packet.get_param_value<GLenum>(0);
4850             GLenum target = get_shared_state()->m_shadow_state.m_objs.get_target(trace_handle);
4851
4852             if (target == VOGL_SHADER_OBJECT)
4853                 handle_delete_shader(trace_handle);
4854             else if (target == VOGL_PROGRAM_OBJECT)
4855                 handle_delete_program(trace_handle);
4856             else
4857             {
4858                 GLuint replay_handle = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle);
4859
4860                 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);
4861                 return cStatusSoftFailure;
4862             }
4863
4864             break;
4865         }
4866         case VOGL_ENTRYPOINT_glDeleteShader:
4867         {
4868             GLuint trace_shader = trace_packet.get_param_value<GLuint>(0);
4869             handle_delete_shader(trace_shader);
4870
4871             break;
4872         }
4873         case VOGL_ENTRYPOINT_glCreateShader:
4874         case VOGL_ENTRYPOINT_glCreateShaderObjectARB:
4875         {
4876             GLuint trace_handle = trace_packet.get_return_value<GLuint>();
4877             if (trace_handle)
4878             {
4879                 GLuint replay_handle;
4880
4881                 if (entrypoint_id == VOGL_ENTRYPOINT_glCreateShader)
4882                     replay_handle = GL_ENTRYPOINT(glCreateShader)(trace_packet.get_param_value<GLenum>(0));
4883                 else
4884                     replay_handle = GL_ENTRYPOINT(glCreateShaderObjectARB)(trace_packet.get_param_value<GLenum>(0));
4885
4886                 VOGL_ASSERT(!replay_handle || (GL_ENTRYPOINT(glIsShader)(replay_handle) != 0));
4887
4888                 if (!gen_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle, replay_handle, VOGL_SHADER_OBJECT))
4889                     return cStatusHardFailure;
4890             }
4891             break;
4892         }
4893         case VOGL_ENTRYPOINT_glAttachShader:
4894         {
4895             GL_ENTRYPOINT(glAttachShader)(
4896                 map_handle(get_shared_state()->m_shadow_state.m_objs, trace_packet.get_param_value<GLuint>(0)),
4897                 map_handle(get_shared_state()->m_shadow_state.m_objs, trace_packet.get_param_value<GLuint>(1)));
4898             break;
4899         }
4900         case VOGL_ENTRYPOINT_glAttachObjectARB:
4901         {
4902             GL_ENTRYPOINT(glAttachObjectARB)(
4903                 map_handle(get_shared_state()->m_shadow_state.m_objs, trace_packet.get_param_value<GLhandleARB>(0)),
4904                 map_handle(get_shared_state()->m_shadow_state.m_objs, trace_packet.get_param_value<GLhandleARB>(1)));
4905             break;
4906         }
4907         case VOGL_ENTRYPOINT_glDetachShader:
4908         {
4909             handle_detach_shader(entrypoint_id);
4910
4911             break;
4912         }
4913         case VOGL_ENTRYPOINT_glDetachObjectARB:
4914         {
4915             GLhandleARB trace_object_handle = trace_packet.get_param_value<GLhandleARB>(1);
4916
4917             GLenum target = get_shared_state()->m_shadow_state.m_objs.get_target(trace_object_handle);
4918
4919             if (target == VOGL_SHADER_OBJECT)
4920                 handle_detach_shader(entrypoint_id);
4921             else
4922             {
4923                 GLuint replay_object_handle = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_object_handle);
4924                 GL_ENTRYPOINT(glDetachObjectARB)(map_handle(get_shared_state()->m_shadow_state.m_objs, trace_packet.get_param_value<GLhandleARB>(0)), replay_object_handle);
4925             }
4926
4927             break;
4928         }
4929         case VOGL_ENTRYPOINT_glBindAttribLocation:
4930         {
4931             GL_ENTRYPOINT(glBindAttribLocation)(
4932                 map_handle(get_shared_state()->m_shadow_state.m_objs, trace_packet.get_param_value<GLuint>(0)),
4933                 trace_packet.get_param_value<GLuint>(1),
4934                 trace_packet.get_param_client_memory<GLchar>(2));
4935             break;
4936         }
4937         case VOGL_ENTRYPOINT_glBindAttribLocationARB:
4938         {
4939             GL_ENTRYPOINT(glBindAttribLocationARB)(
4940                 map_handle(get_shared_state()->m_shadow_state.m_objs, trace_packet.get_param_value<GLhandleARB>(0)),
4941                 trace_packet.get_param_value<GLuint>(1),
4942                 trace_packet.get_param_client_memory<GLcharARB>(2));
4943             break;
4944         }
4945         case VOGL_ENTRYPOINT_glGetObjectParameterivARB:
4946         {
4947             if (!benchmark_mode())
4948             {
4949                 GLenum pname = trace_packet.get_param_value<GLenum>(1);
4950                 const GLint *pParams = trace_packet.get_param_client_memory<GLint>(2);
4951
4952                 int n = g_gl_enums.get_pname_count(pname);
4953                 if (n <= 0)
4954                 {
4955                     process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
4956                     return cStatusSoftFailure;
4957                 }
4958                 else
4959                 {
4960                     vogl::growable_array<GLint, 16> params(n + 1);
4961                     params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC;
4962
4963                     GL_ENTRYPOINT(glGetObjectParameterivARB)(
4964                         map_handle(get_shared_state()->m_shadow_state.m_objs, trace_packet.get_param_value<GLhandleARB>(0)),
4965                         pname,
4966                         params.get_ptr());
4967
4968                     VOGL_VERIFY(params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC);
4969
4970                     if (memcmp(pParams, params.get_ptr(), n * sizeof(GLint)) != 0)
4971                     {
4972                         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));
4973                     }
4974                 }
4975             }
4976             break;
4977         }
4978         case VOGL_ENTRYPOINT_glGetBufferParameteriv:
4979         {
4980             if (!benchmark_mode())
4981             {
4982                 GLenum target = trace_packet.get_param_value<GLenum>(0);
4983                 GLenum value = trace_packet.get_param_value<GLenum>(1);
4984                 const GLint *pTrace_data = trace_packet.get_param_client_memory<GLint>(2);
4985
4986                 int n = g_gl_enums.get_pname_count(value);
4987                 if (n <= 0)
4988                 {
4989                     process_entrypoint_error("%s: Can't determine count of GL value 0x%08X\n", VOGL_METHOD_NAME, value);
4990                     return cStatusSoftFailure;
4991                 }
4992                 else
4993                 {
4994                     vogl::growable_array<GLint, 16> data(n + 1);
4995                     data[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC;
4996
4997                     GL_ENTRYPOINT(glGetBufferParameteriv)(target, value, data.get_ptr());
4998
4999                     VOGL_VERIFY(data[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC);
5000
5001                     GLint trace_data = pTrace_data ? pTrace_data[0] : -1;
5002                     if (data[0] != trace_data)
5003                     {
5004                         process_entrypoint_warning("%s: Replay's returned GLint differed from trace's!\n", VOGL_METHOD_NAME);
5005                         vogl_warning_printf("Trace data: %i, Replay data: %i\n", trace_data, data[0]);
5006                     }
5007                 }
5008             }
5009
5010             break;
5011         }
5012
5013         case VOGL_ENTRYPOINT_glGetBufferPointerv:
5014         {
5015             if (!benchmark_mode())
5016             {
5017                 GLvoid *pReplay_ptr = NULL;
5018                 GL_ENTRYPOINT(glGetBufferPointerv)(trace_packet.get_param_value<GLenum>(0), trace_packet.get_param_value<GLenum>(1), &pReplay_ptr);
5019
5020                 vogl_client_memory_array trace_void_ptr_array = trace_packet.get_param_client_memory_array(2);
5021                 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;
5022
5023                 if ((pReplay_ptr != NULL) != (first_trace_ptr != 0))
5024                 {
5025                     process_entrypoint_warning("%s: First replay's returned GLvoid* differed from trace's!\n", VOGL_METHOD_NAME);
5026                     vogl_warning_printf("Trace: 0x%" PRIx64 ", Replay: 0x%" PRIx64 "\n", first_trace_ptr, reinterpret_cast<uint64_t>(pReplay_ptr));
5027                 }
5028             }
5029
5030             break;
5031         }
5032         case VOGL_ENTRYPOINT_glShaderSource:
5033         case VOGL_ENTRYPOINT_glShaderSourceARB:
5034         {
5035             const status_t status = handle_ShaderSource(trace_packet.get_param_value<GLhandleARB>(0),
5036                                                         trace_packet.get_param_value<GLsizei>(1),
5037                                                         trace_packet.get_param_client_memory_array(2),
5038                                                         trace_packet.get_param_client_memory<const GLint>(3));
5039             if (status != cStatusOK)
5040                 return status;
5041             break;
5042         }
5043         case VOGL_ENTRYPOINT_glGetProgramInfoLog:
5044         {
5045             GLuint trace_object = trace_packet.get_param_value<GLuint>(0);
5046             GLuint replay_object = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_object);
5047
5048             GLint length = -1;
5049             GL_ENTRYPOINT(glGetProgramiv)(replay_object, GL_INFO_LOG_LENGTH, &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<GLchar> log(length);
5058
5059                 GLsizei actual_length = 0;
5060                 GL_ENTRYPOINT(glGetProgramInfoLog)(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_glGetPointerv:
5071         {
5072             if (!benchmark_mode())
5073             {
5074                 GLvoid *ptr = NULL;
5075                 GL_ENTRYPOINT(glGetPointerv)(trace_packet.get_param_value<GLenum>(0), &ptr);
5076
5077                 // TODO: Differ vs. trace's in some way?
5078             }
5079
5080             break;
5081         }
5082         case VOGL_ENTRYPOINT_glGetInfoLogARB:
5083         {
5084             GLhandleARB trace_object = trace_packet.get_param_value<GLhandleARB>(0);
5085             GLhandleARB replay_object = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_object);
5086
5087             GLsizei length = -1;
5088             GL_ENTRYPOINT(glGetObjectParameterivARB)(replay_object, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
5089             if (length < 0)
5090             {
5091                 process_entrypoint_error("%s: Failed retrieving info log length for trace object %u, reply object %u\n", VOGL_METHOD_NAME, trace_object, replay_object);
5092                 return cStatusSoftFailure;
5093             }
5094             else
5095             {
5096                 vogl::vector<GLcharARB> log(length);
5097
5098                 GLsizei actual_length = 0;
5099                 GL_ENTRYPOINT(glGetInfoLogARB)(replay_object, length, &actual_length, log.get_ptr());
5100
5101                 if (actual_length)
5102                 {
5103                     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());
5104                 }
5105             }
5106
5107             break;
5108         }
5109         case VOGL_ENTRYPOINT_glGetUniformLocation:
5110         {
5111             GLhandleARB trace_handle = trace_packet.get_param_value<GLhandleARB>(0);
5112             GLhandleARB replay_handle = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle);
5113             GLint trace_loc = trace_packet.get_return_value<GLint>();
5114
5115             if (replay_handle)
5116             {
5117                 const GLchar *pName = trace_packet.get_param_client_memory<GLchar>(1);
5118
5119                 GLint replay_loc = GL_ENTRYPOINT(glGetUniformLocation)(replay_handle, pName);
5120                 if (replay_loc < 0)
5121                 {
5122                     if (trace_loc >= 0)
5123                         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);
5124                 }
5125                 else
5126                 {
5127                     if (trace_loc < 0)
5128                         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);
5129                     else
5130                     {
5131                         glsl_program_hash_map::iterator it = get_shared_state()->m_glsl_program_hash_map.find(trace_handle);
5132                         if (it == get_shared_state()->m_glsl_program_hash_map.end())
5133                             it = get_shared_state()->m_glsl_program_hash_map.insert(trace_handle).first;
5134
5135                         glsl_program_state &state = it->second;
5136                         state.m_uniform_locations.erase(trace_loc);
5137                         state.m_uniform_locations.insert(trace_loc, replay_loc);
5138                     }
5139                 }
5140             }
5141
5142             break;
5143         }
5144         case VOGL_ENTRYPOINT_glGetUniformLocationARB:
5145         {
5146             GLhandleARB trace_handle = trace_packet.get_param_value<GLhandleARB>(0);
5147             GLhandleARB replay_handle = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle);
5148             GLint trace_loc = trace_packet.get_return_value<GLint>();
5149
5150             if (replay_handle)
5151             {
5152                 const GLcharARB *pName = trace_packet.get_param_client_memory<GLcharARB>(1);
5153
5154                 GLint replay_loc = GL_ENTRYPOINT(glGetUniformLocationARB)(replay_handle, pName);
5155                 if (replay_loc < 0)
5156                 {
5157                     if (trace_loc >= 0)
5158                         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);
5159                 }
5160                 else
5161                 {
5162                     if (trace_loc < 0)
5163                         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);
5164                     else
5165                     {
5166                         glsl_program_hash_map::iterator it = get_shared_state()->m_glsl_program_hash_map.find(trace_handle);
5167                         if (it == get_shared_state()->m_glsl_program_hash_map.end())
5168                             it = get_shared_state()->m_glsl_program_hash_map.insert(trace_handle).first;
5169
5170                         glsl_program_state &state = it->second;
5171                         state.m_uniform_locations.erase(trace_loc);
5172                         state.m_uniform_locations.insert(trace_loc, replay_loc);
5173                     }
5174                 }
5175             }
5176
5177             break;
5178         }
5179         case VOGL_ENTRYPOINT_glGetActiveAttrib:
5180         case VOGL_ENTRYPOINT_glGetActiveUniform:
5181         {
5182             if (!benchmark_mode())
5183             {
5184                 GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
5185                 GLuint replay_handle = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle);
5186
5187                 GLuint index = trace_packet.get_param_value<GLuint>(1);
5188                 GLsizei bufSize = trace_packet.get_param_value<GLsizei>(2);
5189
5190                 GLsizei *pTrace_length = trace_packet.get_param_client_memory<GLsizei>(3);
5191                 GLint *pTrace_size = trace_packet.get_param_client_memory<GLint>(4);
5192                 GLenum *pTrace_type = trace_packet.get_param_client_memory<GLenum>(5);
5193                 GLchar *pTrace_name = trace_packet.get_param_client_memory<GLchar>(6);
5194
5195                 vogl::growable_array<GLchar, 1024> name_buf(bufSize + 1); // + 1 guarantees non-empty and null terminated
5196
5197                 GLsizei len = 0;
5198                 GLint size = 0;
5199                 GLenum type = 0;
5200
5201                 if (entrypoint_id == VOGL_ENTRYPOINT_glGetActiveAttrib)
5202                     GL_ENTRYPOINT(glGetActiveAttrib)(replay_handle, index, bufSize, &len, &size, &type, name_buf.get_ptr());
5203                 else
5204                     GL_ENTRYPOINT(glGetActiveUniform)(replay_handle, index, bufSize, &len, &size, &type, name_buf.get_ptr());
5205
5206                 bool mismatch = false;
5207
5208                 GLsizei trace_len = 0;
5209                 if (pTrace_length)
5210                 {
5211                     trace_len = pTrace_length[0];
5212                     if (trace_len != len)
5213                         mismatch = true;
5214                 }
5215
5216                 GLint trace_size = 0;
5217                 if (pTrace_size)
5218                 {
5219                     trace_size = pTrace_size[0];
5220                     if (trace_size != size)
5221                         mismatch = true;
5222                 }
5223
5224                 GLenum trace_type = 0;
5225                 if (pTrace_type)
5226                 {
5227                     trace_type = pTrace_type[0];
5228                     if (trace_type != type)
5229                         mismatch = true;
5230                 }
5231
5232                 if ((bufSize) && (pTrace_name))
5233                 {
5234                     uint n = vogl_strlen((const char *)pTrace_name) + 1;
5235                     if (bufSize < (GLsizei)n)
5236                         mismatch = true;
5237                     else if (memcmp(name_buf.get_ptr(), pTrace_name, n) != 0)
5238                         mismatch = true;
5239                 }
5240
5241                 if (mismatch)
5242                 {
5243                     process_entrypoint_warning("%s: Replay of %s returned data differed from trace's\n", VOGL_METHOD_NAME, trace_packet.get_entrypoint_desc().m_pName);
5244                     vogl_warning_printf("Trace handle: %u, index: %u, bufSize: %u, trace_len: %u, trace_type: %u, name: %s\n",
5245                                        (uint)trace_handle, (uint)index, (uint)bufSize, (uint)trace_len, (uint)trace_type, (pTrace_name != NULL) ? (const char *)pTrace_name : "");
5246                     vogl_warning_printf("GL handle: %u, index: %u, bufSize: %u, trace_len: %u, trace_type: %u, name: %s\n",
5247                                        (uint)replay_handle, (uint)index, (uint)bufSize, (uint)len, (uint)type, name_buf.get_ptr());
5248                 }
5249             }
5250
5251             break;
5252         }
5253         case VOGL_ENTRYPOINT_glGetAttachedShaders:
5254         {
5255             if (!benchmark_mode())
5256             {
5257                 GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
5258                 GLuint replay_handle = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle);
5259
5260                 GLsizei max_count = trace_packet.get_param_value<GLsizei>(1);
5261                 GLsizei count = 0;
5262                 vogl::growable_array<GLuint, 16> shaders(max_count);
5263
5264                 GL_ENTRYPOINT(glGetAttachedShaders)(replay_handle, trace_packet.get_param_value<GLsizei>(1), &count, shaders.get_ptr());
5265
5266                 // TODO: Diff results
5267             }
5268
5269             break;
5270         }
5271         case VOGL_ENTRYPOINT_glGetAttribLocation:
5272         {
5273             if (!benchmark_mode())
5274             {
5275                 GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
5276                 GLuint replay_handle = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle);
5277
5278                 const GLchar *pName = trace_packet.get_param_client_memory<GLchar>(1);
5279
5280                 GLint replay_result = GL_ENTRYPOINT(glGetAttribLocation)(replay_handle, pName);
5281                 GLint trace_result = trace_packet.get_return_value<GLint>();
5282
5283                 if (replay_result != trace_result)
5284                 {
5285                     process_entrypoint_warning("%s: Replay of %s returned data differed from trace's\n", VOGL_METHOD_NAME, trace_packet.get_entrypoint_desc().m_pName);
5286                     vogl_warning_printf("Trace value: %i, replay: %i\n", trace_result, replay_result);
5287                 }
5288             }
5289
5290             break;
5291         }
5292         case VOGL_ENTRYPOINT_glGetProgramivARB:
5293         {
5294             if (!benchmark_mode())
5295             {
5296                 GLenum pname = trace_packet.get_param_value<GLenum>(1);
5297                 const GLint *pParams = trace_packet.get_param_client_memory<GLint>(2);
5298                 uint params_size = trace_packet.get_param_client_memory_data_size(2);
5299                 uint params_count = params_size / sizeof(GLint);
5300
5301                 int n = g_gl_enums.get_pname_count(pname);
5302                 if (n <= 0)
5303                 {
5304                     process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
5305                     return cStatusSoftFailure;
5306                 }
5307                 else
5308                 {
5309                     vogl::growable_array<GLint, 16> params(n + 1);
5310                     params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC;
5311
5312                     GL_ENTRYPOINT(glGetProgramivARB)(
5313                         trace_packet.get_param_value<GLenum>(0),
5314                         pname,
5315                         params.get_ptr());
5316
5317                     VOGL_VERIFY(params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC);
5318
5319                     if (params_count != static_cast<uint>(n))
5320                     {
5321                         process_entrypoint_warning("%s: Size of replay's params array differs from trace's\n", VOGL_METHOD_NAME);
5322                     }
5323                     else if (pParams && memcmp(pParams, params.get_ptr(), n * sizeof(GLint)) != 0)
5324                     {
5325                         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));
5326                     }
5327                 }
5328             }
5329
5330             break;
5331         }
5332         case VOGL_ENTRYPOINT_glGetProgramiv:
5333         {
5334             if (!benchmark_mode())
5335             {
5336                 GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
5337                 GLuint replay_handle = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle);
5338
5339                 GLenum pname = trace_packet.get_param_value<GLenum>(1);
5340
5341                 const GLint *pParams = trace_packet.get_param_client_memory<GLint>(2);
5342                 uint params_size = trace_packet.get_param_client_memory_data_size(2);
5343                 uint params_count = params_size / sizeof(GLint);
5344
5345                 int n = g_gl_enums.get_pname_count(pname);
5346                 if (n <= 0)
5347                 {
5348                     process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
5349                     return cStatusSoftFailure;
5350                 }
5351                 else
5352                 {
5353                     vogl::growable_array<GLint, 16> params(n + 1);
5354                     params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC;
5355
5356                     GL_ENTRYPOINT(glGetProgramiv)(
5357                         replay_handle,
5358                         pname,
5359                         params.get_ptr());
5360
5361                     VOGL_VERIFY(params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC);
5362
5363                     if (params_count != static_cast<uint>(n))
5364                     {
5365                         process_entrypoint_warning("%s: Size of replay's params array differs from trace's\n", VOGL_METHOD_NAME);
5366                     }
5367                     else if (pParams && memcmp(pParams, params.get_ptr(), n * sizeof(GLint)) != 0)
5368                     {
5369                         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));
5370                     }
5371                 }
5372             }
5373
5374             break;
5375         }
5376         case VOGL_ENTRYPOINT_glLinkProgram:
5377         case VOGL_ENTRYPOINT_glLinkProgramARB:
5378         case VOGL_ENTRYPOINT_glProgramBinary:
5379         {
5380             handle_link_program(entrypoint_id);
5381
5382             break;
5383         }
5384         case VOGL_ENTRYPOINT_glCompileShader:
5385         {
5386             GL_ENTRYPOINT(glCompileShader)(map_handle(get_shared_state()->m_shadow_state.m_objs, trace_packet.get_param_value<GLuint>(0)));
5387             break;
5388         }
5389         case VOGL_ENTRYPOINT_glCompileShaderARB:
5390         {
5391             GL_ENTRYPOINT(glCompileShaderARB)(map_handle(get_shared_state()->m_shadow_state.m_objs, trace_packet.get_param_value<GLhandleARB>(0)));
5392             break;
5393         }
5394         case VOGL_ENTRYPOINT_glGetShaderiv:
5395         {
5396             if (!benchmark_mode())
5397             {
5398                 GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
5399                 GLuint replay_handle = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle);
5400
5401                 GLenum pname = trace_packet.get_param_value<GLenum>(1);
5402                 GLint params = 0;
5403
5404                 const GLint *pClient_params = trace_packet.get_param_client_memory<GLint>(2);
5405
5406                 GL_ENTRYPOINT(glGetShaderiv)(replay_handle, pname, &params);
5407
5408                 if ((pClient_params) && (*pClient_params != params))
5409                 {
5410                     process_entrypoint_warning("%s: Replay's returned data differed from trace's\n", VOGL_METHOD_NAME);
5411                     vogl_warning_printf("Trace data: %i, Replay data: %i\n", pClient_params ? *pClient_params : 0, params);
5412                 }
5413             }
5414
5415             break;
5416         }
5417         case VOGL_ENTRYPOINT_glGetShaderInfoLog:
5418         {
5419             GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
5420             GLuint replay_handle = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle);
5421
5422             GLsizei trace_max_length = trace_packet.get_param_value<GLsizei>(1);
5423             const GLsizei *pTrace_length = trace_packet.get_param_client_memory<GLsizei>(2);
5424             VOGL_NOTE_UNUSED(pTrace_length);
5425             const GLchar *pTrace_info_log = trace_packet.get_param_client_memory<GLchar>(3);
5426             VOGL_NOTE_UNUSED(pTrace_info_log);
5427
5428             vogl::growable_array<GLchar, 512> log(trace_max_length);
5429             GLsizei length = 0;
5430             GL_ENTRYPOINT(glGetShaderInfoLog)(replay_handle, trace_max_length, &length, log.get_ptr());
5431
5432             if (length)
5433             {
5434                 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());
5435             }
5436
5437             break;
5438         }
5439         case VOGL_ENTRYPOINT_glGetBooleanv:
5440         {
5441             if (!benchmark_mode())
5442             {
5443                 GLenum pname = trace_packet.get_param_value<GLenum>(0);
5444                 const GLboolean *pParams = trace_packet.get_param_client_memory<GLboolean>(1);
5445
5446                 int n = g_gl_enums.get_pname_count(pname);
5447                 if (n <= 0)
5448                 {
5449                     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));
5450                     return cStatusSoftFailure;
5451                 }
5452                 else
5453                 {
5454                     vogl::growable_array<GLboolean, 16> params(n + 1);
5455                     params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_BYTE_MAGIC;
5456
5457                     GL_ENTRYPOINT(glGetBooleanv)(pname, params.get_ptr());
5458
5459                     VOGL_VERIFY(params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_BYTE_MAGIC);
5460
5461                     if (memcmp(pParams, params.get_ptr(), n * sizeof(GLboolean)) != 0)
5462                     {
5463                         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));
5464                     }
5465                 }
5466             }
5467
5468             break;
5469         }
5470         case VOGL_ENTRYPOINT_glGetDoublev:
5471         {
5472             if (!benchmark_mode())
5473             {
5474                 GLenum pname = trace_packet.get_param_value<GLenum>(0);
5475                 const GLdouble *pParams = trace_packet.get_param_client_memory<GLdouble>(1);
5476
5477                 int n = g_gl_enums.get_pname_count(pname);
5478                 if (n <= 0)
5479                 {
5480                     process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
5481                     return cStatusSoftFailure;
5482                 }
5483                 else
5484                 {
5485                     vogl::growable_array<GLdouble, 17> params(n + 1);
5486                     params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_FLOAT_MAGIC;
5487
5488                     GL_ENTRYPOINT(glGetDoublev)(pname, params.get_ptr());
5489
5490                     VOGL_VERIFY(params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_FLOAT_MAGIC);
5491
5492                     if (memcmp(pParams, params.get_ptr(), n * sizeof(GLdouble)) != 0)
5493                     {
5494                         process_entrypoint_warning("%s: Replay's returned GLdouble data differed from trace's\n", VOGL_METHOD_NAME);
5495                     }
5496                 }
5497             }
5498
5499             break;
5500         }
5501         case VOGL_ENTRYPOINT_glGetFloatv:
5502         {
5503             if (!benchmark_mode())
5504             {
5505                 GLenum pname = trace_packet.get_param_value<GLenum>(0);
5506                 const GLfloat *pTrace_params = trace_packet.get_param_client_memory<GLfloat>(1);
5507                 uint trace_params_count = trace_packet.get_param_client_memory_data_size(1) / sizeof(GLfloat);
5508
5509                 int n = g_gl_enums.get_pname_count(pname);
5510                 if (n <= 0)
5511                 {
5512                     process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
5513                     return cStatusSoftFailure;
5514                 }
5515
5516                 vogl::growable_array<GLfloat, 17> params(n + 1);
5517                 params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_FLOAT_MAGIC;
5518
5519                 GL_ENTRYPOINT(glGetFloatv)(pname, params.get_ptr());
5520
5521                 VOGL_VERIFY(params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_FLOAT_MAGIC);
5522
5523                 if (static_cast<int>(trace_params_count) < n)
5524                     process_entrypoint_warning("%s: Replay param array size (%u) does not match the expected size (%u)\n", VOGL_METHOD_NAME, trace_params_count, n);
5525                 else if (memcmp(pTrace_params, params.get_ptr(), n * sizeof(GLfloat)) != 0)
5526                 {
5527                     process_entrypoint_warning("%s: Replay's returned GLfloat data differed from trace's\n", VOGL_METHOD_NAME);
5528                 }
5529             }
5530
5531             break;
5532         }
5533         case VOGL_ENTRYPOINT_glGetIntegerv:
5534         {
5535             if (!benchmark_mode())
5536             {
5537                 GLenum pname = trace_packet.get_param_value<GLenum>(0);
5538                 const GLint *pTrace_params = trace_packet.get_param_client_memory<GLint>(1);
5539                 uint trace_params_count = trace_packet.get_param_client_memory_data_size(1) / sizeof(GLint);
5540
5541                 int n = g_gl_enums.get_pname_count(pname);
5542                 if (n <= 0)
5543                 {
5544                     process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
5545                     return cStatusSoftFailure;
5546                 }
5547
5548                 vogl::growable_array<GLint, 16> params(n + 1);
5549                 params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC;
5550
5551                 GL_ENTRYPOINT(glGetIntegerv)(pname, params.get_ptr());
5552
5553                 VOGL_VERIFY(params[n] == (GLint)VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC);
5554
5555                 bool is_binding = false;
5556                 switch (pname)
5557                 {
5558                     case GL_ARRAY_BUFFER_BINDING:
5559                     case GL_COLOR_ARRAY_BUFFER_BINDING:
5560                     case GL_DISPATCH_INDIRECT_BUFFER_BINDING:
5561                     case GL_DRAW_FRAMEBUFFER_BINDING:
5562                     case GL_EDGE_FLAG_ARRAY_BUFFER_BINDING:
5563                     case GL_ELEMENT_ARRAY_BUFFER_BINDING:
5564                     case GL_FOG_COORD_ARRAY_BUFFER_BINDING:
5565                     case GL_INDEX_ARRAY_BUFFER_BINDING:
5566                     case GL_NORMAL_ARRAY_BUFFER_BINDING:
5567                     case GL_PIXEL_PACK_BUFFER_BINDING:
5568                     case GL_PIXEL_UNPACK_BUFFER_BINDING:
5569                     case GL_PROGRAM_PIPELINE_BINDING:
5570                     case GL_READ_FRAMEBUFFER_BINDING:
5571                     case GL_RENDERBUFFER_BINDING:
5572                     case GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING:
5573                     case GL_SHADER_STORAGE_BUFFER_BINDING:
5574                     case GL_TEXTURE_BINDING_1D:
5575                     case GL_TEXTURE_BINDING_1D_ARRAY:
5576                     case GL_TEXTURE_BINDING_2D:
5577                     case GL_TEXTURE_BINDING_2D_ARRAY:
5578                     case GL_TEXTURE_BINDING_2D_MULTISAMPLE:
5579                     case GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY:
5580                     case GL_TEXTURE_BINDING_3D:
5581                     case GL_TEXTURE_BINDING_BUFFER:
5582                     case GL_TEXTURE_BINDING_CUBE_MAP:
5583                     case GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING:
5584                     case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
5585                     case GL_TRANSFORM_FEEDBACK_BUFFER_START:
5586                     case GL_UNIFORM_BUFFER_BINDING:
5587                     case GL_VERTEX_ARRAY_BINDING:
5588                     case GL_VERTEX_ARRAY_BUFFER_BINDING:
5589                     case GL_CURRENT_PROGRAM:
5590                     {
5591                         is_binding = true;
5592                         break;
5593                     }
5594                     default:
5595                         break;
5596                 }
5597
5598                 // Don't bother diffing bindings, the trace's are in the trace domain while the glGet's results are in the replay domain.
5599                 if (!is_binding)
5600                 {
5601                     if (static_cast<int>(trace_params_count) < n)
5602                     {
5603                         process_entrypoint_warning("%s: Replay param array size (%u) does not match the expected size (%u)\n", VOGL_METHOD_NAME, trace_params_count, n);
5604                     }
5605                     else if (memcmp(pTrace_params, params.get_ptr(), n * sizeof(GLint)) != 0)
5606                     {
5607                         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));
5608                         for (int i = 0; i < n; i++)
5609                             vogl_printf("GLint %u: Trace: %i, Replay: %i\n", i, pTrace_params[i], params[i]);
5610                     }
5611                 }
5612             }
5613
5614             break;
5615         }
5616         // glProgramUniform's
5617         case VOGL_ENTRYPOINT_glProgramUniform1f:
5618         {
5619             set_program_uniform_helper1<GLfloat>(GL_ENTRYPOINT(glProgramUniform1f));
5620             break;
5621         }
5622         case VOGL_ENTRYPOINT_glProgramUniform1i:
5623         {
5624             set_program_uniform_helper1<GLint>(GL_ENTRYPOINT(glProgramUniform1i));
5625             break;
5626         }
5627         case VOGL_ENTRYPOINT_glProgramUniform1ui:
5628         {
5629             set_program_uniform_helper1<GLuint>(GL_ENTRYPOINT(glProgramUniform1ui));
5630             break;
5631         }
5632         case VOGL_ENTRYPOINT_glProgramUniform2f:
5633         {
5634             set_program_uniform_helper2<GLfloat>(GL_ENTRYPOINT(glProgramUniform2f));
5635             break;
5636         }
5637         case VOGL_ENTRYPOINT_glProgramUniform2i:
5638         {
5639             set_program_uniform_helper2<GLint>(GL_ENTRYPOINT(glProgramUniform2i));
5640             break;
5641         }
5642         case VOGL_ENTRYPOINT_glProgramUniform2ui:
5643         {
5644             set_program_uniform_helper2<GLuint>(GL_ENTRYPOINT(glProgramUniform2ui));
5645             break;
5646         }
5647         case VOGL_ENTRYPOINT_glProgramUniform3f:
5648         {
5649             set_program_uniform_helper3<GLfloat>(GL_ENTRYPOINT(glProgramUniform3f));
5650             break;
5651         }
5652         case VOGL_ENTRYPOINT_glProgramUniform3i:
5653         {
5654             set_program_uniform_helper3<GLint>(GL_ENTRYPOINT(glProgramUniform3i));
5655             break;
5656         }
5657         case VOGL_ENTRYPOINT_glProgramUniform3ui:
5658         {
5659             set_program_uniform_helper3<GLuint>(GL_ENTRYPOINT(glProgramUniform3ui));
5660             break;
5661         }
5662         case VOGL_ENTRYPOINT_glProgramUniform4f:
5663         {
5664             set_program_uniform_helper4<GLfloat>(GL_ENTRYPOINT(glProgramUniform4f));
5665             break;
5666         }
5667         case VOGL_ENTRYPOINT_glProgramUniform4i:
5668         {
5669             set_program_uniform_helper4<GLint>(GL_ENTRYPOINT(glProgramUniform4i));
5670             break;
5671         }
5672         case VOGL_ENTRYPOINT_glProgramUniform4ui:
5673         {
5674             set_program_uniform_helper4<GLuint>(GL_ENTRYPOINT(glProgramUniform4ui));
5675             break;
5676         }
5677         case VOGL_ENTRYPOINT_glProgramUniform1fv:
5678         {
5679             set_program_uniformv_helper<1, float>(GL_ENTRYPOINT(glProgramUniform1fv));
5680             break;
5681         }
5682         case VOGL_ENTRYPOINT_glProgramUniform2fv:
5683         {
5684             set_program_uniformv_helper<2, float>(GL_ENTRYPOINT(glProgramUniform2fv));
5685             break;
5686         }
5687         case VOGL_ENTRYPOINT_glProgramUniform3fv:
5688         {
5689             set_program_uniformv_helper<3, float>(GL_ENTRYPOINT(glProgramUniform3fv));
5690             break;
5691         }
5692         case VOGL_ENTRYPOINT_glProgramUniform4fv:
5693         {
5694             set_program_uniformv_helper<4, float>(GL_ENTRYPOINT(glProgramUniform4fv));
5695             break;
5696         }
5697         case VOGL_ENTRYPOINT_glProgramUniform1iv:
5698         {
5699             set_program_uniformv_helper<1, GLint>(GL_ENTRYPOINT(glProgramUniform1iv));
5700             break;
5701         }
5702         case VOGL_ENTRYPOINT_glProgramUniform2iv:
5703         {
5704             set_program_uniformv_helper<2, GLint>(GL_ENTRYPOINT(glProgramUniform2iv));
5705             break;
5706         }
5707         case VOGL_ENTRYPOINT_glProgramUniform3iv:
5708         {
5709             set_program_uniformv_helper<3, GLint>(GL_ENTRYPOINT(glProgramUniform3iv));
5710             break;
5711         }
5712         case VOGL_ENTRYPOINT_glProgramUniform4iv:
5713         {
5714             set_program_uniformv_helper<4, GLint>(GL_ENTRYPOINT(glProgramUniform4iv));
5715             break;
5716         }
5717         case VOGL_ENTRYPOINT_glProgramUniform1uiv:
5718         {
5719             set_program_uniformv_helper<1, GLuint>(GL_ENTRYPOINT(glProgramUniform1uiv));
5720             break;
5721         }
5722         case VOGL_ENTRYPOINT_glProgramUniform2uiv:
5723         {
5724             set_program_uniformv_helper<2, GLuint>(GL_ENTRYPOINT(glProgramUniform2uiv));
5725             break;
5726         }
5727         case VOGL_ENTRYPOINT_glProgramUniform3uiv:
5728         {
5729             set_program_uniformv_helper<3, GLuint>(GL_ENTRYPOINT(glProgramUniform3uiv));
5730             break;
5731         }
5732         case VOGL_ENTRYPOINT_glProgramUniform4uiv:
5733         {
5734             set_program_uniformv_helper<4, GLuint>(GL_ENTRYPOINT(glProgramUniform4uiv));
5735             break;
5736         }
5737         case VOGL_ENTRYPOINT_glProgramUniformMatrix2fv:
5738         {
5739             set_program_uniform_matrixv_helper<2, 2, float>(GL_ENTRYPOINT(glProgramUniformMatrix2fv));
5740             break;
5741         }
5742         case VOGL_ENTRYPOINT_glProgramUniformMatrix3fv:
5743         {
5744             set_program_uniform_matrixv_helper<3, 3, float>(GL_ENTRYPOINT(glProgramUniformMatrix3fv));
5745             break;
5746         }
5747         case VOGL_ENTRYPOINT_glProgramUniformMatrix4fv:
5748         {
5749             set_program_uniform_matrixv_helper<4, 4, float>(GL_ENTRYPOINT(glProgramUniformMatrix4fv));
5750             break;
5751         }
5752         case VOGL_ENTRYPOINT_glProgramUniformMatrix2x3fv:
5753         {
5754             set_program_uniform_matrixv_helper<2, 3, float>(GL_ENTRYPOINT(glProgramUniformMatrix2x3fv));
5755             break;
5756         }
5757         case VOGL_ENTRYPOINT_glProgramUniformMatrix3x2fv:
5758         {
5759             set_program_uniform_matrixv_helper<3, 2, float>(GL_ENTRYPOINT(glProgramUniformMatrix3x2fv));
5760             break;
5761         }
5762         case VOGL_ENTRYPOINT_glProgramUniformMatrix2x4fv:
5763         {
5764             set_program_uniform_matrixv_helper<2, 4, float>(GL_ENTRYPOINT(glProgramUniformMatrix2x4fv));
5765             break;
5766         }
5767         case VOGL_ENTRYPOINT_glProgramUniformMatrix4x2fv:
5768         {
5769             set_program_uniform_matrixv_helper<4, 2, float>(GL_ENTRYPOINT(glProgramUniformMatrix4x2fv));
5770             break;
5771         }
5772         case VOGL_ENTRYPOINT_glProgramUniformMatrix3x4fv:
5773         {
5774             set_program_uniform_matrixv_helper<3, 4, float>(GL_ENTRYPOINT(glProgramUniformMatrix3x4fv));
5775             break;
5776         }
5777         case VOGL_ENTRYPOINT_glProgramUniformMatrix4x3fv:
5778         {
5779             set_program_uniform_matrixv_helper<4, 3, float>(GL_ENTRYPOINT(glProgramUniformMatrix4x3fv));
5780             break;
5781         }
5782         // glUniform's
5783         case VOGL_ENTRYPOINT_glUniform1f:
5784         {
5785             set_uniform_helper1<GLfloat>(GL_ENTRYPOINT(glUniform1f));
5786             break;
5787         }
5788         case VOGL_ENTRYPOINT_glUniform1fARB:
5789         {
5790             set_uniform_helper1<GLfloat>(GL_ENTRYPOINT(glUniform1fARB));
5791             break;
5792         }
5793         case VOGL_ENTRYPOINT_glUniform2f:
5794         {
5795             set_uniform_helper2<GLfloat>(GL_ENTRYPOINT(glUniform2f));
5796             break;
5797         }
5798         case VOGL_ENTRYPOINT_glUniform2fARB:
5799         {
5800             set_uniform_helper2<GLfloat>(GL_ENTRYPOINT(glUniform2fARB));
5801             break;
5802         }
5803         case VOGL_ENTRYPOINT_glUniform3f:
5804         {
5805             set_uniform_helper3<GLfloat>(GL_ENTRYPOINT(glUniform3f));
5806             break;
5807         }
5808         case VOGL_ENTRYPOINT_glUniform3fARB:
5809         {
5810             set_uniform_helper3<GLfloat>(GL_ENTRYPOINT(glUniform3fARB));
5811             break;
5812         }
5813         case VOGL_ENTRYPOINT_glUniform4f:
5814         {
5815             set_uniform_helper4<GLfloat>(GL_ENTRYPOINT(glUniform4f));
5816             break;
5817         }
5818         case VOGL_ENTRYPOINT_glUniform4fARB:
5819         {
5820             set_uniform_helper4<GLfloat>(GL_ENTRYPOINT(glUniform4fARB));
5821             break;
5822         }
5823         case VOGL_ENTRYPOINT_glUniform1i:
5824         {
5825             set_uniform_helper1<GLint>(GL_ENTRYPOINT(glUniform1i));
5826             break;
5827         }
5828         case VOGL_ENTRYPOINT_glUniform1iARB:
5829         {
5830             set_uniform_helper1<GLint>(GL_ENTRYPOINT(glUniform1iARB));
5831             break;
5832         }
5833         case VOGL_ENTRYPOINT_glUniform2i:
5834         {
5835             set_uniform_helper2<GLint>(GL_ENTRYPOINT(glUniform2i));
5836             break;
5837         }
5838         case VOGL_ENTRYPOINT_glUniform2iARB:
5839         {
5840             set_uniform_helper2<GLint>(GL_ENTRYPOINT(glUniform2iARB));
5841             break;
5842         }
5843         case VOGL_ENTRYPOINT_glUniform3i:
5844         {
5845             set_uniform_helper3<GLint>(GL_ENTRYPOINT(glUniform3i));
5846             break;
5847         }
5848         case VOGL_ENTRYPOINT_glUniform3iARB:
5849         {
5850             set_uniform_helper3<GLint>(GL_ENTRYPOINT(glUniform3iARB));
5851             break;
5852         }
5853         case VOGL_ENTRYPOINT_glUniform4i:
5854         {
5855             set_uniform_helper4<GLint>(GL_ENTRYPOINT(glUniform4i));
5856             break;
5857         }
5858         case VOGL_ENTRYPOINT_glUniform4iARB:
5859         {
5860             set_uniform_helper4<GLint>(GL_ENTRYPOINT(glUniform4iARB));
5861             break;
5862         }
5863         case VOGL_ENTRYPOINT_glUniform1ui:
5864         {
5865             set_uniform_helper1<GLuint>(GL_ENTRYPOINT(glUniform1ui));
5866             break;
5867         }
5868         case VOGL_ENTRYPOINT_glUniform1uiEXT:
5869         {
5870             set_uniform_helper1<GLuint>(GL_ENTRYPOINT(glUniform1uiEXT));
5871             break;
5872         }
5873         case VOGL_ENTRYPOINT_glUniform2ui:
5874         {
5875             set_uniform_helper2<GLuint>(GL_ENTRYPOINT(glUniform2ui));
5876             break;
5877         }
5878         case VOGL_ENTRYPOINT_glUniform2uiEXT:
5879         {
5880             set_uniform_helper2<GLuint>(GL_ENTRYPOINT(glUniform2uiEXT));
5881             break;
5882         }
5883         case VOGL_ENTRYPOINT_glUniform3ui:
5884         {
5885             set_uniform_helper3<GLuint>(GL_ENTRYPOINT(glUniform3ui));
5886             break;
5887         }
5888         case VOGL_ENTRYPOINT_glUniform3uiEXT:
5889         {
5890             set_uniform_helper3<GLuint>(GL_ENTRYPOINT(glUniform3uiEXT));
5891             break;
5892         }
5893         case VOGL_ENTRYPOINT_glUniform4ui:
5894         {
5895             set_uniform_helper4<GLuint>(GL_ENTRYPOINT(glUniform4ui));
5896             break;
5897         }
5898         case VOGL_ENTRYPOINT_glUniform4uiEXT:
5899         {
5900             set_uniform_helper4<GLuint>(GL_ENTRYPOINT(glUniform4uiEXT));
5901             break;
5902         }
5903         case VOGL_ENTRYPOINT_glUniform1uiv:
5904         {
5905             set_uniformv_helper<1, GLuint>(GL_ENTRYPOINT(glUniform1uiv));
5906             break;
5907         }
5908         case VOGL_ENTRYPOINT_glUniform1uivEXT:
5909         {
5910             set_uniformv_helper<1, GLuint>(GL_ENTRYPOINT(glUniform1uivEXT));
5911             break;
5912         }
5913         case VOGL_ENTRYPOINT_glUniform2uiv:
5914         {
5915             set_uniformv_helper<2, GLuint>(GL_ENTRYPOINT(glUniform2uiv));
5916             break;
5917         }
5918         case VOGL_ENTRYPOINT_glUniform2uivEXT:
5919         {
5920             set_uniformv_helper<2, GLuint>(GL_ENTRYPOINT(glUniform2uivEXT));
5921             break;
5922         }
5923         case VOGL_ENTRYPOINT_glUniform3uiv:
5924         {
5925             set_uniformv_helper<3, GLuint>(GL_ENTRYPOINT(glUniform3uiv));
5926             break;
5927         }
5928         case VOGL_ENTRYPOINT_glUniform3uivEXT:
5929         {
5930             set_uniformv_helper<3, GLuint>(GL_ENTRYPOINT(glUniform3uivEXT));
5931             break;
5932         }
5933         case VOGL_ENTRYPOINT_glUniform4uiv:
5934         {
5935             set_uniformv_helper<4, GLuint>(GL_ENTRYPOINT(glUniform4uiv));
5936             break;
5937         }
5938         case VOGL_ENTRYPOINT_glUniform4uivEXT:
5939         {
5940             set_uniformv_helper<4, GLuint>(GL_ENTRYPOINT(glUniform4uivEXT));
5941             break;
5942         }
5943         case VOGL_ENTRYPOINT_glUniform1iv:
5944         {
5945             set_uniformv_helper<1, GLint>(GL_ENTRYPOINT(glUniform1iv));
5946             break;
5947         }
5948         case VOGL_ENTRYPOINT_glUniform1ivARB:
5949         {
5950             set_uniformv_helper<1, GLint>(GL_ENTRYPOINT(glUniform1ivARB));
5951             break;
5952         }
5953         case VOGL_ENTRYPOINT_glUniform2iv:
5954         {
5955             set_uniformv_helper<2, GLint>(GL_ENTRYPOINT(glUniform2iv));
5956             break;
5957         }
5958         case VOGL_ENTRYPOINT_glUniform2ivARB:
5959         {
5960             set_uniformv_helper<2, GLint>(GL_ENTRYPOINT(glUniform2ivARB));
5961             break;
5962         }
5963         case VOGL_ENTRYPOINT_glUniform3iv:
5964         {
5965             set_uniformv_helper<3, GLint>(GL_ENTRYPOINT(glUniform3iv));
5966             break;
5967         }
5968         case VOGL_ENTRYPOINT_glUniform3ivARB:
5969         {
5970             set_uniformv_helper<3, GLint>(GL_ENTRYPOINT(glUniform3ivARB));
5971             break;
5972         }
5973         case VOGL_ENTRYPOINT_glUniform4iv:
5974         {
5975             set_uniformv_helper<4, GLint>(GL_ENTRYPOINT(glUniform4iv));
5976             break;
5977         }
5978         case VOGL_ENTRYPOINT_glUniform4ivARB:
5979         {
5980             set_uniformv_helper<4, GLint>(GL_ENTRYPOINT(glUniform4ivARB));
5981             break;
5982         }
5983         case VOGL_ENTRYPOINT_glUniform1fv:
5984         {
5985             set_uniformv_helper<1, GLfloat>(GL_ENTRYPOINT(glUniform1fv));
5986             break;
5987         }
5988         case VOGL_ENTRYPOINT_glUniform1fvARB:
5989         {
5990             set_uniformv_helper<1, GLfloat>(GL_ENTRYPOINT(glUniform1fvARB));
5991             break;
5992         }
5993         case VOGL_ENTRYPOINT_glUniform2fv:
5994         {
5995             set_uniformv_helper<2, GLfloat>(GL_ENTRYPOINT(glUniform2fv));
5996             break;
5997         }
5998         case VOGL_ENTRYPOINT_glUniform2fvARB:
5999         {
6000             set_uniformv_helper<2, GLfloat>(GL_ENTRYPOINT(glUniform2fvARB));
6001             break;
6002         }
6003         case VOGL_ENTRYPOINT_glUniform3fv:
6004         {
6005             set_uniformv_helper<3, GLfloat>(GL_ENTRYPOINT(glUniform3fv));
6006             break;
6007         }
6008         case VOGL_ENTRYPOINT_glUniform3fvARB:
6009         {
6010             set_uniformv_helper<3, GLfloat>(GL_ENTRYPOINT(glUniform3fvARB));
6011             break;
6012         }
6013         case VOGL_ENTRYPOINT_glUniform4fv:
6014         {
6015             set_uniformv_helper<4, GLfloat>(GL_ENTRYPOINT(glUniform4fv));
6016             break;
6017         }
6018         case VOGL_ENTRYPOINT_glUniform4fvARB:
6019         {
6020             set_uniformv_helper<4, GLfloat>(GL_ENTRYPOINT(glUniform4fvARB));
6021             break;
6022         }
6023         case VOGL_ENTRYPOINT_glUniformMatrix2fvARB:
6024         {
6025             set_uniform_matrixv_helper<2, 2, GLfloat>(GL_ENTRYPOINT(glUniformMatrix2fvARB));
6026             break;
6027         }
6028         case VOGL_ENTRYPOINT_glUniformMatrix2fv:
6029         {
6030             set_uniform_matrixv_helper<2, 2, GLfloat>(GL_ENTRYPOINT(glUniformMatrix2fv));
6031             break;
6032         }
6033         case VOGL_ENTRYPOINT_glUniformMatrix3fvARB:
6034         {
6035             set_uniform_matrixv_helper<3, 3, GLfloat>(GL_ENTRYPOINT(glUniformMatrix3fvARB));
6036             break;
6037         }
6038         case VOGL_ENTRYPOINT_glUniformMatrix3fv:
6039         {
6040             set_uniform_matrixv_helper<3, 3, GLfloat>(GL_ENTRYPOINT(glUniformMatrix3fv));
6041             break;
6042         }
6043         case VOGL_ENTRYPOINT_glUniformMatrix4fvARB:
6044         {
6045             set_uniform_matrixv_helper<4, 4, GLfloat>(GL_ENTRYPOINT(glUniformMatrix4fvARB));
6046             break;
6047         }
6048         case VOGL_ENTRYPOINT_glUniformMatrix4fv:
6049         {
6050             set_uniform_matrixv_helper<4, 4, GLfloat>(GL_ENTRYPOINT(glUniformMatrix4fv));
6051             break;
6052         }
6053         case VOGL_ENTRYPOINT_glUniformMatrix2x3fv:
6054         {
6055             set_uniform_matrixv_helper<2, 3, GLfloat>(GL_ENTRYPOINT(glUniformMatrix2x3fv));
6056             break;
6057         }
6058         case VOGL_ENTRYPOINT_glUniformMatrix3x2fv:
6059         {
6060             set_uniform_matrixv_helper<3, 2, GLfloat>(GL_ENTRYPOINT(glUniformMatrix3x2fv));
6061             break;
6062         }
6063         case VOGL_ENTRYPOINT_glUniformMatrix2x4fv:
6064         {
6065             set_uniform_matrixv_helper<2, 4, GLfloat>(GL_ENTRYPOINT(glUniformMatrix2x4fv));
6066             break;
6067         }
6068         case VOGL_ENTRYPOINT_glUniformMatrix4x2fv:
6069         {
6070             set_uniform_matrixv_helper<4, 2, GLfloat>(GL_ENTRYPOINT(glUniformMatrix4x2fv));
6071             break;
6072         }
6073         case VOGL_ENTRYPOINT_glUniformMatrix3x4fv:
6074         {
6075             set_uniform_matrixv_helper<3, 4, GLfloat>(GL_ENTRYPOINT(glUniformMatrix3x4fv));
6076             break;
6077         }
6078         case VOGL_ENTRYPOINT_glUniformMatrix4x3fv:
6079         {
6080             set_uniform_matrixv_helper<4, 3, GLfloat>(GL_ENTRYPOINT(glUniformMatrix4x3fv));
6081             break;
6082         }
6083         case VOGL_ENTRYPOINT_glBeginQuery:
6084         case VOGL_ENTRYPOINT_glBeginQueryARB:
6085         {
6086             GLenum target = trace_packet.get_param_value<GLenum>(0);
6087             GLuint trace_handle = trace_packet.get_param_value<GLuint>(1);
6088             GLuint replay_handle = map_handle(get_shared_state()->m_queries, trace_handle);
6089
6090             if (!m_pCur_context_state->m_inside_gl_begin)
6091                 check_gl_error();
6092
6093             if (entrypoint_id == VOGL_ENTRYPOINT_glBeginQuery)
6094                 GL_ENTRYPOINT(glBeginQuery)(target, replay_handle);
6095             else
6096                 GL_ENTRYPOINT(glBeginQueryARB)(target, replay_handle);
6097
6098             if ((replay_handle) && (!m_pCur_context_state->m_inside_gl_begin) && (get_context_state()->m_current_display_list_mode != GL_COMPILE))
6099             {
6100                 if (check_gl_error())
6101                     return cStatusGLError;
6102
6103                 get_shared_state()->m_query_targets[replay_handle] = target;
6104             }
6105
6106             break;
6107         }
6108         case VOGL_ENTRYPOINT_glEndQuery:
6109         {
6110             GL_ENTRYPOINT(glEndQuery)(trace_packet.get_param_value<GLenum>(0));
6111             break;
6112         }
6113         case VOGL_ENTRYPOINT_glEndQueryARB:
6114         {
6115             GL_ENTRYPOINT(glEndQueryARB)(trace_packet.get_param_value<GLenum>(0));
6116             break;
6117         }
6118         case VOGL_ENTRYPOINT_glGetQueryObjectiv:
6119         {
6120             GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
6121             GLuint replay_handle = map_handle(get_shared_state()->m_queries, trace_handle);
6122
6123             GLenum pname = trace_packet.get_param_value<GLenum>(1);
6124
6125             int n = g_gl_enums.get_pname_count(pname);
6126             if (n <= 0)
6127             {
6128                 process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
6129                 return cStatusSoftFailure;
6130             }
6131             else
6132             {
6133                 vogl::growable_array<GLint, 16> params(n + 1);
6134                 params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC;
6135
6136                 GL_ENTRYPOINT(glGetQueryObjectiv)(replay_handle, pname, params.get_ptr());
6137
6138                 VOGL_VERIFY(params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC);
6139             }
6140
6141             break;
6142         }
6143         case VOGL_ENTRYPOINT_glGetQueryObjectivARB:
6144         {
6145             GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
6146             GLuint replay_handle = map_handle(get_shared_state()->m_queries, trace_handle);
6147
6148             GLenum pname = trace_packet.get_param_value<GLenum>(1);
6149
6150             int n = g_gl_enums.get_pname_count(pname);
6151             if (n <= 0)
6152             {
6153                 process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
6154                 return cStatusSoftFailure;
6155             }
6156             else
6157             {
6158                 vogl::growable_array<GLint, 16> params(n + 1);
6159                 params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC;
6160
6161                 GL_ENTRYPOINT(glGetQueryObjectivARB)(replay_handle, pname, params.get_ptr());
6162
6163                 VOGL_VERIFY(params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC);
6164             }
6165
6166             break;
6167         }
6168         case VOGL_ENTRYPOINT_glGetQueryObjectuiv:
6169         {
6170             GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
6171             GLuint replay_handle = map_handle(get_shared_state()->m_queries, trace_handle);
6172
6173             GLenum pname = trace_packet.get_param_value<GLenum>(1);
6174
6175             int n = g_gl_enums.get_pname_count(pname);
6176             if (n <= 0)
6177             {
6178                 process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
6179                 return cStatusSoftFailure;
6180             }
6181             else
6182             {
6183                 vogl::growable_array<GLuint, 16> params(n + 1);
6184                 params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC;
6185
6186                 GL_ENTRYPOINT(glGetQueryObjectuiv)(replay_handle, pname, params.get_ptr());
6187
6188                 VOGL_VERIFY(params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC);
6189             }
6190
6191             break;
6192         }
6193         case VOGL_ENTRYPOINT_glGetQueryObjectuivARB:
6194         {
6195             GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
6196             GLuint replay_handle = map_handle(get_shared_state()->m_queries, trace_handle);
6197
6198             GLenum pname = trace_packet.get_param_value<GLenum>(1);
6199
6200             int n = g_gl_enums.get_pname_count(pname);
6201             if (n <= 0)
6202             {
6203                 process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
6204                 return cStatusSoftFailure;
6205             }
6206             else
6207             {
6208                 vogl::growable_array<GLuint, 16> params(n + 1);
6209                 params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC;
6210
6211                 GL_ENTRYPOINT(glGetQueryObjectuivARB)(replay_handle, pname, params.get_ptr());
6212
6213                 VOGL_VERIFY(params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC);
6214             }
6215
6216             break;
6217         }
6218         case VOGL_ENTRYPOINT_glQueryCounter:
6219         {
6220             VOGL_REPLAY_LOAD_PARAMS_HELPER_glQueryCounter;
6221
6222             id = map_handle(get_shared_state()->m_queries, id);
6223
6224             VOGL_REPLAY_CALL_GL_HELPER_glQueryCounter;
6225
6226             break;
6227         }
6228         case VOGL_ENTRYPOINT_glGetQueryObjecti64v:
6229         {
6230             VOGL_REPLAY_LOAD_PARAMS_HELPER_glGetQueryObjecti64v;
6231             VOGL_NOTE_UNUSED(pTrace_params);
6232
6233             id = map_handle(get_shared_state()->m_queries, id);
6234
6235             int n = g_gl_enums.get_pname_count(pname);
6236             if (n <= 0)
6237             {
6238                 process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
6239                 return cStatusSoftFailure;
6240             }
6241
6242             vogl::growable_array<GLint64, 16> temp_params(n + 1);
6243             temp_params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC;
6244
6245             GLint64 *pReplay_params = temp_params.get_ptr();
6246
6247             VOGL_REPLAY_CALL_GL_HELPER_glGetQueryObjecti64v;
6248
6249             VOGL_VERIFY(temp_params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC);
6250
6251             break;
6252         }
6253         case VOGL_ENTRYPOINT_glGetQueryObjectui64v:
6254         {
6255             VOGL_REPLAY_LOAD_PARAMS_HELPER_glGetQueryObjectui64v;
6256             VOGL_NOTE_UNUSED(pTrace_params);
6257
6258             id = map_handle(get_shared_state()->m_queries, id);
6259
6260             int n = g_gl_enums.get_pname_count(pname);
6261             if (n <= 0)
6262             {
6263                 process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
6264                 return cStatusSoftFailure;
6265             }
6266
6267             vogl::growable_array<GLuint64, 16> temp_params(n + 1);
6268             temp_params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC;
6269
6270             GLuint64 *pReplay_params = temp_params.get_ptr();
6271
6272             VOGL_REPLAY_CALL_GL_HELPER_glGetQueryObjectui64v;
6273
6274             VOGL_VERIFY(temp_params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC);
6275
6276             break;
6277         }
6278         case VOGL_ENTRYPOINT_glBindBuffer:
6279         case VOGL_ENTRYPOINT_glBindBufferARB:
6280         {
6281             GLenum target = trace_packet.get_param_value<GLenum>(0);
6282             GLuint trace_handle = trace_packet.get_param_value<GLuint>(1);
6283             GLuint replay_handle = map_handle(get_shared_state()->m_buffers, trace_handle);
6284
6285             check_gl_error();
6286
6287             SWITCH_GL_ENTRYPOINT2_VOID(glBindBuffer, glBindBufferARB, target, replay_handle);
6288
6289             if (check_gl_error())
6290                 return cStatusGLError;
6291
6292             if ((trace_handle) && (get_context_state()->m_current_display_list_mode != GL_COMPILE))
6293             {
6294                 GLuint *pBinding = get_shared_state()->m_buffer_targets.find_value(trace_handle);
6295                 if (!pBinding)
6296                     process_entrypoint_error("%s: Couldn't find trace buffer handle 0x%X in buffer target map!\n", VOGL_METHOD_NAME, trace_handle);
6297                 else if (*pBinding == GL_NONE)
6298                     *pBinding = target;
6299             }
6300
6301             break;
6302         }
6303         case VOGL_ENTRYPOINT_glBindBufferBase:
6304         case VOGL_ENTRYPOINT_glBindBufferBaseEXT:
6305         case VOGL_ENTRYPOINT_glBindBufferBaseNV:
6306         {
6307             VOGL_REPLAY_LOAD_PARAMS_HELPER_glBindBufferBase;
6308
6309             GLuint trace_buffer = buffer;
6310             buffer = map_handle(get_shared_state()->m_buffers, buffer);
6311
6312             check_gl_error();
6313
6314             if (entrypoint_id == VOGL_ENTRYPOINT_glBindBufferBaseNV)
6315                 VOGL_REPLAY_CALL_GL_HELPER_glBindBufferBaseNV;
6316             else if (entrypoint_id == VOGL_ENTRYPOINT_glBindBufferBaseEXT)
6317                 VOGL_REPLAY_CALL_GL_HELPER_glBindBufferBaseEXT;
6318             else
6319                 VOGL_REPLAY_CALL_GL_HELPER_glBindBufferBase;
6320
6321             if (check_gl_error())
6322                 return cStatusGLError;
6323
6324             if ((trace_buffer) && (get_context_state()->m_current_display_list_mode != GL_COMPILE))
6325             {
6326                 GLuint *pBinding = get_shared_state()->m_buffer_targets.find_value(trace_buffer);
6327                 if (!pBinding)
6328                     process_entrypoint_error("%s: Couldn't find trace buffer handle 0x%X in buffer target map!\n", VOGL_METHOD_NAME, trace_buffer);
6329                 else if (*pBinding == GL_NONE)
6330                     *pBinding = target;
6331             }
6332
6333             break;
6334         }
6335         case VOGL_ENTRYPOINT_glBindBufferRange:
6336         case VOGL_ENTRYPOINT_glBindBufferRangeEXT:
6337         case VOGL_ENTRYPOINT_glBindBufferRangeNV:
6338         {
6339             VOGL_REPLAY_LOAD_PARAMS_HELPER_glBindBufferRange;
6340
6341             GLuint trace_buffer = buffer;
6342             buffer = map_handle(get_shared_state()->m_buffers, buffer);
6343
6344             check_gl_error();
6345
6346             if (entrypoint_id == VOGL_ENTRYPOINT_glBindBufferRangeNV)
6347                 VOGL_REPLAY_CALL_GL_HELPER_glBindBufferRangeNV;
6348             else if (entrypoint_id == VOGL_ENTRYPOINT_glBindBufferRangeEXT)
6349                 VOGL_REPLAY_CALL_GL_HELPER_glBindBufferRangeEXT;
6350             else
6351                 VOGL_REPLAY_CALL_GL_HELPER_glBindBufferRange;
6352
6353             if (check_gl_error())
6354                 return cStatusGLError;
6355
6356             if ((trace_buffer) && (get_context_state()->m_current_display_list_mode != GL_COMPILE))
6357             {
6358                 GLuint *pBinding = get_shared_state()->m_buffer_targets.find_value(trace_buffer);
6359                 if (!pBinding)
6360                     process_entrypoint_error("%s: Couldn't find trace buffer handle 0x%X in buffer target map!\n", VOGL_METHOD_NAME, trace_buffer);
6361                 else if (*pBinding == GL_NONE)
6362                     *pBinding = target;
6363             }
6364
6365             break;
6366         }
6367         case VOGL_ENTRYPOINT_glFenceSync:
6368         {
6369             vogl_sync_ptr_value trace_handle = trace_packet.get_return_ptr_value();
6370             if (trace_handle)
6371             {
6372                 GLsync replay_handle = GL_ENTRYPOINT(glFenceSync)(trace_packet.get_param_value<GLenum>(0), trace_packet.get_param_value<GLbitfield>(1));
6373                 if (!replay_handle)
6374                 {
6375                     process_entrypoint_error("%s: glFenceSync on trace handle 0x%" PRIX64 " succeeded in the trace, but failed during replay!\n", VOGL_METHOD_NAME, trace_handle);
6376                     return cStatusHardFailure;
6377                 }
6378                 else
6379                 {
6380                     get_shared_state()->m_syncs.insert(trace_handle, replay_handle);
6381                 }
6382             }
6383
6384             break;
6385         }
6386         case VOGL_ENTRYPOINT_glWaitSync:
6387         case VOGL_ENTRYPOINT_glClientWaitSync:
6388         {
6389             vogl_sync_ptr_value trace_sync = trace_packet.get_param_ptr_value(0);
6390             GLsync replay_sync = NULL;
6391
6392             gl_sync_hash_map::const_iterator it = get_shared_state()->m_syncs.find(trace_sync);
6393             if (it == get_shared_state()->m_syncs.end())
6394             {
6395                 if (trace_sync)
6396                 {
6397                     process_entrypoint_error("%s: Unable to map trace sync handle 0x%" PRIX64 " to GL handle\n", VOGL_METHOD_NAME, trace_sync);
6398                     return cStatusHardFailure;
6399                 }
6400             }
6401             else
6402             {
6403                 replay_sync = it->second;
6404             }
6405
6406             if (entrypoint_id == VOGL_ENTRYPOINT_glWaitSync)
6407                 GL_ENTRYPOINT(glWaitSync)(replay_sync, trace_packet.get_param_value<GLbitfield>(1), trace_packet.get_param_value<GLuint64>(2));
6408             else
6409                 GL_ENTRYPOINT(glClientWaitSync)(replay_sync, trace_packet.get_param_value<GLbitfield>(1), trace_packet.get_param_value<GLuint64>(2));
6410
6411             break;
6412         }
6413         case VOGL_ENTRYPOINT_glDeleteSync:
6414         {
6415             vogl_sync_ptr_value trace_sync = trace_packet.get_param_ptr_value(0);
6416             GLsync replay_sync = NULL;
6417
6418             gl_sync_hash_map::const_iterator it = get_shared_state()->m_syncs.find(trace_sync);
6419             if (it == get_shared_state()->m_syncs.end())
6420             {
6421                 if (trace_sync)
6422                 {
6423                     process_entrypoint_error("%s: Unable to map trace sync handle 0x%" PRIX64 " to GL handle\n", VOGL_METHOD_NAME, trace_sync);
6424                     return cStatusHardFailure;
6425                 }
6426             }
6427             else
6428             {
6429                 replay_sync = it->second;
6430             }
6431
6432             GL_ENTRYPOINT(glDeleteSync)(replay_sync);
6433
6434             if (trace_sync)
6435             {
6436                 get_shared_state()->m_syncs.erase(trace_sync);
6437             }
6438
6439             break;
6440         }
6441         case VOGL_ENTRYPOINT_glVertexPointer:
6442         {
6443             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),
6444                                 vogl_vertex_pointer_array_id, GL_ENTRYPOINT(glVertexPointer), m_client_side_array_data[vogl_vertex_pointer_array_id]);
6445             break;
6446         }
6447         case VOGL_ENTRYPOINT_glVertexPointerEXT:
6448         {
6449             VOGL_REPLAY_LOAD_PARAMS_HELPER_glVertexPointerEXT;
6450             VOGL_NOTE_UNUSED(pTrace_pointer);
6451
6452             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]);
6453             break;
6454         }
6455         case VOGL_ENTRYPOINT_glColorPointer:
6456         {
6457             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),
6458                                 vogl_color_pointer_array_id, GL_ENTRYPOINT(glColorPointer), m_client_side_array_data[vogl_color_pointer_array_id]);
6459             break;
6460         }
6461         case VOGL_ENTRYPOINT_glColorPointerEXT:
6462         {
6463             VOGL_REPLAY_LOAD_PARAMS_HELPER_glColorPointerEXT;
6464             VOGL_NOTE_UNUSED(pTrace_pointer);
6465
6466             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]);
6467             break;
6468         }
6469         case VOGL_ENTRYPOINT_glSecondaryColorPointer:
6470         {
6471             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),
6472                                 vogl_secondary_color_pointer_array_id, GL_ENTRYPOINT(glSecondaryColorPointer), m_client_side_array_data[vogl_secondary_color_pointer_array_id]);
6473             break;
6474         }
6475         case VOGL_ENTRYPOINT_glSecondaryColorPointerEXT:
6476         {
6477             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),
6478                                 vogl_secondary_color_pointer_array_id, GL_ENTRYPOINT(glSecondaryColorPointerEXT), m_client_side_array_data[vogl_secondary_color_pointer_array_id]);
6479             break;
6480         }
6481         case VOGL_ENTRYPOINT_glTexCoordPointer:
6482         {
6483             GLint cur_client_active_texture = 0;
6484             GL_ENTRYPOINT(glGetIntegerv)(GL_CLIENT_ACTIVE_TEXTURE, &cur_client_active_texture);
6485
6486             int tex_index = cur_client_active_texture - GL_TEXTURE0;
6487             if ((tex_index < 0) || (tex_index >= VOGL_MAX_SUPPORTED_GL_TEXCOORD_ARRAYS))
6488             {
6489                 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);
6490                 return cStatusSoftFailure;
6491             }
6492
6493             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),
6494                                 vogl_texcoord_pointer_array_id, GL_ENTRYPOINT(glTexCoordPointer), m_client_side_texcoord_data[tex_index]);
6495             break;
6496         }
6497         case VOGL_ENTRYPOINT_glTexCoordPointerEXT:
6498         {
6499             VOGL_REPLAY_LOAD_PARAMS_HELPER_glTexCoordPointerEXT;
6500             VOGL_NOTE_UNUSED(pTrace_pointer);
6501
6502             GLint cur_client_active_texture = 0;
6503             GL_ENTRYPOINT(glGetIntegerv)(GL_CLIENT_ACTIVE_TEXTURE, &cur_client_active_texture);
6504
6505             int tex_index = cur_client_active_texture - GL_TEXTURE0;
6506             if ((tex_index < 0) || (tex_index >= VOGL_MAX_SUPPORTED_GL_TEXCOORD_ARRAYS))
6507             {
6508                 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);
6509                 return cStatusSoftFailure;
6510             }
6511
6512             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]);
6513             break;
6514         }
6515         case VOGL_ENTRYPOINT_glFogCoordPointer:
6516         {
6517             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),
6518                                         vogl_fog_coord_pointer_array_id, GL_ENTRYPOINT(glFogCoordPointer));
6519             break;
6520         }
6521         case VOGL_ENTRYPOINT_glFogCoordPointerEXT:
6522         {
6523             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),
6524                                         vogl_fog_coord_pointer_array_id, GL_ENTRYPOINT(glFogCoordPointerEXT));
6525             break;
6526         }
6527         case VOGL_ENTRYPOINT_glIndexPointer:
6528         {
6529             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),
6530                                         vogl_index_pointer_array_id, GL_ENTRYPOINT(glIndexPointer));
6531             break;
6532         }
6533         case VOGL_ENTRYPOINT_glIndexPointerEXT:
6534         {
6535             VOGL_REPLAY_LOAD_PARAMS_HELPER_glIndexPointerEXT;
6536             VOGL_NOTE_UNUSED(pTrace_pointer);
6537
6538             vertex_array_helper_no_size_count(type, stride, count, trace_packet.get_param_ptr_value(3), vogl_index_pointer_array_id, GL_ENTRYPOINT(glIndexPointerEXT));
6539             break;
6540         }
6541         case VOGL_ENTRYPOINT_glNormalPointer:
6542         {
6543             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),
6544                                         vogl_normal_pointer_array_id, GL_ENTRYPOINT(glNormalPointer));
6545             break;
6546         }
6547         case VOGL_ENTRYPOINT_glNormalPointerEXT:
6548         {
6549             VOGL_REPLAY_LOAD_PARAMS_HELPER_glNormalPointerEXT;
6550             VOGL_NOTE_UNUSED(pTrace_pointer);
6551
6552             vertex_array_helper_no_size_count(type, stride, count, trace_packet.get_param_ptr_value(3), vogl_normal_pointer_array_id, GL_ENTRYPOINT(glNormalPointerEXT));
6553             break;
6554         }
6555         case VOGL_ENTRYPOINT_glEdgeFlagPointer:
6556         {
6557             vertex_array_helper_no_type_no_size(trace_packet.get_param_value<GLsizei>(0), trace_packet.get_param_ptr_value(1),
6558                                                 vogl_edge_flag_pointer_array_id, GL_ENTRYPOINT(glEdgeFlagPointer));
6559             break;
6560         }
6561         case VOGL_ENTRYPOINT_glEdgeFlagPointerEXT:
6562         {
6563             VOGL_REPLAY_LOAD_PARAMS_HELPER_glEdgeFlagPointerEXT;
6564             VOGL_NOTE_UNUSED(pTrace_pointer);
6565
6566             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));
6567             break;
6568         }
6569         case VOGL_ENTRYPOINT_glInterleavedArrays:
6570         {
6571             // TODO: Test this more!
6572             GLenum format = trace_packet.get_param_value<GLenum>(0);
6573             GLsizei stride = trace_packet.get_param_value<GLsizei>(1);
6574             const vogl_trace_ptr_value trace_pointer_value = trace_packet.get_param_ptr_value(2);
6575
6576             uint fmt_index;
6577             for (fmt_index = 0; fmt_index < VOGL_INTERLEAVED_ARRAY_SIZE; fmt_index++)
6578                 if (format == vogl_g_interleaved_array_descs[fmt_index].fmt)
6579                     break;
6580             if (fmt_index == VOGL_INTERLEAVED_ARRAY_SIZE)
6581             {
6582                 process_entrypoint_error("%s: Invalid interleaved vertex format: 0x%X \n", VOGL_METHOD_NAME, format);
6583                 return cStatusSoftFailure;
6584             }
6585
6586             if (stride < 0)
6587             {
6588                 process_entrypoint_error("%s: Invalid interleaved vertex stride: %i\n", VOGL_METHOD_NAME, static_cast<int>(stride));
6589                 return cStatusSoftFailure;
6590             }
6591
6592             const interleaved_array_desc_entry_t &fmt = vogl_g_interleaved_array_descs[fmt_index];
6593
6594             if (!stride)
6595             {
6596                 stride = fmt.s;
6597                 VOGL_ASSERT(stride > 0);
6598             }
6599
6600             GL_ENTRYPOINT(glDisableClientState)(GL_EDGE_FLAG_ARRAY);
6601             GL_ENTRYPOINT(glDisableClientState)(GL_INDEX_ARRAY);
6602             GL_ENTRYPOINT(glDisableClientState)(GL_SECONDARY_COLOR_ARRAY);
6603             GL_ENTRYPOINT(glDisableClientState)(GL_FOG_COORD_ARRAY);
6604
6605             check_gl_error();
6606
6607             if (fmt.et)
6608             {
6609                 GLint cur_client_active_texture = 0;
6610                 GL_ENTRYPOINT(glGetIntegerv)(GL_CLIENT_ACTIVE_TEXTURE, &cur_client_active_texture);
6611
6612                 int tex_index = cur_client_active_texture - GL_TEXTURE0;
6613                 if ((tex_index < 0) || (tex_index >= VOGL_MAX_SUPPORTED_GL_TEXCOORD_ARRAYS))
6614                 {
6615                     process_entrypoint_error("%s: glInterleavedArrays called with an invalid or unsupported client active texture (0x%08X)\n", VOGL_METHOD_NAME, cur_client_active_texture);
6616                     return cStatusSoftFailure;
6617                 }
6618
6619                 GL_ENTRYPOINT(glEnableClientState)(GL_TEXTURE_COORD_ARRAY);
6620                 vertex_array_helper(fmt.st, GL_FLOAT, stride, trace_pointer_value,
6621                                     vogl_texcoord_pointer_array_id, GL_ENTRYPOINT(glTexCoordPointer), m_client_side_texcoord_data[tex_index]);
6622             }
6623             else
6624             {
6625                 GL_ENTRYPOINT(glDisableClientState)(GL_TEXTURE_COORD_ARRAY);
6626             }
6627
6628             check_gl_error();
6629
6630             if (fmt.ec)
6631             {
6632                 GL_ENTRYPOINT(glEnableClientState)(GL_COLOR_ARRAY);
6633                 vertex_array_helper(fmt.sc, fmt.tc, stride, trace_pointer_value + fmt.pc,
6634                                     vogl_color_pointer_array_id, GL_ENTRYPOINT(glColorPointer), m_client_side_array_data[vogl_color_pointer_array_id]);
6635             }
6636             else
6637             {
6638                 GL_ENTRYPOINT(glDisableClientState)(GL_COLOR_ARRAY);
6639             }
6640
6641             check_gl_error();
6642
6643             if (fmt.en)
6644             {
6645                 GL_ENTRYPOINT(glEnableClientState)(GL_NORMAL_ARRAY);
6646                 vertex_array_helper_no_size(GL_FLOAT, stride, trace_pointer_value + fmt.pn,
6647                                             vogl_normal_pointer_array_id, GL_ENTRYPOINT(glNormalPointer));
6648             }
6649             else
6650             {
6651                 GL_ENTRYPOINT(glDisableClientState)(GL_NORMAL_ARRAY);
6652             }
6653
6654             check_gl_error();
6655
6656             GL_ENTRYPOINT(glEnableClientState)(GL_VERTEX_ARRAY);
6657             vertex_array_helper(fmt.sv, GL_FLOAT, stride, trace_pointer_value + fmt.pv,
6658                                 vogl_vertex_pointer_array_id, GL_ENTRYPOINT(glVertexPointer), m_client_side_array_data[vogl_vertex_pointer_array_id]);
6659
6660             break;
6661         }
6662         case VOGL_ENTRYPOINT_glVertexAttribIPointer:
6663         case VOGL_ENTRYPOINT_glVertexAttribIPointerEXT:
6664         {
6665             GLuint index = trace_packet.get_param_value<GLuint>(0);
6666             GLint size = trace_packet.get_param_value<GLint>(1);
6667             GLenum type = trace_packet.get_param_value<GLenum>(2);
6668             GLsizei stride = trace_packet.get_param_value<GLsizei>(3);
6669             vogl_trace_ptr_value trace_pointer = trace_packet.get_param_ptr_value(4);
6670
6671             if (index >= m_pCur_context_state->m_context_info.get_max_vertex_attribs())
6672             {
6673                 process_entrypoint_error("%s: Generic vertex attribute index is too large\n", VOGL_METHOD_NAME);
6674                 return cStatusSoftFailure;
6675             }
6676
6677             GLuint buffer = vogl_get_bound_gl_buffer(GL_ARRAY_BUFFER);
6678             void *pPtr = reinterpret_cast<void *>(trace_pointer);
6679             if ((!buffer) && (trace_pointer))
6680             {
6681                 // We've got a trace pointer to client side memory, but we don't have it until the actual draw.
6682                 // So point this guy into one of our client size memory buffers that's hopefully large enough.
6683                 if (!m_client_side_vertex_attrib_data[index].size())
6684                 {
6685                     m_client_side_vertex_attrib_data[index].resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
6686                 }
6687                 pPtr = m_client_side_vertex_attrib_data[index].get_ptr();
6688             }
6689
6690             if (entrypoint_id == VOGL_ENTRYPOINT_glVertexAttribIPointer)
6691                 GL_ENTRYPOINT(glVertexAttribIPointer)(index, size, type, stride, pPtr);
6692             else
6693                 GL_ENTRYPOINT(glVertexAttribIPointerEXT)(index, size, type, stride, pPtr);
6694
6695             break;
6696         }
6697         case VOGL_ENTRYPOINT_glVertexAttribPointerARB:
6698         case VOGL_ENTRYPOINT_glVertexAttribPointer:
6699         {
6700             GLuint index = trace_packet.get_param_value<GLuint>(0);
6701             GLint size = trace_packet.get_param_value<GLint>(1);
6702             GLenum type = trace_packet.get_param_value<GLenum>(2);
6703             GLboolean normalized = trace_packet.get_param_value<GLboolean>(3);
6704             GLsizei stride = trace_packet.get_param_value<GLsizei>(4);
6705             vogl_trace_ptr_value trace_pointer = trace_packet.get_param_ptr_value(5);
6706
6707             if (index >= m_pCur_context_state->m_context_info.get_max_vertex_attribs())
6708             {
6709                 process_entrypoint_error("%s: Generic vertex attribute index is too large\n", VOGL_METHOD_NAME);
6710                 return cStatusSoftFailure;
6711             }
6712
6713             GLuint buffer = vogl_get_bound_gl_buffer(GL_ARRAY_BUFFER);
6714             void *pPtr = reinterpret_cast<void *>(trace_pointer);
6715             if ((!buffer) && (trace_pointer))
6716             {
6717                 // We've got a trace pointer to client side memory, but we don't have it until the actual draw.
6718                 // So point this guy into one of our client size memory buffers that's hopefully large enough.
6719                 if (!m_client_side_vertex_attrib_data[index].size())
6720                 {
6721                     m_client_side_vertex_attrib_data[index].resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
6722                 }
6723                 pPtr = m_client_side_vertex_attrib_data[index].get_ptr();
6724             }
6725
6726             if (entrypoint_id == VOGL_ENTRYPOINT_glVertexAttribPointer)
6727                 GL_ENTRYPOINT(glVertexAttribPointer)(index, size, type, normalized, stride, pPtr);
6728             else
6729                 GL_ENTRYPOINT(glVertexAttribPointerARB)(index, size, type, normalized, stride, pPtr);
6730
6731             break;
6732         }
6733         case VOGL_ENTRYPOINT_glDrawRangeElements:
6734         case VOGL_ENTRYPOINT_glDrawRangeElementsEXT:
6735         {
6736             GLenum mode = trace_packet.get_param_value<GLenum>(0);
6737             GLuint start = trace_packet.get_param_value<GLuint>(1);
6738             GLuint end = trace_packet.get_param_value<GLuint>(2);
6739             GLsizei count = trace_packet.get_param_value<GLsizei>(3);
6740             GLenum type = trace_packet.get_param_value<GLenum>(4);
6741             vogl_trace_ptr_value trace_indices_ptr_value = trace_packet.get_param_ptr_value(5);
6742
6743             const GLvoid *pIndices;
6744             if (!draw_elements_client_side_array_setup(mode, start, end, count, type, trace_indices_ptr_value, pIndices, 0, true, true))
6745                 return cStatusSoftFailure;
6746
6747             if (m_frame_draw_counter < m_frame_draw_counter_kill_threshold)
6748             {
6749                 if (entrypoint_id == VOGL_ENTRYPOINT_glDrawRangeElements)
6750                     GL_ENTRYPOINT(glDrawRangeElements)(mode, start, end, count, type, pIndices);
6751                 else
6752                     GL_ENTRYPOINT(glDrawRangeElementsEXT)(mode, start, end, count, type, pIndices);
6753             }
6754
6755             break;
6756         }
6757         case VOGL_ENTRYPOINT_glDrawRangeElementsBaseVertex:
6758         {
6759             GLenum mode = trace_packet.get_param_value<GLenum>(0);
6760             GLuint start = trace_packet.get_param_value<GLuint>(1);
6761             GLuint end = trace_packet.get_param_value<GLuint>(2);
6762             GLsizei count = trace_packet.get_param_value<GLsizei>(3);
6763             GLenum type = trace_packet.get_param_value<GLenum>(4);
6764             vogl_trace_ptr_value trace_indices_ptr_value = trace_packet.get_param_ptr_value(5);
6765             GLint basevertex = trace_packet.get_param_value<GLint>(6);
6766
6767             const GLvoid *pIndices;
6768             if (!draw_elements_client_side_array_setup(mode, start, end, count, type, trace_indices_ptr_value, pIndices, basevertex, true, true))
6769                 return cStatusSoftFailure;
6770
6771             if (m_frame_draw_counter < m_frame_draw_counter_kill_threshold)
6772             {
6773                 GL_ENTRYPOINT(glDrawRangeElementsBaseVertex)(mode, start, end, count, type, pIndices, basevertex);
6774             }
6775
6776             break;
6777         }
6778         case VOGL_ENTRYPOINT_glDrawElements:
6779         {
6780             GLenum mode = trace_packet.get_param_value<GLenum>(0);
6781             GLsizei count = trace_packet.get_param_value<GLsizei>(1);
6782             GLenum type = trace_packet.get_param_value<GLenum>(2);
6783             vogl_trace_ptr_value trace_indices_ptr_value = trace_packet.get_param_ptr_value(3);
6784
6785             const GLvoid *pIndices;
6786             if (!draw_elements_client_side_array_setup(mode, 0, 0, count, type, trace_indices_ptr_value, pIndices, 0, false, true))
6787                 return cStatusSoftFailure;
6788
6789             if (m_frame_draw_counter < m_frame_draw_counter_kill_threshold)
6790             {
6791                 GL_ENTRYPOINT(glDrawElements)(mode, count, type, pIndices);
6792             }
6793
6794             break;
6795         }
6796         case VOGL_ENTRYPOINT_glDrawArraysInstanced:
6797         case VOGL_ENTRYPOINT_glDrawArraysInstancedEXT:
6798         {
6799             VOGL_REPLAY_LOAD_PARAMS_HELPER_glDrawArraysInstanced;
6800
6801             const GLvoid *pIndices = NULL;
6802             if (!draw_elements_client_side_array_setup(mode, first, first + count - 1, count, GL_UNSIGNED_BYTE, 0, pIndices, 0, true, false))
6803                 return cStatusSoftFailure;
6804
6805             if (entrypoint_id == VOGL_ENTRYPOINT_glDrawArraysInstancedEXT)
6806             {
6807                 GLsizei start = first, primcount = instancecount;
6808                 VOGL_REPLAY_CALL_GL_HELPER_glDrawArraysInstancedEXT;
6809             }
6810             else
6811                 VOGL_REPLAY_CALL_GL_HELPER_glDrawArraysInstanced;
6812
6813             break;
6814         }
6815         case VOGL_ENTRYPOINT_glDrawArrays:
6816         case VOGL_ENTRYPOINT_glDrawArraysEXT:
6817         {
6818             GLenum mode = trace_packet.get_param_value<GLenum>(0);
6819             GLint first = trace_packet.get_param_value<GLint>(1);
6820             GLsizei count = trace_packet.get_param_value<GLsizei>(2);
6821
6822             const GLvoid *pIndices = NULL;
6823             if (!draw_elements_client_side_array_setup(mode, first, first + count - 1, count, GL_UNSIGNED_BYTE, 0, pIndices, 0, true, false))
6824                 return cStatusSoftFailure;
6825
6826             if (m_frame_draw_counter < m_frame_draw_counter_kill_threshold)
6827             {
6828                 if (entrypoint_id == VOGL_ENTRYPOINT_glDrawArraysEXT)
6829                     GL_ENTRYPOINT(glDrawArraysEXT)(mode, first, count);
6830                 else
6831                     GL_ENTRYPOINT(glDrawArrays)(mode, first, count);
6832             }
6833
6834             break;
6835         }
6836         case VOGL_ENTRYPOINT_glDrawElementsInstanced:
6837         case VOGL_ENTRYPOINT_glDrawElementsInstancedARB:
6838         case VOGL_ENTRYPOINT_glDrawElementsInstancedEXT:
6839         {
6840             GLenum mode = trace_packet.get_param_value<GLenum>(0);
6841             GLsizei count = trace_packet.get_param_value<GLsizei>(1);
6842             GLenum type = trace_packet.get_param_value<GLenum>(2);
6843             vogl_trace_ptr_value trace_indices_ptr_value = trace_packet.get_param_ptr_value(3);
6844             GLsizei primcount = trace_packet.get_param_value<GLsizei>(4);
6845
6846             const GLvoid *pIndices;
6847             if (!draw_elements_client_side_array_setup(mode, 0, 0, count, type, trace_indices_ptr_value, pIndices, 0, false, true))
6848                 return cStatusSoftFailure;
6849
6850             if (m_frame_draw_counter < m_frame_draw_counter_kill_threshold)
6851             {
6852                 if (entrypoint_id == VOGL_ENTRYPOINT_glDrawElementsInstanced)
6853                     GL_ENTRYPOINT(glDrawElementsInstanced)(mode, count, type, pIndices, primcount);
6854                 else if (entrypoint_id == VOGL_ENTRYPOINT_glDrawElementsInstancedEXT)
6855                     GL_ENTRYPOINT(glDrawElementsInstancedEXT)(mode, count, type, pIndices, primcount);
6856                 else
6857                     GL_ENTRYPOINT(glDrawElementsInstancedARB)(mode, count, type, pIndices, primcount);
6858             }
6859
6860             break;
6861         }
6862         case VOGL_ENTRYPOINT_glDrawElementsInstancedBaseVertex:
6863         {
6864             GLenum mode = trace_packet.get_param_value<GLenum>(0);
6865             GLsizei count = trace_packet.get_param_value<GLsizei>(1);
6866             GLenum type = trace_packet.get_param_value<GLenum>(2);
6867             vogl_trace_ptr_value trace_indices_ptr_value = trace_packet.get_param_ptr_value(3);
6868             GLsizei primcount = trace_packet.get_param_value<GLsizei>(4);
6869             GLint basevertex = trace_packet.get_param_value<GLint>(5);
6870
6871             const GLvoid *pIndices;
6872             if (!draw_elements_client_side_array_setup(mode, 0, 0, count, type, trace_indices_ptr_value, pIndices, basevertex, false, true))
6873                 return cStatusSoftFailure;
6874
6875             if (m_frame_draw_counter < m_frame_draw_counter_kill_threshold)
6876             {
6877                 GL_ENTRYPOINT(glDrawElementsInstancedBaseVertex)(mode, count, type, pIndices, primcount, basevertex);
6878             }
6879
6880             break;
6881         }
6882         case VOGL_ENTRYPOINT_glMultiDrawArrays:
6883         case VOGL_ENTRYPOINT_glMultiDrawArraysEXT:
6884         {
6885             GLenum mode = trace_packet.get_param_value<GLenum>(0);
6886
6887             const GLint *pFirst = trace_packet.get_param_client_memory<const GLint>(1);
6888             uint first_size = trace_packet.get_param_client_memory_data_size(1);
6889
6890             const GLsizei *pCount = trace_packet.get_param_client_memory<const GLsizei>(2);
6891             uint count_size = trace_packet.get_param_client_memory_data_size(2);
6892
6893             GLsizei primcount = trace_packet.get_param_value<GLsizei>(3);
6894
6895             if ((first_size != primcount * sizeof(GLint)) || (count_size != primcount * sizeof(GLsizei)))
6896             {
6897                 process_entrypoint_error("%s: first and/or count params do not point to arrays of the expected size\n", VOGL_METHOD_NAME);
6898                 return cStatusSoftFailure;
6899             }
6900
6901             if (m_frame_draw_counter < m_frame_draw_counter_kill_threshold)
6902             {
6903                 //  Multi-draws with client side arrays are not supported for replay.
6904                 if (entrypoint_id == VOGL_ENTRYPOINT_glMultiDrawElements)
6905                     GL_ENTRYPOINT(glMultiDrawArrays)(mode, pFirst, pCount, primcount);
6906                 else
6907                     GL_ENTRYPOINT(glMultiDrawArraysEXT)(mode, pFirst, pCount, primcount);
6908             }
6909
6910             break;
6911         }
6912         case VOGL_ENTRYPOINT_glMultiDrawElements:
6913         case VOGL_ENTRYPOINT_glMultiDrawElementsEXT:
6914         {
6915             GLenum mode = trace_packet.get_param_value<GLenum>(0);
6916
6917             const GLsizei *pCount = trace_packet.get_param_client_memory<const GLsizei>(1);
6918             uint count_size = trace_packet.get_param_client_memory_data_size(1);
6919
6920             GLenum type = trace_packet.get_param_value<GLenum>(2);
6921
6922             const vogl_client_memory_array trace_indices_void_ptr_array = trace_packet.get_param_client_memory_array(3); // const GLvoid *
6923
6924             GLsizei primcount = trace_packet.get_param_value<GLsizei>(4);
6925
6926             if ((count_size != static_cast<uint>(primcount * sizeof(GLsizei))) || (trace_indices_void_ptr_array.size() != static_cast<uint>(primcount)))
6927             {
6928                 process_entrypoint_error("%s: count and/or indices params do not point to arrays of the expected size\n", VOGL_METHOD_NAME);
6929                 return cStatusSoftFailure;
6930             }
6931
6932             vogl::growable_array<GLvoid *, 256> replay_indices(trace_indices_void_ptr_array.size());
6933             for (uint i = 0; i < trace_indices_void_ptr_array.size(); i++)
6934                 replay_indices[i] = reinterpret_cast<GLvoid *>(trace_indices_void_ptr_array.get_element<vogl_trace_ptr_value>(i));
6935
6936             if (m_frame_draw_counter < m_frame_draw_counter_kill_threshold)
6937             {
6938                 //  Multi-draws with client side arrays are not supported for replay.
6939                 if (entrypoint_id == VOGL_ENTRYPOINT_glMultiDrawElements)
6940                     GL_ENTRYPOINT(glMultiDrawElements)(mode, pCount, type, replay_indices.get_ptr(), primcount);
6941                 else
6942                     GL_ENTRYPOINT(glMultiDrawElementsEXT)(mode, pCount, type, (const GLvoid **)replay_indices.get_ptr(), primcount);
6943             }
6944
6945             break;
6946         }
6947         case VOGL_ENTRYPOINT_glMultiDrawElementsBaseVertex:
6948         {
6949             GLenum mode = trace_packet.get_param_value<GLenum>(0);
6950
6951             const GLsizei *pCount = trace_packet.get_param_client_memory<const GLsizei>(1);
6952             uint count_size = trace_packet.get_param_client_memory_data_size(1);
6953
6954             GLenum type = trace_packet.get_param_value<GLenum>(2);
6955
6956             const vogl_client_memory_array trace_indices_void_ptr_array = trace_packet.get_param_client_memory_array(3); // const GLvoid *
6957             //GLvoid * const *ppIndices = trace_packet.get_param_client_memory<GLvoid *>(3);
6958             //uint index_size = trace_packet.get_param_client_memory_data_size(3);
6959
6960             GLsizei primcount = trace_packet.get_param_value<GLsizei>(4);
6961
6962             const GLint *pBase_vertex = trace_packet.get_param_client_memory<const GLint>(5);
6963             uint base_vertex_size = trace_packet.get_param_client_memory_data_size(5);
6964
6965             if ((count_size != primcount * sizeof(GLsizei)) ||
6966                 (trace_indices_void_ptr_array.size() != static_cast<uint>(primcount)) ||
6967                 (base_vertex_size != primcount * sizeof(GLint)))
6968             {
6969                 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);
6970                 return cStatusSoftFailure;
6971             }
6972
6973             vogl::growable_array<GLvoid *, 256> replay_indices(trace_indices_void_ptr_array.size());
6974             for (uint i = 0; i < trace_indices_void_ptr_array.size(); i++)
6975                 replay_indices[i] = reinterpret_cast<GLvoid *>(trace_indices_void_ptr_array.get_element<vogl_trace_ptr_value>(i));
6976
6977             if (m_frame_draw_counter < m_frame_draw_counter_kill_threshold)
6978             {
6979                 //  Multi-draws with client side arrays are not supported for replay.
6980                 GL_ENTRYPOINT(glMultiDrawElementsBaseVertex)(mode, pCount, type, replay_indices.get_ptr(), primcount, pBase_vertex);
6981             }
6982
6983             break;
6984         }
6985         case VOGL_ENTRYPOINT_glDrawElementsBaseVertex:
6986         {
6987             GLenum mode = trace_packet.get_param_value<GLenum>(0);
6988             GLsizei count = trace_packet.get_param_value<GLsizei>(1);
6989             GLenum type = trace_packet.get_param_value<GLenum>(2);
6990             vogl_trace_ptr_value trace_indices_ptr_value = trace_packet.get_param_ptr_value(3);
6991             GLint base_vertex = trace_packet.get_param_value<GLint>(4);
6992
6993             const GLvoid *pIndices;
6994             if (!draw_elements_client_side_array_setup(mode, 0, 0, count, type, trace_indices_ptr_value, pIndices, base_vertex, false, true))
6995                 return cStatusSoftFailure;
6996
6997             if (m_frame_draw_counter < m_frame_draw_counter_kill_threshold)
6998             {
6999                 GL_ENTRYPOINT(glDrawElementsBaseVertex)(mode, count, type, pIndices, base_vertex);
7000             }
7001
7002             break;
7003         }
7004         case VOGL_ENTRYPOINT_glGetBufferSubData:
7005         {
7006             if (!benchmark_mode())
7007             {
7008                 GLenum target = trace_packet.get_param_value<GLenum>(0);
7009                 vogl_trace_ptr_value offset = trace_packet.get_param_ptr_value(1);
7010                 vogl_trace_ptr_value size = trace_packet.get_param_ptr_value(2);
7011                 GLvoid *pTrace_ptr = trace_packet.get_param_client_memory<GLvoid>(3);
7012
7013                 if (offset != static_cast<uintptr_t>(offset))
7014                 {
7015                     process_entrypoint_error("%s: offset parameter is too large (%" PRIu64 ")\n", VOGL_METHOD_NAME, (uint64_t)offset);
7016                     return cStatusHardFailure;
7017                 }
7018
7019                 if ((size > cUINT32_MAX) || (size != static_cast<uintptr_t>(size)))
7020                 {
7021                     process_entrypoint_error("%s: size parameter is too large (%" PRIu64 ")\n", VOGL_METHOD_NAME, (uint64_t)size);
7022                     return cStatusHardFailure;
7023                 }
7024
7025                 vogl::growable_array<uint8, 1024> buf(pTrace_ptr ? static_cast<uint>(size) : 0);
7026
7027                 GL_ENTRYPOINT(glGetBufferSubData)(target, static_cast<GLintptr>(offset), static_cast<GLsizeiptr>(size), pTrace_ptr ? buf.get_ptr() : NULL);
7028
7029                 if ((buf.size()) && (pTrace_ptr))
7030                 {
7031                     if (memcmp(buf.get_ptr(), pTrace_ptr, static_cast<size_t>(size)) != 0)
7032                     {
7033                         process_entrypoint_warning("%s: Replay's returned data differed from trace's\n", VOGL_METHOD_NAME);
7034                     }
7035                 }
7036             }
7037
7038             break;
7039         }
7040         case VOGL_ENTRYPOINT_glGetClipPlane:
7041         {
7042             if (!benchmark_mode())
7043             {
7044                 GLenum plane = trace_packet.get_param_value<GLenum>(0);
7045                 const GLdouble *pTrace_equation = trace_packet.get_param_client_memory<GLdouble>(1);
7046
7047                 GLdouble equation[4];
7048                 GL_ENTRYPOINT(glGetClipPlane)(plane, pTrace_equation ? equation : NULL);
7049
7050                 if (pTrace_equation)
7051                 {
7052                     if (memcmp(equation, pTrace_equation, sizeof(GLdouble) * 4) != 0)
7053                     {
7054                         process_entrypoint_warning("%s: Replay's returned data differed from trace's\n", VOGL_METHOD_NAME);
7055                     }
7056                 }
7057             }
7058
7059             break;
7060         }
7061         case VOGL_ENTRYPOINT_glBufferData:
7062         case VOGL_ENTRYPOINT_glBufferDataARB:
7063         {
7064             GLenum target = trace_packet.get_param_value<GLenum>(0);
7065             vogl_trace_ptr_value size = trace_packet.get_param_value<vogl_trace_ptr_value>(1); // GLsizeiptrARB
7066             const GLvoid *data = trace_packet.get_param_client_memory_ptr(2);
7067             uint data_size = trace_packet.get_param_client_memory_data_size(2);
7068             GLenum usage = trace_packet.get_param_value<GLenum>(3);
7069
7070             if ((data) && (static_cast<vogl_trace_ptr_value>(data_size) < size))
7071             {
7072                 process_entrypoint_error("%s: trace's data array is too small\n", VOGL_METHOD_NAME);
7073                 return cStatusHardFailure;
7074             }
7075
7076             if (size != static_cast<uintptr_t>(size))
7077             {
7078                 process_entrypoint_error("%s: size parameter is too large (%" PRIu64 ")\n", VOGL_METHOD_NAME, static_cast<uint64_t>(size));
7079                 return cStatusHardFailure;
7080             }
7081
7082             if (entrypoint_id == VOGL_ENTRYPOINT_glBufferData)
7083                 g_vogl_actual_gl_entrypoints.m_glBufferData(target, static_cast<GLsizeiptr>(size), data, usage);
7084             else
7085                 g_vogl_actual_gl_entrypoints.m_glBufferDataARB(target, static_cast<GLsizeiptrARB>(size), data, usage);
7086
7087             GLuint buffer = vogl_get_bound_gl_buffer(target);
7088             if (buffer)
7089             {
7090                 vogl_mapped_buffer_desc_vec &mapped_bufs = get_shared_state()->m_shadow_state.m_mapped_buffers;
7091
7092                 uint i;
7093                 for (i = 0; i < mapped_bufs.size(); i++)
7094                 {
7095                     if (mapped_bufs[i].m_buffer == buffer)
7096                     {
7097                         process_entrypoint_warning("%s: glBufferData() called on already mapped GL buffer %u, assuming GL will be unmapping it\n", VOGL_METHOD_NAME, buffer);
7098
7099                         mapped_bufs.erase_unordered(i);
7100                         break;
7101                     }
7102                 }
7103             }
7104
7105             break;
7106         }
7107         case VOGL_ENTRYPOINT_glMapBufferARB:
7108         case VOGL_ENTRYPOINT_glMapBuffer:
7109         {
7110             GLenum target = trace_packet.get_param_value<GLenum>(0);
7111             GLenum access = trace_packet.get_param_value<GLenum>(1);
7112             vogl_trace_ptr_value trace_result_ptr_value = trace_packet.get_return_ptr_value();
7113
7114             // FIXME - must call GL even if !pTrace_result
7115             if (trace_result_ptr_value)
7116             {
7117                 void *pMap;
7118                 if (entrypoint_id == VOGL_ENTRYPOINT_glMapBuffer)
7119                     pMap = GL_ENTRYPOINT(glMapBuffer)(target, access);
7120                 else
7121                     pMap = GL_ENTRYPOINT(glMapBufferARB)(target, access);
7122
7123                 if (!pMap)
7124                 {
7125                     process_entrypoint_error("%s: glMapBuffer succeeded during trace, but failed during replay!\n", VOGL_METHOD_NAME);
7126                     return cStatusHardFailure;
7127                 }
7128
7129                 GLuint buffer = vogl_get_bound_gl_buffer(target);
7130
7131                 vogl_mapped_buffer_desc_vec &mapped_bufs = get_shared_state()->m_shadow_state.m_mapped_buffers;
7132
7133                 uint i;
7134                 for (i = 0; i < mapped_bufs.size(); i++)
7135                 {
7136                     if (mapped_bufs[i].m_buffer == buffer)
7137                     {
7138                         process_entrypoint_error("%s: Buffer %u is already mapped\n", VOGL_METHOD_NAME, buffer);
7139                         return cStatusHardFailure;
7140                     }
7141                 }
7142
7143                 if (i == mapped_bufs.size())
7144                 {
7145                     GLint length = 0;
7146                     GL_ENTRYPOINT(glGetBufferParameteriv)(target, GL_BUFFER_SIZE, &length);
7147
7148                     vogl_mapped_buffer_desc m;
7149                     m.m_buffer = buffer;
7150                     m.m_target = target;
7151                     m.m_offset = 0;
7152                     m.m_length = length;
7153                     m.m_access = access;
7154                     m.m_range = false;
7155                     m.m_pPtr = pMap;
7156                     mapped_bufs.push_back(m);
7157                 }
7158             }
7159
7160             break;
7161         }
7162         case VOGL_ENTRYPOINT_glMapBufferRange:
7163         {
7164             GLenum target = trace_packet.get_param_value<GLenum>(0);
7165             vogl_trace_ptr_value offset = trace_packet.get_param_value<vogl_trace_ptr_value>(1); // GLintptr
7166             vogl_trace_ptr_value length = trace_packet.get_param_value<vogl_trace_ptr_value>(2); // GLsizeiptr
7167             GLbitfield access = trace_packet.get_param_value<GLbitfield>(3);
7168             vogl_trace_ptr_value trace_result_ptr_value = trace_packet.get_return_ptr_value();
7169
7170             if (offset != static_cast<uintptr_t>(offset))
7171             {
7172                 process_entrypoint_error("%s: offset parameter is too large (%" PRIu64 ")\n", VOGL_METHOD_NAME, static_cast<uint64_t>(offset));
7173                 return cStatusHardFailure;
7174             }
7175             if (length != static_cast<uintptr_t>(length))
7176             {
7177                 process_entrypoint_error("%s: length parameter is too large (%" PRIu64 ")\n", VOGL_METHOD_NAME, static_cast<uint64_t>(length));
7178                 return cStatusHardFailure;
7179             }
7180
7181             // FIXME - must call GL even if !pTrace_result
7182             if (trace_result_ptr_value)
7183             {
7184                 void *pMap = GL_ENTRYPOINT(glMapBufferRange)(target, static_cast<GLintptr>(offset), static_cast<GLsizeiptr>(length), access);
7185                 if (!pMap)
7186                 {
7187                     process_entrypoint_error("%s: glMapBufferRange succeeded during trace, but failed during replay!\n", VOGL_METHOD_NAME);
7188                     return cStatusHardFailure;
7189                 }
7190
7191                 vogl_mapped_buffer_desc_vec &mapped_bufs = get_shared_state()->m_shadow_state.m_mapped_buffers;
7192
7193                 GLuint buffer = vogl_get_bound_gl_buffer(target);
7194                 uint i;
7195                 for (i = 0; i < mapped_bufs.size(); i++)
7196                 {
7197                     if (mapped_bufs[i].m_buffer == buffer)
7198                     {
7199                         process_entrypoint_error("%s: Buffer %u is already mapped\n", VOGL_METHOD_NAME, buffer);
7200                         return cStatusHardFailure;
7201                     }
7202                 }
7203
7204                 if (i == mapped_bufs.size())
7205                 {
7206                     vogl_mapped_buffer_desc m;
7207                     m.m_buffer = buffer;
7208                     m.m_target = target;
7209                     m.m_offset = offset;
7210                     m.m_length = length;
7211                     m.m_access = access;
7212                     m.m_range = true;
7213                     m.m_pPtr = pMap;
7214                     mapped_bufs.push_back(m);
7215                 }
7216             }
7217
7218             break;
7219         }
7220         case VOGL_ENTRYPOINT_glFlushMappedBufferRange:
7221         {
7222             // vogltrace queues up the flushes, will process them while handling the glUnmapBuffer() call
7223             break;
7224         }
7225         case VOGL_ENTRYPOINT_glUnmapBufferARB:
7226         case VOGL_ENTRYPOINT_glUnmapBuffer:
7227         {
7228             GLenum target = trace_packet.get_param_value<GLenum>(0);
7229             GLboolean trace_result = trace_packet.get_return_value<GLboolean>();
7230
7231             GLuint buffer = vogl_get_bound_gl_buffer(target);
7232
7233             // FIXME - must call GL even if !buffer
7234             if (buffer)
7235             {
7236                 vogl_mapped_buffer_desc_vec &mapped_bufs = get_shared_state()->m_shadow_state.m_mapped_buffers;
7237
7238                 uint mapped_buffers_index;
7239                 for (mapped_buffers_index = 0; mapped_buffers_index < mapped_bufs.size(); mapped_buffers_index++)
7240                     if (mapped_bufs[mapped_buffers_index].m_buffer == buffer)
7241                         break;
7242                 if (mapped_buffers_index == mapped_bufs.size())
7243                 {
7244                     process_entrypoint_error("%s: Unable to find mapped buffer during unmap\n", VOGL_METHOD_NAME);
7245                     return cStatusHardFailure;
7246                 }
7247
7248                 vogl_mapped_buffer_desc &map_desc = mapped_bufs[mapped_buffers_index];
7249
7250                 bool writable_map = false;
7251                 bool explicit_bit = false;
7252                 if (map_desc.m_range)
7253                 {
7254                     writable_map = ((map_desc.m_access & GL_MAP_WRITE_BIT) != 0);
7255                     explicit_bit = (map_desc.m_access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0;
7256                 }
7257                 else
7258                 {
7259                     writable_map = (map_desc.m_access != GL_READ_ONLY);
7260                 }
7261
7262                 if (writable_map)
7263                 {
7264                     const key_value_map &unmap_data = trace_packet.get_key_value_map();
7265
7266                     if (explicit_bit)
7267                     {
7268                         int num_flushed_ranges = unmap_data.get_int(string_hash("flushed_ranges"));
7269
7270                         for (int i = 0; i < num_flushed_ranges; i++)
7271                         {
7272                             int64_t ofs = unmap_data.get_int64(i * 4 + 0);
7273                             int64_t size = unmap_data.get_int64(i * 4 + 1);
7274                             VOGL_NOTE_UNUSED(size);
7275                             const uint8_vec *pData = unmap_data.get_blob(i * 4 + 2);
7276                             if (!pData)
7277                             {
7278                                 process_entrypoint_error("%s: Failed finding flushed range data in key value map\n", VOGL_METHOD_NAME);
7279                                 return cStatusHardFailure;
7280                             }
7281
7282                             if (ofs != static_cast<GLintptr>(ofs))
7283                             {
7284                                 process_entrypoint_error("%s: Flush offset is too large (%" PRIu64 ")\n", VOGL_METHOD_NAME, static_cast<uint64_t>(ofs));
7285                                 return cStatusHardFailure;
7286                             }
7287
7288                             VOGL_ASSERT(size == pData->size());
7289
7290                             memcpy(static_cast<uint8 *>(map_desc.m_pPtr) + ofs, pData->get_ptr(), pData->size());
7291
7292                             GL_ENTRYPOINT(glFlushMappedBufferRange)(target, static_cast<GLintptr>(ofs), pData->size());
7293                         }
7294                     }
7295                     else
7296                     {
7297                         int64_t ofs = unmap_data.get_int64(0);
7298                         VOGL_NOTE_UNUSED(ofs);
7299                         int64_t size = unmap_data.get_int64(1);
7300                         VOGL_NOTE_UNUSED(size);
7301                         const uint8_vec *pData = unmap_data.get_blob(2);
7302                         if (!pData)
7303                         {
7304                             process_entrypoint_error("%s: Failed finding mapped data in key value map\n", VOGL_METHOD_NAME);
7305                             return cStatusHardFailure;
7306                         }
7307                         else
7308                         {
7309                             memcpy(map_desc.m_pPtr, pData->get_ptr(), pData->size());
7310                         }
7311                     }
7312                 }
7313
7314                 get_shared_state()->m_shadow_state.m_mapped_buffers.erase_unordered(mapped_buffers_index);
7315             }
7316
7317             GLboolean replay_result;
7318             if (entrypoint_id == VOGL_ENTRYPOINT_glUnmapBuffer)
7319                 replay_result = GL_ENTRYPOINT(glUnmapBuffer)(target);
7320             else
7321                 replay_result = GL_ENTRYPOINT(glUnmapBufferARB)(target);
7322
7323             if (trace_result != replay_result)
7324                 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);
7325
7326             break;
7327         }
7328         case VOGL_ENTRYPOINT_glGenVertexArrays:
7329         {
7330             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))
7331                 return cStatusHardFailure;
7332             break;
7333         }
7334         case VOGL_ENTRYPOINT_glBindVertexArray:
7335         {
7336             GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
7337             GLuint replay_handle = map_handle(get_context_state()->m_vertex_array_objects, trace_handle);
7338
7339             GL_ENTRYPOINT(glBindVertexArray)(replay_handle);
7340             break;
7341         }
7342         case VOGL_ENTRYPOINT_glDeleteVertexArrays:
7343         {
7344             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));
7345             break;
7346         }
7347         case VOGL_ENTRYPOINT_glIsFramebuffer:
7348         case VOGL_ENTRYPOINT_glIsFramebufferEXT:
7349         {
7350             if (!benchmark_mode())
7351             {
7352                 GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
7353                 GLuint replay_handle = map_handle(get_context_state()->m_framebuffers, trace_handle);
7354                 GLboolean trace_result = trace_packet.get_return_value<GLboolean>();
7355
7356                 GLboolean replay_result;
7357                 if (entrypoint_id == VOGL_ENTRYPOINT_glIsFramebuffer)
7358                     replay_result = GL_ENTRYPOINT(glIsFramebuffer)(replay_handle);
7359                 else
7360                     replay_result = GL_ENTRYPOINT(glIsFramebufferEXT)(replay_handle);
7361
7362                 if (trace_result != replay_result)
7363                     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));
7364             }
7365
7366             break;
7367         }
7368         case VOGL_ENTRYPOINT_glIsBuffer:
7369         {
7370             if (!benchmark_mode())
7371             {
7372                 GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
7373                 GLuint replay_handle = map_handle(get_shared_state()->m_buffers, trace_handle);
7374                 GLboolean trace_result = trace_packet.get_return_value<GLboolean>();
7375
7376                 GLboolean replay_result = GL_ENTRYPOINT(glIsBuffer)(replay_handle);
7377                 if (trace_result != replay_result)
7378                     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));
7379             }
7380             break;
7381         }
7382         case VOGL_ENTRYPOINT_glIsEnabledi:
7383         {
7384             if (!benchmark_mode())
7385             {
7386                 GLenum cap = trace_packet.get_param_value<GLenum>(0);
7387                 GLuint index = trace_packet.get_param_value<GLuint>(1);
7388                 GLboolean trace_result = trace_packet.get_return_value<GLboolean>();
7389
7390                 GLboolean replay_result = GL_ENTRYPOINT(glIsEnabledi)(cap, index);
7391                 if (trace_result != replay_result)
7392                     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));
7393             }
7394             break;
7395         }
7396         case VOGL_ENTRYPOINT_glIsEnabled:
7397         {
7398             if (!benchmark_mode())
7399             {
7400                 GLenum cap = trace_packet.get_param_value<GLenum>(0);
7401                 GLboolean trace_result = trace_packet.get_return_value<GLboolean>();
7402
7403                 GLboolean replay_result = GL_ENTRYPOINT(glIsEnabled)(cap);
7404                 if (trace_result != replay_result)
7405                     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));
7406             }
7407             break;
7408         }
7409         case VOGL_ENTRYPOINT_glIsProgram:
7410         {
7411             if (!benchmark_mode())
7412             {
7413                 GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
7414                 GLuint replay_handle = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle);
7415                 GLboolean trace_result = trace_packet.get_return_value<GLboolean>();
7416
7417                 GLboolean replay_result = GL_ENTRYPOINT(glIsProgram)(replay_handle);
7418
7419                 if (trace_result != replay_result)
7420                     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));
7421             }
7422             break;
7423         }
7424         case VOGL_ENTRYPOINT_glIsQuery:
7425         {
7426             if (!benchmark_mode())
7427             {
7428                 GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
7429                 GLuint replay_handle = map_handle(get_shared_state()->m_queries, trace_handle);
7430                 GLboolean trace_result = trace_packet.get_return_value<GLboolean>();
7431
7432                 GLboolean replay_result = GL_ENTRYPOINT(glIsQuery)(replay_handle);
7433                 if (trace_result != replay_result)
7434                     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));
7435             }
7436             break;
7437         }
7438         case VOGL_ENTRYPOINT_glIsShader:
7439         {
7440             if (!benchmark_mode())
7441             {
7442                 GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
7443                 GLuint replay_handle = map_handle(get_shared_state()->m_shadow_state.m_objs, trace_handle);
7444                 GLboolean trace_result = trace_packet.get_return_value<GLboolean>();
7445
7446                 GLboolean replay_result = GL_ENTRYPOINT(glIsShader)(replay_handle);
7447                 if (trace_result != replay_result)
7448                     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));
7449             }
7450             break;
7451         }
7452         case VOGL_ENTRYPOINT_glIsTexture:
7453         case VOGL_ENTRYPOINT_glIsTextureEXT:
7454         {
7455             if (!benchmark_mode())
7456             {
7457                 GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
7458                 GLuint replay_handle = trace_handle;
7459                 GLboolean trace_result = trace_packet.get_return_value<GLboolean>();
7460
7461                 map_handle(get_shared_state()->m_shadow_state.m_textures, trace_handle, replay_handle);
7462
7463                 GLboolean replay_result;
7464                 if (entrypoint_id == VOGL_ENTRYPOINT_glIsTexture)
7465                     replay_result = GL_ENTRYPOINT(glIsTexture)(replay_handle);
7466                 else
7467                     replay_result = GL_ENTRYPOINT(glIsTextureEXT)(replay_handle);
7468
7469                 if (trace_result != replay_result)
7470                     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));
7471             }
7472
7473             break;
7474         }
7475         case VOGL_ENTRYPOINT_glIsVertexArray:
7476         {
7477             if (!benchmark_mode())
7478             {
7479                 GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
7480                 GLuint replay_handle = map_handle(get_context_state()->m_vertex_array_objects, trace_handle);
7481                 GLboolean trace_result = trace_packet.get_return_value<GLboolean>();
7482
7483                 GLboolean replay_result = GL_ENTRYPOINT(glIsVertexArray)(replay_handle);
7484                 if (trace_result != replay_result)
7485                     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));
7486             }
7487
7488             break;
7489         }
7490         case VOGL_ENTRYPOINT_glGetTexLevelParameterfv:
7491         {
7492             if (!benchmark_mode())
7493             {
7494                 GLenum target = trace_packet.get_param_value<GLenum>(0);
7495                 GLint level = trace_packet.get_param_value<GLint>(1);
7496                 GLenum pname = trace_packet.get_param_value<GLenum>(2);
7497                 const GLfloat *pTrace_params = trace_packet.get_param_client_memory<const GLfloat>(3);
7498                 uint trace_params_size = trace_packet.get_param_client_memory_data_size(3);
7499
7500                 int n = g_gl_enums.get_pname_count(pname);
7501                 if (n <= 0)
7502                 {
7503                     process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
7504                     return cStatusSoftFailure;
7505                 }
7506
7507                 vogl::growable_array<GLfloat, 17> replay_params(n + 1);
7508                 replay_params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_FLOAT_MAGIC;
7509
7510                 GL_ENTRYPOINT(glGetTexLevelParameterfv)(target, level, pname, replay_params.get_ptr());
7511
7512                 VOGL_VERIFY(replay_params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_FLOAT_MAGIC);
7513
7514                 if (!pTrace_params)
7515                     process_entrypoint_warning("%s: Trace param data is missing from packet\n", VOGL_METHOD_NAME);
7516                 else if (trace_params_size != sizeof(GLfloat) * n)
7517                     process_entrypoint_warning("%s: Invalid trace param data size\n", VOGL_METHOD_NAME);
7518                 else if (memcmp(pTrace_params, replay_params.get_ptr(), sizeof(GLfloat) * n) != 0)
7519                     process_entrypoint_error("%s: Trace's param data differs from replay's\n", VOGL_METHOD_NAME);
7520             }
7521
7522             break;
7523         }
7524         case VOGL_ENTRYPOINT_glGetTexLevelParameteriv:
7525         {
7526             if (!benchmark_mode())
7527             {
7528                 GLenum target = trace_packet.get_param_value<GLenum>(0);
7529                 GLint level = trace_packet.get_param_value<GLint>(1);
7530                 GLenum pname = trace_packet.get_param_value<GLenum>(2);
7531                 const GLint *pTrace_params = trace_packet.get_param_client_memory<const GLint>(3);
7532                 uint trace_params_size = trace_packet.get_param_client_memory_data_size(3);
7533
7534                 int n = g_gl_enums.get_pname_count(pname);
7535                 if (n <= 0)
7536                 {
7537                     process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
7538                     return cStatusSoftFailure;
7539                 }
7540
7541                 vogl::growable_array<GLint, 16> replay_params(n + 1);
7542                 replay_params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC;
7543
7544                 GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, level, pname, replay_params.get_ptr());
7545
7546                 VOGL_VERIFY(replay_params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC);
7547
7548                 if (!pTrace_params)
7549                     process_entrypoint_warning("%s: Trace param data is missing from packet\n", VOGL_METHOD_NAME);
7550                 else if (trace_params_size != sizeof(GLint) * n)
7551                     process_entrypoint_warning("%s: Invalid trace param data size\n", VOGL_METHOD_NAME);
7552                 else if (memcmp(pTrace_params, replay_params.get_ptr(), sizeof(GLint) * n) != 0)
7553                     process_entrypoint_error("%s: Trace's param data differs from replay's\n", VOGL_METHOD_NAME);
7554             }
7555
7556             break;
7557         }
7558         case VOGL_ENTRYPOINT_glGetTexParameterIiv:
7559         case VOGL_ENTRYPOINT_glGetTexParameteriv:
7560         {
7561             if (!benchmark_mode())
7562             {
7563                 GLenum target = trace_packet.get_param_value<GLenum>(0);
7564                 GLenum pname = trace_packet.get_param_value<GLenum>(1);
7565                 const GLint *pTrace_params = trace_packet.get_param_client_memory<const GLint>(2);
7566                 uint trace_params_size = trace_packet.get_param_client_memory_data_size(2);
7567
7568                 int n = g_gl_enums.get_pname_count(pname);
7569                 if (n <= 0)
7570                 {
7571                     process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
7572                     return cStatusSoftFailure;
7573                 }
7574
7575                 vogl::growable_array<GLint, 16> replay_params(n + 1);
7576                 replay_params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC;
7577
7578                 if (entrypoint_id == VOGL_ENTRYPOINT_glGetTexParameterIiv)
7579                     GL_ENTRYPOINT(glGetTexParameterIiv)(target, pname, replay_params.get_ptr());
7580                 else
7581                     GL_ENTRYPOINT(glGetTexParameteriv)(target, pname, replay_params.get_ptr());
7582
7583                 VOGL_VERIFY(replay_params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC);
7584
7585                 if (!pTrace_params)
7586                     process_entrypoint_warning("%s: Trace param data is missing from packet\n", VOGL_METHOD_NAME);
7587                 else if (trace_params_size != sizeof(GLint) * n)
7588                     process_entrypoint_warning("%s: Invalid trace param data size\n", VOGL_METHOD_NAME);
7589                 else if (memcmp(pTrace_params, replay_params.get_ptr(), sizeof(GLint) * n) != 0)
7590                     process_entrypoint_error("%s: Trace's param data differs from replay's\n", VOGL_METHOD_NAME);
7591             }
7592
7593             break;
7594         }
7595         case VOGL_ENTRYPOINT_glGetTexParameterIuiv:
7596         {
7597             if (!benchmark_mode())
7598             {
7599                 GLenum target = trace_packet.get_param_value<GLenum>(0);
7600                 GLenum pname = trace_packet.get_param_value<GLenum>(1);
7601                 const GLuint *pTrace_params = trace_packet.get_param_client_memory<const GLuint>(2);
7602                 uint trace_params_size = trace_packet.get_param_client_memory_data_size(2);
7603
7604                 int n = g_gl_enums.get_pname_count(pname);
7605                 if (n <= 0)
7606                 {
7607                     process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
7608                     return cStatusSoftFailure;
7609                 }
7610
7611                 vogl::growable_array<GLuint, 16> replay_params(n + 1);
7612                 replay_params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC;
7613
7614                 GL_ENTRYPOINT(glGetTexParameterIuiv)(target, pname, replay_params.get_ptr());
7615
7616                 VOGL_VERIFY(replay_params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_INT_MAGIC);
7617
7618                 if (!pTrace_params)
7619                     process_entrypoint_warning("%s: Trace param data is missing from packet\n", VOGL_METHOD_NAME);
7620                 else if (trace_params_size != sizeof(GLuint) * n)
7621                     process_entrypoint_warning("%s: Invalid trace param data size\n", VOGL_METHOD_NAME);
7622                 else if (memcmp(pTrace_params, replay_params.get_ptr(), sizeof(GLuint) * n) != 0)
7623                     process_entrypoint_error("%s: Trace's param data differs from replay's\n", VOGL_METHOD_NAME);
7624             }
7625
7626             break;
7627         }
7628         case VOGL_ENTRYPOINT_glGetTexParameterfv:
7629         {
7630             if (!benchmark_mode())
7631             {
7632                 GLenum target = trace_packet.get_param_value<GLenum>(0);
7633                 GLenum pname = trace_packet.get_param_value<GLenum>(1);
7634                 const GLfloat *pTrace_params = trace_packet.get_param_client_memory<const GLfloat>(2);
7635                 uint trace_params_size = trace_packet.get_param_client_memory_data_size(2);
7636
7637                 int n = g_gl_enums.get_pname_count(pname);
7638                 if (n <= 0)
7639                 {
7640                     process_entrypoint_error("%s: Can't determine count of GL pname 0x%08X\n", VOGL_METHOD_NAME, pname);
7641                     return cStatusSoftFailure;
7642                 }
7643
7644                 vogl::growable_array<GLfloat, 17> replay_params(n + 1);
7645                 replay_params[n] = VOGL_GL_REPLAYER_ARRAY_OVERRUN_FLOAT_MAGIC;
7646
7647                 GL_ENTRYPOINT(glGetTexParameterfv)(target, pname, replay_params.get_ptr());
7648
7649                 VOGL_VERIFY(replay_params[n] == VOGL_GL_REPLAYER_ARRAY_OVERRUN_FLOAT_MAGIC);
7650
7651                 if (!pTrace_params)
7652                     process_entrypoint_warning("%s: Trace param data is missing from packet\n", VOGL_METHOD_NAME);
7653                 else if (trace_params_size != sizeof(GLfloat) * n)
7654                     process_entrypoint_warning("%s: Invalid trace param data size\n", VOGL_METHOD_NAME);
7655                 else if (memcmp(pTrace_params, replay_params.get_ptr(), sizeof(GLfloat) * n) != 0)
7656                     process_entrypoint_error("%s: Trace's param data differs from replay's\n", VOGL_METHOD_NAME);
7657             }
7658
7659             break;
7660         }
7661
7662         case VOGL_ENTRYPOINT_glGetVertexAttribdv:
7663         {
7664             status = get_vertex_attrib_helper<GLdouble>(GL_ENTRYPOINT(glGetVertexAttribdv));
7665             if (status != cStatusOK)
7666                 return status;
7667             break;
7668         }
7669         case VOGL_ENTRYPOINT_glGetVertexAttribfv:
7670         {
7671             status = get_vertex_attrib_helper<GLfloat>(GL_ENTRYPOINT(glGetVertexAttribfv));
7672             if (status != cStatusOK)
7673                 return status;
7674             break;
7675         }
7676         case VOGL_ENTRYPOINT_glGetVertexAttribiv:
7677         {
7678             status = get_vertex_attrib_helper<GLint>(GL_ENTRYPOINT(glGetVertexAttribiv));
7679             if (status != cStatusOK)
7680                 return status;
7681             break;
7682         }
7683         case VOGL_ENTRYPOINT_glGetVertexAttribIiv:
7684         {
7685             status = get_vertex_attrib_helper<GLint>(GL_ENTRYPOINT(glGetVertexAttribIiv));
7686             if (status != cStatusOK)
7687                 return status;
7688             break;
7689         }
7690         case VOGL_ENTRYPOINT_glGetVertexAttribIivEXT:
7691         {
7692             status = get_vertex_attrib_helper<GLint>(GL_ENTRYPOINT(glGetVertexAttribIivEXT));
7693             if (status != cStatusOK)
7694                 return status;
7695             break;
7696         }
7697         case VOGL_ENTRYPOINT_glGetVertexAttribIuiv:
7698         {
7699             status = get_vertex_attrib_helper<GLuint>(GL_ENTRYPOINT(glGetVertexAttribIuiv));
7700             if (status != cStatusOK)
7701                 return status;
7702             break;
7703         }
7704         case VOGL_ENTRYPOINT_glGetVertexAttribIuivEXT:
7705         {
7706             status = get_vertex_attrib_helper<GLuint>(GL_ENTRYPOINT(glGetVertexAttribIuivEXT));
7707             if (status != cStatusOK)
7708                 return status;
7709             break;
7710         }
7711         case VOGL_ENTRYPOINT_glGenLists:
7712         {
7713             GLsizei range = trace_packet.get_param_value<GLsizei>(0);
7714             GLuint trace_base_handle = trace_packet.get_return_value<GLuint>();
7715
7716             if (trace_base_handle)
7717             {
7718                 check_gl_error();
7719
7720                 GLuint replay_base_handle = GL_ENTRYPOINT(glGenLists)(range);
7721
7722                 if ((check_gl_error()) || (!replay_base_handle))
7723                 {
7724                     process_entrypoint_error("%s: glGenLists() succeeded in the trace, but failed during replay!\n", VOGL_METHOD_NAME);
7725                     return cStatusHardFailure;
7726                 }
7727
7728                 for (GLsizei i = 0; i < range; i++)
7729                 {
7730                     GLuint trace_handle = trace_base_handle + i;
7731                     GLuint replay_handle = replay_base_handle + i;
7732
7733                     if (!gen_handle(get_shared_state()->m_lists, trace_handle, replay_handle))
7734                         return cStatusHardFailure;
7735
7736                     if (!get_shared_state()->m_shadow_state.m_display_lists.gen_lists(trace_handle, 1, &replay_handle))
7737                     {
7738                         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);
7739                     }
7740                 }
7741             }
7742             else
7743             {
7744                 GLuint replay_base_handle = GL_ENTRYPOINT(glGenLists)(range);
7745                 if (replay_base_handle)
7746                 {
7747                     process_entrypoint_warning("%s: glGenLists() failed in the trace, but succeeded during replay!\n", VOGL_METHOD_NAME);
7748
7749                     GL_ENTRYPOINT(glDeleteLists)(replay_base_handle, range);
7750                 }
7751             }
7752
7753             break;
7754         }
7755         case VOGL_ENTRYPOINT_glCallList:
7756         {
7757             GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
7758             GLuint replay_handle = map_handle(get_shared_state()->m_lists, trace_handle);
7759
7760             GL_ENTRYPOINT(glCallList)(replay_handle);
7761
7762             if (!get_shared_state()->m_shadow_state.m_display_lists.parse_list_and_update_shadows(trace_handle, display_list_bind_callback, this))
7763             {
7764                 process_entrypoint_warning("%s: Failed processing display list shadow for trace handle %u GL handle %u\n", VOGL_METHOD_NAME, trace_handle, replay_handle);
7765             }
7766
7767             if ((status = post_draw_call()) != cStatusOK)
7768                 return status;
7769
7770             break;
7771         }
7772         case VOGL_ENTRYPOINT_glCallLists:
7773         {
7774             GLsizei n = trace_packet.get_param_value<GLsizei>(0);
7775             GLenum type = trace_packet.get_param_value<GLenum>(1);
7776             const GLvoid *pTrace_lists = trace_packet.get_param_client_memory<const GLvoid>(2);
7777             uint trace_lists_size = trace_packet.get_param_client_memory_data_size(2);
7778
7779             uint type_size = vogl_get_gl_type_size(type);
7780             if (!type_size)
7781             {
7782                 process_entrypoint_error("%s: Unable to execute glCallLists, type is invalid\n", VOGL_METHOD_NAME);
7783                 return cStatusSoftFailure;
7784             }
7785
7786             if ((n) && (!pTrace_lists))
7787             {
7788                 process_entrypoint_error("%s: Unable to execute glCallLists, lists param is NULL\n", VOGL_METHOD_NAME);
7789                 return cStatusSoftFailure;
7790             }
7791
7792             if (trace_lists_size < (type_size * n))
7793             {
7794                 process_entrypoint_error("%s: Unable to execute glCallLists, lists param data size is too small in trace\n", VOGL_METHOD_NAME);
7795                 return cStatusSoftFailure;
7796             }
7797
7798             GLuint list_base = 0;
7799             GL_ENTRYPOINT(glGetIntegerv)(GL_LIST_BASE, reinterpret_cast<GLint *>(&list_base));
7800
7801             const uint8 *pTrace_lists_ptr = static_cast<const uint8 *>(pTrace_lists);
7802             for (GLsizei i = 0; i < n; i++)
7803             {
7804                 GLint trace_handle = list_base;
7805                 switch (type)
7806                 {
7807                     case GL_BYTE:
7808                     {
7809                         trace_handle += *reinterpret_cast<const signed char *>(pTrace_lists_ptr);
7810                         pTrace_lists_ptr++;
7811                         break;
7812                     }
7813                     case GL_UNSIGNED_BYTE:
7814                     {
7815                         trace_handle += *pTrace_lists_ptr;
7816                         pTrace_lists_ptr++;
7817                         break;
7818                     }
7819                     case GL_SHORT:
7820                     {
7821                         trace_handle += *reinterpret_cast<const int16 *>(pTrace_lists_ptr);
7822                         pTrace_lists_ptr += sizeof(int16);
7823                         break;
7824                     }
7825                     case GL_UNSIGNED_SHORT:
7826                     {
7827                         trace_handle += *reinterpret_cast<const uint16 *>(pTrace_lists_ptr);
7828                         pTrace_lists_ptr += sizeof(uint16);
7829                         break;
7830                     }
7831                     case GL_INT:
7832                     {
7833                         trace_handle += *reinterpret_cast<const int32 *>(pTrace_lists_ptr);
7834                         pTrace_lists_ptr += sizeof(int32);
7835                         break;
7836                     }
7837                     case GL_UNSIGNED_INT:
7838                     {
7839                         trace_handle += *reinterpret_cast<const uint32 *>(pTrace_lists_ptr);
7840                         pTrace_lists_ptr += sizeof(uint32);
7841                         break;
7842                     }
7843                     case GL_FLOAT:
7844                     {
7845                         trace_handle += static_cast<GLint>(*reinterpret_cast<const float *>(pTrace_lists_ptr));
7846                         pTrace_lists_ptr += sizeof(float);
7847                         break;
7848                     }
7849                     case GL_2_BYTES:
7850                     {
7851                         trace_handle += ((pTrace_lists_ptr[0] << 8U) + pTrace_lists_ptr[1]);
7852                         pTrace_lists_ptr += 2;
7853                         break;
7854                     }
7855                     case GL_3_BYTES:
7856                     {
7857                         trace_handle += ((pTrace_lists_ptr[0] << 16U) + (pTrace_lists_ptr[1] << 8U) + pTrace_lists_ptr[2]);
7858                         pTrace_lists_ptr += 3;
7859                         break;
7860                     }
7861                     case GL_4_BYTES:
7862                     {
7863                         trace_handle += ((pTrace_lists_ptr[0] << 24U) + (pTrace_lists_ptr[1] << 16U) + (pTrace_lists_ptr[2] << 8U) + pTrace_lists_ptr[3]);
7864                         pTrace_lists_ptr += 4;
7865                         break;
7866                     }
7867                     default:
7868                     {
7869                         process_entrypoint_error("%s: Invalid type parameter (0x%08X)\n", VOGL_METHOD_NAME, type);
7870                         return cStatusSoftFailure;
7871                     }
7872                 }
7873
7874                 if (trace_handle <= 0)
7875                 {
7876                     process_entrypoint_error("%s: Trace handle after adding list base is negative (%i), skipping this list index\n", VOGL_METHOD_NAME, trace_handle);
7877                 }
7878                 else
7879                 {
7880                     GLuint replay_handle = map_handle(get_shared_state()->m_lists, trace_handle);
7881                     GL_ENTRYPOINT(glCallList)(replay_handle);
7882
7883                     if (!get_shared_state()->m_shadow_state.m_display_lists.parse_list_and_update_shadows(trace_handle, display_list_bind_callback, this))
7884                     {
7885                         process_entrypoint_warning("%s: Failed processing display list shadow for trace handle %u GL handle %u\n", VOGL_METHOD_NAME, trace_handle, replay_handle);
7886                     }
7887                 }
7888             }
7889
7890             if ((status = post_draw_call()) != cStatusOK)
7891                 return status;
7892
7893             break;
7894         }
7895         case VOGL_ENTRYPOINT_glDeleteLists:
7896         {
7897             GLuint trace_list = trace_packet.get_param_value<GLuint>(0);
7898             GLsizei range = trace_packet.get_param_value<GLsizei>(1);
7899
7900             for (GLsizei i = 0; i < range; i++)
7901             {
7902                 GLuint trace_handle = trace_list + i;
7903                 delete_handles(get_shared_state()->m_lists, 1, &trace_handle, delete_list_helper);
7904
7905                 if (!get_shared_state()->m_shadow_state.m_display_lists.del_lists(trace_handle, 1))
7906                 {
7907                     process_entrypoint_warning("%s: Unable to delete list in display list shadow, trace handle %u\n", VOGL_METHOD_NAME, trace_handle);
7908                 }
7909             }
7910
7911             break;
7912         }
7913         case VOGL_ENTRYPOINT_glIsList:
7914         {
7915             if (!benchmark_mode())
7916             {
7917                 GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
7918                 GLuint replay_handle = map_handle(get_shared_state()->m_lists, trace_handle);
7919                 GLboolean trace_result = trace_packet.get_return_value<GLboolean>();
7920
7921                 GLboolean replay_result = GL_ENTRYPOINT(glIsList)(replay_handle);
7922                 if (trace_result != replay_result)
7923                     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));
7924             }
7925
7926             break;
7927         }
7928         case VOGL_ENTRYPOINT_glNewList:
7929         {
7930             GLuint trace_handle = trace_packet.get_param_value<GLuint>(0);
7931             GLuint replay_handle = map_handle(get_shared_state()->m_lists, trace_handle);
7932             GLenum mode = trace_packet.get_param_value<GLenum>(1);
7933
7934             check_gl_error();
7935
7936             GL_ENTRYPOINT(glNewList)(replay_handle, mode);
7937
7938             if (!check_gl_error())
7939             {
7940                 get_shared_state()->m_shadow_state.m_display_lists.new_list(trace_handle, replay_handle);
7941
7942                 get_context_state()->m_current_display_list_mode = mode;
7943                 get_context_state()->m_current_display_list_handle = trace_handle;
7944             }
7945
7946             // TODO: Check if glNewList() failed vs the replay.
7947             // This is important, because if the new failed during tracing but succeeded during replay then we've seriously diverged.
7948             // 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.
7949             break;
7950         }
7951         case VOGL_ENTRYPOINT_glListBase:
7952         {
7953             GLuint base = trace_packet.get_param_value<GLuint>(0);
7954             GL_ENTRYPOINT(glListBase)(base);
7955             break;
7956         }
7957         case VOGL_ENTRYPOINT_glEndList:
7958         {
7959             GL_ENTRYPOINT(glEndList)();
7960
7961             if (!get_context_state()->is_composing_display_list())
7962             {
7963                 process_entrypoint_warning("%s: glEndList() called without calling glNewList()!\n", VOGL_METHOD_NAME);
7964             }
7965             else
7966             {
7967                 if (!get_shared_state()->m_shadow_state.m_display_lists.end_list(get_context_state()->m_current_display_list_handle))
7968                     process_entrypoint_warning("%s: Failed ending display list, trace handle %u\n", VOGL_METHOD_NAME, get_context_state()->m_current_display_list_handle);
7969
7970                 get_context_state()->m_current_display_list_mode = GL_NONE;
7971                 get_context_state()->m_current_display_list_handle = -1;
7972             }
7973
7974             break;
7975         }
7976         case VOGL_ENTRYPOINT_glFeedbackBuffer:
7977         {
7978             GLsizei size = trace_packet.get_param_value<GLsizei>(0);
7979             GLenum type = trace_packet.get_param_value<GLenum>(1);
7980
7981             if (static_cast<GLsizei>(m_pCur_context_state->m_feedback_buffer.size()) < size)
7982                 m_pCur_context_state->m_feedback_buffer.resize(size);
7983
7984             GL_ENTRYPOINT(glFeedbackBuffer)(size, type, m_pCur_context_state->m_feedback_buffer.get_ptr());
7985
7986             break;
7987         }
7988         case VOGL_ENTRYPOINT_glSeparableFilter2D:
7989         {
7990             GLenum target = trace_packet.get_param_value<GLenum>(0);
7991             GLenum internalformat = trace_packet.get_param_value<GLenum>(1);
7992             GLsizei width = trace_packet.get_param_value<GLsizei>(2);
7993             GLsizei height = trace_packet.get_param_value<GLsizei>(3);
7994             GLenum format = trace_packet.get_param_value<GLenum>(4);
7995             GLenum type = trace_packet.get_param_value<GLenum>(5);
7996
7997             const GLvoid *row = trace_packet.get_param_client_memory<const GLvoid>(6);
7998             uint row_size = trace_packet.get_param_client_memory_data_size(6);
7999             if (row_size < vogl_get_image_size(format, type, width, 1, 1))
8000             {
8001                 process_entrypoint_error("%s: row trace array is too small\n", VOGL_METHOD_NAME);
8002                 return cStatusSoftFailure;
8003             }
8004
8005             const GLvoid *column = trace_packet.get_param_client_memory<const GLvoid>(7);
8006             uint col_size = trace_packet.get_param_client_memory_data_size(7);
8007             if (col_size < vogl_get_image_size(format, type, width, 1, 1))
8008             {
8009                 process_entrypoint_error("%s: column trace array is too small\n", VOGL_METHOD_NAME);
8010                 return cStatusSoftFailure;
8011             }
8012
8013             GL_ENTRYPOINT(glSeparableFilter2D)(target, internalformat, width, height, format, type, row, column);
8014             break;
8015         }
8016
8017         case VOGL_ENTRYPOINT_glNamedProgramLocalParameters4fvEXT:
8018         {
8019             GLuint trace_program = trace_packet.get_param_value<GLuint>(0);
8020             GLuint replay_program = map_handle(get_shared_state()->m_arb_programs, trace_program);
8021
8022             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));
8023             break;
8024         }
8025
8026         case VOGL_ENTRYPOINT_glNamedProgramLocalParameterI4iEXT:
8027         {
8028             GLuint trace_program = trace_packet.get_param_value<GLuint>(0);
8029             GLuint replay_program = map_handle(get_shared_state()->m_arb_programs, trace_program);
8030
8031             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));
8032             break;
8033         }
8034         case VOGL_ENTRYPOINT_glNamedProgramLocalParameterI4ivEXT:
8035         {
8036             GLuint trace_program = trace_packet.get_param_value<GLuint>(0);
8037             GLuint replay_program = map_handle(get_shared_state()->m_arb_programs, trace_program);
8038
8039             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));
8040             break;
8041         }
8042
8043         case VOGL_ENTRYPOINT_glNamedProgramLocalParametersI4ivEXT:
8044         {
8045             GLuint trace_program = trace_packet.get_param_value<GLuint>(0);
8046             GLuint replay_program = map_handle(get_shared_state()->m_arb_programs, trace_program);
8047
8048             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));
8049             break;
8050         }
8051         case VOGL_ENTRYPOINT_glNamedProgramLocalParameterI4uiEXT:
8052         {
8053             GLuint trace_program = trace_packet.get_param_value<GLuint>(0);
8054             GLuint replay_program = map_handle(get_shared_state()->m_arb_programs, trace_program);
8055
8056             GL_ENTRYPOINT(glNamedProgramLocalParameterI4uiEXT)(replay_program, trace_packet.get_param_value<GLenum>(1), trace_packet.get_param_value<GLuint>(2),
8057                                                                trace_packet.get_param_value<GLuint>(3), trace_packet.get_param_value<GLuint>(4),
8058                                                                trace_packet.get_param_value<GLuint>(5), trace_packet.get_param_value<GLuint>(6));
8059             break;
8060         }
8061         case VOGL_ENTRYPOINT_glNamedProgramLocalParameterI4uivEXT:
8062         {
8063             GLuint trace_program = trace_packet.get_param_value<GLuint>(0);
8064             GLuint replay_program = map_handle(get_shared_state()->m_arb_programs, trace_program);
8065
8066             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));
8067             break;
8068         }
8069         case VOGL_ENTRYPOINT_glNamedProgramLocalParametersI4uivEXT:
8070         {
8071             GLuint trace_program = trace_packet.get_param_value<GLuint>(0);
8072             GLuint replay_program = map_handle(get_shared_state()->m_arb_programs, trace_program);
8073
8074             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));
8075             break;
8076         }
8077         case VOGL_ENTRYPOINT_glNamedProgramLocalParameter4fvEXT:
8078         {
8079             GLuint trace_program = trace_packet.get_param_value<GLuint>(0);
8080             GLuint replay_program = map_handle(get_shared_state()->m_arb_programs, trace_program);
8081
8082             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));
8083             break;
8084         }
8085         case VOGL_ENTRYPOINT_glGetTexEnvfv:
8086         {
8087             if (!benchmark_mode())
8088             {
8089                 GLenum target = trace_packet.get_param_value<GLenum>(0);
8090                 GLenum pname = trace_packet.get_param_value<GLenum>(1);
8091                 const GLfloat *pParams = trace_packet.get_param_client_memory<GLfloat>(2);
8092
8093                 GLfloat vals[4] = { 0, 0, 0, 0 };
8094
8095                 int n = g_gl_enums.get_pname_count(pname);
8096                 VOGL_ASSERT(n <= (int)VOGL_ARRAY_SIZE(vals));
8097
8098                 GL_ENTRYPOINT(glGetTexEnvfv)(target, pname, vals);
8099
8100                 if (n < 0)
8101                 {
8102                     process_entrypoint_error("%s: Unable to compute element count for pname 0x%08X\n", VOGL_METHOD_NAME, pname);
8103                 }
8104                 else if (memcmp(pParams, vals, n * sizeof(GLfloat)) != 0)
8105                 {
8106                     process_entrypoint_error("%s: Replay divergence detected\n", VOGL_METHOD_NAME);
8107                 }
8108             }
8109
8110             break;
8111         }
8112         case VOGL_ENTRYPOINT_glGetTexEnviv:
8113         {
8114             if (!benchmark_mode())
8115             {
8116                 GLenum target = trace_packet.get_param_value<GLenum>(0);
8117                 GLenum pname = trace_packet.get_param_value<GLenum>(1);
8118                 const GLint *pParams = trace_packet.get_param_client_memory<GLint>(2);
8119
8120                 GLint vals[4] = { 0, 0, 0, 0 };
8121
8122                 int n = g_gl_enums.get_pname_count(pname);
8123                 VOGL_ASSERT(n <= (int)VOGL_ARRAY_SIZE(vals));
8124
8125                 GL_ENTRYPOINT(glGetTexEnviv)(target, pname, vals);
8126
8127                 if (n < 0)
8128                 {
8129                     process_entrypoint_error("%s: Unable to compute element count for pname 0x%08X\n", VOGL_METHOD_NAME, pname);
8130                 }
8131                 else if (memcmp(pParams, vals, n * sizeof(GLint)) != 0)
8132                 {
8133                     process_entrypoint_error("%s: Replay divergence detected\n", VOGL_METHOD_NAME);
8134                 }
8135             }
8136
8137             break;
8138         }
8139         case VOGL_ENTRYPOINT_glGetTexGendv:
8140         {
8141             if (!benchmark_mode())
8142             {
8143                 GLenum coord = trace_packet.get_param_value<GLenum>(0);
8144                 GLenum pname = trace_packet.get_param_value<GLenum>(1);
8145                 const GLdouble *pParams = trace_packet.get_param_client_memory<GLdouble>(2);
8146
8147                 GLdouble vals[4] = { 0, 0, 0, 0 };
8148
8149                 int n = g_gl_enums.get_pname_count(pname);
8150                 VOGL_ASSERT(n <= (int)VOGL_ARRAY_SIZE(vals));
8151
8152                 GL_ENTRYPOINT(glGetTexGendv)(coord, pname, vals);
8153
8154                 if (n < 0)
8155                 {
8156                     process_entrypoint_error("%s: Unable to compute element count for pname 0x%08X\n", VOGL_METHOD_NAME, pname);
8157                 }
8158                 else if (memcmp(pParams, vals, n * sizeof(GLdouble)) != 0)
8159                 {
8160                     process_entrypoint_error("%s: Replay divergence detected\n", VOGL_METHOD_NAME);
8161                 }
8162             }
8163
8164             break;
8165         }
8166         case VOGL_ENTRYPOINT_glGetTexGenfv:
8167         {
8168             if (!benchmark_mode())
8169             {
8170                 GLenum coord = trace_packet.get_param_value<GLenum>(0);
8171                 GLenum pname = trace_packet.get_param_value<GLenum>(1);
8172                 const GLfloat *pParams = trace_packet.get_param_client_memory<GLfloat>(2);
8173
8174                 GLfloat vals[4] = { 0, 0, 0, 0 };
8175
8176                 int n = g_gl_enums.get_pname_count(pname);
8177                 VOGL_ASSERT(n <= (int)VOGL_ARRAY_SIZE(vals));
8178
8179                 GL_ENTRYPOINT(glGetTexGenfv)(coord, pname, vals);
8180
8181                 if (n < 0)
8182                 {
8183                     process_entrypoint_error("%s: Unable to compute element count for pname 0x%08X\n", VOGL_METHOD_NAME, pname);
8184                 }
8185                 else if (memcmp(pParams, vals, n * sizeof(GLfloat)) != 0)
8186                 {
8187                     process_entrypoint_error("%s: Replay divergence detected\n", VOGL_METHOD_NAME);
8188                 }
8189             }
8190
8191             break;
8192         }
8193         case VOGL_ENTRYPOINT_glGetTexGeniv:
8194         {
8195             if (!benchmark_mode())
8196             {
8197                 GLenum coord = trace_packet.get_param_value<GLenum>(0);
8198                 GLenum pname = trace_packet.get_param_value<GLenum>(1);
8199                 const GLint *pParams = trace_packet.get_param_client_memory<GLint>(2);
8200
8201                 GLint vals[4] = { 0, 0, 0, 0 };
8202
8203                 int n = g_gl_enums.get_pname_count(pname);
8204                 VOGL_ASSERT(n <= (int)VOGL_ARRAY_SIZE(vals));
8205
8206                 GL_ENTRYPOINT(glGetTexGeniv)(coord, pname, vals);
8207
8208                 if (n < 0)
8209                 {
8210                     process_entrypoint_error("%s: Unable to compute element count for pname 0x%08X\n", VOGL_METHOD_NAME, pname);
8211                 }
8212                 else if (memcmp(pParams, vals, n * sizeof(GLint)) != 0)
8213                 {
8214                     process_entrypoint_error("%s: Replay divergence detected\n", VOGL_METHOD_NAME);
8215                 }
8216             }
8217
8218             break;
8219         }
8220         case VOGL_ENTRYPOINT_glGetLightfv:
8221         {
8222             if (!benchmark_mode())
8223             {
8224                 GLenum light = trace_packet.get_param_value<GLenum>(0);
8225                 GLenum pname = trace_packet.get_param_value<GLenum>(1);
8226                 const GLfloat *pParams = trace_packet.get_param_client_memory<GLfloat>(2);
8227
8228                 GLfloat vals[4] = { 0, 0, 0, 0 };
8229
8230                 int n = g_gl_enums.get_pname_count(pname);
8231                 VOGL_ASSERT(n <= (int)VOGL_ARRAY_SIZE(vals));
8232
8233                 GL_ENTRYPOINT(glGetLightfv)(light, pname, vals);
8234
8235                 if (n < 0)
8236                 {
8237                     process_entrypoint_error("%s: Unable to compute element count for pname 0x%08X\n", VOGL_METHOD_NAME, pname);
8238                 }
8239                 else if (memcmp(pParams, vals, n * sizeof(GLfloat)) != 0)
8240                 {
8241                     process_entrypoint_error("%s: Replay divergence detected\n", VOGL_METHOD_NAME);
8242                 }
8243             }
8244
8245             break;
8246         }
8247         case VOGL_ENTRYPOINT_glGetLightiv:
8248         {
8249             if (!benchmark_mode())
8250             {
8251                 GLenum light = trace_packet.get_param_value<GLenum>(0);
8252                 GLenum pname = trace_packet.get_param_value<GLenum>(1);
8253                 const GLint *pParams = trace_packet.get_param_client_memory<GLint>(2);
8254
8255                 GLint vals[4] = { 0, 0, 0, 0 };
8256
8257                 int n = g_gl_enums.get_pname_count(pname);
8258                 VOGL_ASSERT(n <= (int)VOGL_ARRAY_SIZE(vals));
8259
8260                 GL_ENTRYPOINT(glGetLightiv)(light, pname, vals);
8261
8262                 if (n < 0)
8263                 {
8264                     process_entrypoint_error("%s: Unable to compute element count for pname 0x%08X\n", VOGL_METHOD_NAME, pname);
8265                 }
8266                 else if (memcmp(pParams, vals, n * sizeof(GLint)) != 0)
8267                 {
8268                     process_entrypoint_error("%s: Replay divergence detected\n", VOGL_METHOD_NAME);
8269                 }
8270             }
8271
8272             break;
8273         }
8274         case VOGL_ENTRYPOINT_glSelectBuffer:
8275         {
8276             GLsizei size = trace_packet.get_param_value<GLsizei>(0);
8277
8278             if (m_pCur_context_state->m_select_buffer.try_resize(size))
8279             {
8280                 GL_ENTRYPOINT(glSelectBuffer)(size, m_pCur_context_state->m_select_buffer.get_ptr());
8281             }
8282             else
8283             {
8284                 process_entrypoint_error("%s: Failed resizing context's select buffer\n", VOGL_METHOD_NAME);
8285             }
8286
8287             break;
8288         }
8289         case VOGL_ENTRYPOINT_glClearBufferfv:
8290         {
8291             VOGL_REPLAY_LOAD_PARAMS_HELPER_glClearBufferfv;
8292
8293             // TODO: Check params
8294
8295             VOGL_REPLAY_CALL_GL_HELPER_glClearBufferfv;
8296
8297             break;
8298         }
8299         case VOGL_ENTRYPOINT_glClearBufferiv:
8300         {
8301             VOGL_REPLAY_LOAD_PARAMS_HELPER_glClearBufferiv;
8302
8303             // TODO: Check params
8304
8305             VOGL_REPLAY_CALL_GL_HELPER_glClearBufferiv;
8306
8307             break;
8308         }
8309         case VOGL_ENTRYPOINT_glClearBufferuiv:
8310         {
8311             VOGL_REPLAY_LOAD_PARAMS_HELPER_glClearBufferuiv;
8312
8313             // TODO: Check params
8314
8315             VOGL_REPLAY_CALL_GL_HELPER_glClearBufferuiv;
8316
8317             break;
8318         }
8319         case VOGL_ENTRYPOINT_glTexBuffer:
8320         case VOGL_ENTRYPOINT_glTexBufferARB:
8321         case VOGL_ENTRYPOINT_glTexBufferEXT:
8322         {
8323             VOGL_REPLAY_LOAD_PARAMS_HELPER_glTexBuffer;
8324
8325             buffer = map_handle(get_shared_state()->m_buffers, buffer);
8326
8327             SWITCH_GL_ENTRYPOINT3_VOID(glTexBuffer, glTexBufferARB, glTexBufferEXT, target, internalformat, buffer);
8328             break;
8329         }
8330         case VOGL_ENTRYPOINT_glBeginConditionalRender:
8331         {
8332             VOGL_REPLAY_LOAD_PARAMS_HELPER_glBeginConditionalRender;
8333
8334             id = map_handle(get_shared_state()->m_queries, id);
8335
8336             VOGL_REPLAY_CALL_GL_HELPER_glBeginConditionalRender;
8337             break;
8338         }
8339         case VOGL_ENTRYPOINT_glEndConditionalRender:
8340         {
8341             VOGL_REPLAY_LOAD_PARAMS_HELPER_glEndConditionalRender;
8342
8343             VOGL_REPLAY_CALL_GL_HELPER_glEndConditionalRender;
8344             break;
8345         }
8346         case VOGL_ENTRYPOINT_glBeginTransformFeedback:
8347         {
8348             VOGL_REPLAY_LOAD_PARAMS_HELPER_glBeginTransformFeedback;
8349
8350             VOGL_REPLAY_CALL_GL_HELPER_glBeginTransformFeedback;
8351             break;
8352         }
8353         case VOGL_ENTRYPOINT_glEndTransformFeedback:
8354         {
8355             VOGL_REPLAY_LOAD_PARAMS_HELPER_glEndTransformFeedback;
8356
8357             VOGL_REPLAY_CALL_GL_HELPER_glEndTransformFeedback;
8358
8359             break;
8360         }
8361         case VOGL_ENTRYPOINT_glTransformFeedbackVaryings:
8362         {
8363             VOGL_REPLAY_LOAD_PARAMS_HELPER_glTransformFeedbackVaryings;
8364             VOGL_NOTE_UNUSED(pTrace_varyings);
8365
8366             program = map_handle(get_shared_state()->m_shadow_state.m_objs, program);
8367
8368             dynamic_string_array replay_varyings(count);
8369
8370             const key_value_map &key_value_map = trace_packet.get_key_value_map();
8371             const value_to_value_hash_map &hash_map = key_value_map.get_map();
8372
8373             for (value_to_value_hash_map::const_iterator it = hash_map.begin(); it != hash_map.end(); ++it)
8374             {
8375                 int key_index = it->first.get_int();
8376
8377                 if ((key_index >= 0) && (key_index < count))
8378                 {
8379                     const dynamic_string *pName = it->second.get_string_ptr();
8380                     VOGL_ASSERT(pName);
8381
8382                     replay_varyings[key_index] = pName ? *pName : "";
8383                 }
8384                 else
8385                 {
8386                     VOGL_ASSERT_ALWAYS;
8387                 }
8388             }
8389
8390             vogl::vector<const GLchar *> str_ptrs(count);
8391             for (int i = 0; i < count; i++)
8392                 str_ptrs[i] = reinterpret_cast<const GLchar *>(replay_varyings[i].get_ptr());
8393
8394             GLchar *const *pReplay_varyings = (GLchar *const *)(str_ptrs.get_ptr());
8395
8396             VOGL_REPLAY_CALL_GL_HELPER_glTransformFeedbackVaryings;
8397
8398             break;
8399         }
8400         case VOGL_ENTRYPOINT_glUniformBufferEXT:
8401         {
8402             VOGL_REPLAY_LOAD_PARAMS_HELPER_glUniformBufferEXT;
8403
8404             GLuint trace_program = program;
8405
8406             program = map_handle(get_shared_state()->m_shadow_state.m_objs, program);
8407             location = determine_uniform_replay_location(trace_program, location);
8408             buffer = map_handle(get_shared_state()->m_buffers, buffer);
8409
8410             VOGL_REPLAY_CALL_GL_HELPER_glUniformBufferEXT;
8411             break;
8412         }
8413         case VOGL_ENTRYPOINT_glUniformBlockBinding:
8414         {
8415             // TODO: Does any of this other stuff need to be remapped?
8416             VOGL_REPLAY_LOAD_PARAMS_HELPER_glUniformBlockBinding;
8417
8418             program = map_handle(get_shared_state()->m_shadow_state.m_objs, program);
8419
8420             VOGL_REPLAY_CALL_GL_HELPER_glUniformBlockBinding;
8421             break;
8422         }
8423         case VOGL_ENTRYPOINT_glFrameTerminatorGREMEDY:
8424         {
8425             // TODO - we need to hook up this extension to the tracer
8426             break;
8427         }
8428         case VOGL_ENTRYPOINT_glStringMarkerGREMEDY:
8429         {
8430             // TODO - we need to hook up this extension to the tracer
8431             break;
8432         }
8433         case VOGL_ENTRYPOINT_glBitmap:
8434         {
8435             VOGL_REPLAY_LOAD_PARAMS_HELPER_glBitmap;
8436
8437             if (vogl_get_bound_gl_buffer(GL_PIXEL_UNPACK_BUFFER))
8438             {
8439                 vogl_trace_ptr_value ptr_val = trace_packet.get_param_ptr_value(6);
8440                 pTrace_bitmap = (const GLubyte *)ptr_val;
8441             }
8442
8443             VOGL_REPLAY_CALL_GL_HELPER_glBitmap;
8444
8445             break;
8446         }
8447         case VOGL_ENTRYPOINT_glColorSubTable:
8448         {
8449             VOGL_REPLAY_LOAD_PARAMS_HELPER_glColorSubTable;
8450
8451             if (vogl_get_bound_gl_buffer(GL_PIXEL_UNPACK_BUFFER))
8452             {
8453                 vogl_trace_ptr_value ptr_val = trace_packet.get_param_ptr_value(5);
8454                 pTrace_data = (const GLvoid *)ptr_val;
8455             }
8456
8457             VOGL_REPLAY_CALL_GL_HELPER_glColorSubTable;
8458
8459             break;
8460         }
8461         case VOGL_ENTRYPOINT_glColorSubTableEXT:
8462         {
8463             VOGL_REPLAY_LOAD_PARAMS_HELPER_glColorSubTableEXT;
8464
8465             if (vogl_get_bound_gl_buffer(GL_PIXEL_UNPACK_BUFFER))
8466             {
8467                 vogl_trace_ptr_value ptr_val = trace_packet.get_param_ptr_value(5);
8468                 pTrace_data = (const GLvoid *)ptr_val;
8469             }
8470
8471             VOGL_REPLAY_CALL_GL_HELPER_glColorSubTableEXT;
8472
8473             break;
8474         }
8475         case VOGL_ENTRYPOINT_glColorTable:
8476         {
8477             VOGL_REPLAY_LOAD_PARAMS_HELPER_glColorTable;
8478
8479             if (vogl_get_bound_gl_buffer(GL_PIXEL_UNPACK_BUFFER))
8480             {
8481                 vogl_trace_ptr_value ptr_val = trace_packet.get_param_ptr_value(5);
8482                 pTrace_table = (const GLvoid *)ptr_val;
8483             }
8484
8485             VOGL_REPLAY_CALL_GL_HELPER_glColorTable;
8486
8487             break;
8488         }
8489         case VOGL_ENTRYPOINT_glColorTableEXT:
8490         {
8491             VOGL_REPLAY_LOAD_PARAMS_HELPER_glColorTableEXT;
8492
8493             if (vogl_get_bound_gl_buffer(GL_PIXEL_UNPACK_BUFFER))
8494             {
8495                 vogl_trace_ptr_value ptr_val = trace_packet.get_param_ptr_value(5);
8496                 pTrace_table = (const GLvoid *)ptr_val;
8497             }
8498
8499             VOGL_REPLAY_CALL_GL_HELPER_glColorTableEXT;
8500
8501             break;
8502         }
8503         case VOGL_ENTRYPOINT_glConvolutionFilter1D:
8504         {
8505             VOGL_REPLAY_LOAD_PARAMS_HELPER_glConvolutionFilter1D;
8506
8507             if (vogl_get_bound_gl_buffer(GL_PIXEL_UNPACK_BUFFER))
8508             {
8509                 vogl_trace_ptr_value ptr_val = trace_packet.get_param_ptr_value(5);
8510                 pTrace_image = (const GLvoid *)ptr_val;
8511             }
8512
8513             VOGL_REPLAY_CALL_GL_HELPER_glConvolutionFilter1D;
8514
8515             break;
8516         }
8517         case VOGL_ENTRYPOINT_glConvolutionFilter2D:
8518         {
8519             VOGL_REPLAY_LOAD_PARAMS_HELPER_glConvolutionFilter2D;
8520
8521             if (vogl_get_bound_gl_buffer(GL_PIXEL_UNPACK_BUFFER))
8522             {
8523                 vogl_trace_ptr_value ptr_val = trace_packet.get_param_ptr_value(6);
8524                 pTrace_image = (const GLvoid *)ptr_val;
8525             }
8526
8527             VOGL_REPLAY_CALL_GL_HELPER_glConvolutionFilter2D;
8528
8529             break;
8530         }
8531         case VOGL_ENTRYPOINT_glDrawPixels:
8532         {
8533             VOGL_REPLAY_LOAD_PARAMS_HELPER_glDrawPixels;
8534
8535             if (vogl_get_bound_gl_buffer(GL_PIXEL_UNPACK_BUFFER))
8536             {
8537                 vogl_trace_ptr_value ptr_val = trace_packet.get_param_ptr_value(4);
8538                 pTrace_pixels = (const GLvoid *)ptr_val;
8539             }
8540
8541             VOGL_REPLAY_CALL_GL_HELPER_glDrawPixels;
8542
8543             break;
8544         }
8545         case VOGL_ENTRYPOINT_glPolygonStipple:
8546         {
8547             VOGL_REPLAY_LOAD_PARAMS_HELPER_glPolygonStipple;
8548
8549             if (vogl_get_bound_gl_buffer(GL_PIXEL_UNPACK_BUFFER))
8550             {
8551                 vogl_trace_ptr_value ptr_val = trace_packet.get_param_ptr_value(0);
8552                 pTrace_mask = (const GLubyte *)ptr_val;
8553             }
8554
8555             VOGL_REPLAY_CALL_GL_HELPER_glPolygonStipple;
8556
8557             break;
8558         }
8559         case VOGL_ENTRYPOINT_glTexImage1D:
8560         {
8561             VOGL_REPLAY_LOAD_PARAMS_HELPER_glTexImage1D;
8562
8563             if (vogl_get_bound_gl_buffer(GL_PIXEL_UNPACK_BUFFER))
8564             {
8565                 vogl_trace_ptr_value ptr_val = trace_packet.get_param_ptr_value(7);
8566                 pTrace_pixels = (const GLvoid *)ptr_val;
8567             }
8568
8569             VOGL_REPLAY_CALL_GL_HELPER_glTexImage1D;
8570
8571             break;
8572         }
8573         case VOGL_ENTRYPOINT_glTexImage2D:
8574         {
8575             VOGL_REPLAY_LOAD_PARAMS_HELPER_glTexImage2D;
8576
8577             if (vogl_get_bound_gl_buffer(GL_PIXEL_UNPACK_BUFFER))
8578             {
8579                 vogl_trace_ptr_value ptr_val = trace_packet.get_param_ptr_value(8);
8580                 pTrace_pixels = (const GLvoid *)ptr_val;
8581             }
8582
8583             VOGL_REPLAY_CALL_GL_HELPER_glTexImage2D;
8584
8585             break;
8586         }
8587         case VOGL_ENTRYPOINT_glTexImage3D:
8588         {
8589             VOGL_REPLAY_LOAD_PARAMS_HELPER_glTexImage3D;
8590
8591             if (vogl_get_bound_gl_buffer(GL_PIXEL_UNPACK_BUFFER))
8592             {
8593                 vogl_trace_ptr_value ptr_val = trace_packet.get_param_ptr_value(9);
8594                 pTrace_pixels = (const GLvoid *)ptr_val;
8595             }
8596
8597             VOGL_REPLAY_CALL_GL_HELPER_glTexImage3D;
8598
8599             break;
8600         }
8601         case VOGL_ENTRYPOINT_glTexImage3DEXT:
8602         {
8603             VOGL_REPLAY_LOAD_PARAMS_HELPER_glTexImage3DEXT;
8604
8605             if (vogl_get_bound_gl_buffer(GL_PIXEL_UNPACK_BUFFER))
8606             {
8607                 vogl_trace_ptr_value ptr_val = trace_packet.get_param_ptr_value(9);
8608                 pTrace_pixels = (const GLvoid *)ptr_val;
8609             }
8610
8611             VOGL_REPLAY_CALL_GL_HELPER_glTexImage3DEXT;
8612
8613             break;
8614         }
8615         case VOGL_ENTRYPOINT_glTexSubImage1D:
8616         {
8617             VOGL_REPLAY_LOAD_PARAMS_HELPER_glTexSubImage1D;
8618
8619             if (vogl_get_bound_gl_buffer(GL_PIXEL_UNPACK_BUFFER))
8620             {
8621                 vogl_trace_ptr_value ptr_val = trace_packet.get_param_ptr_value(6);
8622                 pTrace_pixels = (const GLvoid *)ptr_val;
8623             }
8624
8625             VOGL_REPLAY_CALL_GL_HELPER_glTexSubImage1D;
8626
8627             break;
8628         }
8629         case VOGL_ENTRYPOINT_glTexSubImage1DEXT:
8630         {
8631             VOGL_REPLAY_LOAD_PARAMS_HELPER_glTexSubImage1DEXT;
8632
8633             if (vogl_get_bound_gl_buffer(GL_PIXEL_UNPACK_BUFFER))
8634             {
8635                 vogl_trace_ptr_value ptr_val = trace_packet.get_param_ptr_value(6);
8636                 pTrace_pixels = (const GLvoid *)ptr_val;
8637             }
8638
8639             VOGL_REPLAY_CALL_GL_HELPER_glTexSubImage1DEXT;
8640
8641             break;
8642         }
8643         case VOGL_ENTRYPOINT_glTexSubImage2D:
8644         {
8645             VOGL_REPLAY_LOAD_PARAMS_HELPER_glTexSubImage2D;
8646
8647             if (vogl_get_bound_gl_buffer(GL_PIXEL_UNPACK_BUFFER))
8648             {
8649                 vogl_trace_ptr_value ptr_val = trace_packet.get_param_ptr_value(8);
8650                 pTrace_pixels = (const GLvoid *)ptr_val;
8651             }
8652
8653             VOGL_REPLAY_CALL_GL_HELPER_glTexSubImage2D;
8654
8655             break;
8656         }
8657         case VOGL_ENTRYPOINT_glTexSubImage2DEXT:
8658         {
8659             VOGL_REPLAY_LOAD_PARAMS_HELPER_glTexSubImage2DEXT;
8660
8661             if (vogl_get_bound_gl_buffer(GL_PIXEL_UNPACK_BUFFER))
8662             {
8663                 vogl_trace_ptr_value ptr_val = trace_packet.get_param_ptr_value(8);
8664                 pTrace_pixels = (const GLvoid *)ptr_val;
8665             }
8666
8667             VOGL_REPLAY_CALL_GL_HELPER_glTexSubImage2DEXT;
8668
8669             break;
8670         }
8671         case VOGL_ENTRYPOINT_glTexSubImage3D:
8672         {
8673             VOGL_REPLAY_LOAD_PARAMS_HELPER_glTexSubImage3D;
8674
8675             if (vogl_get_bound_gl_buffer(GL_PIXEL_UNPACK_BUFFER))
8676             {
8677                 vogl_trace_ptr_value ptr_val = trace_packet.get_param_ptr_value(10);
8678                 pTrace_pixels = (const GLvoid *)ptr_val;
8679             }
8680
8681             VOGL_REPLAY_CALL_GL_HELPER_glTexSubImage3D;
8682
8683             break;
8684         }
8685         case VOGL_ENTRYPOINT_glTexSubImage3DEXT:
8686         {
8687             VOGL_REPLAY_LOAD_PARAMS_HELPER_glTexSubImage3DEXT;
8688
8689             if (vogl_get_bound_gl_buffer(GL_PIXEL_UNPACK_BUFFER))
8690             {
8691                 vogl_trace_ptr_value ptr_val = trace_packet.get_param_ptr_value(10);
8692                 pTrace_pixels = (const GLvoid *)ptr_val;
8693             }
8694
8695             VOGL_REPLAY_CALL_GL_HELPER_glTexSubImage3DEXT;
8696
8697             break;
8698         }
8699         case VOGL_ENTRYPOINT_glDebugMessageInsert:
8700         {
8701             VOGL_REPLAY_LOAD_PARAMS_HELPER_glDebugMessageInsert;
8702
8703             VOGL_REPLAY_CALL_GL_HELPER_glDebugMessageInsert;
8704             break;
8705         }
8706         case VOGL_ENTRYPOINT_glDebugMessageInsertARB:
8707         {
8708             VOGL_REPLAY_LOAD_PARAMS_HELPER_glDebugMessageInsertARB;
8709
8710             VOGL_REPLAY_CALL_GL_HELPER_glDebugMessageInsertARB;
8711             break;
8712         }
8713         case VOGL_ENTRYPOINT_glDebugMessageCallbackARB:
8714         {
8715             GL_ENTRYPOINT(glDebugMessageCallbackARB)(debug_callback_arb, (GLvoid *)m_pCur_context_state);
8716
8717             break;
8718         }
8719         case VOGL_ENTRYPOINT_glDebugMessageCallback:
8720         {
8721             GL_ENTRYPOINT(glDebugMessageCallback)(debug_callback, (GLvoid *)m_pCur_context_state);
8722
8723             break;
8724         }
8725         case VOGL_ENTRYPOINT_glObjectLabel:
8726         {
8727             VOGL_REPLAY_LOAD_PARAMS_HELPER_glObjectLabel;
8728
8729             switch (identifier)
8730             {
8731                 case GL_BUFFER:
8732                 {
8733                     name = map_handle(get_shared_state()->m_buffers, name);
8734                     break;
8735                 }
8736                 case GL_SHADER:
8737                 case GL_PROGRAM:
8738                 {
8739                     name = map_handle(get_shared_state()->m_shadow_state.m_objs, name);
8740                     break;
8741                 }
8742                 case GL_VERTEX_ARRAY:
8743                 {
8744                     name = map_handle(get_shared_state()->m_vertex_array_objects, name);
8745                     break;
8746                 }
8747                 case GL_QUERY:
8748                 {
8749                     name = map_handle(get_shared_state()->m_queries, name);
8750                     break;
8751                 }
8752                 case GL_SAMPLER:
8753                 {
8754                     name = map_handle(get_shared_state()->m_sampler_objects, name);
8755                     break;
8756                 }
8757                 case GL_TEXTURE:
8758                 {
8759                     name = map_handle(get_shared_state()->m_shadow_state.m_textures, name);
8760                     break;
8761                 }
8762                 case GL_RENDERBUFFER:
8763                 {
8764                     name = map_handle(get_shared_state()->m_shadow_state.m_rbos, name);
8765                     break;
8766                 }
8767                 case GL_FRAMEBUFFER:
8768                 {
8769                     name = map_handle(get_shared_state()->m_framebuffers, name);
8770                     break;
8771                 }
8772                 case GL_DISPLAY_LIST:
8773                 {
8774                     name = map_handle(get_shared_state()->m_lists, name);
8775                     break;
8776                 }
8777                 case GL_TRANSFORM_FEEDBACK: // TODO: Investigate this more
8778                 case GL_PROGRAM_PIPELINE: // TODO: We don't support program pipelines yet
8779                 default:
8780                 {
8781                     process_entrypoint_error("%s: Unsupported object identifier 0x%X\n", VOGL_METHOD_NAME, identifier);
8782                     return cStatusSoftFailure;
8783                 }
8784             }
8785
8786             VOGL_REPLAY_CALL_GL_HELPER_glObjectLabel;
8787
8788             break;
8789         }
8790         case VOGL_ENTRYPOINT_glObjectPtrLabel:
8791         {
8792             vogl_sync_ptr_value trace_sync = trace_packet.get_param_ptr_value(0);
8793             GLsizei length = trace_packet.get_param_value<GLsizei>(1);
8794             const GLchar *pTrace_label = reinterpret_cast<const GLchar *>(trace_packet.get_param_client_memory_ptr(2));
8795             GLsync replay_sync = NULL;
8796
8797             if (trace_sync)
8798             {
8799                 gl_sync_hash_map::const_iterator it = get_shared_state()->m_syncs.find(trace_sync);
8800                 if (it == get_shared_state()->m_syncs.end())
8801                 {
8802                     process_entrypoint_error("%s: Failed remapping trace sync value 0x%" PRIx64 "\n", VOGL_METHOD_NAME, static_cast<uint64_t>(trace_sync));
8803                     return cStatusSoftFailure;
8804                 }
8805                 else
8806                 {
8807                     replay_sync = it->second;
8808                 }
8809             }
8810
8811             GL_ENTRYPOINT(glObjectPtrLabel)(replay_sync, length, pTrace_label);
8812
8813             break;
8814         }
8815         case VOGL_ENTRYPOINT_glReadPixels:
8816         {
8817             GLint x = trace_packet.get_param_value<GLint>(0);
8818             GLint y = trace_packet.get_param_value<GLint>(1);
8819             GLsizei width = trace_packet.get_param_value<GLsizei>(2);
8820             GLsizei height = trace_packet.get_param_value<GLsizei>(3);
8821             GLenum format = trace_packet.get_param_value<GLenum>(4);
8822             GLenum type = trace_packet.get_param_value<GLenum>(5);
8823
8824             GLuint pixel_pack_buf = vogl_get_bound_gl_buffer(GL_PIXEL_PACK_BUFFER);
8825             if (pixel_pack_buf)
8826             {
8827                 GL_ENTRYPOINT(glReadPixels)(x, y, width, height, format, type, reinterpret_cast<GLvoid *>(trace_packet.get_param_ptr_value(6)));
8828             }
8829             else
8830             {
8831                 const GLvoid *trace_data = trace_packet.get_param_client_memory<const GLvoid>(6);
8832                 uint trace_data_size = trace_packet.get_param_client_memory_data_size(6);
8833
8834                 size_t replay_data_size = vogl_get_image_size(format, type, width, height, 1);
8835                 if (replay_data_size != trace_data_size)
8836                 {
8837                     process_entrypoint_warning("%s: Unexpected trace data size, got %u expected %" PRIu64 "\n", VOGL_METHOD_NAME, trace_data_size, (uint64_t)replay_data_size);
8838                 }
8839                 else if (!trace_data)
8840                 {
8841                     process_entrypoint_warning("%s: Trace data is missing from packet\n", VOGL_METHOD_NAME);
8842                 }
8843
8844                 if (replay_data_size > cUINT32_MAX)
8845                 {
8846                     process_entrypoint_error("%s: Replay data size is too large (%" PRIu64 ")!\n", VOGL_METHOD_NAME, (uint64_t)replay_data_size);
8847                     return cStatusHardFailure;
8848                 }
8849
8850                 vogl::vector<uint8> data(static_cast<uint>(replay_data_size));
8851                 GL_ENTRYPOINT(glReadPixels)(x, y, width, height, format, type, data.get_ptr());
8852
8853                 if ((trace_data_size == replay_data_size) && (trace_data_size) && (trace_data))
8854                 {
8855                     if (memcmp(data.get_ptr(), trace_data, trace_data_size) != 0)
8856                     {
8857                         process_entrypoint_error("%s: Replay's returned pixel data differed from trace's!\n", VOGL_METHOD_NAME);
8858                     }
8859                 }
8860                 else
8861                 {
8862                     process_entrypoint_warning("%s: Replay's computed glReadPixels image size differs from traces (%u vs %u)!\n", VOGL_METHOD_NAME, static_cast<uint>(trace_data_size), static_cast<uint>(replay_data_size));
8863                 }
8864             }
8865
8866             break;
8867         }
8868         case VOGL_ENTRYPOINT_glGetTexImage:
8869         {
8870             VOGL_REPLAY_LOAD_PARAMS_HELPER_glGetTexImage;
8871
8872             GLuint pixel_pack_buf = vogl_get_bound_gl_buffer(GL_PIXEL_PACK_BUFFER);
8873             if (pixel_pack_buf)
8874             {
8875                 GLvoid *pReplay_pixels = reinterpret_cast<GLvoid *>(trace_packet.get_param_ptr_value(4));
8876
8877                 VOGL_REPLAY_CALL_GL_HELPER_glGetTexImage;
8878             }
8879             else
8880             {
8881                 uint trace_data_size = trace_packet.get_param_client_memory_data_size(4);
8882
8883                 size_t replay_data_size = vogl_get_tex_target_image_size(target, level, format, type);
8884
8885                 if (replay_data_size > cUINT32_MAX)
8886                 {
8887                     process_entrypoint_error("%s: Replay data size is too large (%" PRIu64 ")!\n", VOGL_METHOD_NAME, (uint64_t)replay_data_size);
8888                     return cStatusHardFailure;
8889                 }
8890
8891                 uint8_vec data(static_cast<uint>(replay_data_size));
8892
8893                 GLvoid *pReplay_pixels = data.get_ptr();
8894
8895                 VOGL_REPLAY_CALL_GL_HELPER_glGetTexImage;
8896
8897                 if ((trace_data_size == replay_data_size) && (trace_data_size) && (pTrace_pixels))
8898                 {
8899                     if (memcmp(data.get_ptr(), pTrace_pixels, trace_data_size) != 0)
8900                     {
8901                         process_entrypoint_error("%s: Replay's returned pixel data differed from trace's!\n", VOGL_METHOD_NAME);
8902                     }
8903                 }
8904                 else
8905                 {
8906                     process_entrypoint_warning("%s: Replay's computed glGetTexImage() image size differs from traces (%u vs %u)!\n", VOGL_METHOD_NAME, static_cast<uint>(trace_data_size), static_cast<uint>(replay_data_size));
8907                 }
8908             }
8909
8910             break;
8911         }
8912         case VOGL_ENTRYPOINT_glGetCompressedTexImage:
8913         {
8914             VOGL_REPLAY_LOAD_PARAMS_HELPER_glGetCompressedTexImage
8915
8916             VOGL_NOTE_UNUSED(pTrace_img);
8917
8918             GLuint pixel_pack_buf = vogl_get_bound_gl_buffer(GL_PIXEL_PACK_BUFFER);
8919             if (pixel_pack_buf)
8920             {
8921                 GLvoid *pReplay_img = reinterpret_cast<GLvoid *>(trace_packet.get_param_ptr_value(2));
8922
8923                 VOGL_REPLAY_CALL_GL_HELPER_glGetCompressedTexImage;
8924             }
8925             else
8926             {
8927                 // TODO: Implement non-pixel pack buffer path, compare for divergence
8928             }
8929
8930             break;
8931         }
8932         case VOGL_ENTRYPOINT_glGetDebugMessageLogARB:
8933         case VOGL_ENTRYPOINT_glGetObjectLabel:
8934         case VOGL_ENTRYPOINT_glGetObjectPtrLabel:
8935         case VOGL_ENTRYPOINT_glGetDebugMessageLog:
8936         case VOGL_ENTRYPOINT_glAreTexturesResident:
8937         case VOGL_ENTRYPOINT_glAreTexturesResidentEXT:
8938         case VOGL_ENTRYPOINT_glGetActiveAtomicCounterBufferiv:
8939         case VOGL_ENTRYPOINT_glGetActiveAttribARB:
8940         case VOGL_ENTRYPOINT_glGetActiveSubroutineName:
8941         case VOGL_ENTRYPOINT_glGetActiveSubroutineUniformName:
8942         case VOGL_ENTRYPOINT_glGetActiveSubroutineUniformiv:
8943         case VOGL_ENTRYPOINT_glGetActiveUniformARB:
8944         case VOGL_ENTRYPOINT_glGetActiveUniformBlockName:
8945         case VOGL_ENTRYPOINT_glGetActiveUniformBlockiv:
8946         case VOGL_ENTRYPOINT_glGetActiveUniformName:
8947         case VOGL_ENTRYPOINT_glGetActiveUniformsiv:
8948         case VOGL_ENTRYPOINT_glGetActiveVaryingNV:
8949         case VOGL_ENTRYPOINT_glGetArrayObjectfvATI:
8950         case VOGL_ENTRYPOINT_glGetArrayObjectivATI:
8951         case VOGL_ENTRYPOINT_glGetAttachedObjectsARB:
8952         case VOGL_ENTRYPOINT_glGetAttribLocationARB:
8953         case VOGL_ENTRYPOINT_glGetBooleanIndexedvEXT:
8954         case VOGL_ENTRYPOINT_glGetBooleani_v:
8955         case VOGL_ENTRYPOINT_glGetBufferParameteri64v:
8956         case VOGL_ENTRYPOINT_glGetBufferParameterivARB:
8957         case VOGL_ENTRYPOINT_glGetBufferParameterui64vNV:
8958         case VOGL_ENTRYPOINT_glGetBufferPointervARB:
8959         case VOGL_ENTRYPOINT_glGetBufferSubDataARB:
8960         case VOGL_ENTRYPOINT_glGetClipPlanefOES:
8961         case VOGL_ENTRYPOINT_glGetClipPlanexOES:
8962         case VOGL_ENTRYPOINT_glGetColorTable:
8963         case VOGL_ENTRYPOINT_glGetColorTableEXT:
8964         case VOGL_ENTRYPOINT_glGetColorTableParameterfv:
8965         case VOGL_ENTRYPOINT_glGetColorTableParameterfvEXT:
8966         case VOGL_ENTRYPOINT_glGetColorTableParameterfvSGI:
8967         case VOGL_ENTRYPOINT_glGetColorTableParameteriv:
8968         case VOGL_ENTRYPOINT_glGetColorTableParameterivEXT:
8969         case VOGL_ENTRYPOINT_glGetColorTableParameterivSGI:
8970         case VOGL_ENTRYPOINT_glGetColorTableSGI:
8971         case VOGL_ENTRYPOINT_glGetCombinerInputParameterfvNV:
8972         case VOGL_ENTRYPOINT_glGetCombinerInputParameterivNV:
8973         case VOGL_ENTRYPOINT_glGetCombinerOutputParameterfvNV:
8974         case VOGL_ENTRYPOINT_glGetCombinerOutputParameterivNV:
8975         case VOGL_ENTRYPOINT_glGetCombinerStageParameterfvNV:
8976         case VOGL_ENTRYPOINT_glGetCompressedMultiTexImageEXT:
8977         case VOGL_ENTRYPOINT_glGetCompressedTexImageARB:
8978         case VOGL_ENTRYPOINT_glGetCompressedTextureImageEXT:
8979         case VOGL_ENTRYPOINT_glGetConvolutionFilter:
8980         case VOGL_ENTRYPOINT_glGetConvolutionFilterEXT:
8981         case VOGL_ENTRYPOINT_glGetConvolutionParameterfv:
8982         case VOGL_ENTRYPOINT_glGetConvolutionParameterfvEXT:
8983         case VOGL_ENTRYPOINT_glGetConvolutionParameteriv:
8984         case VOGL_ENTRYPOINT_glGetConvolutionParameterivEXT:
8985         case VOGL_ENTRYPOINT_glGetConvolutionParameterxvOES:
8986         case VOGL_ENTRYPOINT_glGetDebugMessageLogAMD:
8987         case VOGL_ENTRYPOINT_glGetDetailTexFuncSGIS:
8988         case VOGL_ENTRYPOINT_glGetDoubleIndexedvEXT:
8989         case VOGL_ENTRYPOINT_glGetDoublei_v:
8990         case VOGL_ENTRYPOINT_glGetFenceivNV:
8991         case VOGL_ENTRYPOINT_glGetFinalCombinerInputParameterfvNV:
8992         case VOGL_ENTRYPOINT_glGetFinalCombinerInputParameterivNV:
8993         case VOGL_ENTRYPOINT_glGetFixedvOES:
8994         case VOGL_ENTRYPOINT_glGetFloatIndexedvEXT:
8995         case VOGL_ENTRYPOINT_glGetFloati_v:
8996         case VOGL_ENTRYPOINT_glGetFogFuncSGIS:
8997         case VOGL_ENTRYPOINT_glGetFragDataIndex:
8998         case VOGL_ENTRYPOINT_glGetFragDataLocation:
8999         case VOGL_ENTRYPOINT_glGetFragDataLocationEXT:
9000         case VOGL_ENTRYPOINT_glGetFragmentLightfvSGIX:
9001         case VOGL_ENTRYPOINT_glGetFragmentLightivSGIX:
9002         case VOGL_ENTRYPOINT_glGetFragmentMaterialfvSGIX:
9003         case VOGL_ENTRYPOINT_glGetFragmentMaterialivSGIX:
9004         case VOGL_ENTRYPOINT_glGetFramebufferAttachmentParameteriv:
9005         case VOGL_ENTRYPOINT_glGetFramebufferAttachmentParameterivEXT:
9006         case VOGL_ENTRYPOINT_glGetFramebufferParameteriv:
9007         case VOGL_ENTRYPOINT_glGetFramebufferParameterivEXT:
9008         case VOGL_ENTRYPOINT_glGetGraphicsResetStatusARB:
9009         case VOGL_ENTRYPOINT_glGetHandleARB:
9010         case VOGL_ENTRYPOINT_glGetHistogram:
9011         case VOGL_ENTRYPOINT_glGetHistogramEXT:
9012         case VOGL_ENTRYPOINT_glGetHistogramParameterfv:
9013         case VOGL_ENTRYPOINT_glGetHistogramParameterfvEXT:
9014         case VOGL_ENTRYPOINT_glGetHistogramParameteriv:
9015         case VOGL_ENTRYPOINT_glGetHistogramParameterivEXT:
9016         case VOGL_ENTRYPOINT_glGetHistogramParameterxvOES:
9017         case VOGL_ENTRYPOINT_glGetImageHandleNV:
9018         case VOGL_ENTRYPOINT_glGetImageTransformParameterfvHP:
9019         case VOGL_ENTRYPOINT_glGetImageTransformParameterivHP:
9020         case VOGL_ENTRYPOINT_glGetInstrumentsSGIX:
9021         case VOGL_ENTRYPOINT_glGetInteger64i_v:
9022         case VOGL_ENTRYPOINT_glGetInteger64v:
9023         case VOGL_ENTRYPOINT_glGetIntegerIndexedvEXT:
9024         case VOGL_ENTRYPOINT_glGetIntegeri_v:
9025         case VOGL_ENTRYPOINT_glGetIntegerui64i_vNV:
9026         case VOGL_ENTRYPOINT_glGetIntegerui64vNV:
9027         case VOGL_ENTRYPOINT_glGetInternalformati64v:
9028         case VOGL_ENTRYPOINT_glGetInternalformativ:
9029         case VOGL_ENTRYPOINT_glGetInvariantBooleanvEXT:
9030         case VOGL_ENTRYPOINT_glGetInvariantFloatvEXT:
9031         case VOGL_ENTRYPOINT_glGetInvariantIntegervEXT:
9032         case VOGL_ENTRYPOINT_glGetLightxOES:
9033         case VOGL_ENTRYPOINT_glGetListParameterfvSGIX:
9034         case VOGL_ENTRYPOINT_glGetListParameterivSGIX:
9035         case VOGL_ENTRYPOINT_glGetLocalConstantBooleanvEXT:
9036         case VOGL_ENTRYPOINT_glGetLocalConstantFloatvEXT:
9037         case VOGL_ENTRYPOINT_glGetLocalConstantIntegervEXT:
9038         case VOGL_ENTRYPOINT_glGetMapAttribParameterfvNV:
9039         case VOGL_ENTRYPOINT_glGetMapAttribParameterivNV:
9040         case VOGL_ENTRYPOINT_glGetMapControlPointsNV:
9041         case VOGL_ENTRYPOINT_glGetMapParameterfvNV:
9042         case VOGL_ENTRYPOINT_glGetMapParameterivNV:
9043         case VOGL_ENTRYPOINT_glGetMapdv:
9044         case VOGL_ENTRYPOINT_glGetMapfv:
9045         case VOGL_ENTRYPOINT_glGetMapiv:
9046         case VOGL_ENTRYPOINT_glGetMapxvOES:
9047         case VOGL_ENTRYPOINT_glGetMaterialfv:
9048         case VOGL_ENTRYPOINT_glGetMaterialiv:
9049         case VOGL_ENTRYPOINT_glGetMaterialxOES:
9050         case VOGL_ENTRYPOINT_glGetMinmax:
9051         case VOGL_ENTRYPOINT_glGetMinmaxEXT:
9052         case VOGL_ENTRYPOINT_glGetMinmaxParameterfv:
9053         case VOGL_ENTRYPOINT_glGetMinmaxParameterfvEXT:
9054         case VOGL_ENTRYPOINT_glGetMinmaxParameteriv:
9055         case VOGL_ENTRYPOINT_glGetMinmaxParameterivEXT:
9056         case VOGL_ENTRYPOINT_glGetMultiTexEnvfvEXT:
9057         case VOGL_ENTRYPOINT_glGetMultiTexEnvivEXT:
9058         case VOGL_ENTRYPOINT_glGetMultiTexGendvEXT:
9059         case VOGL_ENTRYPOINT_glGetMultiTexGenfvEXT:
9060         case VOGL_ENTRYPOINT_glGetMultiTexGenivEXT:
9061         case VOGL_ENTRYPOINT_glGetMultiTexImageEXT:
9062         case VOGL_ENTRYPOINT_glGetMultiTexLevelParameterfvEXT:
9063         case VOGL_ENTRYPOINT_glGetMultiTexLevelParameterivEXT:
9064         case VOGL_ENTRYPOINT_glGetMultiTexParameterIivEXT:
9065         case VOGL_ENTRYPOINT_glGetMultiTexParameterIuivEXT:
9066         case VOGL_ENTRYPOINT_glGetMultiTexParameterfvEXT:
9067         case VOGL_ENTRYPOINT_glGetMultiTexParameterivEXT:
9068         case VOGL_ENTRYPOINT_glGetMultisamplefv:
9069         case VOGL_ENTRYPOINT_glGetMultisamplefvNV:
9070         case VOGL_ENTRYPOINT_glGetNamedBufferParameterivEXT:
9071         case VOGL_ENTRYPOINT_glGetNamedBufferParameterui64vNV:
9072         case VOGL_ENTRYPOINT_glGetNamedBufferPointervEXT:
9073         case VOGL_ENTRYPOINT_glGetNamedBufferSubDataEXT:
9074         case VOGL_ENTRYPOINT_glGetNamedFramebufferAttachmentParameterivEXT:
9075         case VOGL_ENTRYPOINT_glGetNamedFramebufferParameterivEXT:
9076         case VOGL_ENTRYPOINT_glGetNamedProgramLocalParameterIivEXT:
9077         case VOGL_ENTRYPOINT_glGetNamedProgramLocalParameterIuivEXT:
9078         case VOGL_ENTRYPOINT_glGetNamedProgramLocalParameterdvEXT:
9079         case VOGL_ENTRYPOINT_glGetNamedProgramLocalParameterfvEXT:
9080         case VOGL_ENTRYPOINT_glGetNamedProgramStringEXT:
9081         case VOGL_ENTRYPOINT_glGetNamedProgramivEXT:
9082         case VOGL_ENTRYPOINT_glGetNamedRenderbufferParameterivEXT:
9083         case VOGL_ENTRYPOINT_glGetNamedStringARB:
9084         case VOGL_ENTRYPOINT_glGetNamedStringivARB:
9085         case VOGL_ENTRYPOINT_glGetObjectBufferfvATI:
9086         case VOGL_ENTRYPOINT_glGetObjectBufferivATI:
9087         case VOGL_ENTRYPOINT_glGetObjectParameterfvARB:
9088         case VOGL_ENTRYPOINT_glGetObjectParameterivAPPLE:
9089         case VOGL_ENTRYPOINT_glGetOcclusionQueryivNV:
9090         case VOGL_ENTRYPOINT_glGetOcclusionQueryuivNV:
9091         case VOGL_ENTRYPOINT_glGetPathColorGenfvNV:
9092         case VOGL_ENTRYPOINT_glGetPathColorGenivNV:
9093         case VOGL_ENTRYPOINT_glGetPathCommandsNV:
9094         case VOGL_ENTRYPOINT_glGetPathCoordsNV:
9095         case VOGL_ENTRYPOINT_glGetPathDashArrayNV:
9096         case VOGL_ENTRYPOINT_glGetPathLengthNV:
9097         case VOGL_ENTRYPOINT_glGetPathMetricRangeNV:
9098         case VOGL_ENTRYPOINT_glGetPathMetricsNV:
9099         case VOGL_ENTRYPOINT_glGetPathParameterfvNV:
9100         case VOGL_ENTRYPOINT_glGetPathParameterivNV:
9101         case VOGL_ENTRYPOINT_glGetPathSpacingNV:
9102         case VOGL_ENTRYPOINT_glGetPathTexGenfvNV:
9103         case VOGL_ENTRYPOINT_glGetPathTexGenivNV:
9104         case VOGL_ENTRYPOINT_glGetPerfMonitorCounterDataAMD:
9105         case VOGL_ENTRYPOINT_glGetPerfMonitorCounterInfoAMD:
9106         case VOGL_ENTRYPOINT_glGetPerfMonitorCounterStringAMD:
9107         case VOGL_ENTRYPOINT_glGetPerfMonitorCountersAMD:
9108         case VOGL_ENTRYPOINT_glGetPerfMonitorGroupStringAMD:
9109         case VOGL_ENTRYPOINT_glGetPerfMonitorGroupsAMD:
9110         case VOGL_ENTRYPOINT_glGetPixelMapfv:
9111         case VOGL_ENTRYPOINT_glGetPixelMapuiv:
9112         case VOGL_ENTRYPOINT_glGetPixelMapusv:
9113         case VOGL_ENTRYPOINT_glGetPixelMapxv:
9114         case VOGL_ENTRYPOINT_glGetPixelTexGenParameterfvSGIS:
9115         case VOGL_ENTRYPOINT_glGetPixelTexGenParameterivSGIS:
9116         case VOGL_ENTRYPOINT_glGetPixelTransformParameterfvEXT:
9117         case VOGL_ENTRYPOINT_glGetPixelTransformParameterivEXT:
9118         case VOGL_ENTRYPOINT_glGetPointerIndexedvEXT:
9119         case VOGL_ENTRYPOINT_glGetPointervEXT:
9120         case VOGL_ENTRYPOINT_glGetPolygonStipple:
9121         case VOGL_ENTRYPOINT_glGetProgramBinary:
9122         case VOGL_ENTRYPOINT_glGetProgramEnvParameterIivNV:
9123         case VOGL_ENTRYPOINT_glGetProgramEnvParameterIuivNV:
9124         case VOGL_ENTRYPOINT_glGetProgramEnvParameterdvARB:
9125         case VOGL_ENTRYPOINT_glGetProgramEnvParameterfvARB:
9126         case VOGL_ENTRYPOINT_glGetProgramInterfaceiv:
9127         case VOGL_ENTRYPOINT_glGetProgramLocalParameterIivNV:
9128         case VOGL_ENTRYPOINT_glGetProgramLocalParameterIuivNV:
9129         case VOGL_ENTRYPOINT_glGetProgramLocalParameterdvARB:
9130         case VOGL_ENTRYPOINT_glGetProgramLocalParameterfvARB:
9131         case VOGL_ENTRYPOINT_glGetProgramNamedParameterdvNV:
9132         case VOGL_ENTRYPOINT_glGetProgramNamedParameterfvNV:
9133         case VOGL_ENTRYPOINT_glGetProgramParameterdvNV:
9134         case VOGL_ENTRYPOINT_glGetProgramParameterfvNV:
9135         case VOGL_ENTRYPOINT_glGetProgramPipelineInfoLog:
9136         case VOGL_ENTRYPOINT_glGetProgramPipelineiv:
9137         case VOGL_ENTRYPOINT_glGetProgramResourceIndex:
9138         case VOGL_ENTRYPOINT_glGetProgramResourceLocation:
9139         case VOGL_ENTRYPOINT_glGetProgramResourceLocationIndex:
9140         case VOGL_ENTRYPOINT_glGetProgramResourceName:
9141         case VOGL_ENTRYPOINT_glGetProgramResourceiv:
9142         case VOGL_ENTRYPOINT_glGetProgramStageiv:
9143         case VOGL_ENTRYPOINT_glGetProgramStringARB:
9144         case VOGL_ENTRYPOINT_glGetProgramStringNV:
9145         case VOGL_ENTRYPOINT_glGetProgramSubroutineParameteruivNV:
9146         case VOGL_ENTRYPOINT_glGetProgramivNV:
9147         case VOGL_ENTRYPOINT_glGetQueryIndexediv:
9148         case VOGL_ENTRYPOINT_glGetQueryObjecti64vEXT:
9149         case VOGL_ENTRYPOINT_glGetQueryObjectui64vEXT:
9150         case VOGL_ENTRYPOINT_glGetQueryiv:
9151         case VOGL_ENTRYPOINT_glGetQueryivARB:
9152         case VOGL_ENTRYPOINT_glGetSamplerParameterIiv:
9153         case VOGL_ENTRYPOINT_glGetSamplerParameterIuiv:
9154         case VOGL_ENTRYPOINT_glGetSamplerParameterfv:
9155         case VOGL_ENTRYPOINT_glGetSamplerParameteriv:
9156         case VOGL_ENTRYPOINT_glGetSeparableFilter:
9157         case VOGL_ENTRYPOINT_glGetSeparableFilterEXT:
9158         case VOGL_ENTRYPOINT_glGetShaderPrecisionFormat:
9159         case VOGL_ENTRYPOINT_glGetShaderSource:
9160         case VOGL_ENTRYPOINT_glGetShaderSourceARB:
9161         case VOGL_ENTRYPOINT_glGetSharpenTexFuncSGIS:
9162         case VOGL_ENTRYPOINT_glGetSubroutineIndex:
9163         case VOGL_ENTRYPOINT_glGetSubroutineUniformLocation:
9164         case VOGL_ENTRYPOINT_glGetSynciv:
9165         case VOGL_ENTRYPOINT_glGetTexBumpParameterfvATI:
9166         case VOGL_ENTRYPOINT_glGetTexBumpParameterivATI:
9167         case VOGL_ENTRYPOINT_glGetTexEnvxvOES:
9168         case VOGL_ENTRYPOINT_glGetTexFilterFuncSGIS:
9169         case VOGL_ENTRYPOINT_glGetTexGenxvOES:
9170         case VOGL_ENTRYPOINT_glGetTexLevelParameterxvOES:
9171         case VOGL_ENTRYPOINT_glGetTexParameterIivEXT:
9172         case VOGL_ENTRYPOINT_glGetTexParameterIuivEXT:
9173         case VOGL_ENTRYPOINT_glGetTexParameterPointervAPPLE:
9174         case VOGL_ENTRYPOINT_glGetTexParameterxvOES:
9175         case VOGL_ENTRYPOINT_glGetTextureHandleNV:
9176         case VOGL_ENTRYPOINT_glGetTextureImageEXT:
9177         case VOGL_ENTRYPOINT_glGetTextureLevelParameterfvEXT:
9178         case VOGL_ENTRYPOINT_glGetTextureLevelParameterivEXT:
9179         case VOGL_ENTRYPOINT_glGetTextureParameterIivEXT:
9180         case VOGL_ENTRYPOINT_glGetTextureParameterIuivEXT:
9181         case VOGL_ENTRYPOINT_glGetTextureParameterfvEXT:
9182         case VOGL_ENTRYPOINT_glGetTextureParameterivEXT:
9183         case VOGL_ENTRYPOINT_glGetTextureSamplerHandleNV:
9184         case VOGL_ENTRYPOINT_glGetTrackMatrixivNV:
9185         case VOGL_ENTRYPOINT_glGetTransformFeedbackVarying:
9186         case VOGL_ENTRYPOINT_glGetTransformFeedbackVaryingEXT:
9187         case VOGL_ENTRYPOINT_glGetTransformFeedbackVaryingNV:
9188         case VOGL_ENTRYPOINT_glGetUniformBlockIndex:
9189         case VOGL_ENTRYPOINT_glGetUniformBufferSizeEXT:
9190         case VOGL_ENTRYPOINT_glGetUniformIndices:
9191         case VOGL_ENTRYPOINT_glGetUniformOffsetEXT:
9192         case VOGL_ENTRYPOINT_glGetUniformSubroutineuiv:
9193         case VOGL_ENTRYPOINT_glGetUniformdv:
9194         case VOGL_ENTRYPOINT_glGetUniformfv:
9195         case VOGL_ENTRYPOINT_glGetUniformfvARB:
9196         case VOGL_ENTRYPOINT_glGetUniformi64vNV:
9197         case VOGL_ENTRYPOINT_glGetUniformiv:
9198         case VOGL_ENTRYPOINT_glGetUniformivARB:
9199         case VOGL_ENTRYPOINT_glGetUniformui64vNV:
9200         case VOGL_ENTRYPOINT_glGetUniformuiv:
9201         case VOGL_ENTRYPOINT_glGetUniformuivEXT:
9202         case VOGL_ENTRYPOINT_glGetVariantArrayObjectfvATI:
9203         case VOGL_ENTRYPOINT_glGetVariantArrayObjectivATI:
9204         case VOGL_ENTRYPOINT_glGetVariantBooleanvEXT:
9205         case VOGL_ENTRYPOINT_glGetVariantFloatvEXT:
9206         case VOGL_ENTRYPOINT_glGetVariantIntegervEXT:
9207         case VOGL_ENTRYPOINT_glGetVariantPointervEXT:
9208         case VOGL_ENTRYPOINT_glGetVaryingLocationNV:
9209         case VOGL_ENTRYPOINT_glGetVertexAttribArrayObjectfvATI:
9210         case VOGL_ENTRYPOINT_glGetVertexAttribArrayObjectivATI:
9211         case VOGL_ENTRYPOINT_glGetVertexAttribLdv:
9212         case VOGL_ENTRYPOINT_glGetVertexAttribLdvEXT:
9213         case VOGL_ENTRYPOINT_glGetVertexAttribLi64vNV:
9214         case VOGL_ENTRYPOINT_glGetVertexAttribLui64vNV:
9215         case VOGL_ENTRYPOINT_glGetVertexAttribPointerv:
9216         case VOGL_ENTRYPOINT_glGetVertexAttribPointervARB:
9217         case VOGL_ENTRYPOINT_glGetVertexAttribPointervNV:
9218         case VOGL_ENTRYPOINT_glGetVertexAttribdvARB:
9219         case VOGL_ENTRYPOINT_glGetVertexAttribdvNV:
9220         case VOGL_ENTRYPOINT_glGetVertexAttribfvARB:
9221         case VOGL_ENTRYPOINT_glGetVertexAttribfvNV:
9222         case VOGL_ENTRYPOINT_glGetVertexAttribivARB:
9223         case VOGL_ENTRYPOINT_glGetVertexAttribivNV:
9224         case VOGL_ENTRYPOINT_glGetVideoCaptureStreamdvNV:
9225         case VOGL_ENTRYPOINT_glGetVideoCaptureStreamfvNV:
9226         case VOGL_ENTRYPOINT_glGetVideoCaptureStreamivNV:
9227         case VOGL_ENTRYPOINT_glGetVideoCaptureivNV:
9228         case VOGL_ENTRYPOINT_glGetVideoi64vNV:
9229         case VOGL_ENTRYPOINT_glGetVideoivNV:
9230         case VOGL_ENTRYPOINT_glGetVideoui64vNV:
9231         case VOGL_ENTRYPOINT_glGetVideouivNV:
9232         case VOGL_ENTRYPOINT_glGetnColorTableARB:
9233         case VOGL_ENTRYPOINT_glGetnCompressedTexImageARB:
9234         case VOGL_ENTRYPOINT_glGetnConvolutionFilterARB:
9235         case VOGL_ENTRYPOINT_glGetnHistogramARB:
9236         case VOGL_ENTRYPOINT_glGetnMapdvARB:
9237         case VOGL_ENTRYPOINT_glGetnMapfvARB:
9238         case VOGL_ENTRYPOINT_glGetnMapivARB:
9239         case VOGL_ENTRYPOINT_glGetnMinmaxARB:
9240         case VOGL_ENTRYPOINT_glGetnPixelMapfvARB:
9241         case VOGL_ENTRYPOINT_glGetnPixelMapuivARB:
9242         case VOGL_ENTRYPOINT_glGetnPixelMapusvARB:
9243         case VOGL_ENTRYPOINT_glGetnPolygonStippleARB:
9244         case VOGL_ENTRYPOINT_glGetnSeparableFilterARB:
9245         case VOGL_ENTRYPOINT_glGetnTexImageARB:
9246         case VOGL_ENTRYPOINT_glGetnUniformdvARB:
9247         case VOGL_ENTRYPOINT_glGetnUniformfvARB:
9248         case VOGL_ENTRYPOINT_glGetnUniformivARB:
9249         case VOGL_ENTRYPOINT_glGetnUniformuivARB:
9250         case VOGL_ENTRYPOINT_glIsBufferARB:
9251         case VOGL_ENTRYPOINT_glIsEnabledIndexedEXT:
9252         case VOGL_ENTRYPOINT_glIsQueryARB:
9253         case VOGL_ENTRYPOINT_glIsSync:
9254         case VOGL_ENTRYPOINT_glPrioritizeTextures:
9255         case VOGL_ENTRYPOINT_glPrioritizeTexturesEXT:
9256         {
9257             if (!(g_vogl_entrypoint_descs[entrypoint_id].m_flags & cGLEFPrintedUnimplementedWarning))
9258             {
9259                 process_entrypoint_warning("%s: TODO: Implement glGet() function %s\n", VOGL_METHOD_NAME, g_vogl_entrypoint_descs[entrypoint_id].m_pName);
9260
9261                 g_vogl_entrypoint_descs[entrypoint_id].m_flags |= cGLEFPrintedUnimplementedWarning;
9262             }
9263             break;
9264         }
9265         default:
9266         {
9267             if (g_vogl_entrypoint_descs[entrypoint_id].m_is_whitelisted)
9268                 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);
9269             else
9270                 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);
9271             return cStatusSoftFailure;
9272         }
9273     }
9274
9275     m_last_processed_call_counter = trace_packet.get_call_counter();
9276
9277     if (!m_pCur_context_state->m_inside_gl_begin)
9278     {
9279         if (check_gl_error())
9280             return cStatusGLError;
9281     }
9282
9283     if (vogl_is_draw_entrypoint(entrypoint_id) || vogl_is_clear_entrypoint(entrypoint_id) || (entrypoint_id == VOGL_ENTRYPOINT_glBitmap))
9284     {
9285         if ((status = post_draw_call()) != cStatusOK)
9286             return status;
9287     }
9288
9289     return cStatusOK;
9290 }
9291
9292 //----------------------------------------------------------------------------------------------------------------------
9293 // vogl_gl_replayer::snapshot_backbuffer
9294 //----------------------------------------------------------------------------------------------------------------------
9295 void vogl_gl_replayer::snapshot_backbuffer()
9296 {
9297     VOGL_FUNC_TRACER
9298
9299     if (!m_pCur_context_state)
9300     {
9301         vogl_warning_printf("%s: Can't take snapshot without an active context\n", VOGL_METHOD_NAME);
9302         return;
9303     }
9304
9305     uint recorded_width = m_pWindow->get_width();
9306     uint recorded_height = m_pWindow->get_height();
9307
9308     uint width = 0, height = 0;
9309     m_pWindow->get_actual_dimensions(width, height);
9310
9311     VOGL_ASSERT((recorded_width == width) && (recorded_height == height));
9312     VOGL_NOTE_UNUSED(recorded_width);
9313     VOGL_NOTE_UNUSED(recorded_height);
9314
9315     m_screenshot_buffer.resize(width * height * 3);
9316
9317     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);
9318     if (!success)
9319     {
9320         process_entrypoint_error("%s: Failed calling glReadPixels() to take screenshot\n", VOGL_METHOD_NAME);
9321     }
9322
9323     if (m_flags & cGLReplayerDumpScreenshots)
9324     {
9325         size_t png_size = 0;
9326         void *pPNG_data = tdefl_write_image_to_png_file_in_memory_ex(m_screenshot_buffer.get_ptr(), width, height, 3, &png_size, 1, true);
9327
9328         dynamic_string screenshot_filename(cVarArg, "%s_%07u.png", m_screenshot_prefix.get_ptr(), m_total_swaps);
9329         if (!file_utils::write_buf_to_file(screenshot_filename.get_ptr(), pPNG_data, png_size))
9330         {
9331             process_entrypoint_error("Failed writing PNG screenshot to file %s\n", screenshot_filename.get_ptr());
9332         }
9333         else
9334         {
9335             vogl_message_printf("Wrote screenshot to file %s\n", screenshot_filename.get_ptr());
9336         }
9337
9338         mz_free(pPNG_data);
9339     }
9340
9341     if ((m_flags & cGLReplayerDumpBackbufferHashes) || (m_flags & cGLReplayerHashBackbuffer))
9342     {
9343         uint64_t backbuffer_crc64;
9344
9345         if (m_flags & cGLReplayerSumHashing)
9346         {
9347             backbuffer_crc64 = calc_sum64(m_screenshot_buffer.get_ptr(), m_screenshot_buffer.size());
9348         }
9349         else
9350         {
9351             backbuffer_crc64 = calc_crc64(CRC64_INIT, m_screenshot_buffer.get_ptr(), m_screenshot_buffer.size());
9352         }
9353
9354         vogl_printf("Frame %u hash: 0x%016" PRIX64 "\n", m_frame_index, backbuffer_crc64);
9355
9356         if (m_backbuffer_hash_filename.has_content())
9357         {
9358             FILE *pFile = vogl_fopen(m_backbuffer_hash_filename.get_ptr(), "a");
9359             if (!pFile)
9360                 vogl_error_printf("Failed writing to backbuffer hash file %s\n", m_backbuffer_hash_filename.get_ptr());
9361             else
9362             {
9363                 vogl_fprintf(pFile, "0x%016" PRIX64 "\n", cast_val_to_uint64(backbuffer_crc64));
9364                 vogl_fclose(pFile);
9365             }
9366         }
9367     }
9368 }
9369
9370 //----------------------------------------------------------------------------------------------------------------------
9371 // vogl_gl_replayer::is_valid_handle
9372 //----------------------------------------------------------------------------------------------------------------------
9373 bool vogl_gl_replayer::replay_to_trace_handle_remapper::is_valid_handle(vogl_namespace_t handle_namespace, uint64_t replay_handle)
9374 {
9375     VOGL_FUNC_TRACER
9376
9377     if (!replay_handle)
9378         return 0;
9379
9380     uint32 replay_handle32 = static_cast<uint32>(replay_handle);
9381
9382     switch (handle_namespace)
9383     {
9384         case VOGL_NAMESPACE_VERTEX_ARRAYS:
9385         {
9386             VOGL_ASSERT(replay_handle32 == replay_handle);
9387             return (m_replayer.get_context_state()->m_vertex_array_objects.search_table_for_value_get_count(replay_handle32) != 0);
9388         }
9389         case VOGL_NAMESPACE_FRAMEBUFFERS:
9390         {
9391             VOGL_ASSERT(replay_handle32 == replay_handle);
9392             return (m_replayer.get_context_state()->m_framebuffers.search_table_for_value_get_count(replay_handle32) != 0);
9393         }
9394         case VOGL_NAMESPACE_TEXTURES:
9395         {
9396             VOGL_ASSERT(replay_handle32 == replay_handle);
9397             return (m_replayer.get_shared_state()->m_shadow_state.m_textures.contains_inv(replay_handle32) != 0);
9398         }
9399         case VOGL_NAMESPACE_RENDER_BUFFERS:
9400         {
9401             VOGL_ASSERT(replay_handle32 == replay_handle);
9402             return (m_replayer.get_shared_state()->m_shadow_state.m_rbos.contains_inv(replay_handle32) != 0);
9403         }
9404         case VOGL_NAMESPACE_QUERIES:
9405         {
9406             VOGL_ASSERT(replay_handle32 == replay_handle);
9407             return (m_replayer.get_shared_state()->m_queries.search_table_for_value_get_count(replay_handle32) != 0);
9408         }
9409         case VOGL_NAMESPACE_SAMPLERS:
9410         {
9411             VOGL_ASSERT(replay_handle32 == replay_handle);
9412             return (m_replayer.get_shared_state()->m_sampler_objects.search_table_for_value_get_count(replay_handle32) != 0);
9413         }
9414         case VOGL_NAMESPACE_PROGRAMS:
9415         {
9416             VOGL_ASSERT(replay_handle32 == replay_handle);
9417             return m_replayer.get_shared_state()->m_shadow_state.m_objs.get_target_inv(replay_handle32) == VOGL_PROGRAM_OBJECT;
9418         }
9419         case VOGL_NAMESPACE_SHADERS:
9420         {
9421             VOGL_ASSERT(replay_handle32 == replay_handle);
9422             return m_replayer.get_shared_state()->m_shadow_state.m_objs.get_target_inv(replay_handle32) == VOGL_SHADER_OBJECT;
9423         }
9424         case VOGL_NAMESPACE_BUFFERS:
9425         {
9426             VOGL_ASSERT(replay_handle32 == replay_handle);
9427             return m_replayer.get_shared_state()->m_buffers.search_table_for_value_get_count(replay_handle32);
9428         }
9429         case VOGL_NAMESPACE_SYNCS:
9430         {
9431             GLsync replay_sync = vogl_handle_to_sync(replay_handle);
9432             return m_replayer.get_shared_state()->m_syncs.search_table_for_value_get_count(replay_sync) != 0;
9433         }
9434         case VOGL_NAMESPACE_PROGRAM_ARB:
9435         {
9436             VOGL_ASSERT(replay_handle32 == replay_handle);
9437             return m_replayer.get_shared_state()->m_arb_programs.search_table_for_value_get_count(replay_handle32) != 0;
9438         }
9439         default:
9440             break;
9441     }
9442
9443     VOGL_VERIFY(0);
9444
9445     return false;
9446 }
9447
9448 //----------------------------------------------------------------------------------------------------------------------
9449 // vogl_gl_replayer::remap_handle
9450 //----------------------------------------------------------------------------------------------------------------------
9451 uint64_t vogl_gl_replayer::replay_to_trace_handle_remapper::remap_handle(vogl_namespace_t handle_namespace, uint64_t replay_handle)
9452 {
9453     VOGL_FUNC_TRACER
9454
9455     if (!replay_handle)
9456         return 0;
9457
9458     uint32 replay_handle32 = static_cast<uint32>(replay_handle);
9459
9460     switch (handle_namespace)
9461     {
9462         case VOGL_NAMESPACE_VERTEX_ARRAYS:
9463         {
9464             VOGL_ASSERT(replay_handle32 == replay_handle);
9465             if (remap_replay_to_trace_handle(m_replayer.get_context_state()->m_vertex_array_objects, replay_handle32))
9466                 return replay_handle32;
9467             break;
9468         }
9469         case VOGL_NAMESPACE_FRAMEBUFFERS:
9470         {
9471             VOGL_ASSERT(replay_handle32 == replay_handle);
9472             if (remap_replay_to_trace_handle(m_replayer.get_context_state()->m_framebuffers, replay_handle32))
9473                 return replay_handle32;
9474             break;
9475         }
9476         case VOGL_NAMESPACE_TEXTURES:
9477         {
9478             VOGL_ASSERT(replay_handle32 == replay_handle);
9479
9480             uint32 trace_handle = replay_handle32;
9481             if (m_replayer.get_shared_state()->m_shadow_state.m_textures.map_inv_handle_to_handle(replay_handle32, trace_handle))
9482                 return trace_handle;
9483
9484             break;
9485         }
9486         case VOGL_NAMESPACE_RENDER_BUFFERS:
9487         {
9488             VOGL_ASSERT(replay_handle32 == replay_handle);
9489             GLuint trace_handle = replay_handle32;
9490             if (m_replayer.get_shared_state()->m_shadow_state.m_rbos.map_inv_handle_to_handle(replay_handle32, trace_handle))
9491                 return trace_handle;
9492
9493             break;
9494         }
9495         case VOGL_NAMESPACE_QUERIES:
9496         {
9497             VOGL_ASSERT(replay_handle32 == replay_handle);
9498             if (remap_replay_to_trace_handle(m_replayer.get_shared_state()->m_queries, replay_handle32))
9499                 return replay_handle32;
9500             break;
9501         }
9502         case VOGL_NAMESPACE_SAMPLERS:
9503         {
9504             VOGL_ASSERT(replay_handle32 == replay_handle);
9505             if (remap_replay_to_trace_handle(m_replayer.get_shared_state()->m_sampler_objects, replay_handle32))
9506                 return replay_handle32;
9507             break;
9508         }
9509         case VOGL_NAMESPACE_PROGRAMS:
9510         {
9511             VOGL_ASSERT(replay_handle32 == replay_handle);
9512             VOGL_ASSERT(m_replayer.get_shared_state()->m_shadow_state.m_objs.get_target_inv(replay_handle32) == VOGL_PROGRAM_OBJECT);
9513             GLuint trace_handle = replay_handle32;
9514             if (m_replayer.get_shared_state()->m_shadow_state.m_objs.map_inv_handle_to_handle(replay_handle32, trace_handle))
9515                 return trace_handle;
9516             break;
9517         }
9518         case VOGL_NAMESPACE_SHADERS:
9519         {
9520             VOGL_ASSERT(replay_handle32 == replay_handle);
9521             VOGL_ASSERT(m_replayer.get_shared_state()->m_shadow_state.m_objs.get_target_inv(replay_handle32) == VOGL_SHADER_OBJECT);
9522             GLuint trace_handle = replay_handle32;
9523             if (m_replayer.get_shared_state()->m_shadow_state.m_objs.map_inv_handle_to_handle(replay_handle32, trace_handle))
9524                 return trace_handle;
9525             break;
9526         }
9527         case VOGL_NAMESPACE_BUFFERS:
9528         {
9529             VOGL_ASSERT(replay_handle32 == replay_handle);
9530             if (remap_replay_to_trace_handle(m_replayer.get_shared_state()->m_buffers, replay_handle32))
9531                 return replay_handle32;
9532             break;
9533         }
9534         case VOGL_NAMESPACE_SYNCS:
9535         {
9536             GLsync replay_sync = vogl_handle_to_sync(replay_handle);
9537
9538             gl_sync_hash_map::const_iterator it(m_replayer.get_shared_state()->m_syncs.search_table_for_value(replay_sync));
9539             if (it != m_replayer.get_shared_state()->m_syncs.end())
9540             {
9541                 VOGL_ASSERT(it->second == replay_sync);
9542                 return it->first;
9543             }
9544
9545             break;
9546         }
9547         case VOGL_NAMESPACE_PROGRAM_ARB:
9548         {
9549             VOGL_ASSERT(replay_handle32 == replay_handle);
9550             if (remap_replay_to_trace_handle(m_replayer.get_shared_state()->m_arb_programs, replay_handle32))
9551                 return replay_handle32;
9552             break;
9553         }
9554         default:
9555         {
9556             break;
9557         }
9558     }
9559
9560     // This is BAD.
9561     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));
9562
9563     VOGL_ASSERT_ALWAYS;
9564
9565     return replay_handle;
9566 }
9567
9568 //----------------------------------------------------------------------------------------------------------------------
9569 // vogl_gl_replayer::replay_to_trace_handle_remapper::remap_location
9570 //----------------------------------------------------------------------------------------------------------------------
9571 int32 vogl_gl_replayer::replay_to_trace_handle_remapper::remap_location(uint32 replay_program, int32 replay_location)
9572 {
9573     VOGL_FUNC_TRACER
9574
9575     if ((!replay_program) || (replay_location < 0))
9576         return replay_location;
9577
9578     GLuint trace_program = static_cast<GLuint>(remap_handle(VOGL_NAMESPACE_PROGRAMS, replay_program));
9579
9580     glsl_program_hash_map::const_iterator it(m_replayer.get_shared_state()->m_glsl_program_hash_map.find(trace_program));
9581     if (it != m_replayer.get_shared_state()->m_glsl_program_hash_map.end())
9582     {
9583         const glsl_program_state &state = it->second;
9584
9585         uniform_location_hash_map::const_iterator loc_it(state.m_uniform_locations.search_table_for_value(replay_location));
9586         if (loc_it != state.m_uniform_locations.end())
9587             return loc_it->first;
9588     }
9589
9590     vogl_warning_printf("%s: Failed remapping location %i of program %u\n", VOGL_METHOD_NAME, replay_location, replay_program);
9591
9592     return replay_location;
9593 }
9594
9595 //----------------------------------------------------------------------------------------------------------------------
9596 // vogl_gl_replayer::replay_to_trace_handle_remapper::determine_from_object_target
9597 //----------------------------------------------------------------------------------------------------------------------
9598 bool vogl_gl_replayer::replay_to_trace_handle_remapper::determine_from_object_target(vogl_namespace_t handle_namespace, uint64_t replay_handle, GLenum &target)
9599 {
9600     VOGL_FUNC_TRACER
9601
9602     target = GL_NONE;
9603
9604     uint32 handle32 = static_cast<uint32>(replay_handle);
9605
9606     switch (handle_namespace)
9607     {
9608         case VOGL_NAMESPACE_TEXTURES:
9609         {
9610             VOGL_ASSERT(handle32 == replay_handle);
9611             if (!m_replayer.get_shared_state()->m_shadow_state.m_textures.contains_inv(handle32))
9612                 return false;
9613
9614             target = m_replayer.get_shared_state()->m_shadow_state.m_textures.get_target_inv(handle32);
9615             return true;
9616         }
9617         default:
9618             break;
9619     }
9620
9621     VOGL_VERIFY(0);
9622     return false;
9623 }
9624
9625 //----------------------------------------------------------------------------------------------------------------------
9626 // vogl_gl_replayer::replay_to_trace_handle_remapper::determine_to_object_target
9627 //----------------------------------------------------------------------------------------------------------------------
9628 bool vogl_gl_replayer::replay_to_trace_handle_remapper::determine_to_object_target(vogl_namespace_t handle_namespace, uint64_t trace_handle, GLenum &target)
9629 {
9630     VOGL_FUNC_TRACER
9631
9632     target = GL_NONE;
9633
9634     uint32 handle32 = static_cast<uint32>(trace_handle);
9635
9636     switch (handle_namespace)
9637     {
9638         case VOGL_NAMESPACE_TEXTURES:
9639         {
9640             VOGL_ASSERT(handle32 == trace_handle);
9641             if (!m_replayer.get_shared_state()->m_shadow_state.m_textures.contains(handle32))
9642                 return false;
9643
9644             target = m_replayer.get_shared_state()->m_shadow_state.m_textures.get_target(handle32);
9645             return true;
9646         }
9647         default:
9648             break;
9649     }
9650
9651     VOGL_VERIFY(0);
9652     return false;
9653 }
9654
9655 //----------------------------------------------------------------------------------------------------------------------
9656 // vogl_replayer::determine_used_program_handles
9657 //----------------------------------------------------------------------------------------------------------------------
9658 bool vogl_gl_replayer::determine_used_program_handles(const vogl_trace_packet_array &trim_packets, vogl_handle_hash_set &replay_program_handles)
9659 {
9660     VOGL_FUNC_TRACER
9661
9662     trace_to_replay_handle_remapper trace_to_replay_remapper(*this);
9663
9664 #if 0
9665         GLint cur_program_handle = 0;
9666         GL_ENTRYPOINT(glGetIntegerv)(GL_CURRENT_PROGRAM, &cur_program_handle);
9667         check_gl_error();
9668
9669         if (cur_program_handle)
9670                 replay_program_handles.insert(cur_program_handle);
9671 #endif
9672
9673     // Scan for bound programs on all contexts in this sharegroup
9674     context_state *pContext_shareroot = m_pCur_context_state->m_pShared_state;
9675     for (context_hash_map::iterator it = m_contexts.begin(); it != m_contexts.end(); ++it)
9676     {
9677         context_state *pContext = it->second;
9678         if (pContext->m_pShared_state == pContext_shareroot)
9679         {
9680             if (pContext->m_cur_replay_program)
9681                 replay_program_handles.insert(pContext->m_cur_replay_program);
9682         }
9683     }
9684
9685     for (uint packet_index = 0; packet_index < trim_packets.size(); packet_index++)
9686     {
9687         if (trim_packets.get_packet_type(packet_index) != cTSPTGLEntrypoint)
9688             continue;
9689
9690         const uint8_vec &packet_buf = trim_packets.get_packet_buf(packet_index);
9691
9692         // 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.
9693         if (!m_temp2_gl_packet.deserialize(packet_buf.get_ptr(), packet_buf.size(), true))
9694             return false;
9695
9696         GLuint trace_handle = 0;
9697         bool refers_to_program = vogl_does_packet_refer_to_program(m_temp2_gl_packet, trace_handle);
9698         if (!refers_to_program)
9699             continue;
9700         if (!trace_handle)
9701             continue;
9702
9703         // 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
9704         // 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).
9705         if (!trace_to_replay_remapper.is_valid_handle(VOGL_NAMESPACE_PROGRAMS, trace_handle))
9706             continue;
9707
9708         uint64_t replay_handle = trace_to_replay_remapper.remap_handle(VOGL_NAMESPACE_PROGRAMS, trace_handle);
9709         if (!replay_handle)
9710             continue;
9711
9712         VOGL_ASSERT(utils::is_32bit(replay_handle));
9713
9714         replay_program_handles.insert(static_cast<uint32>(replay_handle));
9715     }
9716
9717     vogl_message_printf("%s: Found %u actually referenced program handles\n", VOGL_METHOD_NAME, replay_program_handles.size());
9718
9719     return true;
9720 }
9721
9722 //----------------------------------------------------------------------------------------------------------------------
9723 // vogl_replayer::fill_replay_handle_hash_set
9724 //----------------------------------------------------------------------------------------------------------------------
9725 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)
9726 {
9727     VOGL_FUNC_TRACER
9728
9729     replay_handle_hash.reset();
9730     replay_handle_hash.reserve(trace_to_replay_hash.size());
9731     for (gl_handle_hash_map::const_iterator it = trace_to_replay_hash.begin(); it != trace_to_replay_hash.end(); ++it)
9732     {
9733         // Insert replay handles into destination hash table
9734         bool success = replay_handle_hash.insert(it->second).second;
9735         VOGL_ASSERT(success);
9736         VOGL_NOTE_UNUSED(success);
9737     }
9738 }
9739
9740 //----------------------------------------------------------------------------------------------------------------------
9741 // vogl_replayer::snapshot_state
9742 //----------------------------------------------------------------------------------------------------------------------
9743 vogl_gl_state_snapshot *vogl_gl_replayer::snapshot_state(const vogl_trace_packet_array *pTrim_packets, bool optimize_snapshot)
9744 {
9745     VOGL_FUNC_TRACER
9746
9747     timed_scope ts(VOGL_METHOD_NAME);
9748
9749     vogl_gl_state_snapshot *pSnapshot = vogl_new(vogl_gl_state_snapshot);
9750
9751     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,
9752                        m_pWindow->get_width(), m_pWindow->get_height(), m_cur_trace_context, m_frame_index, m_last_parsed_call_counter, m_at_frame_boundary);
9753
9754     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))
9755     {
9756         vogl_error_printf("%s: Failed beginning capture\n", VOGL_METHOD_NAME);
9757
9758         vogl_delete(pSnapshot);
9759         pSnapshot = NULL;
9760
9761         return NULL;
9762     }
9763
9764     vogl_client_side_array_desc_vec client_side_vertex_attrib_ptrs;
9765     for (uint i = 0; i < VOGL_ARRAY_SIZE(m_client_side_vertex_attrib_data); i++)
9766         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()));
9767
9768     vogl_client_side_array_desc_vec client_side_array_ptrs;
9769     for (uint i = 0; i < VOGL_ARRAY_SIZE(m_client_side_array_data); i++)
9770         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()));
9771
9772     vogl_client_side_array_desc_vec client_side_texcoord_ptrs;
9773     for (uint i = 0; i < VOGL_ARRAY_SIZE(m_client_side_texcoord_data); i++)
9774         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()));
9775
9776     pSnapshot->add_client_side_array_ptrs(client_side_vertex_attrib_ptrs, client_side_array_ptrs, client_side_texcoord_ptrs);
9777
9778     vogl_printf("%s: Capturing %u context(s)\n", VOGL_METHOD_NAME, m_contexts.size());
9779
9780     context_hash_map::iterator it;
9781     for (it = m_contexts.begin(); it != m_contexts.end(); ++it)
9782     {
9783         context_state *pContext_state = it->second;
9784
9785         if (pContext_state->m_deleted)
9786         {
9787             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));
9788             break;
9789         }
9790
9791         vogl_capture_context_params temp_shadow_state;
9792         vogl_capture_context_params *pShadow_state = &temp_shadow_state;
9793
9794         if (pContext_state->m_has_been_made_current)
9795         {
9796             status_t status = switch_contexts(it->first);
9797             if (status != cStatusOK)
9798             {
9799                 vogl_error_printf("%s: Failed switching to trace context 0x%" PRIX64 ", capture failed\n", VOGL_METHOD_NAME, cast_val_to_uint64(it->first));
9800                 break;
9801             }
9802
9803             VOGL_ASSERT(m_pCur_context_state == pContext_state);
9804
9805             if (m_pCur_context_state->m_inside_gl_begin)
9806             {
9807                 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));
9808                 pSnapshot->set_is_restorable(false);
9809             }
9810
9811
9812             // Init the shadow state needed by the snapshot code.
9813             if (!m_pCur_context_state->is_root_context())
9814             {
9815                 // Only fill in non-shared state.
9816                 fill_replay_handle_hash_set(pShadow_state->m_framebuffers, get_context_state()->m_framebuffers);
9817                 fill_replay_handle_hash_set(pShadow_state->m_vaos, get_context_state()->m_vertex_array_objects);
9818             }
9819             else
9820             {
9821                 pShadow_state = &m_pCur_context_state->m_shadow_state;
9822
9823                 pShadow_state->m_query_targets = get_shared_state()->m_query_targets;
9824
9825                 fill_replay_handle_hash_set(pShadow_state->m_samplers, get_shared_state()->m_sampler_objects);
9826                 fill_replay_handle_hash_set(pShadow_state->m_framebuffers, get_context_state()->m_framebuffers);
9827                 fill_replay_handle_hash_set(pShadow_state->m_vaos, get_context_state()->m_vertex_array_objects);
9828
9829                 // Buffer targets
9830                 pShadow_state->m_buffer_targets.reset();
9831                 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)
9832                 {
9833                     GLuint trace_handle = buf_it->first;
9834                     GLuint replay_handle = buf_it->second;
9835
9836                     gl_handle_hash_map::const_iterator target_it = get_shared_state()->m_buffer_targets.find(trace_handle);
9837                     if (target_it == get_shared_state()->m_buffer_targets.end())
9838                     {
9839                         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);
9840                         continue;
9841                     }
9842                     GLenum target = target_it->second;
9843
9844                     pShadow_state->m_buffer_targets.insert(replay_handle, target);
9845                 }
9846
9847                 // Syncs
9848                 pShadow_state->m_syncs.reset();
9849                 pShadow_state->m_syncs.reserve(get_shared_state()->m_syncs.size());
9850                 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)
9851                 {
9852                     bool success = pShadow_state->m_syncs.insert(vogl_sync_to_handle(sync_it->second)).second;
9853                     VOGL_ASSERT(success);
9854                     VOGL_NOTE_UNUSED(success);
9855                 }
9856
9857                 // Program handles filter
9858                 pShadow_state->m_filter_program_handles = false;
9859                 pShadow_state->m_program_handles_filter.reset();
9860
9861 #if 0
9862                                 // 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).
9863                                 // This is an optimization issue, and we're concentrating on correctness right now so let's figure this out later.
9864                                 if ((pTrim_packets) && (optimize_snapshot))
9865                                 {
9866                     if (!determine_used_program_handles(*pTrim_packets, pShadow_state->m_program_handles_filter))
9867                                         {
9868                                                 vogl_warning_printf("%s: Failed determining used program handles\n", VOGL_METHOD_NAME);
9869                                                 pShadow_state->m_program_handles_filter.clear();
9870                                         }
9871                                         else
9872                                         {
9873                                                 pShadow_state->m_filter_program_handles = true;
9874                                         }
9875                                 }
9876 #else
9877                 VOGL_NOTE_UNUSED(optimize_snapshot);
9878                 VOGL_NOTE_UNUSED(pTrim_packets);
9879 #endif
9880
9881                 // ARB program targets
9882                 pShadow_state->m_arb_program_targets.reset();
9883                 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)
9884                 {
9885                     GLuint trace_handle = arb_prog_it->first;
9886                     GLuint replay_handle = get_shared_state()->m_arb_programs.value(trace_handle);
9887                     if ((!trace_handle) || (!replay_handle))
9888                     {
9889                         VOGL_ASSERT_ALWAYS;
9890                         continue;
9891                     }
9892
9893                     GLenum target = arb_prog_it->second;
9894                     pShadow_state->m_arb_program_targets.insert(replay_handle, target);
9895                 }
9896
9897                 // Deal with any currently mapped buffers.
9898                 vogl_mapped_buffer_desc_vec &mapped_bufs = get_shared_state()->m_shadow_state.m_mapped_buffers;
9899
9900                 pShadow_state->m_mapped_buffers = mapped_bufs;
9901
9902                 if (mapped_bufs.size())
9903                 {
9904                     vogl_warning_printf("%s: %u buffer(s) are currently mapped, these will be temporarily unmapped in order to snapshot them and then remapped\n", VOGL_METHOD_NAME, m_pCur_context_state->m_shadow_state.m_mapped_buffers.size());
9905
9906                     for (uint i = 0; i < mapped_bufs.size(); i++)
9907                     {
9908                         vogl_mapped_buffer_desc &desc = mapped_bufs[i];
9909
9910                         GLuint prev_handle = vogl_get_bound_gl_buffer(desc.m_target);
9911
9912                         GL_ENTRYPOINT(glBindBuffer)(desc.m_target, desc.m_buffer);
9913                         VOGL_CHECK_GL_ERROR;
9914
9915                         GL_ENTRYPOINT(glUnmapBuffer)(desc.m_target);
9916                         VOGL_CHECK_GL_ERROR;
9917
9918                         desc.m_pPtr = NULL;
9919
9920                         GL_ENTRYPOINT(glBindBuffer)(desc.m_target, prev_handle);
9921                         VOGL_CHECK_GL_ERROR;
9922                     }
9923                 }
9924
9925             } // if (!m_pCur_context_state->is_root_context())
9926
9927         } // if (pContext_state->m_has_been_made_current)
9928
9929         if (!pSnapshot->capture_context(pContext_state->m_context_desc, pContext_state->m_context_info, m_replay_to_trace_remapper, *pShadow_state))
9930         {
9931             vogl_error_printf("%s: Failed capturing trace context 0x%" PRIX64 ", capture failed\n", VOGL_METHOD_NAME, static_cast<uint64_t>(it->first));
9932             break;
9933         }
9934
9935         if ((pContext_state->m_has_been_made_current) && (m_pCur_context_state->is_root_context()))
9936         {
9937             vogl_mapped_buffer_desc_vec &mapped_bufs = get_shared_state()->m_shadow_state.m_mapped_buffers;
9938
9939             // Now remap any mapped buffers
9940             for (uint i = 0; i < mapped_bufs.size(); i++)
9941             {
9942                 vogl_mapped_buffer_desc &desc = mapped_bufs[i];
9943
9944                 GLuint prev_handle = vogl_get_bound_gl_buffer(desc.m_target);
9945
9946                 GL_ENTRYPOINT(glBindBuffer)(desc.m_target, desc.m_buffer);
9947                 VOGL_CHECK_GL_ERROR;
9948
9949                 if (desc.m_range)
9950                 {
9951                     desc.m_pPtr = GL_ENTRYPOINT(glMapBufferRange)(desc.m_target, static_cast<GLintptr>(desc.m_offset), static_cast<GLsizeiptr>(desc.m_length), desc.m_access);
9952                     VOGL_CHECK_GL_ERROR;
9953                 }
9954                 else
9955                 {
9956                     desc.m_pPtr = GL_ENTRYPOINT(glMapBuffer)(desc.m_target, desc.m_access);
9957                     VOGL_CHECK_GL_ERROR;
9958                 }
9959
9960                 GL_ENTRYPOINT(glBindBuffer)(desc.m_target, prev_handle);
9961                 VOGL_CHECK_GL_ERROR;
9962
9963             }
9964         }
9965     }
9966
9967     if ((it == m_contexts.end()) && (pSnapshot->end_capture()))
9968     {
9969         vogl_printf("%s: Capture succeeded\n", VOGL_METHOD_NAME);
9970     }
9971     else
9972     {
9973         vogl_printf("%s: Capture failed\n", VOGL_METHOD_NAME);
9974
9975         vogl_delete(pSnapshot);
9976         pSnapshot = NULL;
9977     }
9978
9979     return pSnapshot;
9980 }
9981
9982 //----------------------------------------------------------------------------------------------------------------------
9983 // vogl_replayer::reset_state
9984 //----------------------------------------------------------------------------------------------------------------------
9985 void vogl_gl_replayer::reset_state()
9986 {
9987     VOGL_FUNC_TRACER
9988
9989     // Purposely does NOT destroy the cached snapshots
9990
9991     destroy_pending_snapshot();
9992     destroy_contexts();
9993
9994     m_pending_make_current_packet.clear();
9995     m_pending_window_resize_width = 0;
9996     m_pending_window_resize_height = 0;
9997     m_pending_window_resize_attempt_counter = 0;
9998
9999     m_frame_index = 0;
10000     m_last_parsed_call_counter = -1;
10001     m_last_processed_call_counter = -1;
10002     m_at_frame_boundary = true;
10003
10004     m_cur_trace_context = 0;
10005     m_cur_replay_context = 0;
10006     m_pCur_context_state = NULL;
10007
10008     // Testing
10009     //if (m_pWindow->is_opened())
10010     //   m_pWindow->clear_window();
10011 }
10012
10013 //----------------------------------------------------------------------------------------------------------------------
10014 // trace_to_replay_handle_remapper::is_valid_handle
10015 //----------------------------------------------------------------------------------------------------------------------
10016 bool vogl_gl_replayer::trace_to_replay_handle_remapper::is_valid_handle(vogl_namespace_t handle_namespace, uint64_t from_handle)
10017 {
10018     VOGL_FUNC_TRACER
10019
10020     if (!from_handle)
10021         return false;
10022
10023     uint32 from_handle32 = static_cast<uint32>(from_handle);
10024
10025     switch (handle_namespace)
10026     {
10027         case VOGL_NAMESPACE_VERTEX_ARRAYS:
10028         {
10029             VOGL_ASSERT(from_handle32 == from_handle);
10030             return m_replayer.get_context_state()->m_vertex_array_objects.contains(from_handle32);
10031         }
10032         case VOGL_NAMESPACE_TEXTURES:
10033         {
10034             VOGL_ASSERT(from_handle32 == from_handle);
10035             return m_replayer.get_shared_state()->m_shadow_state.m_textures.contains(from_handle32);
10036         }
10037         case VOGL_NAMESPACE_SAMPLERS:
10038         {
10039             VOGL_ASSERT(from_handle32 == from_handle);
10040             return m_replayer.get_shared_state()->m_sampler_objects.contains(from_handle32);
10041         }
10042         case VOGL_NAMESPACE_BUFFERS:
10043         {
10044             VOGL_ASSERT(from_handle32 == from_handle);
10045             return m_replayer.get_shared_state()->m_buffers.contains(from_handle32);
10046         }
10047         case VOGL_NAMESPACE_SHADERS:
10048         case VOGL_NAMESPACE_PROGRAMS:
10049         {
10050             VOGL_ASSERT(from_handle32 == from_handle);
10051             return m_replayer.get_shared_state()->m_shadow_state.m_objs.contains(from_handle32);
10052         }
10053         case VOGL_NAMESPACE_FRAMEBUFFERS:
10054         {
10055             VOGL_ASSERT(from_handle32 == from_handle);
10056             return m_replayer.get_context_state()->m_framebuffers.contains(from_handle32);
10057         }
10058         case VOGL_NAMESPACE_RENDER_BUFFERS:
10059         {
10060             VOGL_ASSERT(from_handle32 == from_handle);
10061             return m_replayer.get_shared_state()->m_shadow_state.m_rbos.contains(from_handle32);
10062         }
10063         case VOGL_NAMESPACE_QUERIES:
10064         {
10065             VOGL_ASSERT(from_handle32 == from_handle);
10066             return m_replayer.get_shared_state()->m_queries.contains(from_handle32);
10067         }
10068         case VOGL_NAMESPACE_SYNCS:
10069         {
10070             return m_replayer.get_shared_state()->m_syncs.contains(from_handle);
10071         }
10072         case VOGL_NAMESPACE_PROGRAM_ARB:
10073         {
10074             return m_replayer.get_shared_state()->m_arb_programs.contains(from_handle32);
10075         }
10076         default:
10077             break;
10078     }
10079
10080     VOGL_VERIFY(0);
10081
10082     return false;
10083 }
10084
10085 //----------------------------------------------------------------------------------------------------------------------
10086 // trace_to_replay_handle_remapper::remap_handle
10087 //----------------------------------------------------------------------------------------------------------------------
10088 uint64_t vogl_gl_replayer::trace_to_replay_handle_remapper::remap_handle(vogl_namespace_t handle_namespace, uint64_t from_handle)
10089 {
10090     VOGL_FUNC_TRACER
10091
10092     if (!from_handle)
10093         return from_handle;
10094
10095     uint32 from_handle32 = static_cast<uint32>(from_handle);
10096
10097     switch (handle_namespace)
10098     {
10099         case VOGL_NAMESPACE_VERTEX_ARRAYS:
10100         {
10101             VOGL_ASSERT(from_handle32 == from_handle);
10102             return m_replayer.get_context_state()->m_vertex_array_objects.value(from_handle32, from_handle32);
10103         }
10104         case VOGL_NAMESPACE_TEXTURES:
10105         {
10106             VOGL_ASSERT(from_handle32 == from_handle);
10107
10108             uint32 replay_handle = from_handle32;
10109             if (m_replayer.get_shared_state()->m_shadow_state.m_textures.map_handle_to_inv_handle(from_handle32, replay_handle))
10110                 return replay_handle;
10111             break;
10112         }
10113         case VOGL_NAMESPACE_SAMPLERS:
10114         {
10115             VOGL_ASSERT(from_handle32 == from_handle);
10116             return m_replayer.get_shared_state()->m_sampler_objects.value(from_handle32, from_handle32);
10117         }
10118         case VOGL_NAMESPACE_BUFFERS:
10119         {
10120             VOGL_ASSERT(from_handle32 == from_handle);
10121             return m_replayer.get_shared_state()->m_buffers.value(from_handle32, from_handle32);
10122         }
10123         case VOGL_NAMESPACE_SHADERS:
10124         case VOGL_NAMESPACE_PROGRAMS:
10125         {
10126             VOGL_ASSERT(from_handle32 == from_handle);
10127
10128             GLuint replay_handle = from_handle32;
10129             if (m_replayer.get_shared_state()->m_shadow_state.m_objs.map_handle_to_inv_handle(from_handle32, replay_handle))
10130                 return replay_handle;
10131             break;
10132         }
10133         case VOGL_NAMESPACE_FRAMEBUFFERS:
10134         {
10135             VOGL_ASSERT(from_handle32 == from_handle);
10136             return m_replayer.get_context_state()->m_framebuffers.value(from_handle32, from_handle32);
10137         }
10138         case VOGL_NAMESPACE_RENDER_BUFFERS:
10139         {
10140             VOGL_ASSERT(from_handle32 == from_handle);
10141
10142             GLuint replay_handle = from_handle32;
10143             if (m_replayer.get_shared_state()->m_shadow_state.m_rbos.map_handle_to_inv_handle(from_handle32, replay_handle))
10144                 return replay_handle;
10145
10146             break;
10147         }
10148         case VOGL_NAMESPACE_QUERIES:
10149         {
10150             VOGL_ASSERT(from_handle32 == from_handle);
10151             return m_replayer.get_shared_state()->m_queries.value(from_handle32, from_handle32);
10152         }
10153         case VOGL_NAMESPACE_SYNCS:
10154         {
10155             return vogl_sync_to_handle(m_replayer.get_shared_state()->m_syncs.value(from_handle, vogl_handle_to_sync(from_handle)));
10156         }
10157         case VOGL_NAMESPACE_PROGRAM_ARB:
10158         {
10159             return m_replayer.get_shared_state()->m_arb_programs.value(from_handle32, from_handle32);
10160         }
10161         default:
10162         {
10163             break;
10164         }
10165     }
10166
10167     VOGL_ASSERT_ALWAYS;
10168
10169     vogl_error_printf("%s: Failed remapping handle %" PRIu64 " in namespace %s.\n", VOGL_METHOD_NAME, from_handle, vogl_get_namespace_name(handle_namespace));
10170
10171     return from_handle;
10172 }
10173
10174 //----------------------------------------------------------------------------------------------------------------------
10175 // trace_to_replay_handle_remapper::remap_location
10176 //----------------------------------------------------------------------------------------------------------------------
10177 int32 vogl_gl_replayer::trace_to_replay_handle_remapper::remap_location(uint32 trace_program, int32 from_location)
10178 {
10179     VOGL_FUNC_TRACER
10180
10181     VOGL_NOTE_UNUSED(trace_program);
10182
10183     // restoring declares, but doesn't need to remap
10184     VOGL_ASSERT_ALWAYS;
10185
10186     return from_location;
10187 }
10188
10189 //----------------------------------------------------------------------------------------------------------------------
10190 // trace_to_replay_handle_remapper::remap_vertex_attrib_ptr
10191 //----------------------------------------------------------------------------------------------------------------------
10192 vogl_trace_ptr_value vogl_gl_replayer::trace_to_replay_handle_remapper::remap_vertex_attrib_ptr(uint index, vogl_trace_ptr_value ptr_val)
10193 {
10194     VOGL_FUNC_TRACER
10195
10196     if (!ptr_val)
10197         return ptr_val;
10198
10199     VOGL_ASSERT(index < VOGL_ARRAY_SIZE(m_replayer.m_client_side_vertex_attrib_data));
10200     if (!m_replayer.m_client_side_vertex_attrib_data[index].size())
10201     {
10202         m_replayer.m_client_side_vertex_attrib_data[index].resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
10203     }
10204
10205     return reinterpret_cast<vogl_trace_ptr_value>(m_replayer.m_client_side_vertex_attrib_data[index].get_ptr());
10206 }
10207
10208 //----------------------------------------------------------------------------------------------------------------------
10209 // trace_to_replay_handle_remapper::remap_vertex_array_ptr
10210 //----------------------------------------------------------------------------------------------------------------------
10211 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)
10212 {
10213     VOGL_FUNC_TRACER
10214
10215     VOGL_ASSERT(id < VOGL_NUM_CLIENT_SIDE_ARRAY_DESCS);
10216
10217     if (!ptr_val)
10218         return ptr_val;
10219
10220     if (id == vogl_texcoord_pointer_array_id)
10221     {
10222         VOGL_ASSERT(index < VOGL_ARRAY_SIZE(m_replayer.m_client_side_texcoord_data));
10223
10224         if (!m_replayer.m_client_side_texcoord_data[index].size())
10225         {
10226             m_replayer.m_client_side_texcoord_data[index].resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
10227         }
10228
10229         return reinterpret_cast<vogl_trace_ptr_value>(m_replayer.m_client_side_texcoord_data[index].get_ptr());
10230     }
10231     else
10232     {
10233         VOGL_ASSERT(index < VOGL_ARRAY_SIZE(m_replayer.m_client_side_array_data));
10234
10235         if (!m_replayer.m_client_side_array_data[id].size())
10236         {
10237             m_replayer.m_client_side_array_data[id].resize(VOGL_MAX_CLIENT_SIDE_VERTEX_ARRAY_SIZE);
10238         }
10239
10240         return reinterpret_cast<vogl_trace_ptr_value>(m_replayer.m_client_side_array_data[id].get_ptr());
10241     }
10242 }
10243
10244 //----------------------------------------------------------------------------------------------------------------------
10245 // trace_to_replay_handle_remapper::declare_handle
10246 //----------------------------------------------------------------------------------------------------------------------
10247 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)
10248 {
10249     VOGL_FUNC_TRACER
10250
10251     if ((!from_handle) || (!to_handle))
10252     {
10253         VOGL_ASSERT_ALWAYS;
10254         return;
10255     }
10256
10257     uint32 from_handle32 = static_cast<uint32>(from_handle);
10258     uint32 to_handle32 = static_cast<uint32>(to_handle);
10259
10260     switch (handle_namespace)
10261     {
10262         case VOGL_NAMESPACE_VERTEX_ARRAYS:
10263         {
10264             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
10265             m_replayer.get_context_state()->m_vertex_array_objects.insert(from_handle32, to_handle32);
10266             break;
10267         }
10268         case VOGL_NAMESPACE_TEXTURES:
10269         {
10270             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
10271             if (!m_replayer.get_shared_state()->m_shadow_state.m_textures.update(from_handle32, to_handle32, target))
10272                 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);
10273             break;
10274         }
10275         case VOGL_NAMESPACE_SAMPLERS:
10276         {
10277             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
10278             m_replayer.get_shared_state()->m_sampler_objects.insert(from_handle32, to_handle32);
10279             break;
10280         }
10281         case VOGL_NAMESPACE_BUFFERS:
10282         {
10283             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
10284             m_replayer.get_shared_state()->m_buffers.insert(from_handle32, to_handle32);
10285             m_replayer.get_shared_state()->m_buffer_targets.insert(from_handle32, target);
10286             break;
10287         }
10288         case VOGL_NAMESPACE_SHADERS:
10289         {
10290             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
10291             if (!m_replayer.get_shared_state()->m_shadow_state.m_objs.insert(from_handle32, to_handle32, VOGL_SHADER_OBJECT))
10292                 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);
10293             break;
10294         }
10295         case VOGL_NAMESPACE_PROGRAMS:
10296         {
10297             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
10298             if (!m_replayer.get_shared_state()->m_shadow_state.m_objs.insert(from_handle32, to_handle32, VOGL_PROGRAM_OBJECT))
10299                 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);
10300             break;
10301         }
10302         case VOGL_NAMESPACE_FRAMEBUFFERS:
10303         {
10304             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
10305             m_replayer.get_context_state()->m_framebuffers.insert(from_handle32, to_handle32);
10306             break;
10307         }
10308         case VOGL_NAMESPACE_RENDER_BUFFERS:
10309         {
10310             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
10311             if (!m_replayer.get_shared_state()->m_shadow_state.m_rbos.insert(from_handle32, to_handle32, GL_NONE))
10312                 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);
10313             break;
10314         }
10315         case VOGL_NAMESPACE_QUERIES:
10316         {
10317             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
10318             m_replayer.get_shared_state()->m_queries.insert(from_handle32, to_handle32);
10319             m_replayer.get_shared_state()->m_query_targets[to_handle32] = target;
10320             break;
10321         }
10322         case VOGL_NAMESPACE_SYNCS:
10323         {
10324             m_replayer.get_shared_state()->m_syncs.insert(from_handle, vogl_handle_to_sync(to_handle));
10325             break;
10326         }
10327         case VOGL_NAMESPACE_PROGRAM_ARB:
10328         {
10329             m_replayer.get_shared_state()->m_arb_programs.insert(from_handle32, to_handle32);
10330             m_replayer.get_shared_state()->m_arb_program_targets.insert(from_handle32, target);
10331             break;
10332         }
10333         default:
10334         {
10335             VOGL_VERIFY(0);
10336             break;
10337         }
10338     }
10339 }
10340
10341 //----------------------------------------------------------------------------------------------------------------------
10342 // trace_to_replay_handle_remapper::delete_handle_and_object
10343 //----------------------------------------------------------------------------------------------------------------------
10344 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)
10345 {
10346     VOGL_FUNC_TRACER
10347
10348     if ((!from_handle) || (!to_handle))
10349     {
10350         VOGL_ASSERT_ALWAYS;
10351         return;
10352     }
10353
10354     uint32 from_handle32 = static_cast<uint32>(from_handle);
10355     uint32 to_handle32 = static_cast<uint32>(to_handle);
10356     VOGL_NOTE_UNUSED(to_handle32);
10357
10358     switch (handle_namespace)
10359     {
10360         case VOGL_NAMESPACE_VERTEX_ARRAYS:
10361         {
10362             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
10363             m_replayer.get_context_state()->m_vertex_array_objects.erase(from_handle32);
10364             vogl_destroy_gl_object(handle_namespace, to_handle);
10365             break;
10366         }
10367         case VOGL_NAMESPACE_TEXTURES:
10368         {
10369             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
10370             if (!m_replayer.get_shared_state()->m_shadow_state.m_textures.erase(from_handle32))
10371                 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);
10372
10373             vogl_destroy_gl_object(handle_namespace, to_handle);
10374             break;
10375         }
10376         case VOGL_NAMESPACE_SAMPLERS:
10377         {
10378             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
10379             m_replayer.get_shared_state()->m_sampler_objects.erase(from_handle32);
10380             vogl_destroy_gl_object(handle_namespace, to_handle);
10381             break;
10382         }
10383         case VOGL_NAMESPACE_BUFFERS:
10384         {
10385             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
10386             m_replayer.get_shared_state()->m_buffers.erase(from_handle32);
10387             m_replayer.get_shared_state()->m_buffer_targets.erase(from_handle32);
10388             vogl_destroy_gl_object(handle_namespace, to_handle);
10389             break;
10390         }
10391         case VOGL_NAMESPACE_SHADERS:
10392         {
10393             m_replayer.handle_delete_shader(from_handle32);
10394             break;
10395         }
10396         case VOGL_NAMESPACE_PROGRAMS:
10397         {
10398             m_replayer.handle_delete_program(from_handle32);
10399             break;
10400         }
10401         case VOGL_NAMESPACE_FRAMEBUFFERS:
10402         {
10403             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
10404             m_replayer.get_context_state()->m_framebuffers.erase(from_handle32);
10405             vogl_destroy_gl_object(handle_namespace, to_handle);
10406             break;
10407         }
10408         case VOGL_NAMESPACE_RENDER_BUFFERS:
10409         {
10410             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
10411
10412             if (!m_replayer.get_shared_state()->m_shadow_state.m_rbos.erase(from_handle32))
10413                 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);
10414
10415             vogl_destroy_gl_object(handle_namespace, to_handle);
10416             break;
10417         }
10418         case VOGL_NAMESPACE_QUERIES:
10419         {
10420             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
10421             m_replayer.get_shared_state()->m_queries.erase(from_handle32);
10422             vogl_destroy_gl_object(handle_namespace, to_handle);
10423             break;
10424         }
10425         case VOGL_NAMESPACE_SYNCS:
10426         {
10427             m_replayer.get_shared_state()->m_syncs.erase(from_handle);
10428             vogl_destroy_gl_object(handle_namespace, to_handle);
10429             break;
10430         }
10431         case VOGL_NAMESPACE_PROGRAM_ARB:
10432         {
10433             VOGL_ASSERT((from_handle32 == from_handle) && (to_handle32 == to_handle));
10434             m_replayer.get_shared_state()->m_arb_programs.erase(from_handle32);
10435             m_replayer.get_shared_state()->m_arb_program_targets.erase(from_handle32);
10436             vogl_destroy_gl_object(handle_namespace, to_handle);
10437             break;
10438         }
10439         default:
10440         {
10441             VOGL_VERIFY(0);
10442             break;
10443         }
10444     }
10445 }
10446
10447 //----------------------------------------------------------------------------------------------------------------------
10448 // vogl_replayer::trace_to_replay_handle_remapper::declare_location
10449 //----------------------------------------------------------------------------------------------------------------------
10450 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)
10451 {
10452     VOGL_FUNC_TRACER
10453
10454     GLuint check_replay_handle = 0;
10455     VOGL_ASSERT(m_replayer.get_shared_state()->m_shadow_state.m_objs.map_handle_to_inv_handle(from_program_handle, check_replay_handle));
10456     VOGL_ASSERT(check_replay_handle == to_program_handle);
10457     VOGL_NOTE_UNUSED(check_replay_handle);
10458
10459     VOGL_NOTE_UNUSED(to_program_handle);
10460
10461     glsl_program_hash_map::iterator it(m_replayer.get_shared_state()->m_glsl_program_hash_map.insert(from_program_handle).first);
10462
10463     glsl_program_state &prog_state = it->second;
10464
10465     VOGL_ASSERT(!prog_state.m_uniform_locations.contains(from_location));
10466
10467     prog_state.m_uniform_locations.insert(from_location, to_location);
10468 }
10469
10470 //----------------------------------------------------------------------------------------------------------------------
10471 // vogl_gl_replayer::trace_to_replay_handle_remapper::determine_from_object_target
10472 //----------------------------------------------------------------------------------------------------------------------
10473 bool vogl_gl_replayer::trace_to_replay_handle_remapper::determine_from_object_target(vogl_namespace_t handle_namespace, uint64_t trace_handle, GLenum &target)
10474 {
10475     VOGL_FUNC_TRACER
10476
10477     target = GL_NONE;
10478
10479     uint32 handle32 = static_cast<uint32>(trace_handle);
10480
10481     switch (handle_namespace)
10482     {
10483         case VOGL_NAMESPACE_TEXTURES:
10484         {
10485             VOGL_ASSERT(handle32 == trace_handle);
10486             if (!m_replayer.get_shared_state()->m_shadow_state.m_textures.contains(handle32))
10487                 return false;
10488
10489             target = m_replayer.get_shared_state()->m_shadow_state.m_textures.get_target(handle32);
10490             return true;
10491         }
10492         default:
10493             break;
10494     }
10495
10496     VOGL_VERIFY(0);
10497     return false;
10498 }
10499
10500 //----------------------------------------------------------------------------------------------------------------------
10501 // vogl_gl_replayer::trace_to_replay_handle_remapper::determine_to_object_target
10502 //----------------------------------------------------------------------------------------------------------------------
10503 bool vogl_gl_replayer::trace_to_replay_handle_remapper::determine_to_object_target(vogl_namespace_t handle_namespace, uint64_t replay_handle, GLenum &target)
10504 {
10505     VOGL_FUNC_TRACER
10506
10507     target = GL_NONE;
10508
10509     uint32 handle32 = static_cast<uint32>(replay_handle);
10510
10511     switch (handle_namespace)
10512     {
10513         case VOGL_NAMESPACE_TEXTURES:
10514         {
10515             VOGL_ASSERT(handle32 == replay_handle);
10516             if (!m_replayer.get_shared_state()->m_shadow_state.m_textures.contains_inv(handle32))
10517                 return false;
10518
10519             target = m_replayer.get_shared_state()->m_shadow_state.m_textures.get_target_inv(handle32);
10520             return true;
10521         }
10522         default:
10523             break;
10524     }
10525
10526     VOGL_VERIFY(0);
10527     return false;
10528 }
10529
10530 //----------------------------------------------------------------------------------------------------------------------
10531 // vogl_replayer::restore_objects
10532 //----------------------------------------------------------------------------------------------------------------------
10533 vogl_gl_replayer::status_t vogl_gl_replayer::restore_objects(
10534     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,
10535     vogl_const_gl_object_state_ptr_vec &objects_to_delete)
10536 {
10537     VOGL_FUNC_TRACER
10538
10539     VOGL_NOTE_UNUSED(snapshot);
10540
10541     if (m_flags & cGLReplayerVerboseMode)
10542         vogl_printf("%s: Restoring %s objects\n", VOGL_METHOD_NAME, get_gl_object_state_type_str(state_type));
10543
10544     vogl::timer tm;
10545     if (m_flags & cGLReplayerVerboseMode)
10546         tm.start();
10547
10548     const vogl_gl_object_state_ptr_vec &object_ptrs = context_state.get_objects();
10549
10550     uint n = 0;
10551
10552     for (uint i = 0; i < object_ptrs.size(); i++)
10553     {
10554         const vogl_gl_object_state *pState_obj = object_ptrs[i];
10555
10556         if (pState_obj->get_type() != state_type)
10557             continue;
10558
10559         GLuint64 restore_handle = 0;
10560         if (!pState_obj->restore(m_pCur_context_state->m_context_info, trace_to_replay_remapper, restore_handle))
10561         {
10562             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);
10563             return cStatusHardFailure;
10564         }
10565         n++;
10566
10567         if (pState_obj->get_marked_for_deletion())
10568         {
10569             objects_to_delete.push_back(pState_obj);
10570         }
10571
10572         VOGL_ASSERT(trace_to_replay_remapper.remap_handle(pState_obj->get_handle_namespace(), pState_obj->get_snapshot_handle()) == restore_handle);
10573
10574         switch (pState_obj->get_type())
10575         {
10576             case cGLSTQuery:
10577             {
10578                 const vogl_query_state *pQuery = static_cast<const vogl_query_state *>(pState_obj);
10579
10580                 VOGL_ASSERT(restore_handle <= cUINT32_MAX);
10581                 get_shared_state()->m_query_targets[static_cast<GLuint>(restore_handle)] = pQuery->get_target();
10582
10583                 break;
10584             }
10585             case cGLSTProgram:
10586             {
10587                 const vogl_program_state *pProg = static_cast<const vogl_program_state *>(pState_obj);
10588
10589                 if (pProg->has_link_time_snapshot())
10590                 {
10591                     vogl_program_state link_snapshot(*pProg->get_link_time_snapshot());
10592                     if (!link_snapshot.remap_handles(trace_to_replay_remapper))
10593                     {
10594                         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);
10595                     }
10596                     else
10597                     {
10598                         get_shared_state()->m_shadow_state.m_linked_programs.add_snapshot(static_cast<uint32>(restore_handle), link_snapshot);
10599                     }
10600                 }
10601
10602                 if (m_flags & cGLReplayerVerboseMode)
10603                 {
10604                     if ((n & 255) == 255)
10605                         vogl_printf("%s: Restored %u programs\n", VOGL_METHOD_NAME, n);
10606                 }
10607
10608                 break;
10609             }
10610             case cGLSTBuffer:
10611             {
10612                 const vogl_buffer_state *pBuf = static_cast<const vogl_buffer_state *>(pState_obj);
10613
10614                 // Check if the buffer was mapped during the snapshot, if so remap it and record the ptr in the replayer's context shadow.
10615                 if (pBuf->get_is_mapped())
10616                 {
10617                     vogl_mapped_buffer_desc map_desc;
10618                     map_desc.m_buffer = static_cast<GLuint>(restore_handle);
10619                     map_desc.m_target = pBuf->get_target();
10620                     map_desc.m_offset = pBuf->get_map_ofs();
10621                     map_desc.m_length = pBuf->get_map_size();
10622                     map_desc.m_access = pBuf->get_map_access();
10623                     map_desc.m_range = pBuf->get_is_map_range();
10624
10625                     GLuint prev_handle = vogl_get_bound_gl_buffer(map_desc.m_target);
10626
10627                     GL_ENTRYPOINT(glBindBuffer)(map_desc.m_target, map_desc.m_buffer);
10628                     VOGL_CHECK_GL_ERROR;
10629
10630                     if (map_desc.m_range)
10631                     {
10632                         map_desc.m_pPtr = GL_ENTRYPOINT(glMapBufferRange)(map_desc.m_target, static_cast<GLintptr>(map_desc.m_offset), static_cast<GLintptr>(map_desc.m_length), map_desc.m_access);
10633                         VOGL_CHECK_GL_ERROR;
10634                     }
10635                     else
10636                     {
10637                         map_desc.m_pPtr = GL_ENTRYPOINT(glMapBuffer)(map_desc.m_target, map_desc.m_access);
10638                         VOGL_CHECK_GL_ERROR;
10639                     }
10640
10641                     GL_ENTRYPOINT(glBindBuffer)(map_desc.m_target, prev_handle);
10642                     VOGL_CHECK_GL_ERROR;
10643
10644                     vogl_mapped_buffer_desc_vec &mapped_bufs = get_shared_state()->m_shadow_state.m_mapped_buffers;
10645                     mapped_bufs.push_back(map_desc);
10646                 }
10647
10648                 break;
10649             }
10650             default:
10651                 break;
10652         }
10653     }
10654
10655     if (m_flags & cGLReplayerVerboseMode)
10656     {
10657         tm.stop();
10658         vogl_printf("%s: Restore took %f secs\n", VOGL_METHOD_NAME, tm.get_elapsed_secs());
10659
10660         vogl_printf("%s: Finished restoring %u %s objects\n", VOGL_METHOD_NAME, n, get_gl_object_state_type_str(state_type));
10661     }
10662
10663     return cStatusOK;
10664 }
10665
10666 //----------------------------------------------------------------------------------------------------------------------
10667 // vogl_xfont_cache
10668 //----------------------------------------------------------------------------------------------------------------------
10669 class vogl_xfont_cache
10670 {
10671     VOGL_NO_COPY_OR_ASSIGNMENT_OP(vogl_xfont_cache);
10672
10673 public:
10674     vogl_xfont_cache(Display *dpy)
10675         : m_dpy(dpy)
10676     {
10677         VOGL_FUNC_TRACER
10678     }
10679
10680     ~vogl_xfont_cache()
10681     {
10682         VOGL_FUNC_TRACER
10683
10684         clear();
10685     }
10686
10687     void clear()
10688     {
10689         VOGL_FUNC_TRACER
10690
10691         for (xfont_map::iterator it = m_xfonts.begin(); it != m_xfonts.end(); ++it)
10692             XFreeFont(m_dpy, it->second);
10693         m_xfonts.clear();
10694     }
10695
10696     XFontStruct *get_or_create(const char *pName)
10697     {
10698         VOGL_FUNC_TRACER
10699
10700         XFontStruct **ppXFont = m_xfonts.find_value(pName);
10701         if (ppXFont)
10702             return *ppXFont;
10703
10704         XFontStruct *pXFont = XLoadQueryFont(m_dpy, pName);
10705         if (pXFont)
10706             m_xfonts.insert(pName, pXFont);
10707
10708         return pXFont;
10709     }
10710
10711 private:
10712     Display *m_dpy;
10713
10714     typedef vogl::map<dynamic_string, XFontStruct *> xfont_map;
10715     xfont_map m_xfonts;
10716 };
10717
10718 //----------------------------------------------------------------------------------------------------------------------
10719 // vogl_replayer::restore_display_lists
10720 //----------------------------------------------------------------------------------------------------------------------
10721 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)
10722 {
10723     VOGL_FUNC_TRACER
10724
10725     VOGL_NOTE_UNUSED(trace_to_replay_remapper);
10726     VOGL_NOTE_UNUSED(snapshot);
10727
10728     VOGL_ASSERT(m_cur_trace_context);
10729
10730     check_gl_error();
10731
10732     const vogl_display_list_state &disp_lists = context_snapshot.get_display_list_state();
10733
10734     if (!disp_lists.size())
10735         return cStatusOK;
10736
10737     vogl_message_printf("%s: Recreating %u display lists\n", VOGL_METHOD_NAME, disp_lists.get_display_list_map().size());
10738
10739     vogl_xfont_cache xfont_cache(m_pWindow->get_display());
10740
10741     const vogl_display_list_map &disp_list_map = disp_lists.get_display_list_map();
10742
10743     for (vogl_display_list_map::const_iterator it = disp_list_map.begin(); it != disp_list_map.end(); ++it)
10744     {
10745         GLuint trace_handle = it->first;
10746         const vogl_display_list &disp_list = it->second;
10747
10748         if (!trace_handle)
10749         {
10750             VOGL_ASSERT_ALWAYS;
10751             continue;
10752         }
10753
10754         GLuint replay_handle = GL_ENTRYPOINT(glGenLists)(1);
10755         if (check_gl_error() || !replay_handle)
10756             goto handle_failure;
10757
10758         if (disp_list.is_valid())
10759         {
10760             if (disp_list.is_xfont())
10761             {
10762                 XFontStruct *pXFont = xfont_cache.get_or_create(disp_list.get_xfont_name().get_ptr());
10763                 if (!pXFont)
10764                 {
10765                     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);
10766                 }
10767                 else
10768                 {
10769                     GL_ENTRYPOINT(glXUseXFont)(pXFont->fid, disp_list.get_xfont_glyph(), 1, replay_handle);
10770                 }
10771             }
10772             else
10773             {
10774                 GL_ENTRYPOINT(glNewList)(replay_handle, GL_COMPILE);
10775
10776                 if (check_gl_error() || !replay_handle)
10777                 {
10778                     GL_ENTRYPOINT(glDeleteLists)(replay_handle, 1);
10779                     check_gl_error();
10780
10781                     goto handle_failure;
10782                 }
10783
10784                 const vogl_trace_packet_array &packets = disp_list.get_packets();
10785
10786                 for (uint packet_index = 0; packet_index < packets.size(); packet_index++)
10787                 {
10788                     if (packets.get_packet_type(packet_index) != cTSPTGLEntrypoint)
10789                     {
10790                         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);
10791                         continue;
10792                     }
10793
10794                     const uint8_vec &packet_buf = packets.get_packet_buf(packet_index);
10795
10796                     if (!m_temp2_gl_packet.deserialize(packet_buf, true))
10797                     {
10798                         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);
10799                         continue;
10800                     }
10801
10802                     vogl_trace_gl_entrypoint_packet &gl_entrypoint_packet = m_temp2_gl_packet.get_entrypoint_packet();
10803
10804                     gl_entrypoint_packet.m_context_handle = m_cur_trace_context;
10805
10806                     if (m_flags & cGLReplayerDebugMode)
10807                         dump_trace_gl_packet_debug_info(gl_entrypoint_packet);
10808
10809                     int64_t prev_parsed_call_counter = m_last_parsed_call_counter;
10810                     int64_t prev_processed_call_counter = m_last_processed_call_counter;
10811                     m_last_parsed_call_counter = gl_entrypoint_packet.m_call_counter;
10812                     m_last_processed_call_counter = gl_entrypoint_packet.m_call_counter;
10813                     bool prev_at_frame_boundary = m_at_frame_boundary;
10814
10815                     const vogl_trace_packet *pPrev_gl_packet = m_pCur_gl_packet;
10816
10817                     m_pCur_gl_packet = &m_temp2_gl_packet;
10818
10819                     vogl_gl_replayer::status_t status = process_gl_entrypoint_packet_internal(m_temp2_gl_packet);
10820
10821                     m_pCur_gl_packet = pPrev_gl_packet;
10822
10823                     m_last_parsed_call_counter = prev_parsed_call_counter;
10824                     m_last_processed_call_counter = prev_processed_call_counter;
10825                     m_at_frame_boundary = prev_at_frame_boundary;
10826
10827                     if (status != cStatusOK)
10828                     {
10829                         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);
10830                         continue;
10831                     }
10832                 }
10833
10834                 // TODO: Set context state because we're currently generating a display list!
10835                 if (disp_list.is_generating())
10836                 {
10837                     VOGL_ASSERT_ALWAYS;
10838                 }
10839
10840                 GL_ENTRYPOINT(glEndList)();
10841                 check_gl_error();
10842             }
10843         }
10844
10845         get_shared_state()->m_lists.insert(trace_handle, replay_handle);
10846
10847         if (!get_shared_state()->m_shadow_state.m_display_lists.define_list(trace_handle, replay_handle, disp_list))
10848         {
10849             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);
10850         }
10851     }
10852
10853     check_gl_error();
10854
10855     vogl_message_printf("%s: Done recreating display lists\n", VOGL_METHOD_NAME);
10856
10857     return cStatusOK;
10858
10859 handle_failure:
10860     return cStatusHardFailure;
10861 }
10862
10863 //----------------------------------------------------------------------------------------------------------------------
10864 // vogl_replayer::restore_general_state
10865 //----------------------------------------------------------------------------------------------------------------------
10866 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)
10867 {
10868     VOGL_FUNC_TRACER
10869
10870     VOGL_NOTE_UNUSED(snapshot);
10871
10872     vogl_general_context_state::vogl_persistent_restore_state persistent_restore_state;
10873     persistent_restore_state.m_pSelect_buffer = &m_pCur_context_state->m_select_buffer;
10874
10875     if (!context_snapshot.get_general_state().restore(m_pCur_context_state->m_context_info, trace_to_replay_remapper, persistent_restore_state))
10876         return cStatusHardFailure;
10877
10878     if (!m_pCur_context_state->m_context_info.is_core_profile())
10879     {
10880         if (context_snapshot.get_texenv_state().is_valid())
10881         {
10882             if (!context_snapshot.get_texenv_state().restore(m_pCur_context_state->m_context_info))
10883                 return cStatusHardFailure;
10884         }
10885
10886         if (context_snapshot.get_material_state().is_valid())
10887         {
10888             if (!context_snapshot.get_material_state().restore(m_pCur_context_state->m_context_info))
10889                 return cStatusHardFailure;
10890         }
10891
10892         if (context_snapshot.get_light_state().is_valid())
10893         {
10894             if (!context_snapshot.get_light_state().restore(m_pCur_context_state->m_context_info))
10895                 return cStatusHardFailure;
10896         }
10897
10898         if (context_snapshot.get_matrix_state().is_valid())
10899         {
10900             if (!context_snapshot.get_matrix_state().restore(m_pCur_context_state->m_context_info))
10901                 return cStatusHardFailure;
10902         }
10903
10904         if (context_snapshot.get_polygon_stipple_state().is_valid())
10905         {
10906             if (!context_snapshot.get_polygon_stipple_state().restore(m_pCur_context_state->m_context_info))
10907                 return cStatusHardFailure;
10908         }
10909
10910         if (context_snapshot.get_arb_program_environment_state().is_valid())
10911         {
10912             if (m_pCur_context_state->m_context_info.supports_extension("GL_ARB_vertex_program"))
10913             {
10914                 if (!context_snapshot.get_arb_program_environment_state().restore(m_pCur_context_state->m_context_info, trace_to_replay_remapper))
10915                     return cStatusHardFailure;
10916             }
10917             else
10918             {
10919                 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);
10920             }
10921         }
10922     }
10923
10924     if (context_snapshot.get_current_vertex_attrib_state().is_valid())
10925     {
10926         if (!context_snapshot.get_current_vertex_attrib_state().restore(m_pCur_context_state->m_context_info))
10927             return cStatusHardFailure;
10928     }
10929
10930     return cStatusOK;
10931 }
10932
10933 //----------------------------------------------------------------------------------------------------------------------
10934 // vogl_replayer::validate_program_and_shader_handle_tables
10935 //----------------------------------------------------------------------------------------------------------------------
10936 bool vogl_gl_replayer::validate_program_and_shader_handle_tables()
10937 {
10938     VOGL_FUNC_TRACER
10939
10940     if (!m_pCur_context_state)
10941         return true;
10942
10943     if (!get_shared_state()->m_shadow_state.m_objs.check())
10944         vogl_error_printf("%s: Object handle tracker failed validation!\n", VOGL_METHOD_NAME);
10945
10946     uint_vec replay_handles;
10947     get_shared_state()->m_shadow_state.m_objs.get_inv_handles(replay_handles);
10948
10949     for (uint i = 0; i < replay_handles.size(); i++)
10950     {
10951         GLuint replay_handle = replay_handles[i];
10952         GLuint trace_handle = replay_handle;
10953         bool map_succeeded = get_shared_state()->m_shadow_state.m_objs.map_inv_handle_to_handle(replay_handle, trace_handle);
10954         VOGL_ASSERT(map_succeeded);
10955         VOGL_NOTE_UNUSED(map_succeeded);
10956
10957         GLenum target = get_shared_state()->m_shadow_state.m_objs.get_target_inv(replay_handle);
10958         VOGL_ASSERT(target == get_shared_state()->m_shadow_state.m_objs.get_target(trace_handle));
10959
10960         if (target == VOGL_PROGRAM_OBJECT)
10961         {
10962             if (!GL_ENTRYPOINT(glIsProgram)(replay_handle))
10963             {
10964                 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);
10965             }
10966
10967             if (!get_shared_state()->m_glsl_program_hash_map.contains(trace_handle))
10968             {
10969                 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);
10970             }
10971         }
10972         else if (target == VOGL_SHADER_OBJECT)
10973         {
10974             if (!GL_ENTRYPOINT(glIsShader)(replay_handle))
10975             {
10976                 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);
10977             }
10978         }
10979         else
10980         {
10981             VOGL_ASSERT_ALWAYS;
10982         }
10983     }
10984
10985     return true;
10986 }
10987
10988 //----------------------------------------------------------------------------------------------------------------------
10989 // vogl_replayer::validate_textures
10990 //----------------------------------------------------------------------------------------------------------------------
10991 bool vogl_gl_replayer::validate_textures()
10992 {
10993     VOGL_FUNC_TRACER
10994
10995     if (!m_pCur_context_state)
10996         return true;
10997
10998     if (!get_shared_state()->m_shadow_state.m_textures.check())
10999         vogl_error_printf("%s: Texture handle tracker failed validation!\n", VOGL_METHOD_NAME);
11000
11001     for (uint replay_handle = 1; replay_handle <= 0xFFFFU; replay_handle++)
11002     {
11003         bool is_tex = GL_ENTRYPOINT(glIsTexture)(replay_handle) != 0;
11004
11005         bool found_in_shadow = get_shared_state()->m_shadow_state.m_textures.contains_inv(replay_handle);
11006
11007         if (!is_tex)
11008         {
11009             if (found_in_shadow)
11010             {
11011                 GLuint trace_handle = 0;
11012                 get_shared_state()->m_shadow_state.m_textures.map_inv_handle_to_handle(replay_handle, trace_handle);
11013                 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);
11014             }
11015         }
11016         else
11017         {
11018             if (!found_in_shadow)
11019             {
11020                 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);
11021             }
11022         }
11023     }
11024
11025     return true;
11026 }
11027
11028 //----------------------------------------------------------------------------------------------------------------------
11029 // vogl_replayer::update_context_shadows
11030 //----------------------------------------------------------------------------------------------------------------------
11031 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)
11032 {
11033     VOGL_FUNC_TRACER
11034
11035     VOGL_NOTE_UNUSED(snapshot);
11036     VOGL_NOTE_UNUSED(context_snapshot);
11037     VOGL_NOTE_UNUSED(trace_to_replay_remapper);
11038
11039     check_gl_error();
11040
11041     // Make sure shadow is good
11042     GLint actual_current_replay_program = 0;
11043     GL_ENTRYPOINT(glGetIntegerv)(GL_CURRENT_PROGRAM, &actual_current_replay_program);
11044     check_gl_error();
11045
11046     m_pCur_context_state->m_cur_replay_program = actual_current_replay_program;
11047     if (!actual_current_replay_program)
11048         m_pCur_context_state->m_cur_trace_program = 0;
11049     else
11050     {
11051         GLuint trace_handle = actual_current_replay_program;
11052         if (!get_shared_state()->m_shadow_state.m_objs.map_inv_handle_to_handle(actual_current_replay_program, trace_handle))
11053         {
11054             process_entrypoint_error("%s: Failed finding restored GL shader %u in program/shader object handle hashmap\n", VOGL_METHOD_NAME, actual_current_replay_program);
11055
11056             m_pCur_context_state->m_cur_replay_program = 0;
11057             m_pCur_context_state->m_cur_trace_program = 0;
11058         }
11059         else
11060         {
11061             m_pCur_context_state->m_cur_trace_program = trace_handle;
11062         }
11063     }
11064
11065     check_program_binding_shadow();
11066
11067     return cStatusOK;
11068 }
11069
11070 //----------------------------------------------------------------------------------------------------------------------
11071 // vogl_replayer::handle_marked_for_deleted_objects
11072 //----------------------------------------------------------------------------------------------------------------------
11073 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)
11074 {
11075     VOGL_FUNC_TRACER
11076
11077     if (m_flags & cGLReplayerVerboseMode)
11078     {
11079         vogl_debug_printf("%s: %u program/shader objects where marked as deleted\n", VOGL_METHOD_NAME, objects_to_delete.size());
11080     }
11081
11082     for (uint i = 0; i < objects_to_delete.size(); i++)
11083     {
11084         const vogl_gl_object_state *pState_obj = objects_to_delete[i];
11085
11086         GLuint64 trace_handle = pState_obj->get_snapshot_handle();
11087         GLuint64 restore_handle = trace_to_replay_remapper.remap_handle(pState_obj->get_handle_namespace(), pState_obj->get_snapshot_handle());
11088
11089         if (m_flags & cGLReplayerVerboseMode)
11090         {
11091             // This should be a rare/exception case so let's try to be a little paranoid.
11092             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,
11093                              get_gl_object_state_type_str(pState_obj->get_type()), (uint64_t)trace_handle, (uint64_t)restore_handle);
11094         }
11095
11096         GLboolean object_is_still_a_name = true;
11097
11098         switch (pState_obj->get_type())
11099         {
11100             case cGLSTProgram:
11101             {
11102                 handle_delete_program(static_cast<GLuint>(trace_handle));
11103
11104                 object_is_still_a_name = GL_ENTRYPOINT(glIsProgram)(static_cast<GLuint>(restore_handle));
11105
11106                 break;
11107             }
11108             case cGLSTShader:
11109             {
11110                 handle_delete_shader(static_cast<GLuint>(trace_handle));
11111
11112                 object_is_still_a_name = GL_ENTRYPOINT(glIsShader)(static_cast<GLuint>(restore_handle));
11113
11114                 break;
11115             }
11116             default:
11117             {
11118                 VOGL_ASSERT_ALWAYS;
11119                 break;
11120             }
11121         }
11122
11123         // "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."
11124         // Same for shaders.
11125         if (!object_is_still_a_name)
11126         {
11127             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,
11128                              get_gl_object_state_type_str(pState_obj->get_type()), (uint64_t)trace_handle, (uint64_t)restore_handle);
11129         }
11130     }
11131 }
11132
11133 //----------------------------------------------------------------------------------------------------------------------
11134 // vogl_replayer::begin_applying_snapshot
11135 // Takes ownership (even on errors) when delete_snapshot_after_applying is true.
11136 //----------------------------------------------------------------------------------------------------------------------
11137 vogl_gl_replayer::status_t vogl_gl_replayer::begin_applying_snapshot(const vogl_gl_state_snapshot *pSnapshot, bool delete_snapshot_after_applying)
11138 {
11139     VOGL_FUNC_TRACER
11140
11141     if (!pSnapshot->is_valid())
11142     {
11143         if (delete_snapshot_after_applying)
11144             vogl_delete(const_cast<vogl_gl_state_snapshot *>(pSnapshot));
11145
11146         return cStatusHardFailure;
11147     }
11148
11149     reset_state();
11150
11151     m_pPending_snapshot = pSnapshot;
11152     m_delete_pending_snapshot_after_applying = delete_snapshot_after_applying;
11153
11154     m_frame_index = pSnapshot->get_frame_index();
11155     m_last_parsed_call_counter = pSnapshot->get_gl_call_counter();
11156     m_last_processed_call_counter = pSnapshot->get_gl_call_counter();
11157     m_at_frame_boundary = false;
11158
11159     if (!(m_flags & cGLReplayerLockWindowDimensions))
11160     {
11161         return trigger_pending_window_resize(pSnapshot->get_window_width(), pSnapshot->get_window_height());
11162     }
11163
11164     return process_applying_pending_snapshot();
11165 }
11166
11167 //----------------------------------------------------------------------------------------------------------------------
11168 // vogl_replayer::restore_context
11169 //----------------------------------------------------------------------------------------------------------------------
11170 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)
11171 {
11172     VOGL_FUNC_TRACER
11173
11174     VOGL_NOTE_UNUSED(trace_to_replay_remapper);
11175     VOGL_NOTE_UNUSED(snapshot);
11176
11177     // TODO: This always creates with attribs, also need to support plain glXCreateContext()
11178
11179     Display *dpy = m_pWindow->get_display();
11180     GLXFBConfig fb_config = m_pWindow->get_fb_configs()[0];
11181
11182     vogl_trace_context_ptr_value trace_share_context = context_snapshot.get_context_desc().get_trace_share_context();
11183
11184     GLXContext replay_share_context = remap_context(trace_share_context);
11185     if ((trace_share_context) && (!replay_share_context))
11186     {
11187         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));
11188         return cStatusHardFailure;
11189     }
11190
11191     GLboolean direct = context_snapshot.get_context_desc().get_direct();
11192
11193     vogl_trace_context_ptr_value trace_context = context_snapshot.get_context_desc().get_trace_context();
11194
11195     status_t status = create_context_attribs(trace_context, dpy, fb_config, trace_share_context, replay_share_context, direct,
11196                                              context_snapshot.get_context_desc().get_attribs().get_vec().get_ptr(),
11197                                              context_snapshot.get_context_desc().get_attribs().get_vec().size(), true);
11198     if (status != cStatusOK)
11199     {
11200         vogl_error_printf("%s: Failed creating new context\n", VOGL_METHOD_NAME);
11201         return status;
11202     }
11203
11204     // Has this context ever been made current?
11205     if (context_snapshot.get_context_info().is_valid())
11206     {
11207         context_state *pContext_state = get_trace_context_state(trace_context);
11208         if (!pContext_state)
11209         {
11210             vogl_error_printf("%s: Failed finding replay context current\n", VOGL_METHOD_NAME);
11211             return cStatusHardFailure;
11212         }
11213
11214         GLXContext replay_context = pContext_state->m_replay_context;
11215         if (!replay_context)
11216         {
11217             vogl_error_printf("%s: Failed finding replay context current\n", VOGL_METHOD_NAME);
11218             return cStatusHardFailure;
11219         }
11220
11221         GLXDrawable drawable = m_pWindow->get_xwindow();
11222
11223         Bool result = GL_ENTRYPOINT(glXMakeCurrent)(dpy, drawable, replay_context);
11224         if (!result)
11225         {
11226             vogl_error_printf("%s: Failed making context current\n", VOGL_METHOD_NAME);
11227             return cStatusHardFailure;
11228         }
11229
11230         m_cur_trace_context = trace_context;
11231         m_cur_replay_context = replay_context;
11232         m_pCur_context_state = pContext_state;
11233
11234         if (!handle_context_made_current())
11235             return cStatusHardFailure;
11236     }
11237
11238     return cStatusOK;
11239 }
11240
11241 //----------------------------------------------------------------------------------------------------------------------
11242 // vogl_replayer::process_applying_pending_snapshot
11243 //----------------------------------------------------------------------------------------------------------------------
11244 vogl_gl_replayer::status_t vogl_gl_replayer::process_applying_pending_snapshot()
11245 {
11246     VOGL_FUNC_TRACER
11247
11248     if (!m_pPending_snapshot)
11249         return cStatusOK;
11250
11251     timed_scope ts(VOGL_METHOD_NAME);
11252
11253     const vogl_gl_state_snapshot &snapshot = *m_pPending_snapshot;
11254
11255     trace_to_replay_handle_remapper trace_to_replay_remapper(*this);
11256
11257     m_frame_index = snapshot.get_frame_index();
11258     m_last_parsed_call_counter = snapshot.get_gl_call_counter();
11259     m_last_processed_call_counter = snapshot.get_gl_call_counter();
11260     m_at_frame_boundary = snapshot.get_at_frame_boundary();
11261
11262     // Ensure the client side array bufs are large enough (we don't care about the actual ptr values).
11263     for (uint i = 0; i < snapshot.get_client_side_vertex_attrib_ptrs().size(); i++)
11264         m_client_side_vertex_attrib_data[i].resize(snapshot.get_client_side_vertex_attrib_ptrs()[i].m_size);
11265
11266     for (uint i = 0; i < snapshot.get_client_side_array_ptrs().size(); i++)
11267         m_client_side_array_data[i].resize(snapshot.get_client_side_array_ptrs()[i].m_size);
11268
11269     for (uint i = 0; i < snapshot.get_client_side_texcoord_ptrs().size(); i++)
11270         m_client_side_texcoord_data[i].resize(snapshot.get_client_side_texcoord_ptrs()[i].m_size);
11271
11272     const vogl_context_snapshot_ptr_vec &context_ptrs = snapshot.get_contexts();
11273
11274     vogl_context_snapshot_ptr_vec restore_context_ptrs(snapshot.get_contexts());
11275     vogl::vector<vogl_const_gl_object_state_ptr_vec> objects_to_delete_vec(context_ptrs.size());
11276
11277     status_t status = cStatusOK;
11278     uint total_contexts_restored = 0;
11279     bool restored_default_framebuffer = false;
11280
11281     for (;;)
11282     {
11283         uint num_contexts_restored_in_this_pass = 0;
11284
11285         for (uint context_index = 0; context_index < restore_context_ptrs.size(); context_index++)
11286         {
11287             if (!restore_context_ptrs[context_index])
11288                 continue;
11289
11290             const vogl_context_snapshot &context_state = *restore_context_ptrs[context_index];
11291
11292             if (context_state.get_context_desc().get_trace_share_context())
11293             {
11294                 // Don't restore this context if its sharelist context hasn't been restored yet
11295                 if (!remap_context(context_state.get_context_desc().get_trace_share_context()))
11296                     continue;
11297             }
11298
11299             status = restore_context(trace_to_replay_remapper, snapshot, context_state);
11300             if (status != cStatusOK)
11301                 goto handle_error;
11302
11303             // Has this context ever been made current?
11304             if (context_state.get_context_info().is_valid())
11305             {
11306                 // 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!)
11307                 const vogl_gl_object_state_type s_object_type_restore_order[] = { cGLSTBuffer, cGLSTSampler, cGLSTQuery, cGLSTRenderbuffer, cGLSTTexture, cGLSTFramebuffer, cGLSTVertexArray, cGLSTShader, cGLSTProgram, cGLSTSync, cGLSTARBProgram };
11308                 VOGL_ASSUME(VOGL_ARRAY_SIZE(s_object_type_restore_order) == (cGLSTTotalTypes - 1));
11309
11310                 if (m_flags & cGLReplayerLowLevelDebugMode)
11311                 {
11312                     if (!validate_textures())
11313                         vogl_warning_printf("%s: Failed validating texture handles against handle mapping tables\n", VOGL_METHOD_NAME);
11314                 }
11315
11316                 vogl_const_gl_object_state_ptr_vec &objects_to_delete = objects_to_delete_vec[context_index];
11317
11318                 for (uint i = 0; i < VOGL_ARRAY_SIZE(s_object_type_restore_order); i++)
11319                 {
11320                     status = restore_objects(trace_to_replay_remapper, snapshot, context_state, s_object_type_restore_order[i], objects_to_delete);
11321                     if (status != cStatusOK)
11322                         goto handle_error;
11323
11324                     if (m_flags & cGLReplayerLowLevelDebugMode)
11325                     {
11326                         if (!validate_program_and_shader_handle_tables())
11327                             vogl_error_printf("%s: Program/shader handle table validation failed!\n", VOGL_METHOD_NAME);
11328
11329                         if (!validate_textures())
11330                             vogl_warning_printf("%s: Failed validating texture handles against handle mapping tables\n", VOGL_METHOD_NAME);
11331                     }
11332                 }
11333
11334                 if (m_flags & cGLReplayerLowLevelDebugMode)
11335                 {
11336                     if (!validate_textures())
11337                         vogl_warning_printf("%s: Failed validating texture handles against handle mapping tables\n", VOGL_METHOD_NAME);
11338                 }
11339
11340                 status = restore_display_lists(trace_to_replay_remapper, snapshot, context_state);
11341                 if (status != cStatusOK)
11342                     goto handle_error;
11343
11344                 // Restore default framebuffer
11345                 if ((!restored_default_framebuffer) && (snapshot.get_default_framebuffer().is_valid()))
11346                 {
11347                     restored_default_framebuffer = true;
11348
11349                     if (!snapshot.get_default_framebuffer().restore(m_pCur_context_state->m_context_info))
11350                     {
11351                         vogl_warning_printf("%s: Failed restoring default framebuffer!\n", VOGL_METHOD_NAME);
11352                     }
11353                 }
11354
11355                 // Beware: restore_general_state() will bind a bunch of stuff from the trace!
11356                 status = restore_general_state(trace_to_replay_remapper, snapshot, context_state);
11357                 if (status != cStatusOK)
11358                     goto handle_error;
11359
11360                 status = update_context_shadows(trace_to_replay_remapper, snapshot, context_state);
11361                 if (status != cStatusOK)
11362                     goto handle_error;
11363
11364                 if (m_flags & cGLReplayerLowLevelDebugMode)
11365                 {
11366                     if (!validate_program_and_shader_handle_tables())
11367                         vogl_error_printf("%s: Program/shader handle table validation failed!\n", VOGL_METHOD_NAME);
11368
11369                     if (!validate_textures())
11370                         vogl_warning_printf("%s: Failed validating texture handles against handle mapping tables\n", VOGL_METHOD_NAME);
11371                 }
11372             }
11373
11374             num_contexts_restored_in_this_pass++;
11375
11376             total_contexts_restored++;
11377
11378             restore_context_ptrs[context_index] = NULL;
11379         }
11380
11381         if (!num_contexts_restored_in_this_pass)
11382             break;
11383     }
11384
11385     if (total_contexts_restored != snapshot.get_contexts().size())
11386     {
11387         vogl_error_printf("%s: Failed satisfying sharelist dependency during context restoration\n", VOGL_METHOD_NAME);
11388         goto handle_error;
11389     }
11390
11391     for (uint context_index = 0; context_index < context_ptrs.size(); context_index++)
11392     {
11393         const vogl_context_snapshot &context_state = *context_ptrs[context_index];
11394
11395         if (!context_state.get_context_info().is_valid())
11396             continue;
11397
11398         status_t status = switch_contexts(context_state.get_context_desc().get_trace_context());
11399         if (status != cStatusOK)
11400         {
11401             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()));
11402             goto handle_error;
11403         }
11404
11405         vogl_const_gl_object_state_ptr_vec &objects_to_delete = objects_to_delete_vec[context_index];
11406
11407         handle_marked_for_deleted_objects(objects_to_delete, trace_to_replay_remapper);
11408     }
11409
11410     destroy_pending_snapshot();
11411
11412     return cStatusOK;
11413
11414 handle_error:
11415
11416     reset_state();
11417
11418     return status;
11419 }
11420
11421 //----------------------------------------------------------------------------------------------------------------------
11422 // vogl_gl_replayer::write_trim_file_internal
11423 //----------------------------------------------------------------------------------------------------------------------
11424 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)
11425 {
11426     // Open the output trace
11427     // 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.
11428     const vogl_ctypes &trace_gl_ctypes = get_trace_gl_ctypes();
11429
11430     vogl_trace_packet trace_packet(&trace_gl_ctypes);
11431
11432     // TODO: This seems like WAY too much work! Move the snapshot to the beginning of the trace, in the header!
11433     bool found_state_snapshot = false;
11434     dynamic_string binary_snapshot_id, text_snapshot_id;
11435
11436     bool is_at_start_of_trace = false;
11437     VOGL_NOTE_UNUSED(is_at_start_of_trace);
11438
11439     int demarcation_packet_index = -1;
11440     for (uint packet_index = 0; packet_index < trim_packets.size(); packet_index++)
11441     {
11442         const vogl_trace_stream_packet_types_t packet_type = trim_packets.get_packet_type(packet_index);
11443         if (packet_type != cTSPTGLEntrypoint)
11444             continue;
11445
11446         const uint8_vec &packet_buf = trim_packets.get_packet_buf(packet_index);
11447
11448         const vogl_trace_gl_entrypoint_packet *pGL_packet = &trim_packets.get_packet<vogl_trace_gl_entrypoint_packet>(packet_index);
11449         if (pGL_packet->m_entrypoint_id != VOGL_ENTRYPOINT_glInternalTraceCommandRAD)
11450             continue;
11451
11452         if (!trace_packet.deserialize(packet_buf.get_ptr(), packet_buf.size(), true))
11453         {
11454             console::error("%s: Failed parsing glInternalTraceCommandRAD packet\n", VOGL_FUNCTION_NAME);
11455             return false;
11456         }
11457
11458         GLuint cmd = trace_packet.get_param_value<GLuint>(0);
11459         if (cmd == cITCRDemarcation)
11460         {
11461             is_at_start_of_trace = true;
11462             demarcation_packet_index = packet_index;
11463         }
11464         else if (cmd == cITCRKeyValueMap)
11465         {
11466             key_value_map &kvm = trace_packet.get_key_value_map();
11467
11468             dynamic_string cmd_type(kvm.get_string("command_type"));
11469
11470             if (cmd_type == "state_snapshot")
11471             {
11472                 found_state_snapshot = true;
11473
11474                 text_snapshot_id = kvm.get_string("id");
11475                 binary_snapshot_id = kvm.get_string("binary_id");
11476             }
11477         }
11478     }
11479
11480     vogl_trace_file_writer trace_writer(&trace_gl_ctypes);
11481     if (!trace_writer.open(trim_filename.get_ptr(), NULL, true, false, m_trace_pointer_size_in_bytes))
11482     {
11483         console::error("%s: Failed creating trimmed trace file \"%s\"!\n", VOGL_FUNCTION_NAME, trim_filename.get_ptr());
11484         return false;
11485     }
11486
11487     if (found_state_snapshot)
11488     {
11489         // Copy over the source trace's archive (it contains the snapshot, along with any files it refers to).
11490         if (trace_reader.get_archive_blob_manager().is_initialized())
11491         {
11492             dynamic_string_array blob_files(trace_reader.get_archive_blob_manager().enumerate());
11493             for (uint i = 0; i < blob_files.size(); i++)
11494             {
11495                 if ((blob_files[i].is_empty()) || (blob_files[i] == VOGL_TRACE_ARCHIVE_FRAME_FILE_OFFSETS_FILENAME))
11496                     continue;
11497
11498                 vogl_message_printf("Adding blob file %s to output trace archive\n", blob_files[i].get_ptr());
11499
11500                 if (!trace_writer.get_trace_archive()->copy_file(trace_reader.get_archive_blob_manager(), blob_files[i], blob_files[i]).has_content())
11501                 {
11502                     vogl_error_printf("%s: Failed copying blob data for file \"%s\" to output trace archive!\n", VOGL_FUNCTION_NAME, blob_files[i].get_ptr());
11503                     return false;
11504                 }
11505             }
11506         }
11507     }
11508     else
11509     {
11510         // Copy over the source trace's backtrace map, machine info, etc. files.
11511         if (trace_reader.get_archive_blob_manager().is_initialized())
11512         {
11513             // compiler_info.json
11514             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);
11515             // machine_info.json
11516             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);
11517             // backtrace_map_syms.json
11518             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);
11519             // backtrace_map_addrs.json
11520             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);
11521         }
11522
11523         vogl_unique_ptr<vogl_gl_state_snapshot> pTrim_snapshot(snapshot_state(&trim_packets, optimize_snapshot));
11524
11525         if (!pTrim_snapshot.get())
11526         {
11527             console::error("%s: Failed creating replayer GL snapshot!\n", VOGL_FUNCTION_NAME);
11528             return false;
11529         }
11530
11531         pTrim_snapshot->set_frame_index(0);
11532
11533         json_document doc;
11534         if (!pTrim_snapshot->serialize(*doc.get_root(), *trace_writer.get_trace_archive(), &trace_gl_ctypes))
11535         {
11536             console::error("%s: Failed serializing GL state snapshot!\n", VOGL_FUNCTION_NAME);
11537             trace_writer.close();
11538             file_utils::delete_file(trim_filename.get_ptr());
11539             return false;
11540         }
11541
11542         vogl::vector<char> snapshot_data;
11543         doc.serialize(snapshot_data, true, 0, false);
11544
11545         uint8_vec binary_snapshot_data;
11546         doc.binary_serialize(binary_snapshot_data);
11547
11548         pTrim_snapshot.reset();
11549
11550         // Write the state_snapshot file to the trace archive
11551         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));
11552         if (snapshot_id.is_empty())
11553         {
11554             console::error("%s: Failed adding GL snapshot file to output blob manager!\n", VOGL_FUNCTION_NAME);
11555             trace_writer.close();
11556             file_utils::delete_file(trim_filename.get_ptr());
11557             return false;
11558         }
11559
11560         if (pSnapshot_id)
11561             *pSnapshot_id = snapshot_id;
11562
11563         snapshot_data.clear();
11564
11565         // Write the binary_state_snapshot file to the trace archive
11566         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));
11567         if (binary_snapshot_id.is_empty())
11568         {
11569             console::error("%s: Failed adding binary GL snapshot file to output blob manager!\n", VOGL_FUNCTION_NAME);
11570             trace_writer.close();
11571             file_utils::delete_file(trim_filename.get_ptr());
11572             return false;
11573         }
11574
11575         binary_snapshot_data.clear();
11576
11577         key_value_map snapshot_key_value_map;
11578         snapshot_key_value_map.insert("command_type", "state_snapshot");
11579         snapshot_key_value_map.insert("id", snapshot_id);
11580         snapshot_key_value_map.insert("binary_id", binary_snapshot_id);
11581
11582         dynamic_stream snapshot_stream(0);
11583         if (!vogl_write_glInternalTraceCommandRAD(snapshot_stream, &trace_gl_ctypes, cITCRKeyValueMap, sizeof(snapshot_key_value_map), reinterpret_cast<const GLubyte *>(&snapshot_key_value_map)))
11584         {
11585             console::error("%s: Failed serializing snapshot packet!\n", VOGL_FUNCTION_NAME);
11586             trace_writer.close();
11587             file_utils::delete_file(trim_filename.get_ptr());
11588             return false;
11589         }
11590
11591         if (demarcation_packet_index >= 0)
11592         {
11593             trim_packets.insert(demarcation_packet_index, snapshot_stream.get_buf());
11594             demarcation_packet_index++;
11595         }
11596         else
11597         {
11598             dynamic_stream demarcation_stream(0);
11599             vogl_write_glInternalTraceCommandRAD(demarcation_stream, &trace_gl_ctypes, cITCRDemarcation, 0, NULL);
11600
11601             // Screw the ctypes packet, it's only used for debugging right now anyway.
11602             trim_packets.insert(0, snapshot_stream.get_buf());
11603             trim_packets.insert(1, demarcation_stream.get_buf());
11604         }
11605     }
11606
11607     for (uint packet_index = 0; packet_index < trim_packets.size(); packet_index++)
11608     {
11609         const uint8_vec &packet_buf = trim_packets.get_packet_buf(packet_index);
11610
11611         const bool is_swap = trim_packets.is_swap_buffers_packet(packet_index);
11612
11613         const vogl_trace_stream_packet_types_t packet_type = trim_packets.get_packet_type(packet_index);
11614         if (packet_type == cTSPTEOF)
11615             break;
11616         else if (packet_type != cTSPTGLEntrypoint)
11617         {
11618             VOGL_ASSERT_ALWAYS;
11619         }
11620
11621         if (!trace_writer.write_packet(packet_buf.get_ptr(), packet_buf.size(), is_swap))
11622         {
11623             console::error("%s: Failed writing trace packet to output trace file \"%s\"!\n", VOGL_FUNCTION_NAME, trim_filename.get_ptr());
11624             trace_writer.close();
11625             file_utils::delete_file(trim_filename.get_ptr());
11626             return false;
11627         }
11628     }
11629
11630     bool success = trace_writer.close();
11631     if (!success)
11632         console::error("%s: Failed closing wrote trim trace file \"%s\"\n", VOGL_FUNCTION_NAME, trim_filename.get_ptr());
11633     else
11634         console::message("%s: Successfully wrote trim trace file \"%s\"\n", VOGL_FUNCTION_NAME, trim_filename.get_ptr());
11635
11636     return success;
11637 }
11638
11639 //----------------------------------------------------------------------------------------------------------------------
11640 // vogl_gl_replayer::write_trim_file
11641 //----------------------------------------------------------------------------------------------------------------------
11642 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)
11643 {
11644     VOGL_FUNC_TRACER
11645
11646     if (!m_is_valid)
11647     {
11648         console::error("%s: Trace is not open\n", VOGL_METHOD_NAME);
11649         return false;
11650     }
11651
11652     bool from_start_of_frame = (flags & cWriteTrimFileFromStartOfFrame) != 0;
11653
11654     if ((!from_start_of_frame) || (!trim_len))
11655         flags &= ~cWriteTrimFileOptimizeSnapshot;
11656
11657     const uint trim_frame = static_cast<uint>(get_frame_index());
11658     const int64_t trim_call_counter = get_last_parsed_call_counter();
11659
11660     // Read the desired packets from the source trace file
11661     vogl_trace_packet_array trim_packets;
11662
11663     if ((trim_len) || (!trim_frame))
11664     {
11665         console::message("%s: Reading trim packets from source trace file\n", VOGL_FUNCTION_NAME);
11666
11667         uint frames_to_read = trim_len;
11668         if ((from_start_of_frame) && (!trim_frame) && (!trim_len))
11669             frames_to_read = 1;
11670
11671         uint actual_trim_len = 0;
11672         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);
11673         if (read_packets_status == vogl_trace_file_reader::cFailed)
11674         {
11675             console::error("%s: Failed reading source trace file packets beginning at frame %u!\n", VOGL_FUNCTION_NAME, trim_frame);
11676             return false;
11677         }
11678
11679         if (actual_trim_len != frames_to_read)
11680         {
11681             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);
11682         }
11683
11684         if (from_start_of_frame)
11685         {
11686             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);
11687
11688             if ((!trim_frame) && (!trim_len))
11689             {
11690                 // 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.
11691                 // TODO: Most of this will go away once we move the state snapshot into the trace archive.
11692
11693                 vogl_trace_packet_array new_trim_packets;
11694
11695                 vogl_trace_packet trace_packet(&get_trace_gl_ctypes());
11696
11697                 for (uint packet_index = 0; packet_index < trim_packets.size(); packet_index++)
11698                 {
11699                     const vogl_trace_stream_packet_types_t packet_type = trim_packets.get_packet_type(packet_index);
11700                     if (packet_type != cTSPTGLEntrypoint)
11701                         break;
11702
11703                     const uint8_vec &packet_buf = trim_packets.get_packet_buf(packet_index);
11704
11705                     const vogl_trace_gl_entrypoint_packet *pGL_packet = &trim_packets.get_packet<vogl_trace_gl_entrypoint_packet>(packet_index);
11706                     if (pGL_packet->m_entrypoint_id != VOGL_ENTRYPOINT_glInternalTraceCommandRAD)
11707                         break;
11708
11709                     if (!trace_packet.deserialize(packet_buf.get_ptr(), packet_buf.size(), true))
11710                     {
11711                         console::error("%s: Failed parsing glInternalTraceCommandRAD packet\n", VOGL_FUNCTION_NAME);
11712                         return false;
11713                     }
11714
11715                     GLuint cmd = trace_packet.get_param_value<GLuint>(0);
11716
11717                     new_trim_packets.push_back(packet_buf);
11718
11719                     if (cmd == cITCRDemarcation)
11720                         break;
11721                 }
11722
11723                 trim_packets.swap(new_trim_packets);
11724             }
11725         }
11726         else if (trim_call_counter >= 0)
11727         {
11728             uint orig_num_packets = trim_packets.size();
11729             uint total_erased_packets = 0;
11730
11731             // Remove any calls before the current one.
11732             for (int64_t packet_index = 0; packet_index < trim_packets.size(); packet_index++)
11733             {
11734                 if (trim_packets.get_packet_type(static_cast<uint>(packet_index)) != cTSPTGLEntrypoint)
11735                     continue;
11736
11737                 const vogl_trace_gl_entrypoint_packet *pGL_packet = &trim_packets.get_packet<vogl_trace_gl_entrypoint_packet>(static_cast<uint>(packet_index));
11738
11739                 if (static_cast<int64_t>(pGL_packet->m_call_counter) <= trim_call_counter)
11740                 {
11741                     trim_packets.erase(static_cast<uint>(packet_index));
11742                     packet_index--;
11743
11744                     total_erased_packets++;
11745                 }
11746             }
11747
11748             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());
11749         }
11750     }
11751
11752     if (!write_trim_file_internal(trim_packets, trim_filename, trace_reader, (flags & cWriteTrimFileOptimizeSnapshot) != 0, pSnapshot_id))
11753     {
11754         console::warning("%s: Trim file write failed, deleting invalid trim trace file %s\n", VOGL_METHOD_NAME, trim_filename.get_ptr());
11755
11756         file_utils::delete_file(trim_filename.get_ptr());
11757         return false;
11758     }
11759
11760     return true;
11761 }