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_vao_state.cpp
27 #include "vogl_vao_state.h"
29 bool vogl_vertex_attrib_desc::operator==(const vogl_vertex_attrib_desc &rhs) const
37 CMP(m_element_array_binding);
50 vogl_vao_state::vogl_vao_state()
51 : m_snapshot_handle(0),
52 m_has_been_bound(false),
58 vogl_vao_state::~vogl_vao_state()
63 static int vogl_get_vertex_attrib_int(uint index, GLenum pname)
67 int values[4] = { 0, 0, 0, 0 };
68 GL_ENTRYPOINT(glGetVertexAttribIiv)(index, pname, values);
72 static uint vogl_get_vertex_attrib_uint(uint index, GLenum pname)
76 uint values[4] = { 0, 0, 0, 0 };
77 GL_ENTRYPOINT(glGetVertexAttribIuiv)(index, pname, values);
82 static vec4D vogl_get_vertex_attrib_vec4D(uint index, GLenum pname)
85 ACTUAL_GL_ENTRYPOINT(glGetVertexAttribdv)(index, pname, &values[0]);
90 bool vogl_vao_state::snapshot(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint64 handle, GLenum target)
94 VOGL_NOTE_UNUSED(target);
95 VOGL_NOTE_UNUSED(remapper);
101 VOGL_ASSERT(handle <= cUINT32_MAX);
103 m_snapshot_handle = static_cast<GLuint>(handle);
105 // TODO: Core profile support
106 m_has_been_bound = handle ? (GL_ENTRYPOINT(glIsVertexArray)(static_cast<GLuint>(handle)) != 0) : true;
108 if (m_has_been_bound)
110 vogl_scoped_binding_state orig_binding(GL_VERTEX_ARRAY);
112 GL_ENTRYPOINT(glBindVertexArray)(m_snapshot_handle);
115 m_vertex_attribs.resize(context_info.get_max_vertex_attribs());
117 for (uint i = 0; i < context_info.get_max_vertex_attribs(); i++)
119 vogl_vertex_attrib_desc &desc = m_vertex_attribs[i];
121 desc.m_element_array_binding = vogl_get_gl_integer(GL_ELEMENT_ARRAY_BUFFER_BINDING);
122 desc.m_array_binding = vogl_get_vertex_attrib_int(i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING);
123 desc.m_enabled = vogl_get_vertex_attrib_int(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED) != 0;
124 desc.m_size = vogl_get_vertex_attrib_int(i, GL_VERTEX_ATTRIB_ARRAY_SIZE);
125 desc.m_type = vogl_get_vertex_attrib_int(i, GL_VERTEX_ATTRIB_ARRAY_TYPE);
126 desc.m_normalized = vogl_get_vertex_attrib_int(i, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED) != 0;
127 desc.m_stride = vogl_get_vertex_attrib_int(i, GL_VERTEX_ATTRIB_ARRAY_STRIDE);
128 desc.m_integer = vogl_get_vertex_attrib_int(i, GL_VERTEX_ATTRIB_ARRAY_INTEGER) != 0;
129 desc.m_divisor = vogl_get_vertex_attrib_uint(i, GL_VERTEX_ATTRIB_ARRAY_DIVISOR);
132 GL_ENTRYPOINT(glGetVertexAttribPointerv)(i, GL_VERTEX_ATTRIB_ARRAY_POINTER, &ptr);
133 desc.m_pointer = reinterpret_cast<vogl_trace_ptr_value>(ptr);
144 bool vogl_vao_state::restore(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint64 &handle) const
153 vogl_scoped_binding_state orig_binding(GL_VERTEX_ARRAY, GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER);
155 if ((!m_snapshot_handle) && (!handle))
157 GL_ENTRYPOINT(glBindVertexArray)(0);
165 GL_ENTRYPOINT(glGenVertexArrays)(1, &handle32);
166 if ((vogl_check_gl_error()) || (!handle32))
170 if (m_snapshot_handle)
172 remapper.declare_handle(VOGL_NAMESPACE_VERTEX_ARRAYS, m_snapshot_handle, handle, GL_NONE);
173 VOGL_ASSERT(remapper.remap_handle(VOGL_NAMESPACE_VERTEX_ARRAYS, m_snapshot_handle) == handle);
177 if (m_has_been_bound)
179 GL_ENTRYPOINT(glBindVertexArray)(static_cast<GLuint>(handle));
184 if (m_has_been_bound)
186 if (m_vertex_attribs.size() > context_info.get_max_vertex_attribs())
188 vogl_warning_printf("%s: Saved VAO state has %u attribs, but context only allows %u attribs\n", VOGL_METHOD_NAME, m_vertex_attribs.size(), context_info.get_max_vertex_attribs());
191 for (uint i = 0; i < math::minimum<uint>(context_info.get_max_vertex_attribs(), m_vertex_attribs.size()); i++)
193 const vogl_vertex_attrib_desc &desc = m_vertex_attribs[i];
195 GL_ENTRYPOINT(glBindBuffer)(GL_ELEMENT_ARRAY_BUFFER, static_cast<GLuint>(remapper.remap_handle(VOGL_NAMESPACE_BUFFERS, desc.m_element_array_binding)));
198 GL_ENTRYPOINT(glBindBuffer)(GL_ARRAY_BUFFER, static_cast<GLuint>(remapper.remap_handle(VOGL_NAMESPACE_BUFFERS, desc.m_array_binding)));
201 vogl_trace_ptr_value trace_ptr_val = desc.m_pointer;
203 vogl_trace_ptr_value restore_ptr_val = trace_ptr_val;
204 if ((!desc.m_array_binding) && (trace_ptr_val) && (context_info.is_compatibility_profile()))
205 restore_ptr_val = remapper.remap_vertex_attrib_ptr(i, trace_ptr_val);
207 void *pRestore_ptr = reinterpret_cast<void *>(restore_ptr_val);
209 if ((handle) && (desc.m_array_binding == 0))
211 // If it's a non-default VAO, and there's no array binding, we can't call glVertexAttribPointer() because it's not allowed by AMD drivers (it thinks we're trying to set client side array data)
212 // "OpenGL: glVertexAttribPointer failed because it is not allowed to specify a client-side vertex or element array when a non-default vertex array object is bound (GL_INVALID_OPERATION) [source=API type=ERROR severity=HIGH id=2100]"
215 if ((pRestore_ptr != NULL) || (desc.m_stride) || (desc.m_enabled))
217 vogl_warning_printf("%s: Can't bind client side vertex array data on a non-default VAO, trace handle %u GL handle %u, restore ptr %p, size %i stride %i enabled %u\n",
218 VOGL_METHOD_NAME, m_snapshot_handle, static_cast<uint>(handle), pRestore_ptr, desc.m_size, desc.m_stride, desc.m_enabled);
225 GL_ENTRYPOINT(glVertexAttribIPointer)(i, desc.m_size, desc.m_type, desc.m_stride, pRestore_ptr);
230 GL_ENTRYPOINT(glVertexAttribPointer)(i, desc.m_size, desc.m_type, desc.m_normalized, desc.m_stride, pRestore_ptr);
235 GL_ENTRYPOINT(glVertexAttribDivisor)(i, desc.m_divisor);
240 GL_ENTRYPOINT(glEnableVertexAttribArray)(i);
245 GL_ENTRYPOINT(glDisableVertexAttribArray)(i);
254 bool vogl_vao_state::remap_handles(vogl_handle_remapper &remapper)
258 m_snapshot_handle = static_cast<GLuint>(remapper.remap_handle(VOGL_NAMESPACE_VERTEX_ARRAYS, m_snapshot_handle));
260 for (uint i = 0; i < m_vertex_attribs.size(); i++)
262 if (m_vertex_attribs[i].m_element_array_binding)
263 m_vertex_attribs[i].m_element_array_binding = static_cast<GLuint>(remapper.remap_handle(VOGL_NAMESPACE_BUFFERS, m_vertex_attribs[i].m_element_array_binding));
265 if (m_vertex_attribs[i].m_array_binding)
266 m_vertex_attribs[i].m_array_binding = static_cast<GLuint>(remapper.remap_handle(VOGL_NAMESPACE_BUFFERS, m_vertex_attribs[i].m_array_binding));
268 else if (m_vertex_attribs[i].m_pointer)
269 m_vertex_attribs[i].m_pointer = remapper.remap_vertex_attrib_ptr(i, m_vertex_attribs[i].m_pointer);
275 void vogl_vao_state::clear()
279 m_vertex_attribs.clear();
280 m_snapshot_handle = 0;
281 m_has_been_bound = false;
285 bool vogl_vao_state::serialize(json_node &node, vogl_blob_manager &blob_manager) const
289 VOGL_NOTE_UNUSED(blob_manager);
294 node.add_key_value("handle", m_snapshot_handle);
295 node.add_key_value("has_been_bound", m_has_been_bound);
297 json_node &vertex_attribs_array = node.add_array("vertex_attribs");
298 for (uint i = 0; i < m_vertex_attribs.size(); i++)
300 const vogl_vertex_attrib_desc &desc = m_vertex_attribs[i];
302 json_node &attribs_obj = vertex_attribs_array.add_object();
303 attribs_obj.add_key_value("pointer", desc.m_pointer);
304 attribs_obj.add_key_value("element_array_binding", desc.m_element_array_binding);
305 attribs_obj.add_key_value("array_binding", desc.m_array_binding);
306 attribs_obj.add_key_value("size", desc.m_size);
307 attribs_obj.add_key_value("type", g_gl_enums.find_gl_name(desc.m_type));
308 attribs_obj.add_key_value("stride", desc.m_stride);
309 attribs_obj.add_key_value("integer", desc.m_integer);
310 attribs_obj.add_key_value("divisor", desc.m_divisor);
311 attribs_obj.add_key_value("enabled", desc.m_enabled);
312 attribs_obj.add_key_value("normalized", desc.m_normalized);
318 bool vogl_vao_state::deserialize(const json_node &node, const vogl_blob_manager &blob_manager)
322 VOGL_NOTE_UNUSED(blob_manager);
326 m_snapshot_handle = node.value_as_uint32("handle");
327 m_has_been_bound = node.value_as_bool("has_been_bound", true);
329 const json_node *pVertex_attribs_array = node.find_child_array("vertex_attribs");
330 if (!pVertex_attribs_array)
333 m_vertex_attribs.resize(pVertex_attribs_array->size());
334 for (uint i = 0; i < pVertex_attribs_array->size(); i++)
336 vogl_vertex_attrib_desc &desc = m_vertex_attribs[i];
338 const json_node *pAttribs_obj = pVertex_attribs_array->get_value_as_object(i);
342 desc.m_pointer = static_cast<vogl_trace_ptr_value>(pAttribs_obj->value_as_uint64("pointer"));
343 desc.m_element_array_binding = pAttribs_obj->value_as_uint32("element_array_binding");
344 desc.m_array_binding = pAttribs_obj->value_as_uint32("array_binding");
345 desc.m_size = pAttribs_obj->value_as_int("size");
346 desc.m_type = vogl_get_json_value_as_enum(*pAttribs_obj, "type");
347 desc.m_stride = pAttribs_obj->value_as_int("stride");
348 desc.m_integer = pAttribs_obj->value_as_bool("integer");
349 desc.m_divisor = pAttribs_obj->value_as_uint32("divisor");
350 desc.m_enabled = pAttribs_obj->value_as_bool("enabled");
351 desc.m_normalized = pAttribs_obj->value_as_bool("normalized");
359 bool vogl_vao_state::compare_all_state(const vogl_vao_state &rhs) const
363 if ((!is_valid()) || (!rhs.is_valid()))
369 return (m_snapshot_handle == rhs.m_snapshot_handle) && (m_vertex_attribs == rhs.m_vertex_attribs) && (m_has_been_bound == rhs.m_has_been_bound);
372 bool vogl_vao_state::compare_restorable_state(const vogl_gl_object_state &rhs_obj) const
376 if ((!is_valid()) || (!rhs_obj.is_valid()))
379 if (rhs_obj.get_type() != cGLSTVertexArray)
382 const vogl_vao_state &rhs = static_cast<const vogl_vao_state &>(rhs_obj);
387 if (m_has_been_bound != rhs.m_has_been_bound)
390 if (m_vertex_attribs.size() != rhs.m_vertex_attribs.size())
393 for (uint i = 0; i < m_vertex_attribs.size(); i++)
395 const vogl_vertex_attrib_desc &lhs_desc = m_vertex_attribs[i];
396 const vogl_vertex_attrib_desc &rhs_desc = rhs.m_vertex_attribs[i];
398 if ((lhs_desc.m_element_array_binding != 0) != (rhs_desc.m_element_array_binding != 0))
401 if ((lhs_desc.m_array_binding != 0) != (rhs_desc.m_array_binding != 0))
405 if (lhs_desc.x != rhs_desc.x) \