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_buffer_state.cpp
27 #include "vogl_common.h"
28 #include "vogl_buffer_state.h"
30 vogl_buffer_state::vogl_buffer_state()
31 : m_snapshot_handle(0),
38 vogl_buffer_state::~vogl_buffer_state()
43 // TODO: GL3/4 buffer types, add GL_QUERY_BUFFER
44 bool vogl_buffer_state::snapshot(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint64 handle, GLenum target)
48 VOGL_NOTE_UNUSED(remapper);
49 VOGL_NOTE_UNUSED(context_info);
55 VOGL_ASSERT(handle <= cUINT32_MAX);
57 m_snapshot_handle = static_cast<GLuint>(handle);
60 if (m_target != GL_NONE)
62 vogl_scoped_binding_state orig_bindings(target);
64 GL_ENTRYPOINT(glBindBuffer)(target, m_snapshot_handle);
67 bool any_gl_errors = false;
69 #define GET_INT(pname) \
73 GL_ENTRYPOINT(glGetBufferParameteriv)(m_target, pname, &value); \
74 if (vogl_check_gl_error()) \
75 any_gl_errors = true; \
76 m_params.insert(pname, 0, &value, sizeof(value)); \
79 GET_INT(GL_BUFFER_ACCESS);
80 GET_INT(GL_BUFFER_MAPPED);
81 GET_INT(GL_BUFFER_SIZE);
82 GET_INT(GL_BUFFER_USAGE);
86 GLvoid *pSnapshot_map_ptr;
87 GL_ENTRYPOINT(glGetBufferPointerv)(m_target, GL_BUFFER_MAP_POINTER, &pSnapshot_map_ptr);
88 if (vogl_check_gl_error())
93 vogl_error_printf("%s: GL error while retrieving buffer %" PRIu64 " target %s's params\n", VOGL_METHOD_NAME,
94 (uint64_t)handle, g_gl_enums.find_gl_name(target));
99 if (m_params.get_value<int>(GL_BUFFER_MAPPED) != 0)
101 vogl_error_printf("%s: Can't snapshot buffer %" PRIu64 " target %s while it's currently mapped\n", VOGL_METHOD_NAME,
102 (uint64_t)handle, g_gl_enums.find_gl_name(target));
107 int buf_size = m_params.get_value<int>(GL_BUFFER_SIZE);
110 vogl_error_printf("%s: Invalid buffer size, buffer %" PRIu64 " target %s size %i\n", VOGL_METHOD_NAME, (uint64_t)handle, g_gl_enums.find_gl_name(target), buf_size);
117 if (!m_buffer_data.try_resize(buf_size))
119 vogl_error_printf("%s: Out of memory while trying to allocate buffer, buffer %" PRIu64 " target %s size %i\n", VOGL_METHOD_NAME, (uint64_t)handle, g_gl_enums.find_gl_name(target), buf_size);
124 // This will fail if the buffer is currently mapped.
125 GL_ENTRYPOINT(glGetBufferSubData)(target, 0, buf_size, m_buffer_data.get_ptr());
127 if (vogl_check_gl_error())
129 vogl_warning_printf("%s: GL error while retrieving buffer data, buffer %" PRIu64 " target %s size %i\n", VOGL_METHOD_NAME, (uint64_t)handle, g_gl_enums.find_gl_name(target), buf_size);
139 bool vogl_buffer_state::restore(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint64 &handle) const
143 VOGL_NOTE_UNUSED(context_info);
145 int buf_usage = 0, buf_size = 0;
152 bool created_handle = false;
157 GL_ENTRYPOINT(glGenBuffers)(1, &handle32);
158 if ((vogl_check_gl_error()) || (!handle32))
163 remapper.declare_handle(VOGL_NAMESPACE_BUFFERS, m_snapshot_handle, handle, m_target);
164 VOGL_ASSERT(remapper.remap_handle(VOGL_NAMESPACE_BUFFERS, m_snapshot_handle) == handle);
166 created_handle = true;
169 if (m_target != GL_NONE)
171 vogl_scoped_binding_state orig_bindings(m_target);
173 GL_ENTRYPOINT(glBindBuffer)(m_target, static_cast<GLuint>(handle));
174 if (vogl_check_gl_error())
177 buf_usage = m_params.get_value<int>(GL_BUFFER_USAGE);
178 buf_size = m_params.get_value<int>(GL_BUFFER_SIZE);
180 if (buf_size != static_cast<int>(m_buffer_data.size()))
186 GL_ENTRYPOINT(glBufferData)(m_target, buf_size, m_buffer_data.get_ptr(), buf_usage);
187 if (vogl_check_gl_error())
194 vogl_error_printf("%s: Failed restoring trace buffer %u target %s size %u\n", VOGL_METHOD_NAME, m_snapshot_handle, g_gl_enums.find_gl_name(m_target), buf_size);
196 GL_ENTRYPOINT(glBindBuffer)(m_target, 0);
199 if ((handle) && (created_handle))
201 remapper.delete_handle_and_object(VOGL_NAMESPACE_BUFFERS, m_snapshot_handle, handle);
203 //GLuint handle32 = static_cast<GLuint>(handle);
204 //GL_ENTRYPOINT(glDeleteBuffers)(1, &handle32);
205 //VOGL_CHECK_GL_ERROR;
213 bool vogl_buffer_state::remap_handles(vogl_handle_remapper &remapper)
220 m_snapshot_handle = static_cast<GLuint>(remapper.remap_handle(VOGL_NAMESPACE_BUFFERS, m_snapshot_handle));
225 void vogl_buffer_state::clear()
229 m_snapshot_handle = 0;
231 m_buffer_data.clear();
236 bool vogl_buffer_state::serialize(json_node &node, vogl_blob_manager &blob_manager) const
243 dynamic_string blob_id;
245 if (m_buffer_data.size())
247 const char *pBuf_type = utils::map_value(static_cast<int>(m_target), "buf",
248 GL_ARRAY_BUFFER, "buf_vertex",
249 GL_ELEMENT_ARRAY_BUFFER, "buf_index",
250 GL_UNIFORM_BUFFER, "buf_uniform");
252 dynamic_string prefix;
253 prefix.format("%s_0x%04X", pBuf_type, m_params.get_value<int>(GL_BUFFER_USAGE));
255 blob_id = blob_manager.add_buf_compute_unique_id(m_buffer_data.get_ptr(), m_buffer_data.size(), prefix.get_ptr(), "raw");
256 if (blob_id.is_empty())
260 node.add_key_value("handle", m_snapshot_handle);
261 node.add_key_value("target", g_gl_enums.find_gl_name(m_target));
262 node.add_key_value("buffer_data_blob_id", blob_id);
264 if (!m_params.serialize(node.add_object("params"), blob_manager))
270 bool vogl_buffer_state::deserialize(const json_node &node, const vogl_blob_manager &blob_manager)
276 m_snapshot_handle = node.value_as_uint32("handle");
277 m_target = vogl_get_json_value_as_enum(node, "target");
278 if (m_target != GL_NONE)
280 const json_node *pParams_obj = node.find_child_object("params");
287 if (!m_params.deserialize(*pParams_obj, blob_manager))
293 int buf_size = m_params.get_value<int>(GL_BUFFER_SIZE);
297 dynamic_string blob_id(node.value_as_string_ptr("buffer_data_blob_id"));
298 if (blob_id.is_empty())
304 if (!blob_manager.get(blob_id, m_buffer_data))
311 if (buf_size != static_cast<int>(m_buffer_data.size()))
323 // Content comparison, ignores handle.
324 bool vogl_buffer_state::compare_restorable_state(const vogl_gl_object_state &rhs_obj) const
328 if ((!m_is_valid) || (!rhs_obj.is_valid()))
331 if (rhs_obj.get_type() != cGLSTBuffer)
334 const vogl_buffer_state &rhs = static_cast<const vogl_buffer_state &>(rhs_obj);
339 if (m_target != rhs.m_target)
342 if (m_buffer_data != rhs.m_buffer_data)
345 if (m_params != rhs.m_params)