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"
29 #include "vogl_gl_state_snapshot.h"
31 vogl_buffer_state::vogl_buffer_state()
32 : m_snapshot_handle(0),
39 vogl_buffer_state::~vogl_buffer_state()
44 // TODO: GL3/4 buffer types, add GL_QUERY_BUFFER
45 bool vogl_buffer_state::snapshot(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint64 handle, GLenum target)
49 VOGL_NOTE_UNUSED(remapper);
50 VOGL_NOTE_UNUSED(context_info);
56 VOGL_ASSERT(handle <= cUINT32_MAX);
58 m_snapshot_handle = static_cast<GLuint>(handle);
61 if (m_target != GL_NONE)
63 vogl_scoped_binding_state orig_bindings(target);
65 GL_ENTRYPOINT(glBindBuffer)(target, m_snapshot_handle);
68 bool any_gl_errors = false;
70 #define GET_INT(pname) \
74 GL_ENTRYPOINT(glGetBufferParameteriv)(m_target, pname, &value); \
75 if (vogl_check_gl_error()) \
76 any_gl_errors = true; \
77 m_params.insert(pname, 0, &value, sizeof(value)); \
80 GET_INT(GL_BUFFER_ACCESS);
81 GET_INT(GL_BUFFER_MAPPED);
82 GET_INT(GL_BUFFER_SIZE);
83 GET_INT(GL_BUFFER_USAGE);
87 GLvoid *pSnapshot_map_ptr;
88 GL_ENTRYPOINT(glGetBufferPointerv)(m_target, GL_BUFFER_MAP_POINTER, &pSnapshot_map_ptr);
89 if (vogl_check_gl_error())
94 vogl_error_printf("%s: GL error while retrieving buffer %" PRIu64 " target %s's params\n", VOGL_METHOD_NAME,
95 (uint64_t)handle, g_gl_enums.find_gl_name(target));
100 int buf_size = m_params.get_value<int>(GL_BUFFER_SIZE);
103 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);
108 if (m_params.get_value<int>(GL_BUFFER_MAPPED) != 0)
110 vogl_error_printf("%s: Can't snapshot buffer %" PRIu64 " target %s while it's currently mapped\n", VOGL_METHOD_NAME,
111 (uint64_t)handle, g_gl_enums.find_gl_name(target));
118 if (!m_buffer_data.try_resize(buf_size))
120 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);
125 // This will fail if the buffer is currently mapped.
126 GL_ENTRYPOINT(glGetBufferSubData)(target, 0, buf_size, m_buffer_data.get_ptr());
128 if (vogl_check_gl_error())
130 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);
140 void vogl_buffer_state::set_mapped_buffer_snapshot_state(const vogl_mapped_buffer_desc &map_desc)
144 VOGL_ASSERT(map_desc.m_buffer == m_snapshot_handle);
148 m_map_ofs = map_desc.m_offset;
149 m_map_size = map_desc.m_length;
150 m_map_access = map_desc.m_access;
151 m_map_range = map_desc.m_range;
154 bool vogl_buffer_state::restore(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint64 &handle) const
158 VOGL_NOTE_UNUSED(context_info);
160 int buf_usage = 0, buf_size = 0;
167 bool created_handle = false;
172 GL_ENTRYPOINT(glGenBuffers)(1, &handle32);
173 if ((vogl_check_gl_error()) || (!handle32))
178 remapper.declare_handle(VOGL_NAMESPACE_BUFFERS, m_snapshot_handle, handle, m_target);
179 VOGL_ASSERT(remapper.remap_handle(VOGL_NAMESPACE_BUFFERS, m_snapshot_handle) == handle);
181 created_handle = true;
184 if (m_target != GL_NONE)
186 vogl_scoped_binding_state orig_bindings(m_target);
188 GL_ENTRYPOINT(glBindBuffer)(m_target, static_cast<GLuint>(handle));
189 if (vogl_check_gl_error())
192 buf_usage = m_params.get_value<int>(GL_BUFFER_USAGE);
193 buf_size = m_params.get_value<int>(GL_BUFFER_SIZE);
195 if (buf_size != static_cast<int>(m_buffer_data.size()))
201 GL_ENTRYPOINT(glBufferData)(m_target, buf_size, m_buffer_data.get_ptr(), buf_usage);
202 if (vogl_check_gl_error())
209 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);
211 GL_ENTRYPOINT(glBindBuffer)(m_target, 0);
214 if ((handle) && (created_handle))
216 remapper.delete_handle_and_object(VOGL_NAMESPACE_BUFFERS, m_snapshot_handle, handle);
218 //GLuint handle32 = static_cast<GLuint>(handle);
219 //GL_ENTRYPOINT(glDeleteBuffers)(1, &handle32);
220 //VOGL_CHECK_GL_ERROR;
228 bool vogl_buffer_state::remap_handles(vogl_handle_remapper &remapper)
235 m_snapshot_handle = static_cast<GLuint>(remapper.remap_handle(VOGL_NAMESPACE_BUFFERS, m_snapshot_handle));
240 void vogl_buffer_state::clear()
244 m_snapshot_handle = 0;
246 m_buffer_data.clear();
257 bool vogl_buffer_state::serialize(json_node &node, vogl_blob_manager &blob_manager) const
264 dynamic_string blob_id;
266 if (m_buffer_data.size())
268 const char *pBuf_type = utils::map_value(static_cast<int>(m_target), "buf",
269 GL_ARRAY_BUFFER, "buf_vertex",
270 GL_ELEMENT_ARRAY_BUFFER, "buf_index",
271 GL_UNIFORM_BUFFER, "buf_uniform");
273 dynamic_string prefix;
274 prefix.format("%s_0x%04X", pBuf_type, m_params.get_value<int>(GL_BUFFER_USAGE));
276 blob_id = blob_manager.add_buf_compute_unique_id(m_buffer_data.get_ptr(), m_buffer_data.size(), prefix.get_ptr(), "raw");
277 if (blob_id.is_empty())
281 node.add_key_value("handle", m_snapshot_handle);
282 node.add_key_value("target", g_gl_enums.find_gl_name(m_target));
283 node.add_key_value("buffer_data_blob_id", blob_id);
285 node.add_key_value("map_ofs", m_map_ofs);
286 node.add_key_value("map_size", m_map_size);
287 node.add_key_value("map_access", m_map_access);
288 node.add_key_value("map_range", m_map_range);
289 node.add_key_value("is_mapped", m_is_mapped);
291 if (!m_params.serialize(node.add_object("params"), blob_manager))
297 bool vogl_buffer_state::deserialize(const json_node &node, const vogl_blob_manager &blob_manager)
303 m_snapshot_handle = node.value_as_uint32("handle");
304 m_target = vogl_get_json_value_as_enum(node, "target");
305 if (m_target != GL_NONE)
307 const json_node *pParams_obj = node.find_child_object("params");
314 if (!m_params.deserialize(*pParams_obj, blob_manager))
320 int buf_size = m_params.get_value<int>(GL_BUFFER_SIZE);
324 dynamic_string blob_id(node.value_as_string_ptr("buffer_data_blob_id"));
325 if (blob_id.is_empty())
331 if (!blob_manager.get(blob_id, m_buffer_data))
338 if (buf_size != static_cast<int>(m_buffer_data.size()))
345 m_map_ofs = node.value_as_uint64("map_ofs");
346 m_map_size = node.value_as_uint64("map_size");
347 m_map_access = node.value_as_uint32("map_access");
348 m_map_range = node.value_as_bool("map_range");
349 m_is_mapped = node.value_as_bool("is_mapped");
356 // Content comparison, ignores handle.
357 bool vogl_buffer_state::compare_restorable_state(const vogl_gl_object_state &rhs_obj) const
361 if ((!m_is_valid) || (!rhs_obj.is_valid()))
364 if (rhs_obj.get_type() != cGLSTBuffer)
367 const vogl_buffer_state &rhs = static_cast<const vogl_buffer_state &>(rhs_obj);
372 if (m_target != rhs.m_target)
375 if (m_buffer_data != rhs.m_buffer_data)
378 if (m_params != rhs.m_params)