bool vogl_vao_state::remap_handles(vogl_handle_remapper &remapper) { VOGL_FUNC_TRACER m_snapshot_handle = static_cast<GLuint>(remapper.remap_handle(VOGL_NAMESPACE_VERTEX_ARRAYS, m_snapshot_handle)); if (m_element_array_binding) m_element_array_binding = static_cast<GLuint>(remapper.remap_handle(VOGL_NAMESPACE_BUFFERS, m_element_array_binding)); for (uint32_t i = 0; i < m_vertex_attribs.size(); i++) { if (m_vertex_attribs[i].m_array_binding) m_vertex_attribs[i].m_array_binding = static_cast<GLuint>(remapper.remap_handle(VOGL_NAMESPACE_BUFFERS, m_vertex_attribs[i].m_array_binding)); else if (m_vertex_attribs[i].m_pointer) m_vertex_attribs[i].m_pointer = remapper.remap_vertex_attrib_ptr(i, m_vertex_attribs[i].m_pointer); } return true; }
bool vogl_vao_state::restore(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint64 &handle) const { VOGL_FUNC_TRACER VOGL_CHECK_GL_ERROR; if (!m_is_valid) return false; vogl_scoped_binding_state orig_binding(GL_VERTEX_ARRAY, GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER); if ((!m_snapshot_handle) && (!handle)) { GL_ENTRYPOINT(glBindVertexArray)(0); VOGL_CHECK_GL_ERROR; } else { if (!handle) { GLuint handle32 = 0; GL_ENTRYPOINT(glGenVertexArrays)(1, &handle32); if ((vogl_check_gl_error()) || (!handle32)) return false; handle = handle32; if (m_snapshot_handle) { remapper.declare_handle(VOGL_NAMESPACE_VERTEX_ARRAYS, m_snapshot_handle, handle, GL_NONE); VOGL_ASSERT(remapper.remap_handle(VOGL_NAMESPACE_VERTEX_ARRAYS, m_snapshot_handle) == handle); } } if (m_has_been_bound) { GL_ENTRYPOINT(glBindVertexArray)(static_cast<GLuint>(handle)); VOGL_CHECK_GL_ERROR; } } if (m_has_been_bound) { GL_ENTRYPOINT(glBindBuffer)(GL_ELEMENT_ARRAY_BUFFER, static_cast<GLuint>(remapper.remap_handle(VOGL_NAMESPACE_BUFFERS, m_element_array_binding))); VOGL_CHECK_GL_ERROR; if (m_vertex_attribs.size() > context_info.get_max_vertex_attribs()) { vogl_warning_printf("Saved VAO state has %u attribs, but context only allows %u attribs\n", m_vertex_attribs.size(), context_info.get_max_vertex_attribs()); } for (uint32_t i = 0; i < math::minimum<uint32_t>(context_info.get_max_vertex_attribs(), m_vertex_attribs.size()); i++) { const vogl_vertex_attrib_desc &desc = m_vertex_attribs[i]; GL_ENTRYPOINT(glBindBuffer)(GL_ARRAY_BUFFER, static_cast<GLuint>(remapper.remap_handle(VOGL_NAMESPACE_BUFFERS, desc.m_array_binding))); VOGL_CHECK_GL_ERROR; vogl_trace_ptr_value trace_ptr_val = desc.m_pointer; vogl_trace_ptr_value restore_ptr_val = trace_ptr_val; if ((!desc.m_array_binding) && (trace_ptr_val) && (context_info.is_compatibility_profile())) restore_ptr_val = remapper.remap_vertex_attrib_ptr(i, trace_ptr_val); void *pRestore_ptr = reinterpret_cast<void *>(restore_ptr_val); if ((handle) && (desc.m_array_binding == 0)) { // 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) // "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]" // Sanity checks. if ((pRestore_ptr != NULL) || (desc.m_stride) || (desc.m_enabled)) { vogl_warning_printf("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", m_snapshot_handle, static_cast<uint32_t>(handle), pRestore_ptr, desc.m_size, desc.m_stride, desc.m_enabled); } } else { if (desc.m_integer) { GL_ENTRYPOINT(glVertexAttribIPointer)(i, desc.m_size, desc.m_type, desc.m_stride, pRestore_ptr); VOGL_CHECK_GL_ERROR; } else { GL_ENTRYPOINT(glVertexAttribPointer)(i, desc.m_size, desc.m_type, desc.m_normalized, desc.m_stride, pRestore_ptr); VOGL_CHECK_GL_ERROR; } } GL_ENTRYPOINT(glVertexAttribDivisor)(i, desc.m_divisor); VOGL_CHECK_GL_ERROR; if (desc.m_enabled) { GL_ENTRYPOINT(glEnableVertexAttribArray)(i); VOGL_CHECK_GL_ERROR; } else { GL_ENTRYPOINT(glDisableVertexAttribArray)(i); VOGL_CHECK_GL_ERROR; } } } return true; }