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_arb_program_state.cpp
27 #include "vogl_arb_program_state.h"
29 static const char *vogl_get_arb_program_target_name(GLenum target)
33 VOGL_ASSERT((target == GL_VERTEX_PROGRAM_ARB) || (target == GL_FRAGMENT_PROGRAM_ARB));
34 return (target == GL_VERTEX_PROGRAM_ARB) ? "vertex" : "fragment";
37 vogl_arb_program_state::vogl_arb_program_state()
38 : m_snapshot_handle(0),
42 m_num_instructions(0),
43 m_program_format(GL_NONE),
49 vogl_arb_program_state::~vogl_arb_program_state()
54 GLint vogl_arb_program_state::get_program_int(GLenum pname) const
59 GL_ENTRYPOINT(glGetProgramivARB)(m_target, pname, &val);
64 bool vogl_arb_program_state::snapshot(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint64 handle, GLenum target)
68 VOGL_NOTE_UNUSED(context_info);
69 VOGL_NOTE_UNUSED(remapper);
75 VOGL_ASSERT(handle <= cUINT32_MAX);
77 m_snapshot_handle = static_cast<GLuint>(handle);
80 if (m_target != GL_NONE)
82 vogl_scoped_state_saver state_saver(cGSTARBVertexProgram, cGSTARBFragmentProgram);
84 GL_ENTRYPOINT(glBindProgramARB)(m_target, m_snapshot_handle);
87 m_program_format = get_program_int(GL_PROGRAM_FORMAT_ARB);
89 // Note: there doesn't seem a way to query if this program was compiled sucessfully (without trying to recompile it)?
90 m_num_instructions = get_program_int(GL_PROGRAM_INSTRUCTIONS_ARB);
91 m_is_native = get_program_int(GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB) != 0;
93 int program_len = get_program_int(GL_PROGRAM_LENGTH_ARB);
94 if ((program_len < 0) || (!m_program_string.try_resize(program_len)))
102 GL_ENTRYPOINT(glGetProgramStringARB)(m_target, GL_PROGRAM_STRING_ARB, m_program_string.get_ptr());
106 int num_local_params = get_program_int(GL_PROGRAM_PARAMETERS_ARB);
107 if ((num_local_params < 0) || (!m_local_params.try_resize(num_local_params)))
113 for (int i = 0; i < num_local_params; i++)
115 GL_ENTRYPOINT(glGetProgramLocalParameterfvARB)(m_target, i, m_local_params[i].get_ptr());
125 bool vogl_arb_program_state::restore(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint64 &handle) const
129 VOGL_NOTE_UNUSED(context_info);
136 bool created_handle = false;
137 VOGL_NOTE_UNUSED(created_handle);
139 VOGL_ASSERT(static_cast<GLuint>(handle) == handle);
141 GLuint handle32 = static_cast<GLuint>(handle);
145 GL_ENTRYPOINT(glGenProgramsARB)(1, &handle32);
146 if ((vogl_check_gl_error()) || (!handle32))
151 remapper.declare_handle(VOGL_NAMESPACE_PROGRAM_ARB, m_snapshot_handle, handle, m_target);
152 VOGL_ASSERT(remapper.remap_handle(VOGL_NAMESPACE_PROGRAM_ARB, m_snapshot_handle) == handle);
154 created_handle = true;
157 if (m_target != GL_NONE)
159 vogl_scoped_state_saver state_saver(cGSTARBVertexProgram, cGSTARBFragmentProgram);
161 GL_ENTRYPOINT(glBindProgramARB)(m_target, handle32);
164 if (m_program_string.size() && (m_program_format != GL_NONE))
166 GL_ENTRYPOINT(glProgramStringARB)(m_target, m_program_format, m_program_string.size(), m_program_string.get_ptr());
168 bool failed = vogl_check_gl_error();
170 m_error_position = vogl_get_gl_integer(GL_PROGRAM_ERROR_POSITION_ARB);
171 m_is_native = get_program_int(GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB) != 0;
173 if ((failed) || (m_error_position >= 0) || (!m_is_native))
175 const GLubyte *pError_string = NULL;
176 pError_string = static_cast<const GLubyte *>(GL_ENTRYPOINT(glGetString)(GL_PROGRAM_ERROR_STRING_ARB));
179 m_error_string.set(pError_string ? reinterpret_cast<const char *>(pError_string) : "");
181 vogl_error_printf("%s: Failed restoring ARB %s shader, GL handle %u, error position %i, is native: %u, error string: %s\n", VOGL_METHOD_NAME,
182 vogl_get_arb_program_target_name(m_target), handle32, m_error_position, m_is_native, m_error_string.get_ptr());
186 for (uint i = 0; i < m_local_params.size(); i++)
188 GL_ENTRYPOINT(glProgramLocalParameter4fvARB)(m_target, i, m_local_params[i].get_ptr());
196 bool vogl_arb_program_state::remap_handles(vogl_handle_remapper &remapper)
203 uint replay_handle = m_snapshot_handle;
204 VOGL_NOTE_UNUSED(replay_handle);
206 uint trace_handle = static_cast<GLuint>(remapper.remap_handle(VOGL_NAMESPACE_PROGRAM_ARB, m_snapshot_handle));
208 m_snapshot_handle = trace_handle;
213 void vogl_arb_program_state::clear()
217 m_snapshot_handle = 0;
220 m_error_position = -1;
221 m_error_string.clear();
223 m_program_format = GL_NONE;
224 m_num_instructions = 0;
226 m_program_string.clear();
227 m_local_params.clear();
232 bool vogl_arb_program_state::serialize(json_node &node, vogl_blob_manager &blob_manager) const
239 node.add_key_value("snapshot_handle", m_snapshot_handle);
240 node.add_key_value("target", g_gl_enums.find_gl_name(m_target));
241 node.add_key_value("error_position", m_error_position);
242 node.add_key_value("error_string", m_error_string);
243 node.add_key_value("is_native", m_is_native);
244 node.add_key_value("num_instructions", m_num_instructions);
245 node.add_key_value("program_format", g_gl_enums.find_gl_name(m_program_format));
247 if (m_program_string.size())
249 dynamic_string prefix(cVarArg, "arb_%s_program", vogl_get_arb_program_target_name(m_target));
251 dynamic_string id(blob_manager.add_buf_compute_unique_id(m_program_string.get_ptr(), m_program_string.size(), prefix.get_ptr(), "txt"));
255 node.add_key_value("program_string", id);
258 if (m_local_params.size())
260 json_node ¶m_array = node.add_array("local_params");
261 for (uint i = 0; i < m_local_params.size(); i++)
262 if (!vogl_json_serialize_vec4F(param_array.add_array(), m_local_params[i]))
269 bool vogl_arb_program_state::deserialize(const json_node &node, const vogl_blob_manager &blob_manager)
275 if (!node.is_object())
278 m_snapshot_handle = node.value_as_int("snapshot_handle");
279 m_target = vogl_get_json_value_as_enum(node, "target");
280 m_error_position = node.value_as_int("error_position");
281 m_error_string = node.value_as_string("error_string");
282 m_is_native = node.value_as_bool("is_native");
283 m_num_instructions = node.value_as_int("num_instructions");
284 m_program_format = vogl_get_json_value_as_enum(node, "program_format");
286 if (node.has_key("program_string"))
288 if (!blob_manager.get(node.value_as_string("program_string"), m_program_string))
295 const json_node *pParams_node = node.find_child_array("local_params");
298 if (!pParams_node->are_all_children_arrays())
301 m_local_params.resize(pParams_node->size());
302 for (uint i = 0; i < pParams_node->size(); i++)
304 if (!vogl_json_deserialize_vec4F(*pParams_node->get_child(i), m_local_params[i]))
317 bool vogl_arb_program_state::compare_restorable_state(const vogl_gl_object_state &rhs_obj) const
321 if ((!m_is_valid) || (!rhs_obj.is_valid()))
324 if (get_type() != rhs_obj.get_type())
327 const vogl_arb_program_state &rhs = static_cast<const vogl_arb_program_state &>(rhs_obj);
336 CMP(m_program_format);
337 CMP(m_program_string);
338 CMP(m_local_params.size());
341 for (uint i = 0; i < m_local_params.size(); i++)
342 if (!m_local_params[i].equal_tol(rhs.m_local_params[i], .00125f))
348 vogl_arb_program_environment_state::vogl_arb_program_environment_state()
353 VOGL_ASSUME(cNumTargets == 2);
355 utils::zero_object(m_cur_programs);
358 vogl_arb_program_environment_state::~vogl_arb_program_environment_state()
363 bool vogl_arb_program_environment_state::snapshot(const vogl_context_info &context_info)
371 for (uint i = 0; i < cNumTargets; i++)
373 GLenum target = get_target_enum(i);
375 GL_ENTRYPOINT(glGetProgramivARB)(target, GL_PROGRAM_BINDING_ARB, reinterpret_cast<GLint *>(&m_cur_programs[i]));
378 GLuint num = (i == cVertexTarget) ? context_info.get_max_arb_vertex_program_env_params() : context_info.get_max_arb_fragment_program_env_params();
380 m_env_params[i].resize(num);
381 for (uint j = 0; j < num; j++)
383 GL_ENTRYPOINT(glGetProgramEnvParameterfvARB)(target, j, m_env_params[i][j].get_ptr());
393 bool vogl_arb_program_environment_state::restore(const vogl_context_info &context_info, vogl_handle_remapper &trace_to_replay_remapper) const
405 for (uint i = 0; i < cNumTargets; i++)
407 GLenum target = get_target_enum(i);
409 GLuint binding = static_cast<GLuint>(trace_to_replay_remapper.remap_handle(VOGL_NAMESPACE_PROGRAM_ARB, m_cur_programs[i]));
411 GL_ENTRYPOINT(glBindProgramARB)(target, binding);
414 GLuint num = (i == cVertexTarget) ? context_info.get_max_arb_vertex_program_env_params() : context_info.get_max_arb_fragment_program_env_params();
416 if (m_env_params[i].size() > num)
417 vogl_error_printf("%s: Context only supports %u max ARB program env programs, but the snapshot has %u params\n", VOGL_METHOD_NAME, num, m_env_params[i].size());
419 num = math::minimum<uint>(num, m_env_params[i].size());
421 for (uint j = 0; j < num; j++)
423 GL_ENTRYPOINT(glProgramEnvParameter4fvARB)(target, j, m_env_params[i][j].get_ptr());
431 bool vogl_arb_program_environment_state::remap_handles(vogl_handle_remapper &remapper)
441 for (uint target = 0; target < cNumTargets; target++)
443 uint replay_handle = m_cur_programs[target];
446 uint trace_handle = static_cast<GLuint>(remapper.remap_handle(VOGL_NAMESPACE_PROGRAM_ARB, replay_handle));
448 m_cur_programs[target] = trace_handle;
455 void vogl_arb_program_environment_state::clear()
459 utils::zero_object(m_cur_programs);
463 for (uint i = 0; i < cNumTargets; i++)
464 m_env_params[i].clear();
467 bool vogl_arb_program_environment_state::serialize(json_node &node, vogl_blob_manager &blob_manager) const
471 VOGL_NOTE_UNUSED(blob_manager);
479 for (uint target = 0; target < cNumTargets; target++)
481 json_node &state_node = node.add_object(get_target_index_name(target));
483 state_node.add_key_value("cur_program", m_cur_programs[target]);
485 json_node &env_params_node = state_node.add_array("env_params");
487 for (uint j = 0; j < m_env_params[target].size(); j++)
488 if (!vogl_json_serialize_vec4F(env_params_node.add_array(), m_env_params[target][j]))
495 bool vogl_arb_program_environment_state::deserialize(const json_node &node, const vogl_blob_manager &blob_manager)
499 VOGL_NOTE_UNUSED(blob_manager);
503 if (!node.is_object())
506 for (uint target = 0; target < cNumTargets; target++)
508 const json_node *pState = node.find_child_object(get_target_index_name(target));
512 m_cur_programs[target] = pState->value_as_uint32("cur_program");
514 const json_node *pArray = pState->find_child_array("env_params");
517 m_env_params[target].resize(pArray->size());
518 for (uint i = 0; i < pArray->size(); i++)
520 if (!vogl_json_deserialize_vec4F(*pArray->get_value_as_array(i), m_env_params[target][i]))
534 bool vogl_arb_program_environment_state::compare_restorable_state(const vogl_arb_program_environment_state &rhs) const
538 if (m_is_valid != rhs.m_is_valid)
544 for (uint i = 0; i < cNumTargets; i++)
546 if (m_cur_programs[i] != rhs.m_cur_programs[i])
549 if (m_env_params[i].size() != rhs.m_env_params[i].size())
552 for (uint j = 0; j < m_env_params[i].size(); j++)
553 if (!m_env_params[i][j].equal_tol(rhs.m_env_params[i][j], .00125f))