]> git.cworth.org Git - vogl/blob - src/voglcommon/vogl_buffer_state.cpp
Initial vogl checkin
[vogl] / src / voglcommon / vogl_buffer_state.cpp
1 /**************************************************************************
2  *
3  * Copyright 2013-2014 RAD Game Tools and Valve Software
4  * All Rights Reserved.
5  *
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:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
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
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26 // File: vogl_buffer_state.cpp
27 #include "vogl_common.h"
28 #include "vogl_buffer_state.h"
29
30 vogl_buffer_state::vogl_buffer_state()
31     : m_snapshot_handle(0),
32       m_target(GL_NONE),
33       m_is_valid(false)
34 {
35     VOGL_FUNC_TRACER
36 }
37
38 vogl_buffer_state::~vogl_buffer_state()
39 {
40     VOGL_FUNC_TRACER
41 }
42
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)
45 {
46     VOGL_FUNC_TRACER
47
48     VOGL_NOTE_UNUSED(remapper);
49     VOGL_NOTE_UNUSED(context_info);
50
51     VOGL_CHECK_GL_ERROR;
52
53     clear();
54
55     VOGL_ASSERT(handle <= cUINT32_MAX);
56
57     m_snapshot_handle = static_cast<GLuint>(handle);
58     m_target = target;
59
60     if (m_target != GL_NONE)
61     {
62         vogl_scoped_binding_state orig_bindings(target);
63
64         GL_ENTRYPOINT(glBindBuffer)(target, m_snapshot_handle);
65         VOGL_CHECK_GL_ERROR;
66
67         bool any_gl_errors = false;
68
69 #define GET_INT(pname)                                                  \
70     do                                                                  \
71     {                                                                   \
72         int value = 0;                                                  \
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));               \
77     } while (0)
78
79         GET_INT(GL_BUFFER_ACCESS);
80         GET_INT(GL_BUFFER_MAPPED);
81         GET_INT(GL_BUFFER_SIZE);
82         GET_INT(GL_BUFFER_USAGE);
83
84 #undef GET_INT
85
86         GLvoid *pSnapshot_map_ptr;
87         GL_ENTRYPOINT(glGetBufferPointerv)(m_target, GL_BUFFER_MAP_POINTER, &pSnapshot_map_ptr);
88         if (vogl_check_gl_error())
89             any_gl_errors = true;
90
91         if (any_gl_errors)
92         {
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));
95             clear();
96             return false;
97         }
98
99         if (m_params.get_value<int>(GL_BUFFER_MAPPED) != 0)
100         {
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));
103             clear();
104             return false;
105         }
106
107         int buf_size = m_params.get_value<int>(GL_BUFFER_SIZE);
108         if (buf_size < 0)
109         {
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);
111             clear();
112             return false;
113         }
114
115         if (buf_size)
116         {
117             if (!m_buffer_data.try_resize(buf_size))
118             {
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);
120                 clear();
121                 return false;
122             }
123
124             // This will fail if the buffer is currently mapped.
125             GL_ENTRYPOINT(glGetBufferSubData)(target, 0, buf_size, m_buffer_data.get_ptr());
126
127             if (vogl_check_gl_error())
128             {
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);
130             }
131         }
132     }
133
134     m_is_valid = true;
135
136     return true;
137 }
138
139 bool vogl_buffer_state::restore(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint64 &handle) const
140 {
141     VOGL_FUNC_TRACER
142
143     VOGL_NOTE_UNUSED(context_info);
144
145     int buf_usage = 0, buf_size = 0;
146
147     if (!m_is_valid)
148         return false;
149
150     VOGL_CHECK_GL_ERROR;
151
152     bool created_handle = false;
153
154     if (!handle)
155     {
156         GLuint handle32 = 0;
157         GL_ENTRYPOINT(glGenBuffers)(1, &handle32);
158         if ((vogl_check_gl_error()) || (!handle32))
159             return false;
160
161         handle = handle32;
162
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);
165
166         created_handle = true;
167     }
168
169     if (m_target != GL_NONE)
170     {
171         vogl_scoped_binding_state orig_bindings(m_target);
172
173         GL_ENTRYPOINT(glBindBuffer)(m_target, static_cast<GLuint>(handle));
174         if (vogl_check_gl_error())
175             goto handle_failure;
176
177         buf_usage = m_params.get_value<int>(GL_BUFFER_USAGE);
178         buf_size = m_params.get_value<int>(GL_BUFFER_SIZE);
179
180         if (buf_size != static_cast<int>(m_buffer_data.size()))
181         {
182             VOGL_ASSERT_ALWAYS;
183             goto handle_failure;
184         }
185
186         GL_ENTRYPOINT(glBufferData)(m_target, buf_size, m_buffer_data.get_ptr(), buf_usage);
187         if (vogl_check_gl_error())
188             goto handle_failure;
189     }
190
191     return true;
192
193 handle_failure:
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);
195
196     GL_ENTRYPOINT(glBindBuffer)(m_target, 0);
197     VOGL_CHECK_GL_ERROR;
198
199     if ((handle) && (created_handle))
200     {
201         remapper.delete_handle_and_object(VOGL_NAMESPACE_BUFFERS, m_snapshot_handle, handle);
202
203         //GLuint handle32 = static_cast<GLuint>(handle);
204         //GL_ENTRYPOINT(glDeleteBuffers)(1, &handle32);
205         //VOGL_CHECK_GL_ERROR;
206
207         handle = 0;
208     }
209
210     return false;
211 }
212
213 bool vogl_buffer_state::remap_handles(vogl_handle_remapper &remapper)
214 {
215     VOGL_FUNC_TRACER
216
217     if (!m_is_valid)
218         return false;
219
220     m_snapshot_handle = static_cast<GLuint>(remapper.remap_handle(VOGL_NAMESPACE_BUFFERS, m_snapshot_handle));
221
222     return true;
223 }
224
225 void vogl_buffer_state::clear()
226 {
227     VOGL_FUNC_TRACER
228
229     m_snapshot_handle = 0;
230     m_target = GL_NONE;
231     m_buffer_data.clear();
232     m_params.clear();
233     m_is_valid = false;
234 }
235
236 bool vogl_buffer_state::serialize(json_node &node, vogl_blob_manager &blob_manager) const
237 {
238     VOGL_FUNC_TRACER
239
240     if (!m_is_valid)
241         return false;
242
243     dynamic_string blob_id;
244
245     if (m_buffer_data.size())
246     {
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");
251
252         dynamic_string prefix;
253         prefix.format("%s_0x%04X", pBuf_type, m_params.get_value<int>(GL_BUFFER_USAGE));
254
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())
257             return false;
258     }
259
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);
263
264     if (!m_params.serialize(node.add_object("params"), blob_manager))
265         return false;
266
267     return true;
268 }
269
270 bool vogl_buffer_state::deserialize(const json_node &node, const vogl_blob_manager &blob_manager)
271 {
272     VOGL_FUNC_TRACER
273
274     clear();
275
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)
279     {
280         const json_node *pParams_obj = node.find_child_object("params");
281         if (!pParams_obj)
282         {
283             clear();
284             return false;
285         }
286
287         if (!m_params.deserialize(*pParams_obj, blob_manager))
288         {
289             clear();
290             return false;
291         }
292
293         int buf_size = m_params.get_value<int>(GL_BUFFER_SIZE);
294
295         if (buf_size)
296         {
297             dynamic_string blob_id(node.value_as_string_ptr("buffer_data_blob_id"));
298             if (blob_id.is_empty())
299             {
300                 clear();
301                 return false;
302             }
303
304             if (!blob_manager.get(blob_id, m_buffer_data))
305             {
306                 clear();
307                 return false;
308             }
309         }
310
311         if (buf_size != static_cast<int>(m_buffer_data.size()))
312         {
313             clear();
314             return false;
315         }
316     }
317
318     m_is_valid = true;
319
320     return true;
321 }
322
323 // Content comparison, ignores handle.
324 bool vogl_buffer_state::compare_restorable_state(const vogl_gl_object_state &rhs_obj) const
325 {
326     VOGL_FUNC_TRACER
327
328     if ((!m_is_valid) || (!rhs_obj.is_valid()))
329         return false;
330
331     if (rhs_obj.get_type() != cGLSTBuffer)
332         return false;
333
334     const vogl_buffer_state &rhs = static_cast<const vogl_buffer_state &>(rhs_obj);
335
336     if (this == &rhs)
337         return true;
338
339     if (m_target != rhs.m_target)
340         return false;
341
342     if (m_buffer_data != rhs.m_buffer_data)
343         return false;
344
345     if (m_params != rhs.m_params)
346         return false;
347
348     return true;
349 }