1 /**************************************************************************
3 * Copyright 2013-2014 RAD Game Tools and Valve Software
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 **************************************************************************/
26 // File: vogl_program_state.cpp
27 // TODO: Remap uniform block locations
29 #include "vogl_program_state.h"
31 #define VOGL_PROGRAM_VERSION 0x0100
33 static bool get_program_bool(GLuint handle, GLenum pname)
38 GL_ENTRYPOINT(glGetProgramiv)(handle, pname, &val);
43 static int get_program_int(GLuint handle, GLenum pname)
48 GL_ENTRYPOINT(glGetProgramiv)(handle, pname, &val);
53 vogl_program_state::vogl_program_state()
54 : m_snapshot_handle(0),
55 m_program_binary_format(GL_NONE),
56 m_num_active_attribs(0),
57 m_num_active_uniforms(0),
58 m_num_active_uniform_blocks(0),
59 m_transform_feedback_mode(GL_NONE),
60 m_transform_feedback_num_varyings(0),
61 m_marked_for_deletion(false),
63 m_verify_status(false),
64 m_link_snapshot(false),
70 vogl_program_state::vogl_program_state(const vogl_program_state &other)
71 : m_snapshot_handle(0),
72 m_program_binary_format(GL_NONE),
73 m_num_active_attribs(0),
74 m_num_active_uniforms(0),
75 m_num_active_uniform_blocks(0),
76 m_transform_feedback_mode(GL_NONE),
77 m_transform_feedback_num_varyings(0),
78 m_marked_for_deletion(false),
80 m_verify_status(false),
81 m_link_snapshot(false),
88 vogl_program_state::~vogl_program_state()
93 vogl_program_state &vogl_program_state::operator=(const vogl_program_state &rhs)
102 #define CPY(x) x = rhs.x;
104 CPY(m_snapshot_handle);
106 CPY(m_program_binary);
107 CPY(m_program_binary_format);
109 CPY(m_attached_shaders);
113 CPY(m_num_active_attribs);
114 CPY(m_num_active_uniforms);
115 CPY(m_num_active_uniform_blocks);
119 CPY(m_uniform_blocks);
124 CPY(m_transform_feedback_mode);
125 CPY(m_transform_feedback_num_varyings);
128 CPY(m_marked_for_deletion);
130 CPY(m_verify_status);
131 CPY(m_link_snapshot);
137 if (rhs.m_pLink_time_snapshot.get())
139 m_pLink_time_snapshot.reset(vogl_new(vogl_program_state, *(rhs.m_pLink_time_snapshot.get())));
145 bool vogl_program_state::snapshot_uniforms(const vogl_context_info &context_info, vogl_handle_remapper &remapper)
149 VOGL_NOTE_UNUSED(context_info);
150 VOGL_NOTE_UNUSED(remapper);
152 growable_array<GLchar, 4096> temp_buf;
154 // Snapshot active uniforms
155 GLint active_uniform_max_length = math::maximum(1024, get_program_int(m_snapshot_handle, GL_ACTIVE_UNIFORM_MAX_LENGTH));
156 temp_buf.resize(active_uniform_max_length);
157 m_uniforms.resize(m_num_active_uniforms);
158 for (uint uniform_iter = 0; uniform_iter < m_num_active_uniforms; uniform_iter++)
160 GLsizei actual_len = 0;
162 GLenum type = GL_NONE;
164 GL_ENTRYPOINT(glGetActiveUniform)(m_snapshot_handle, uniform_iter, active_uniform_max_length, &actual_len, &size, &type, temp_buf.get_ptr());
167 vogl_program_uniform_state &uniform = m_uniforms[uniform_iter];
168 uniform.m_size = size;
169 uniform.m_type = type;
170 uniform.m_name.set(reinterpret_cast<char *>(temp_buf.get_ptr()));
171 uniform.m_base_location = -1;
173 if (!uniform.m_name.begins_with("gl_", true))
175 uniform.m_base_location = GL_ENTRYPOINT(glGetUniformLocation)(m_snapshot_handle, temp_buf.get_ptr());
179 uint type_size_in_bytes = vogl_gl_get_uniform_size_in_bytes(type);
180 if (!type_size_in_bytes)
183 GLenum base_type = vogl_gl_get_uniform_base_type(type);
184 if (base_type == GL_NONE)
187 uniform.m_data.resize(size * type_size_in_bytes);
189 if (uniform.m_base_location != -1)
191 for (int element = 0; element < size; element++)
193 uint8 *pDst = &uniform.m_data[element * type_size_in_bytes];
195 if (base_type == GL_FLOAT)
196 GL_ENTRYPOINT(glGetUniformfv)(m_snapshot_handle, uniform.m_base_location + element, (GLfloat *)pDst);
197 else if (base_type == GL_DOUBLE)
198 GL_ENTRYPOINT(glGetUniformdv)(m_snapshot_handle, uniform.m_base_location + element, (GLdouble *)pDst);
199 else if (base_type == GL_UNSIGNED_INT)
200 GL_ENTRYPOINT(glGetUniformuiv)(m_snapshot_handle, uniform.m_base_location + element, (GLuint *)pDst);
202 GL_ENTRYPOINT(glGetUniformiv)(m_snapshot_handle, uniform.m_base_location + element, (GLint *)pDst);
212 bool vogl_program_state::snapshot_uniform_blocks(const vogl_context_info &context_info, vogl_handle_remapper &remapper)
216 VOGL_NOTE_UNUSED(remapper);
218 // Snapshot active uniform blocks
219 if ((context_info.get_version() >= VOGL_GL_VERSION_3_1) && GL_ENTRYPOINT(glGetActiveUniformBlockiv) && GL_ENTRYPOINT(glGetActiveUniformBlockName))
221 growable_array<char, 256> name_buf;
223 m_uniform_blocks.reserve(m_num_active_uniform_blocks);
225 for (uint uniform_block_index = 0; uniform_block_index < m_num_active_uniform_blocks; uniform_block_index++)
228 GL_ENTRYPOINT(glGetActiveUniformBlockiv)(m_snapshot_handle, uniform_block_index, GL_UNIFORM_BLOCK_NAME_LENGTH, &name_len);
231 vogl_program_uniform_block_state state;
233 state.m_uniform_block_index = uniform_block_index;
235 name_buf.resize(name_len);
237 GLsizei actual_len = 0;
238 GL_ENTRYPOINT(glGetActiveUniformBlockName)(m_snapshot_handle, uniform_block_index, name_len, &actual_len, reinterpret_cast<GLchar *>(name_buf.get_ptr()));
242 state.m_name.set(name_buf.get_ptr());
244 GL_ENTRYPOINT(glGetActiveUniformBlockiv)(m_snapshot_handle, uniform_block_index, GL_UNIFORM_BLOCK_BINDING, &state.m_uniform_block_binding_point);
247 GL_ENTRYPOINT(glGetActiveUniformBlockiv)(m_snapshot_handle, uniform_block_index, GL_UNIFORM_BLOCK_DATA_SIZE, &state.m_uniform_block_data_size);
250 GL_ENTRYPOINT(glGetActiveUniformBlockiv)(m_snapshot_handle, uniform_block_index, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &state.m_uniform_block_active_uniforms);
253 // TODO: Get and store referenced flags: GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER, GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER, or GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER, etc.
255 m_uniform_blocks.push_back(state);
262 bool vogl_program_state::snapshot_active_attribs(const vogl_context_info &context_info, vogl_handle_remapper &remapper)
266 VOGL_NOTE_UNUSED(context_info);
267 VOGL_NOTE_UNUSED(remapper);
269 growable_array<GLchar, 4096> temp_buf;
271 // Snapshot active attribs
272 GLint active_attrib_max_length = math::maximum(1024, get_program_int(m_snapshot_handle, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH));
273 temp_buf.resize(active_attrib_max_length);
275 m_attribs.resize(m_num_active_attribs);
276 for (uint attrib_iter = 0; attrib_iter < m_num_active_attribs; attrib_iter++)
279 GLenum type = GL_NONE;
280 GLsizei actual_len = 0;
282 GL_ENTRYPOINT(glGetActiveAttrib)(m_snapshot_handle, attrib_iter, active_attrib_max_length, &actual_len, &size, &type, temp_buf.get_ptr());
285 vogl_program_attrib_state &attrib = m_attribs[attrib_iter];
286 attrib.m_name.set(reinterpret_cast<char *>(temp_buf.get_ptr()));
289 if (!attrib.m_name.begins_with("gl_", true))
291 loc = GL_ENTRYPOINT(glGetAttribLocation)(m_snapshot_handle, temp_buf.get_ptr());
294 attrib.m_bound_location = loc;
296 attrib.m_size = size;
297 attrib.m_type = type;
303 bool vogl_program_state::snapshot_attached_shaders(const vogl_context_info &context_info, vogl_handle_remapper &remapper, bool linked_using_binary)
307 VOGL_NOTE_UNUSED(context_info);
308 VOGL_NOTE_UNUSED(remapper);
310 GLint num_attached_shaders = get_program_int(m_snapshot_handle, GL_ATTACHED_SHADERS);
311 if (num_attached_shaders)
313 m_attached_shaders.resize(num_attached_shaders);
315 GLsizei actual_count = 0;
316 GL_ENTRYPOINT(glGetAttachedShaders)(m_snapshot_handle, num_attached_shaders, &actual_count, m_attached_shaders.get_ptr());
319 VOGL_ASSERT(static_cast<uint>(actual_count) == m_attached_shaders.size());
321 // We can't trust glIsShader(), we must check our own shadow to determine if these are our handles or not.
322 attached_shader_vec actual_attached_shaders;
324 for (GLsizei i = 0; i < actual_count; i++)
326 if (remapper.is_valid_handle(VOGL_NAMESPACE_SHADERS, m_attached_shaders[i]))
327 actual_attached_shaders.push_back(m_attached_shaders[i]);
328 else if (!linked_using_binary)
329 vogl_warning_printf("%s: GL shader %u attached to GL program %u cannot be found in our object shadow\n", VOGL_METHOD_NAME, m_attached_shaders[i], m_snapshot_handle);
332 m_attached_shaders.swap(actual_attached_shaders);
333 num_attached_shaders = m_attached_shaders.size();
339 bool vogl_program_state::snapshot_shader_objects(const vogl_context_info &context_info, vogl_handle_remapper &remapper)
343 m_shaders.resize(m_attached_shaders.size());
344 for (uint i = 0; i < m_shaders.size(); i++)
346 GLuint handle = m_attached_shaders[i];
348 if (!m_shaders[i].snapshot(context_info, remapper, handle, GL_NONE))
355 bool vogl_program_state::snapshot_info_log(const vogl_context_info &context_info, vogl_handle_remapper &remapper)
359 VOGL_NOTE_UNUSED(context_info);
360 VOGL_NOTE_UNUSED(remapper);
362 GLint info_log_len = get_program_int(m_snapshot_handle, GL_INFO_LOG_LENGTH);
364 growable_array<GLchar, 4096> temp_buf(info_log_len);
366 // Snapshot program info log
369 GLsizei actual_len = 0;
370 GL_ENTRYPOINT(glGetProgramInfoLog)(m_snapshot_handle, info_log_len, &actual_len, temp_buf.get_ptr());
372 m_info_log.set(reinterpret_cast<char *>(temp_buf.get_ptr()));
378 bool vogl_program_state::snapshot_program_binary(const vogl_context_info &context_info, vogl_handle_remapper &remapper)
382 VOGL_NOTE_UNUSED(context_info);
383 VOGL_NOTE_UNUSED(remapper);
385 // HACK HACK - this crashes AMD's driver in Sam3 in interactive mode when we try to get the program binary's length, no idea why yet
389 int retrievable_hint = get_program_int(m_snapshot_handle, GL_PROGRAM_BINARY_RETRIEVABLE_HINT);
390 if (retrievable_hint)
392 int program_binary_length = get_program_int(m_snapshot_handle, GL_PROGRAM_BINARY_LENGTH);
394 if (!vogl_check_gl_error() && program_binary_length)
396 m_program_binary.resize(program_binary_length);
398 GLsizei actual_len = 0;
399 GL_ENTRYPOINT(glGetProgramBinary)(m_snapshot_handle, program_binary_length, &actual_len, &m_program_binary_format, m_program_binary.get_ptr());
401 if (!vogl_check_gl_error())
403 m_program_binary.resize(actual_len);
407 vogl_error_printf("%s: Failed retrieving program binary for GL program %u!\n", VOGL_METHOD_NAME, m_snapshot_handle);
409 m_program_binary.clear();
410 m_program_binary_format = GL_NONE;
420 bool vogl_program_state::snapshot_basic_info(const vogl_context_info &context_info, vogl_handle_remapper &remapper)
424 VOGL_NOTE_UNUSED(remapper);
426 m_link_status = get_program_bool(m_snapshot_handle, GL_LINK_STATUS);
427 m_marked_for_deletion = get_program_bool(m_snapshot_handle, GL_DELETE_STATUS);
428 m_verify_status = get_program_bool(m_snapshot_handle, GL_VALIDATE_STATUS);
429 m_num_active_attribs = get_program_int(m_snapshot_handle, GL_ACTIVE_ATTRIBUTES);
430 m_num_active_uniforms = get_program_int(m_snapshot_handle, GL_ACTIVE_UNIFORMS);
432 if ((context_info.get_version() >= VOGL_GL_VERSION_3_1) && GL_ENTRYPOINT(glGetActiveUniformBlockiv))
433 m_num_active_uniform_blocks = get_program_int(m_snapshot_handle, GL_ACTIVE_UNIFORM_BLOCKS);
438 bool vogl_program_state::snapshot_outputs(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint program)
441 VOGL_NOTE_UNUSED(remapper);
443 if ((!context_info.supports_extension("GL_ARB_program_interface_query")) ||
444 (!GL_ENTRYPOINT(glGetProgramInterfaceiv)) || (!GL_ENTRYPOINT(glGetProgramResourceName)) || (!GL_ENTRYPOINT(glGetProgramResourceiv)))
449 GLint num_active_outputs = 0;
450 GL_ENTRYPOINT(glGetProgramInterfaceiv)(program, GL_PROGRAM_OUTPUT, GL_ACTIVE_RESOURCES, &num_active_outputs);
453 m_outputs.resize(num_active_outputs);
454 for (int i = 0; i < num_active_outputs; i++)
456 vogl_program_output_state &output = m_outputs[i];
461 GLsizei name_len = 0;
462 GL_ENTRYPOINT(glGetProgramResourceName)(program, GL_PROGRAM_OUTPUT, i, sizeof(name), &name_len, name);
465 const GLenum props_to_query[5] = { GL_LOCATION, GL_LOCATION_INDEX, GL_TYPE, GL_ARRAY_SIZE, GL_IS_PER_PATCH }; // TODO: GL_LOCATION_COMPONENT
466 GLint props[5] = { 0, 0, 0, 0, 0 };
467 GL_ENTRYPOINT(glGetProgramResourceiv)(program, GL_PROGRAM_OUTPUT, i, VOGL_ARRAY_SIZE(props_to_query), props_to_query, VOGL_ARRAY_SIZE(props), NULL, props);
470 output.m_name = reinterpret_cast<const char *>(name);
471 output.m_location = props[0];
472 output.m_location_index = props[1];
473 output.m_type = props[2];
474 output.m_array_size = props[3];
475 output.m_is_per_patch = props[4] != 0;
481 bool vogl_program_state::snapshot_transform_feedback(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint program)
484 VOGL_NOTE_UNUSED(remapper);
485 VOGL_NOTE_UNUSED(context_info);
487 // The latest/current mode
488 GL_ENTRYPOINT(glGetProgramiv)(program, GL_TRANSFORM_FEEDBACK_BUFFER_MODE, reinterpret_cast<GLint *>(&m_transform_feedback_mode));
491 // This is the linked state, NOT the current state
492 GL_ENTRYPOINT(glGetProgramiv)(program, GL_TRANSFORM_FEEDBACK_VARYINGS, reinterpret_cast<GLint *>(&m_transform_feedback_num_varyings));
495 m_varyings.resize(m_transform_feedback_num_varyings);
497 for (uint i = 0; i < m_transform_feedback_num_varyings; i++)
499 GLchar name[512] = { '\0' };
500 GLsizei length = 0, size = 0;
501 GLenum type = GL_NONE;
503 // This is the linked state, NOT the current state
504 GL_ENTRYPOINT(glGetTransformFeedbackVarying)(program, i, sizeof(name), &length, &size, &type, name);
507 vogl_program_transform_feedback_varying &varying = m_varyings[i];
511 varying.m_name.set(reinterpret_cast<const char *>(name));
512 varying.m_size = size;
513 varying.m_type = type;
519 bool vogl_program_state::snapshot(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint64 handle, GLenum target)
523 VOGL_NOTE_UNUSED(context_info);
524 VOGL_NOTE_UNUSED(target);
530 VOGL_ASSERT(handle <= cUINT32_MAX);
532 m_snapshot_handle = static_cast<GLuint>(handle);
534 if (!snapshot_basic_info(context_info, remapper))
540 if (!snapshot_outputs(context_info, remapper, m_snapshot_handle))
546 if (!snapshot_program_binary(context_info, remapper))
552 if (!snapshot_info_log(context_info, remapper))
558 if (!snapshot_attached_shaders(context_info, remapper, false))
564 if (!snapshot_active_attribs(context_info, remapper))
570 if (!snapshot_uniforms(context_info, remapper))
576 if (!snapshot_uniform_blocks(context_info, remapper))
582 // We'll snapshot this stuff, although some of it is linked state.
583 if (!snapshot_transform_feedback(context_info, remapper, m_snapshot_handle))
589 m_link_snapshot = false;
595 bool vogl_program_state::link_snapshot(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint handle, const void *pBinary, uint binary_size, GLenum binary_format)
603 m_snapshot_handle = handle;
605 bool linked_using_binary = pBinary && binary_size;
607 if (!snapshot_basic_info(context_info, remapper))
613 if (!snapshot_outputs(context_info, remapper, handle))
619 if (linked_using_binary)
620 m_program_binary.append(static_cast<const uint8 *>(pBinary), binary_size);
622 m_program_binary_format = binary_format;
624 if (!snapshot_info_log(context_info, remapper))
630 if (!snapshot_active_attribs(context_info, remapper))
636 if (!snapshot_attached_shaders(context_info, remapper, linked_using_binary))
642 if (!snapshot_shader_objects(context_info, remapper))
648 if (!linked_using_binary)
650 if (!snapshot_program_binary(context_info, remapper))
657 if (!snapshot_transform_feedback(context_info, remapper, handle))
663 if ((m_link_status) && (!m_attached_shaders.size()) && (!linked_using_binary))
665 vogl_error_printf("%s: Program %u was successfully linked, but there are no attached shaders!\n", VOGL_METHOD_NAME, m_snapshot_handle);
668 // We don't care about the attached shader handlers, we've now snapshotted and copied the ACTUAL shaders.
669 m_attached_shaders.clear();
671 m_link_snapshot = true;
677 void vogl_program_state::set_link_time_snapshot(vogl_unique_ptr<vogl_program_state> &pSnapshot)
681 if (pSnapshot.get() && !pSnapshot->is_valid())
687 m_pLink_time_snapshot = pSnapshot;
690 bool vogl_program_state::restore_uniforms(uint32 handle32, const vogl_context_info &context_info, vogl_handle_remapper &remapper, bool &any_restore_warnings, bool &any_gl_errors) const
694 VOGL_NOTE_UNUSED(context_info);
696 const GLint num_active_uniforms = get_program_int(handle32, GL_ACTIVE_UNIFORMS);
698 const GLint active_uniform_max_length = math::maximum(1024, get_program_int(handle32, GL_ACTIVE_UNIFORM_MAX_LENGTH));
700 growable_array<GLchar, 1024> temp_buf(active_uniform_max_length);
702 vogl_uniform_state_vec uniforms_to_restore(num_active_uniforms);
704 // Restore active uniforms
705 for (int uniform_iter = 0; uniform_iter < num_active_uniforms; uniform_iter++)
707 GLsizei actual_len = 0;
709 GLenum type = GL_NONE;
711 GL_ENTRYPOINT(glGetActiveUniform)(handle32, uniform_iter, temp_buf.size(), &actual_len, &size, &type, temp_buf.get_ptr());
712 if (vogl_check_gl_error())
713 any_gl_errors = true;
715 VOGL_ASSERT(actual_len <= static_cast<GLsizei>(temp_buf.size()));
717 vogl_program_uniform_state &uniform = uniforms_to_restore[uniform_iter];
718 uniform.m_size = size;
719 uniform.m_type = type;
720 uniform.m_name.set(reinterpret_cast<char *>(temp_buf.get_ptr()));
721 uniform.m_base_location = -1;
723 if (!uniform.m_name.begins_with("gl_", true))
725 uniform.m_base_location = GL_ENTRYPOINT(glGetUniformLocation)(handle32, temp_buf.get_ptr());
726 if (vogl_check_gl_error())
727 any_gl_errors = true;
731 for (uint uniform_iter = 0; uniform_iter < m_uniforms.size(); uniform_iter++)
733 const vogl_program_uniform_state &trace_uniform = m_uniforms[uniform_iter];
734 if ((trace_uniform.m_name.begins_with("_gl", true)) || (trace_uniform.m_base_location < 0) || (!trace_uniform.m_data.size()))
737 uint restore_uniform_index;
738 for (restore_uniform_index = 0; restore_uniform_index < uniforms_to_restore.size(); restore_uniform_index++)
739 if (uniforms_to_restore[restore_uniform_index].m_name.compare(trace_uniform.m_name, true) == 0)
742 if (restore_uniform_index == uniforms_to_restore.size())
744 vogl_warning_printf("%s: Failed finding trace uniform \"%s\", trace program %u GL program %u\n", VOGL_METHOD_NAME,
745 trace_uniform.m_name.get_ptr(), m_snapshot_handle, handle32);
746 any_restore_warnings = true;
750 const vogl_program_uniform_state &restore_uniform = uniforms_to_restore[restore_uniform_index];
752 if (restore_uniform.m_base_location < 0)
754 vogl_warning_printf("%s: Trace uniform \"%s\"'s type %s was found in the restored program but the restore handle is invalid, trace program %u GL program %u.\n", VOGL_METHOD_NAME,
755 trace_uniform.m_name.get_ptr(), g_gl_enums.find_gl_name(trace_uniform.m_type), m_snapshot_handle, handle32);
756 any_restore_warnings = true;
760 if (restore_uniform.m_type != trace_uniform.m_type)
762 vogl_warning_printf("%s: Trace uniform \"%s\"'s type (%s) is different from restored trace program type (%s), trace program %u GL program %u. Uniform type conversion is not yet supported, skipping uniform!\n", VOGL_METHOD_NAME,
763 trace_uniform.m_name.get_ptr(), g_gl_enums.find_gl_name(trace_uniform.m_type), g_gl_enums.find_gl_name(restore_uniform.m_type),
764 m_snapshot_handle, handle32);
765 any_restore_warnings = true;
769 if (restore_uniform.m_size != trace_uniform.m_size)
771 vogl_warning_printf("%s: Trace uniform \"%s\" type %s array size (%u) is different from restored program's array size (%u), trace program %u GL program %u. Will set as many array entries as possible and hope for the best.\n", VOGL_METHOD_NAME,
772 trace_uniform.m_name.get_ptr(), g_gl_enums.find_gl_name(trace_uniform.m_type), trace_uniform.m_size, restore_uniform.m_size,
773 m_snapshot_handle, handle32);
774 any_restore_warnings = true;
777 const uint array_size = math::minimum<uint>(restore_uniform.m_size, trace_uniform.m_size);
778 const void *pTrace_data = trace_uniform.m_data.get_ptr();
779 const GLint restore_location = restore_uniform.m_base_location;
781 for (uint i = 0; i < array_size; i++)
782 remapper.declare_location(m_snapshot_handle, handle32, restore_uniform.m_base_location + i, restore_location + i);
786 switch (restore_uniform.m_type)
790 GL_ENTRYPOINT(glUniform1dv)(restore_location, array_size, static_cast<const GLdouble *>(pTrace_data));
795 GL_ENTRYPOINT(glUniform2dv)(restore_location, array_size, static_cast<const GLdouble *>(pTrace_data));
800 GL_ENTRYPOINT(glUniform3dv)(restore_location, array_size, static_cast<const GLdouble *>(pTrace_data));
805 GL_ENTRYPOINT(glUniform4dv)(restore_location, array_size, static_cast<const GLdouble *>(pTrace_data));
810 GL_ENTRYPOINT(glUniformMatrix2dv)(restore_location, array_size, GL_FALSE, static_cast<const GLdouble *>(pTrace_data));
815 GL_ENTRYPOINT(glUniformMatrix3dv)(restore_location, array_size, GL_FALSE, static_cast<const GLdouble *>(pTrace_data));
820 GL_ENTRYPOINT(glUniformMatrix4dv)(restore_location, array_size, GL_FALSE, static_cast<const GLdouble *>(pTrace_data));
823 case GL_DOUBLE_MAT2x3:
825 GL_ENTRYPOINT(glUniformMatrix2x3dv)(restore_location, array_size, GL_FALSE, static_cast<const GLdouble *>(pTrace_data));
828 case GL_DOUBLE_MAT3x2:
830 GL_ENTRYPOINT(glUniformMatrix3x2dv)(restore_location, array_size, GL_FALSE, static_cast<const GLdouble *>(pTrace_data));
833 case GL_DOUBLE_MAT2x4:
835 GL_ENTRYPOINT(glUniformMatrix2x4dv)(restore_location, array_size, GL_FALSE, static_cast<const GLdouble *>(pTrace_data));
838 case GL_DOUBLE_MAT4x2:
840 GL_ENTRYPOINT(glUniformMatrix4x2dv)(restore_location, array_size, GL_FALSE, static_cast<const GLdouble *>(pTrace_data));
843 case GL_DOUBLE_MAT3x4:
845 GL_ENTRYPOINT(glUniformMatrix3x4dv)(restore_location, array_size, GL_FALSE, static_cast<const GLdouble *>(pTrace_data));
848 case GL_DOUBLE_MAT4x3:
850 GL_ENTRYPOINT(glUniformMatrix4x3dv)(restore_location, array_size, GL_FALSE, static_cast<const GLdouble *>(pTrace_data));
856 GL_ENTRYPOINT(glUniform1fv)(restore_location, array_size, static_cast<const GLfloat *>(pTrace_data));
861 GL_ENTRYPOINT(glUniform2fv)(restore_location, array_size, static_cast<const GLfloat *>(pTrace_data));
866 GL_ENTRYPOINT(glUniform3fv)(restore_location, array_size, static_cast<const GLfloat *>(pTrace_data));
871 GL_ENTRYPOINT(glUniform4fv)(restore_location, array_size, static_cast<const GLfloat *>(pTrace_data));
876 GL_ENTRYPOINT(glUniformMatrix2fv)(restore_location, array_size, GL_FALSE, static_cast<const GLfloat *>(pTrace_data));
881 GL_ENTRYPOINT(glUniformMatrix3fv)(restore_location, array_size, GL_FALSE, static_cast<const GLfloat *>(pTrace_data));
886 GL_ENTRYPOINT(glUniformMatrix4fv)(restore_location, array_size, GL_FALSE, static_cast<const GLfloat *>(pTrace_data));
889 case GL_FLOAT_MAT2x3:
891 GL_ENTRYPOINT(glUniformMatrix2x3fv)(restore_location, array_size, GL_FALSE, static_cast<const GLfloat *>(pTrace_data));
894 case GL_FLOAT_MAT3x2:
896 GL_ENTRYPOINT(glUniformMatrix3x2fv)(restore_location, array_size, GL_FALSE, static_cast<const GLfloat *>(pTrace_data));
899 case GL_FLOAT_MAT2x4:
901 GL_ENTRYPOINT(glUniformMatrix2x4fv)(restore_location, array_size, GL_FALSE, static_cast<const GLfloat *>(pTrace_data));
904 case GL_FLOAT_MAT4x2:
906 GL_ENTRYPOINT(glUniformMatrix4x2fv)(restore_location, array_size, GL_FALSE, static_cast<const GLfloat *>(pTrace_data));
909 case GL_FLOAT_MAT3x4:
911 GL_ENTRYPOINT(glUniformMatrix3x4fv)(restore_location, array_size, GL_FALSE, static_cast<const GLfloat *>(pTrace_data));
914 case GL_FLOAT_MAT4x3:
916 GL_ENTRYPOINT(glUniformMatrix4x3fv)(restore_location, array_size, GL_FALSE, static_cast<const GLfloat *>(pTrace_data));
923 case GL_SAMPLER_CUBE:
924 case GL_SAMPLER_1D_SHADOW:
925 case GL_SAMPLER_2D_SHADOW:
926 case GL_SAMPLER_1D_ARRAY:
927 case GL_SAMPLER_2D_ARRAY:
928 case GL_SAMPLER_1D_ARRAY_SHADOW:
929 case GL_SAMPLER_2D_ARRAY_SHADOW:
930 case GL_SAMPLER_2D_MULTISAMPLE:
931 case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
932 case GL_SAMPLER_CUBE_SHADOW:
933 case GL_SAMPLER_BUFFER:
934 case GL_SAMPLER_2D_RECT:
935 case GL_SAMPLER_2D_RECT_SHADOW:
936 case GL_INT_SAMPLER_1D:
937 case GL_INT_SAMPLER_2D:
938 case GL_INT_SAMPLER_3D:
939 case GL_INT_SAMPLER_CUBE:
940 case GL_INT_SAMPLER_1D_ARRAY:
941 case GL_INT_SAMPLER_2D_ARRAY:
942 case GL_INT_SAMPLER_2D_MULTISAMPLE:
943 case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
944 case GL_INT_SAMPLER_BUFFER:
945 case GL_INT_SAMPLER_2D_RECT:
946 case GL_UNSIGNED_INT_SAMPLER_1D:
947 case GL_UNSIGNED_INT_SAMPLER_2D:
948 case GL_UNSIGNED_INT_SAMPLER_3D:
949 case GL_UNSIGNED_INT_SAMPLER_CUBE:
950 case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
951 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
952 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
953 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
954 case GL_UNSIGNED_INT_SAMPLER_BUFFER:
955 case GL_UNSIGNED_INT_SAMPLER_2D_RECT:
960 case GL_IMAGE_2D_RECT:
962 case GL_IMAGE_BUFFER:
963 case GL_IMAGE_1D_ARRAY:
964 case GL_IMAGE_2D_ARRAY:
965 case GL_IMAGE_2D_MULTISAMPLE:
966 case GL_IMAGE_2D_MULTISAMPLE_ARRAY:
967 case GL_INT_IMAGE_1D:
968 case GL_INT_IMAGE_2D:
969 case GL_INT_IMAGE_3D:
970 case GL_INT_IMAGE_2D_RECT:
971 case GL_INT_IMAGE_CUBE:
972 case GL_INT_IMAGE_BUFFER:
973 case GL_INT_IMAGE_1D_ARRAY:
974 case GL_INT_IMAGE_2D_ARRAY:
975 case GL_INT_IMAGE_2D_MULTISAMPLE:
976 case GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY:
977 case GL_UNSIGNED_INT_IMAGE_1D:
978 case GL_UNSIGNED_INT_IMAGE_2D:
979 case GL_UNSIGNED_INT_IMAGE_3D:
980 case GL_UNSIGNED_INT_IMAGE_2D_RECT:
981 case GL_UNSIGNED_INT_IMAGE_CUBE:
982 case GL_UNSIGNED_INT_IMAGE_BUFFER:
983 case GL_UNSIGNED_INT_IMAGE_1D_ARRAY:
984 case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
985 case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE:
986 case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY:
991 GL_ENTRYPOINT(glUniform1iv)(restore_location, array_size, static_cast<const GLint *>(pTrace_data));
997 GL_ENTRYPOINT(glUniform2iv)(restore_location, array_size, static_cast<const GLint *>(pTrace_data));
1003 GL_ENTRYPOINT(glUniform3iv)(restore_location, array_size, static_cast<const GLint *>(pTrace_data));
1009 GL_ENTRYPOINT(glUniform4iv)(restore_location, array_size, static_cast<const GLint *>(pTrace_data));
1012 case GL_UNSIGNED_INT:
1013 case GL_UNSIGNED_INT_ATOMIC_COUNTER: // TODO: is this correct?
1015 GL_ENTRYPOINT(glUniform1uiv)(restore_location, array_size, static_cast<const GLuint *>(pTrace_data));
1018 case GL_UNSIGNED_INT_VEC2:
1020 GL_ENTRYPOINT(glUniform2uiv)(restore_location, array_size, static_cast<const GLuint *>(pTrace_data));
1023 case GL_UNSIGNED_INT_VEC3:
1025 GL_ENTRYPOINT(glUniform3uiv)(restore_location, array_size, static_cast<const GLuint *>(pTrace_data));
1028 case GL_UNSIGNED_INT_VEC4:
1030 GL_ENTRYPOINT(glUniform4uiv)(restore_location, array_size, static_cast<const GLuint *>(pTrace_data));
1036 vogl_warning_printf("%s: Unknown uniform type 0x%04X\n", VOGL_FUNCTION_NAME, restore_uniform.m_type);
1037 any_restore_warnings = true;
1042 if (vogl_check_gl_error())
1044 any_gl_errors = true;
1046 vogl_warning_printf("%s: A GL error occurred while attempting to restore trace uniform \"%s\" type %s, trace program %u GL program %u.\n", VOGL_METHOD_NAME,
1047 trace_uniform.m_name.get_ptr(), g_gl_enums.find_gl_name(trace_uniform.m_type), m_snapshot_handle, handle32);
1055 bool vogl_program_state::restore_uniform_blocks(uint32 handle32, const vogl_context_info &context_info, vogl_handle_remapper &remapper, bool &any_restore_warnings, bool &any_gl_errors) const
1059 VOGL_NOTE_UNUSED(remapper);
1061 // Restore active uniform blocks
1062 if ((context_info.get_version() >= VOGL_GL_VERSION_3_1) && GL_ENTRYPOINT(glGetUniformBlockIndex) && GL_ENTRYPOINT(glUniformBlockBinding))
1064 VOGL_CHECK_GL_ERROR;
1066 growable_array<char, 256> name_buf;
1068 for (uint uniform_block_index = 0; uniform_block_index < m_num_active_uniform_blocks; uniform_block_index++)
1070 const vogl_program_uniform_block_state &state = m_uniform_blocks[uniform_block_index];
1072 if (state.m_name.is_empty())
1074 vogl_error_printf("%s: Trace program %u GL program %u: Invalid uniform block name!\n", VOGL_METHOD_NAME, m_snapshot_handle, handle32);
1075 any_restore_warnings = true;
1079 GLuint restore_block_index = GL_ENTRYPOINT(glGetUniformBlockIndex)(handle32, reinterpret_cast<const GLchar *>(state.m_name.get_ptr()));
1080 bool gl_err = vogl_check_gl_error();
1082 any_gl_errors = true;
1084 if ((gl_err) || (restore_block_index == GL_INVALID_INDEX))
1086 vogl_error_printf("%s: Trace program %u GL program %u: Failed finding uniform block \"%s\"\n", VOGL_METHOD_NAME, m_snapshot_handle, handle32, state.m_name.get_ptr());
1087 any_restore_warnings = true;
1091 if (restore_block_index != state.m_uniform_block_index)
1093 vogl_error_printf("%s: Trace program %u GL program %u: Uniform block \"%s\"'s restore block index (%u) differs from it's trace index (%u)! Uniform block indices are not currently remapped while replaying GL calls, so this trace may not be replayable!\n",
1094 VOGL_METHOD_NAME, (uint)m_snapshot_handle, handle32, state.m_name.get_ptr(), state.m_uniform_block_index, restore_block_index);
1095 any_restore_warnings = true;
1098 GL_ENTRYPOINT(glUniformBlockBinding)(handle32, restore_block_index, state.m_uniform_block_binding_point);
1099 if (vogl_check_gl_error())
1101 any_gl_errors = true;
1103 vogl_error_printf("%s: Trace program %u GL program %u: Failed restoring uniform block \"%s\"'s binding point %u\n", VOGL_METHOD_NAME, m_snapshot_handle, handle32, state.m_name.get_ptr(), state.m_uniform_block_binding_point);
1104 any_restore_warnings = true;
1108 GLint restore_block_data_size = 0;
1109 GL_ENTRYPOINT(glGetActiveUniformBlockiv)(handle32, restore_block_index, GL_UNIFORM_BLOCK_DATA_SIZE, &restore_block_data_size);
1110 if (vogl_check_gl_error())
1111 any_gl_errors = true;
1113 if (state.m_uniform_block_data_size != restore_block_data_size)
1115 vogl_warning_printf("%s: Trace program %u GL program %u: Uniform block \"%s\"'s data size (%u) differs from trace's (%u)\n", VOGL_METHOD_NAME, m_snapshot_handle, handle32, state.m_name.get_ptr(), state.m_uniform_block_data_size, restore_block_data_size);
1116 any_restore_warnings = true;
1119 GLint restore_block_active_uniforms = 0;
1120 GL_ENTRYPOINT(glGetActiveUniformBlockiv)(handle32, restore_block_index, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &restore_block_active_uniforms);
1121 if (vogl_check_gl_error())
1122 any_gl_errors = true;
1124 if (state.m_uniform_block_active_uniforms != restore_block_active_uniforms)
1126 vogl_warning_printf("%s: Trace program %u GL program %u: Uniform block \"%s\"'s number of active block uniforms (%u) differs from trace's (%i)\n",
1127 VOGL_METHOD_NAME, (uint)m_snapshot_handle, handle32, state.m_name.get_ptr(), state.m_uniform_block_active_uniforms, restore_block_active_uniforms);
1128 any_restore_warnings = true;
1132 else if (m_num_active_uniform_blocks)
1134 vogl_error_printf("%s: Trace program %u GL program %u has %u active uniform blocks, but the current context does not support uniform blocks!\n", VOGL_METHOD_NAME, m_snapshot_handle, handle32, m_num_active_uniform_blocks);
1135 any_restore_warnings = true;
1141 bool vogl_program_state::restore_active_attribs(uint32 handle32, const vogl_context_info &context_info, vogl_handle_remapper &remapper, bool &any_restore_warnings, bool &any_gl_errors) const
1145 VOGL_NOTE_UNUSED(context_info);
1146 VOGL_NOTE_UNUSED(remapper);
1147 VOGL_NOTE_UNUSED(any_restore_warnings);
1149 // Restore active attribs
1150 for (uint attrib_iter = 0; attrib_iter < m_num_active_attribs; attrib_iter++)
1152 const vogl_program_attrib_state &attrib = m_attribs[attrib_iter];
1153 if ((attrib.m_name.begins_with("_gl", true)) || (attrib.m_bound_location < 0))
1156 GL_ENTRYPOINT(glBindAttribLocation)(handle32, attrib.m_bound_location, reinterpret_cast<const GLchar *>(attrib.m_name.get_ptr()));
1158 if (vogl_check_gl_error())
1160 any_gl_errors = true;
1162 vogl_warning_printf("%s: GL error while binding attrib location %i name %s of trace program %u GL program %u\n", VOGL_METHOD_NAME, attrib.m_bound_location, attrib.m_name.get_ptr(), m_snapshot_handle, handle32);
1169 bool vogl_program_state::restore_outputs(uint32 handle32, const vogl_context_info &context_info, vogl_handle_remapper &remapper, bool &any_restore_warnings, bool &any_gl_errors) const
1172 VOGL_NOTE_UNUSED(remapper);
1174 for (uint i = 0; i < m_outputs.size(); i++)
1176 const vogl_program_output_state &output = m_outputs[i];
1178 if ((output.m_name.is_empty()) || (output.m_name.begins_with("gl_", true)))
1181 int location = output.m_location;
1182 int location_index = output.m_location_index;
1184 if ((context_info.supports_extension("GL_ARB_blend_func_extended")) && (GL_ENTRYPOINT(glBindFragDataLocationIndexed)))
1186 GL_ENTRYPOINT(glBindFragDataLocationIndexed)(handle32, location, location_index, reinterpret_cast<const GLchar *>(output.m_name.get_ptr()));
1192 // TODO: This is not a warning, but we'll try to soldier on anyway.
1193 any_restore_warnings = true;
1195 vogl_error_printf("%s: GL_ARB_blend_func_extended is not supported, but GL program %u uses a non-zero location index\n", VOGL_METHOD_NAME, handle32);
1198 GL_ENTRYPOINT(glBindFragDataLocation)(handle32, location, reinterpret_cast<const GLchar *>(output.m_name.get_ptr()));
1201 if (vogl_check_gl_error())
1203 any_gl_errors = true;
1205 vogl_error_printf("%s: GL error while binding fragdata location %i location index %i name %s GL program %u\n", VOGL_METHOD_NAME, output.m_location, output.m_location_index, output.m_name.get_ptr(), handle32);
1212 bool vogl_program_state::restore_transform_feedback(uint32 handle32, const vogl_context_info &context_info, vogl_handle_remapper &remapper, bool &any_restore_warnings, bool &any_gl_errors) const
1215 VOGL_NOTE_UNUSED(context_info);
1216 VOGL_NOTE_UNUSED(remapper);
1217 VOGL_NOTE_UNUSED(any_restore_warnings);
1219 if (!m_varyings.size())
1222 dynamic_string_array names;
1224 for (uint i = 0; i < m_varyings.size(); i++)
1226 const vogl_program_transform_feedback_varying &varying = m_varyings[i];
1228 GLint index = varying.m_index;
1232 names.ensure_element_is_valid(index);
1233 names[index] = varying.m_name;
1236 vogl::vector<GLchar *> varyings(names.size());
1237 for (uint i = 0; i < names.size(); i++)
1238 varyings[i] = (GLchar *)(names[i].get_ptr());
1240 GL_ENTRYPOINT(glTransformFeedbackVaryings)(handle32, varyings.size(), varyings.get_ptr(), m_transform_feedback_mode);
1241 if (vogl_check_gl_error())
1243 any_gl_errors = true;
1245 vogl_error_printf("%s: GL error while setting transform feedback varyings, GL program %u\n", VOGL_METHOD_NAME, handle32);
1251 bool vogl_program_state::restore_link_snapshot(uint32 handle32, const vogl_context_info &context_info, vogl_handle_remapper &remapper, bool &any_restore_warnings, bool &any_gl_errors, bool &link_succeeded) const
1255 if (vogl_check_gl_error())
1256 any_gl_errors = true;
1258 VOGL_ASSERT(m_link_snapshot);
1260 if (!restore_active_attribs(handle32, context_info, remapper, any_restore_warnings, any_gl_errors))
1263 if (!restore_outputs(handle32, context_info, remapper, any_restore_warnings, any_gl_errors))
1266 if (!restore_transform_feedback(handle32, context_info, remapper, any_restore_warnings, any_gl_errors))
1269 uint_vec shader_handles;
1271 if (m_program_binary.size())
1273 GL_ENTRYPOINT(glProgramBinary)(handle32, m_program_binary_format, m_program_binary.get_ptr(), m_program_binary.size());
1274 if (vogl_check_gl_error())
1276 vogl_warning_printf("%s: GL error while setting link-time snapshot program binary on trace program %u GL program %u\n", VOGL_METHOD_NAME, m_snapshot_handle, handle32);
1277 any_gl_errors = true;
1279 else if (get_program_bool(handle32, GL_LINK_STATUS))
1280 link_succeeded = true;
1283 if ((!link_succeeded) && (m_shaders.size()))
1285 shader_handles.resize(m_shaders.size());
1287 for (uint i = 0; i < m_shaders.size(); i++)
1289 shader_handles[i] = GL_ENTRYPOINT(glCreateShader)(m_shaders[i].get_shader_type());
1290 if ((vogl_check_gl_error()) || (!shader_handles[i]))
1293 GLuint64 handle = shader_handles[i];
1294 if (!m_shaders[i].restore(context_info, remapper, handle))
1297 if (!m_shaders[i].get_restore_compile_status())
1299 vogl_warning_printf("%s: Failed compiling shadowed link-time shader while restoring program, trace program %u GL program %u\n", VOGL_METHOD_NAME, m_snapshot_handle, handle32);
1300 any_restore_warnings = true;
1304 for (uint i = 0; i < m_shaders.size(); i++)
1306 GL_ENTRYPOINT(glAttachShader)(handle32, shader_handles[i]);
1308 if (vogl_check_gl_error())
1310 for (uint j = 0; j < i; j++)
1311 GL_ENTRYPOINT(glDetachShader)(handle32, shader_handles[j]);
1317 GL_ENTRYPOINT(glLinkProgram)(handle32);
1319 if (vogl_check_gl_error())
1321 vogl_warning_printf("%s: GL error while linking link-time snapshot program on trace program %u GL program %u\n", VOGL_METHOD_NAME, m_snapshot_handle, handle32);
1322 any_gl_errors = true;
1324 else if (get_program_bool(handle32, GL_LINK_STATUS))
1325 link_succeeded = true;
1327 for (uint i = 0; i < shader_handles.size(); i++)
1329 GL_ENTRYPOINT(glDetachShader)(handle32, shader_handles[i]);
1330 if (vogl_check_gl_error())
1331 any_gl_errors = true;
1333 GL_ENTRYPOINT(glDeleteShader)(shader_handles[i]);
1334 shader_handles[i] = 0;
1336 if (vogl_check_gl_error())
1337 any_gl_errors = true;
1344 for (uint i = 0; i < shader_handles.size(); i++)
1345 if (shader_handles[i])
1346 GL_ENTRYPOINT(glDeleteShader)(shader_handles[i]);
1348 if (vogl_check_gl_error())
1349 any_gl_errors = true;
1354 bool vogl_program_state::link_program(uint32 handle32, const vogl_context_info &context_info, vogl_handle_remapper &remapper, bool &any_restore_warnings, bool &any_gl_errors, bool &link_succeeded) const
1358 if (vogl_check_gl_error())
1359 any_gl_errors = true;
1361 if (m_link_snapshot)
1362 return restore_link_snapshot(handle32, context_info, remapper, any_restore_warnings, any_gl_errors, link_succeeded);
1364 // First restore the program's linked state.
1365 if (m_pLink_time_snapshot.get())
1367 if (!m_pLink_time_snapshot->link_program(handle32, context_info, remapper, any_restore_warnings, any_gl_errors, link_succeeded))
1371 // Now restore the program's actual/current state.
1372 if (!restore_active_attribs(handle32, context_info, remapper, any_restore_warnings, any_gl_errors))
1375 if (!restore_outputs(handle32, context_info, remapper, any_restore_warnings, any_gl_errors))
1378 // TODO: Restore the CURRENT transform feedback state (not just the last linked state) - this will require deeper shadowing and considering how rarely transform feedback is used by games it's low priority.
1380 if (m_attached_shaders.size())
1382 for (uint i = 0; i < m_attached_shaders.size(); i++)
1384 GLuint trace_handle = m_attached_shaders[i];
1385 GLuint replay_handle = static_cast<GLuint>(remapper.remap_handle(VOGL_NAMESPACE_SHADERS, trace_handle));
1388 GL_ENTRYPOINT(glAttachShader)(handle32, replay_handle);
1389 if (vogl_check_gl_error())
1391 vogl_error_printf("%s: GL error while attaching shader %u to trace program %u GL program %u\n", VOGL_METHOD_NAME, replay_handle, m_snapshot_handle, handle32);
1401 bool vogl_program_state::restore(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint64 &handle) const
1405 VOGL_NOTE_UNUSED(context_info);
1407 VOGL_CHECK_GL_ERROR;
1412 vogl_scoped_binding_state orig_binding(GL_PROGRAM);
1414 bool created_handle = false;
1418 handle = GL_ENTRYPOINT(glCreateProgram)();
1419 if ((vogl_check_gl_error()) || (!handle))
1422 remapper.declare_handle(VOGL_NAMESPACE_PROGRAMS, m_snapshot_handle, handle, GL_NONE);
1423 VOGL_ASSERT(remapper.remap_handle(VOGL_NAMESPACE_PROGRAMS, m_snapshot_handle) == handle);
1425 created_handle = true;
1428 VOGL_ASSERT(handle <= cUINT32_MAX);
1429 GLuint handle32 = static_cast<GLuint>(handle);
1431 bool any_gl_errors = false;
1432 bool any_restore_warnings = false;
1434 bool link_succeeded = false;
1435 if (!link_program(handle32, context_info, remapper, any_restore_warnings, any_gl_errors, link_succeeded))
1438 if ((m_pLink_time_snapshot.get()) && (link_succeeded != m_pLink_time_snapshot->m_link_status))
1440 if (!link_succeeded)
1442 if (m_pLink_time_snapshot->m_link_status)
1444 vogl_error_printf("%s: Failed linking trace program %u GL program %u, but this program was recorded as successfully linked in the trace\n", VOGL_METHOD_NAME, m_snapshot_handle, handle32);
1449 vogl_debug_printf("%s: Failed linking trace program %u GL program %u, but this program was also recorded as not successfully linked in the trace\n", VOGL_METHOD_NAME, m_snapshot_handle, handle32);
1452 else if (!m_pLink_time_snapshot->m_link_status)
1454 vogl_warning_printf("%s: Succeeded linking trace program %u GL program %u, which is odd because this program was recorded as not successfully linked in the trace\n", VOGL_METHOD_NAME, m_snapshot_handle, handle32);
1455 any_restore_warnings = true;
1461 GL_ENTRYPOINT(glUseProgram)(handle32);
1462 if (vogl_check_gl_error())
1464 any_gl_errors = true;
1468 if (!restore_uniforms(handle32, context_info, remapper, any_restore_warnings, any_gl_errors))
1471 if (!restore_uniform_blocks(handle32, context_info, remapper, any_restore_warnings, any_gl_errors))
1474 } // if (link_succeeded)
1478 vogl_warning_printf("%s: One or more GL errors occurred while attempting to restore trace program %u GL program %u. This program has been restored as much as possible, but the replay may diverge.\n", VOGL_METHOD_NAME, m_snapshot_handle, handle32);
1481 if (any_restore_warnings)
1483 vogl_warning_printf("%s: One or more restore warnings occurred while attempting to restore trace program %u GL program %u. This program has been restored as much as possible, but the replay may diverge.\n", VOGL_METHOD_NAME, m_snapshot_handle, handle32);
1489 vogl_error_printf("%s: Failed restoring trace program %u GL program %u\n", VOGL_METHOD_NAME, m_snapshot_handle, handle32);
1491 if ((handle) && (created_handle))
1493 GL_ENTRYPOINT(glUseProgram)(0);
1494 VOGL_CHECK_GL_ERROR;
1496 remapper.delete_handle_and_object(VOGL_NAMESPACE_PROGRAMS, m_snapshot_handle, handle);
1505 bool vogl_program_state::remap_handles(vogl_handle_remapper &remapper)
1512 uint replay_handle = m_snapshot_handle;
1514 uint trace_handle = static_cast<GLuint>(remapper.remap_handle(VOGL_NAMESPACE_PROGRAMS, m_snapshot_handle));
1516 m_snapshot_handle = trace_handle;
1518 if (!m_link_snapshot)
1520 for (uint i = 0; i < m_attached_shaders.size(); i++)
1521 m_attached_shaders[i] = static_cast<GLuint>(remapper.remap_handle(VOGL_NAMESPACE_SHADERS, m_attached_shaders[i]));
1525 for (uint i = 0; i < m_shaders.size(); i++)
1527 // Try to remap the shader's handle, although it could be dead by now. This makes it easier to diff state captures.
1528 if (m_shaders[i].is_valid())
1530 GLuint64 snapshot_handle = m_shaders[i].get_snapshot_handle();
1531 if (remapper.is_valid_handle(VOGL_NAMESPACE_SHADERS, snapshot_handle))
1532 m_shaders[i].set_snapshot_handle(remapper.remap_handle(VOGL_NAMESPACE_SHADERS, snapshot_handle));
1537 for (uint i = 0; i < m_uniforms.size(); i++)
1538 if (m_uniforms[i].m_base_location >= 0)
1539 m_uniforms[i].m_base_location = remapper.remap_location(replay_handle, m_uniforms[i].m_base_location);
1541 if (m_pLink_time_snapshot.get())
1543 if (!m_pLink_time_snapshot->remap_handles(remapper))
1550 void vogl_program_state::clear()
1554 m_snapshot_handle = 0;
1556 m_program_binary.clear();
1557 m_program_binary_format = GL_NONE;
1559 m_attached_shaders.clear();
1563 m_num_active_attribs = 0;
1564 m_num_active_uniforms = 0;
1565 m_num_active_uniform_blocks = 0;
1569 m_uniform_blocks.clear();
1575 m_pLink_time_snapshot.reset();
1577 m_transform_feedback_mode = GL_NONE;
1578 m_transform_feedback_num_varyings = 0;
1581 m_marked_for_deletion = false;
1582 m_link_status = false;
1583 m_verify_status = false;
1585 m_link_snapshot = false;
1589 bool vogl_program_state::serialize(json_node &node, vogl_blob_manager &blob_manager) const
1593 VOGL_NOTE_UNUSED(blob_manager);
1598 node.add_key_value("version", VOGL_PROGRAM_VERSION);
1599 node.add_key_value("handle", m_snapshot_handle);
1600 node.add_key_value("link_snapshot", m_link_snapshot);
1601 node.add_key_value("link_status", m_link_status);
1602 node.add_key_value("verify_status", m_verify_status);
1603 node.add_key_value("marked_for_deletion", m_marked_for_deletion);
1604 node.add_key_value("num_active_attribs", m_num_active_attribs);
1605 node.add_key_value("num_active_uniforms", m_num_active_uniforms);
1606 node.add_key_value("num_active_uniform_blocks", m_num_active_uniform_blocks);
1607 node.add_key_value("info_log", m_info_log);
1609 node.add_key_value("program_binary_format", m_program_binary_format);
1610 if (m_program_binary.size())
1612 dynamic_string id(blob_manager.add_buf_compute_unique_id(m_program_binary.get_ptr(), m_program_binary.size(), "program_binary", "bin"));
1613 node.add_key_value("program_binary", id);
1616 if (m_attached_shaders.size())
1618 json_node &attached_shaders_array = node.add_array("attached_shaders");
1619 for (uint i = 0; i < m_attached_shaders.size(); i++)
1620 attached_shaders_array.add_value(m_attached_shaders[i]);
1623 if (m_shaders.size())
1625 json_node &shader_objects_array = node.add_array("shader_objects");
1626 for (uint i = 0; i < m_shaders.size(); i++)
1627 if (!m_shaders[i].serialize(shader_objects_array.add_object(), blob_manager))
1631 if (m_attribs.size())
1633 json_node &active_attribs_array = node.add_array("active_attribs");
1634 for (uint i = 0; i < m_attribs.size(); i++)
1636 const vogl_program_attrib_state &attrib = m_attribs[i];
1638 json_node &attrib_node = active_attribs_array.add_object();
1639 attrib_node.add_key_value("name", attrib.m_name);
1640 attrib_node.add_key_value("type", g_gl_enums.find_gl_name(attrib.m_type));
1641 attrib_node.add_key_value("size", attrib.m_size);
1642 attrib_node.add_key_value("location", attrib.m_bound_location);
1646 if (m_uniforms.size())
1648 json_node &active_uniforms_array = node.add_array("active_uniforms");
1650 vogl::vector<char> temp_buf;
1651 temp_buf.reserve(64);
1653 for (uint i = 0; i < m_uniforms.size(); i++)
1655 const vogl_program_uniform_state &uniform = m_uniforms[i];
1657 json_node &uniform_node = active_uniforms_array.add_object();
1658 uniform_node.add_key_value("name", uniform.m_name);
1659 uniform_node.add_key_value("type", g_gl_enums.find_gl_name(uniform.m_type));
1660 uniform_node.add_key_value("size", uniform.m_size);
1661 uniform_node.add_key_value("base_location", uniform.m_base_location);
1663 json_node &uniform_data = uniform_node.add_array("uniform_data");
1665 if (uniform.m_data.size())
1667 const uint type_size_in_GLints = vogl_gl_get_uniform_size_in_GLints(uniform.m_type);
1668 const uint type_size = vogl_gl_get_uniform_size_in_bytes(uniform.m_type);
1669 const GLenum base_type = vogl_gl_get_uniform_base_type(uniform.m_type);
1671 for (int element = 0; element < uniform.m_size; element++)
1673 for (uint element_ofs = 0; element_ofs < type_size_in_GLints; element_ofs++)
1675 const uint32 *pData = reinterpret_cast<const uint32 *>(uniform.m_data.get_ptr() + type_size * element + sizeof(uint32) * element_ofs);
1677 if (base_type == GL_FLOAT)
1679 float f = *reinterpret_cast<const float *>(pData);
1685 v.serialize(temp_buf, false);
1689 if (dv.deserialize(temp_buf.get_ptr(), temp_buf.size()))
1691 if (static_cast<float>(dv.as_double()) == f)
1697 dynamic_string str(cVarArg, "0x%08X", *pData);
1698 uniform_data.add_value(str);
1702 uniform_data.add_value(f);
1705 else if (base_type == GL_DOUBLE)
1707 double f = *reinterpret_cast<const double *>(pData);
1713 v.serialize(temp_buf, false);
1718 if (dv.deserialize(temp_buf.get_ptr(), temp_buf.size()))
1720 if (dv.as_double() == f)
1726 uniform_data.add_value(*reinterpret_cast<const uint64_t *>(pData));
1730 uniform_data.add_value(f);
1733 else if (base_type == GL_BOOL)
1735 uniform_data.add_value(*pData != 0);
1737 else if (base_type == GL_UNSIGNED_INT)
1739 uniform_data.add_value(*reinterpret_cast<const GLuint *>(pData));
1743 uniform_data.add_value(*reinterpret_cast<const GLint *>(pData));
1751 if (m_uniform_blocks.size())
1753 json_node &active_uniforms_blocks_array = node.add_array("active_uniform_blocks");
1754 for (uint i = 0; i < m_uniform_blocks.size(); i++)
1756 const vogl_program_uniform_block_state &state = m_uniform_blocks[i];
1758 json_node &uniform_block_node = active_uniforms_blocks_array.add_object();
1759 uniform_block_node.add_key_value("block_index", state.m_uniform_block_index);
1760 uniform_block_node.add_key_value("name", state.m_name);
1761 uniform_block_node.add_key_value("binding_point", state.m_uniform_block_binding_point);
1762 uniform_block_node.add_key_value("data_size", state.m_uniform_block_data_size);
1763 uniform_block_node.add_key_value("active_uniforms", state.m_uniform_block_active_uniforms);
1767 if (m_outputs.size())
1769 json_node &outputs_array = node.add_array("outputs");
1770 for (uint i = 0; i < m_outputs.size(); i++)
1772 const vogl_program_output_state &output = m_outputs[i];
1774 json_node &outputs_node = outputs_array.add_object();
1775 outputs_node.add_key_value("index", i);
1776 outputs_node.add_key_value("name", output.m_name);
1777 outputs_node.add_key_value("location", output.m_location);
1778 outputs_node.add_key_value("location_index", output.m_location_index);
1779 outputs_node.add_key_value("type", g_gl_enums.find_gl_name(output.m_type));
1780 outputs_node.add_key_value("array_size", output.m_array_size);
1781 outputs_node.add_key_value("is_per_patch", output.m_is_per_patch);
1785 node.add_key_value("transform_feedback_mode", g_gl_enums.find_gl_name(m_transform_feedback_mode));
1786 node.add_key_value("transform_feedback_num_varyings", m_transform_feedback_num_varyings);
1788 if (m_transform_feedback_num_varyings)
1790 json_node &varyings_array = node.add_array("transform_feedback_varyings");
1791 for (uint i = 0; i < m_varyings.size(); i++)
1793 const vogl_program_transform_feedback_varying &varying = m_varyings[i];
1795 json_node &node = varyings_array.add_object();
1796 node.add_key_value("index", varying.m_index);
1797 node.add_key_value("name", varying.m_name);
1798 node.add_key_value("size", varying.m_size);
1799 node.add_key_value("type", g_gl_enums.find_gl_name(varying.m_type));
1803 if (m_pLink_time_snapshot.get())
1805 if (!m_pLink_time_snapshot->serialize(node.add_object("link_time_snapshot"), blob_manager))
1812 bool vogl_program_state::deserialize(const json_node &node, const vogl_blob_manager &blob_manager)
1816 VOGL_NOTE_UNUSED(blob_manager);
1820 if (!node.is_object())
1823 m_snapshot_handle = node.value_as_uint32("handle");
1824 m_link_snapshot = node.value_as_bool("link_snapshot");
1825 m_link_status = node.value_as_bool("link_status");
1826 m_verify_status = node.value_as_bool("verify_status");
1827 m_marked_for_deletion = node.value_as_bool("marked_for_deletion");
1828 m_num_active_attribs = node.value_as_int("num_active_attribs");
1829 m_num_active_uniforms = node.value_as_int("num_active_uniforms");
1830 m_num_active_uniform_blocks = node.value_as_int("num_active_uniform_blocks");
1831 m_info_log = node.value_as_string("info_log");
1833 m_program_binary_format = node.value_as_uint32("program_binary_format");
1834 if (node.has_key("program_binary"))
1836 if (!blob_manager.get(node.value_as_string("program_binary"), m_program_binary))
1838 vogl_warning_printf("%s: Failed retreiving program_binary data blob from trace program %u\n", VOGL_METHOD_NAME, m_snapshot_handle);
1842 const json_node *pAttached_shaders_array = node.find_child_array("attached_shaders");
1843 if (pAttached_shaders_array)
1845 m_attached_shaders.resize(pAttached_shaders_array->size());
1846 for (uint i = 0; i < m_attached_shaders.size(); i++)
1847 m_attached_shaders[i] = pAttached_shaders_array->value_as_uint32(i);
1850 const json_node *pShader_objects_array = node.find_child_array("shader_objects");
1851 if (pShader_objects_array)
1853 if (!pShader_objects_array->are_all_children_objects())
1854 vogl_warning_printf("%s: shader_objects node must contain all objects, trace program %u\n", VOGL_METHOD_NAME, m_snapshot_handle);
1857 m_shaders.resize(pShader_objects_array->size());
1858 for (uint i = 0; i < m_shaders.size(); i++)
1859 if (!m_shaders[i].deserialize(*pShader_objects_array->get_value_as_object(i), blob_manager))
1864 const json_node *pActive_attribs_array = node.find_child_array("active_attribs");
1865 if (pActive_attribs_array)
1867 m_attribs.resize(pActive_attribs_array->size());
1869 for (uint i = 0; i < m_attribs.size(); i++)
1871 const json_node *pAttrib_node = pActive_attribs_array->get_value_as_object(i);
1874 vogl_warning_printf("%s: Missing attrib object in active_attribs array, trace program %u\n", VOGL_METHOD_NAME, m_snapshot_handle);
1878 vogl_program_attrib_state &attrib = m_attribs[i];
1880 attrib.m_name = pAttrib_node->value_as_string("name");
1881 attrib.m_type = vogl_get_json_value_as_enum(*pAttrib_node, "type");
1882 attrib.m_size = pAttrib_node->value_as_int32("size");
1883 attrib.m_bound_location = pAttrib_node->value_as_int32("location");
1888 const json_node *pActive_uniforms_array = node.find_child_array("active_uniforms");
1889 if (pActive_uniforms_array)
1891 m_uniforms.resize(pActive_uniforms_array->size());
1893 for (uint i = 0; i < m_uniforms.size(); i++)
1895 const json_node *pUniform_node = pActive_uniforms_array->get_value_as_object(i);
1898 vogl_warning_printf("%s: Missing uniform object in active_uniforms array, trace program %u\n", VOGL_METHOD_NAME, m_snapshot_handle);
1902 vogl_program_uniform_state &uniform = m_uniforms[i];
1903 uniform.m_name = pUniform_node->value_as_string("name");
1904 uniform.m_type = vogl_get_json_value_as_enum(*pUniform_node, "type");
1905 uniform.m_size = pUniform_node->value_as_int32("size");
1906 uniform.m_base_location = pUniform_node->value_as_int32("base_location");
1908 const json_node *pUniform_data = pUniform_node->find_child_array("uniform_data");
1911 vogl_warning_printf("%s: Missing uniform_data child array in active_uniforms array, trace program %u\n", VOGL_METHOD_NAME, m_snapshot_handle);
1915 const uint type_size_in_GLints = vogl_gl_get_uniform_size_in_GLints(uniform.m_type);
1916 const uint type_size = vogl_gl_get_uniform_size_in_bytes(uniform.m_type);
1917 const GLenum base_type = vogl_gl_get_uniform_base_type(uniform.m_type);
1919 uint uniform_data_size_in_bytes = type_size * uniform.m_size;
1920 if (uniform_data_size_in_bytes > 0)
1922 uniform.m_data.resize(uniform_data_size_in_bytes);
1925 if ((!type_size_in_GLints) || (!type_size))
1927 vogl_warning_printf("%s: Uniform type error while processing active_uniforms array, trace program %u\n", VOGL_METHOD_NAME, m_snapshot_handle);
1931 if (pUniform_data->size() != uniform.m_size * type_size_in_GLints)
1933 vogl_warning_printf("%s: uniform_data array's size is invalid, trace program %u\n", VOGL_METHOD_NAME, m_snapshot_handle);
1937 for (int element = 0; element < uniform.m_size; element++)
1939 for (uint element_ofs = 0; element_ofs < type_size_in_GLints; element_ofs++)
1941 const uint array_index = element * type_size_in_GLints + element_ofs;
1943 uint32 *pData = reinterpret_cast<uint32 *>(uniform.m_data.get_ptr() + type_size * element + sizeof(uint32) * element_ofs);
1944 float *pFloat_data = reinterpret_cast<float *>(pData);
1945 double *pDouble_data = reinterpret_cast<double *>(pData);
1947 const json_value &json_val = pUniform_data->get_value(array_index);
1949 if (json_val.is_string())
1951 dynamic_string str(json_val.as_string());
1955 bool is_hex = str.begins_with("0x", true);
1956 bool is_negative = str.begins_with("-", true);
1958 const char *pBuf = str.get_ptr();
1961 bool success = is_negative ? string_ptr_to_int64(pBuf, reinterpret_cast<int64_t &>(val64)) : string_ptr_to_uint64(pBuf, val64);
1964 vogl_warning_printf("%s: Failed converting uniform array element \"%s\" to integer, trace program %u\n", VOGL_METHOD_NAME, str.get_ptr(), m_snapshot_handle);
1965 else if (base_type == GL_FLOAT)
1968 *pFloat_data = *reinterpret_cast<const float *>(&val64);
1970 *pFloat_data = static_cast<float>(val64);
1972 else if (base_type == GL_DOUBLE)
1975 *pDouble_data = *reinterpret_cast<const double *>(&val64);
1977 *pDouble_data = static_cast<double>(val64);
1980 *pData = static_cast<uint32>(val64);
1984 if (base_type == GL_FLOAT)
1985 *pFloat_data = json_val.as_float();
1986 else if (base_type == GL_DOUBLE)
1987 *pDouble_data = json_val.as_double();
1988 else if (base_type == GL_UNSIGNED_INT)
1989 *pData = json_val.as_uint32();
1991 *pData = json_val.as_int32();
1998 const json_node *pActive_uniforms_blocks_array = node.find_child_array("active_uniform_blocks");
1999 if (pActive_uniforms_blocks_array)
2001 if (!pActive_uniforms_blocks_array->are_all_children_objects())
2003 vogl_warning_printf("%s: active_uniform_blocks child array does not contain all child objects in trace program %u\n", VOGL_METHOD_NAME, m_snapshot_handle);
2007 m_uniform_blocks.resize(pActive_uniforms_blocks_array->size());
2009 for (uint i = 0; i < pActive_uniforms_blocks_array->size(); i++)
2011 vogl_program_uniform_block_state &state = m_uniform_blocks[i];
2013 const json_node &uniform_block_node = *pActive_uniforms_blocks_array->get_value_as_object(i);
2015 state.m_uniform_block_index = uniform_block_node.value_as_uint32("block_index");
2016 state.m_name = uniform_block_node.value_as_string("name");
2017 state.m_uniform_block_binding_point = uniform_block_node.value_as_int("binding_point");
2018 state.m_uniform_block_data_size = uniform_block_node.value_as_int("data_size");
2019 state.m_uniform_block_active_uniforms = uniform_block_node.value_as_int("active_uniforms");
2024 const json_node *pOutputs_array = node.find_child_array("outputs");
2027 if (!pOutputs_array->are_all_children_objects())
2029 vogl_warning_printf("%s: outputs child array does not contain all child objects in trace program %u\n", VOGL_METHOD_NAME, m_snapshot_handle);
2033 m_outputs.resize(pOutputs_array->size());
2034 for (uint i = 0; i < pOutputs_array->size(); i++)
2036 const json_node &output_node = *pOutputs_array->get_value_as_object(i);
2038 vogl_program_output_state &output = m_outputs[i];
2042 output.m_name = output_node.value_as_string("name");
2043 output.m_location = output_node.value_as_int32("location");
2044 output.m_location_index = output_node.value_as_int32("location_index");
2045 output.m_type = vogl_get_json_value_as_enum(output_node, "type", GL_NONE);
2046 output.m_array_size = output_node.value_as_int32("array_size");
2047 output.m_is_per_patch = output_node.value_as_bool("is_per_patch");
2052 const json_node *pLink_time_snapshot_node = node.find_child_object("link_time_snapshot");
2053 if (pLink_time_snapshot_node)
2055 m_pLink_time_snapshot.reset(vogl_new(vogl_program_state));
2056 if (!m_pLink_time_snapshot->deserialize(*pLink_time_snapshot_node, blob_manager))
2059 if (!m_pLink_time_snapshot->is_valid())
2061 vogl_warning_printf("%s: Deserialized link-time snapshot, but it wasn't valid! Trace program %u\n", VOGL_METHOD_NAME, m_snapshot_handle);
2063 m_pLink_time_snapshot.reset();
2067 m_transform_feedback_mode = vogl_get_json_value_as_enum(node, "transform_feedback_mode", GL_NONE);
2068 m_transform_feedback_num_varyings = node.value_as_uint32("transform_feedback_num_varyings");
2070 if (m_transform_feedback_num_varyings)
2072 const json_node *pVaryings_array = node.find_child_array("transform_feedback_varyings");
2073 if (pVaryings_array)
2075 m_varyings.resize(m_transform_feedback_num_varyings);
2077 for (uint i = 0; i < m_transform_feedback_num_varyings; i++)
2079 const json_node &varying_node = *pVaryings_array->get_value_as_object(i);
2081 vogl_program_transform_feedback_varying &varying = m_varyings[i];
2085 m_varyings[i].m_index = varying_node.value_as_uint32("index");
2086 m_varyings[i].m_name = varying_node.value_as_string("name");
2087 m_varyings[i].m_size = varying_node.value_as_int("size");
2088 m_varyings[i].m_type = vogl_get_json_value_as_enum(varying_node, "type");
2093 vogl_warning_printf("%s: transform_feedback_num_varyings is %u, but the transform_feedback_varyings array wasn't found! Trace program %u\n", VOGL_METHOD_NAME, m_transform_feedback_num_varyings, m_snapshot_handle);
2097 m_transform_feedback_mode = GL_NONE;
2098 m_transform_feedback_num_varyings = 0;
2107 // TODO: This is not currently used for anything, needs more testing.
2108 // true if rhs is *exactly* the same.
2109 bool vogl_program_state::compare_full_state(const vogl_program_state &rhs) const
2117 CMP(m_link_snapshot);
2119 CMP(m_snapshot_handle);
2120 CMP(m_attached_shaders);
2123 CMP(m_uniform_blocks);
2127 CMP(m_num_active_attribs);
2128 CMP(m_num_active_uniforms);
2129 CMP(m_num_active_uniform_blocks);
2131 CMP(m_transform_feedback_mode);
2132 CMP(m_transform_feedback_num_varyings);
2135 CMP(m_marked_for_deletion);
2137 CMP(m_verify_status);
2141 if ((m_pLink_time_snapshot.get() != NULL) != (rhs.m_pLink_time_snapshot.get() != NULL))
2144 if (m_pLink_time_snapshot.get())
2146 if (!m_pLink_time_snapshot->compare_full_state(*rhs.m_pLink_time_snapshot.get()))
2150 if (m_shaders.size() != rhs.m_shaders.size())
2152 for (uint i = 0; i < m_shaders.size(); i++)
2153 if (!m_shaders[i].compare_full_state(rhs.m_shaders[i]))
2159 // TODO: This is not currently used for anything, needs more testing.
2160 // true if rhs is more or less GL equivalent (not everything in vogl_program_state is either restorable to a GL program object, or makes sense to restore).
2161 // Note that restoring a program on a different driver may result in the restored state's to not exactly match (due to different optimization levels for example).
2162 bool vogl_program_state::compare_restorable_state(const vogl_gl_object_state &rhs_obj) const
2166 if ((!m_is_valid) || (!rhs_obj.is_valid()))
2169 if (rhs_obj.get_type() != cGLSTProgram)
2172 const vogl_program_state &rhs = static_cast<const vogl_program_state &>(rhs_obj);
2181 CMP(m_link_snapshot);
2182 CMP(m_uniform_blocks);
2185 for (uint i = 0; i < m_attribs.size(); i++)
2187 if (m_attribs[i].m_name.begins_with("gl_", true))
2191 for (j = 0; j < rhs.m_attribs.size(); j++)
2192 if (m_attribs[i].m_name.compare(rhs.m_attribs[j].m_name, true) == 0)
2194 if (j == rhs.m_attribs.size())
2197 if (m_attribs[i].m_bound_location != rhs.m_attribs[j].m_bound_location)
2199 if (m_attribs[i].m_size != rhs.m_attribs[j].m_size)
2201 if (m_attribs[i].m_type != rhs.m_attribs[j].m_type)
2205 for (uint i = 0; i < m_uniforms.size(); i++)
2207 if (m_uniforms[i].m_name.begins_with("gl_", true))
2211 for (j = 0; j < rhs.m_uniforms.size(); j++)
2212 if (m_uniforms[i].m_name.compare(rhs.m_uniforms[j].m_name, true) == 0)
2214 if (j == rhs.m_uniforms.size())
2217 if (m_uniforms[i].m_base_location != rhs.m_uniforms[j].m_base_location)
2219 if (m_uniforms[i].m_size != rhs.m_uniforms[j].m_size)
2221 if (m_uniforms[i].m_type != rhs.m_uniforms[j].m_type)
2223 if (m_uniforms[i].m_data != rhs.m_uniforms[j].m_data)
2230 vogl_linked_program_state::vogl_linked_program_state()
2235 vogl_linked_program_state::vogl_linked_program_state(const vogl_linked_program_state &other)
2236 : m_linked_programs(other.m_linked_programs)
2241 vogl_linked_program_state::~vogl_linked_program_state()
2246 vogl_linked_program_state &vogl_linked_program_state::operator=(const vogl_linked_program_state &rhs)
2253 m_linked_programs = rhs.m_linked_programs;
2258 void vogl_linked_program_state::clear()
2262 m_linked_programs.clear();
2265 bool vogl_linked_program_state::add_snapshot(GLuint handle, const vogl_program_state &prog)
2269 m_linked_programs[handle] = prog;
2273 bool vogl_linked_program_state::add_snapshot(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint handle, GLenum binary_format, const void *pBinary, uint binary_size)
2277 vogl_program_state_map::insert_result res(m_linked_programs.insert(handle));
2279 vogl_program_state &prog = (res.first)->second;
2281 if (!prog.link_snapshot(context_info, remapper, handle, pBinary, binary_size, binary_format))
2283 m_linked_programs.erase(handle);
2290 bool vogl_linked_program_state::remove_snapshot(GLuint handle)
2294 return m_linked_programs.erase(handle);
2297 const vogl_program_state *vogl_linked_program_state::find_snapshot(GLuint handle) const
2301 return m_linked_programs.find_value(handle);
2304 vogl_program_state *vogl_linked_program_state::find_snapshot(GLuint handle)
2308 return m_linked_programs.find_value(handle);
2311 bool vogl_linked_program_state::serialize(json_node &node, vogl_blob_manager &blob_manager) const
2317 for (vogl_program_state_map::const_iterator it = m_linked_programs.begin(); it != m_linked_programs.end(); ++it)
2319 VOGL_ASSERT(it->first == it->second.get_snapshot_handle());
2321 if (!it->second.serialize(node.add_object(), blob_manager))
2328 bool vogl_linked_program_state::deserialize(const json_node &node, const vogl_blob_manager &blob_manager)
2334 if (!node.is_array() || !node.are_all_children_objects())
2341 vogl_program_state prog;
2343 for (uint i = 0; i < node.size(); i++)
2345 if (!prog.deserialize(*node.get_value_as_object(i), blob_manager))
2353 if (static_cast<uint32>(prog.get_snapshot_handle()) != prog.get_snapshot_handle())
2361 if (!m_linked_programs.insert(static_cast<uint32>(prog.get_snapshot_handle()), prog).second)
2373 bool vogl_linked_program_state::remap_handles(vogl_handle_remapper &remapper)
2377 vogl_program_state_map new_linked_programs;
2379 for (vogl_program_state_map::iterator it = m_linked_programs.begin(); it != m_linked_programs.end(); ++it)
2381 VOGL_ASSERT(it->first == it->second.get_snapshot_handle());
2383 GLuint new_handle = static_cast<uint32>(remapper.remap_handle(VOGL_NAMESPACE_PROGRAMS, it->first));
2385 vogl_program_state new_prog_state(it->second);
2386 if (!new_prog_state.remap_handles(remapper))
2389 VOGL_ASSERT(new_handle == new_prog_state.get_snapshot_handle());
2391 if (!new_linked_programs.insert(new_handle, new_prog_state).second)
2395 m_linked_programs.swap(new_linked_programs);