]> git.cworth.org Git - vogl/blob - src/voglcommon/vogl_gl_state_snapshot.cpp
- Features for 10ft: PBO's, snapshotting/restoring mapped buffers during replaying
[vogl] / src / voglcommon / vogl_gl_state_snapshot.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_gl_state_snapshot.cpp
27 #include "vogl_gl_state_snapshot.h"
28 #include "vogl_uuid.h"
29
30 vogl_context_snapshot::vogl_context_snapshot()
31     : m_is_valid(false)
32 {
33     VOGL_FUNC_TRACER
34 }
35
36 vogl_context_snapshot::~vogl_context_snapshot()
37 {
38     VOGL_FUNC_TRACER
39
40     destroy_objects();
41 }
42
43 void vogl_context_snapshot::destroy_objects()
44 {
45     VOGL_FUNC_TRACER
46
47     for (uint i = 0; i < m_object_ptrs.size(); i++)
48         vogl_delete(m_object_ptrs[i]);
49     m_object_ptrs.clear();
50 }
51
52 void vogl_context_snapshot::clear()
53 {
54     VOGL_FUNC_TRACER
55
56     m_context_desc.clear();
57     m_context_info.clear();
58     m_general_state.clear();
59     m_texenv_state.clear();
60     m_light_state.clear();
61     m_material_state.clear();
62     m_display_list_state.clear();
63     m_matrix_state.clear();
64     m_polygon_stipple_state.clear();
65     m_current_vertex_attrib_state.clear();
66     m_arb_program_environment_state.clear();
67
68     destroy_objects();
69
70     m_is_valid = false;
71 }
72
73 // Note info may NOT be valid here if the context was never made current!
74 bool vogl_context_snapshot::capture(const vogl_context_desc &desc, const vogl_context_info &info, const vogl_capture_context_params &capture_params, vogl_handle_remapper &remapper)
75 {
76     VOGL_FUNC_TRACER
77
78     VOGL_CHECK_GL_ERROR;
79
80     clear();
81
82     vogl_printf("%s: Starting capture on trace context 0x%" PRIx64 ", has context info: %u\n", VOGL_METHOD_NAME, cast_val_to_uint64(desc.get_trace_context()), info.is_valid());
83
84     m_context_desc = desc;
85     m_context_info = info;
86     m_display_list_state = capture_params.m_display_lists;
87
88     // Has this context been ever made current?
89     if (info.is_valid())
90     {
91         if (!m_general_state.snapshot(m_context_info))
92             goto handle_error;
93
94         if (!m_current_vertex_attrib_state.snapshot(m_context_info))
95             goto handle_error;
96
97         if (!info.is_core_profile())
98         {
99             if (!m_texenv_state.snapshot(m_context_info))
100                 goto handle_error;
101
102             if (!m_light_state.snapshot(m_context_info))
103                 goto handle_error;
104
105             if (!m_material_state.snapshot(m_context_info))
106                 goto handle_error;
107
108             if (!m_matrix_state.snapshot(m_context_info))
109                 goto handle_error;
110
111             if (!m_polygon_stipple_state.snapshot(m_context_info))
112                 goto handle_error;
113
114             if (info.supports_extension("GL_ARB_vertex_program"))
115             {
116                 if (!m_arb_program_environment_state.snapshot(m_context_info))
117                     goto handle_error;
118             }
119         }
120
121         // Keep this list in sync with vogl_gl_object_state_type (order doesn't matter, just make sure all valid object types are present)
122         const vogl_gl_object_state_type s_object_type_capture_order[] = { cGLSTTexture, cGLSTBuffer, cGLSTSampler, cGLSTQuery, cGLSTRenderbuffer, cGLSTFramebuffer, cGLSTVertexArray, cGLSTShader, cGLSTProgram, cGLSTSync, cGLSTARBProgram };
123         VOGL_ASSUME(VOGL_ARRAY_SIZE(s_object_type_capture_order) == cGLSTTotalTypes - 1);
124
125         for (uint i = 0; i < VOGL_ARRAY_SIZE(s_object_type_capture_order); i++)
126             if (!capture_objects(s_object_type_capture_order[i], capture_params, remapper))
127                 goto handle_error;
128     }
129
130     m_is_valid = true;
131
132     VOGL_CHECK_GL_ERROR;
133
134     vogl_printf("%s: Capture succeeded\n", VOGL_METHOD_NAME);
135
136     return true;
137
138 handle_error:
139     VOGL_CHECK_GL_ERROR;
140     vogl_printf("%s: Capture failed\n", VOGL_METHOD_NAME);
141     return false;
142 }
143
144 bool vogl_context_snapshot::remap_handles(vogl_handle_remapper &remapper)
145 {
146     VOGL_FUNC_TRACER
147
148     if (!m_is_valid)
149         return false;
150
151     vogl_printf("%s: Remapping object handles and program locations\n", VOGL_METHOD_NAME);
152
153     if (!m_general_state.remap_handles(remapper))
154         return false;
155
156     if (m_arb_program_environment_state.is_valid())
157     {
158         if (!m_arb_program_environment_state.remap_handles(remapper))
159             return false;
160     }
161
162     for (uint i = 0; i < m_object_ptrs.size(); i++)
163     {
164         uint64_t orig_handle = m_object_ptrs[i]->get_snapshot_handle();
165
166         if (!m_object_ptrs[i]->remap_handles(remapper))
167             return false;
168
169         uint64_t new_handle = m_object_ptrs[i]->get_snapshot_handle();
170         VOGL_NOTE_UNUSED(new_handle);
171
172         if (orig_handle)
173         {
174             VOGL_ASSERT(new_handle);
175
176             // TODO: Validate the inverse mapping is good to catch silly bugs
177         }
178     }
179
180     vogl_printf("%s: Remap complete\n", VOGL_METHOD_NAME);
181
182     return true;
183 }
184
185 bool vogl_context_snapshot::capture_objects(vogl_gl_object_state_type state_type, const vogl_capture_context_params &capture_params, vogl_handle_remapper &remapper)
186 {
187     VOGL_FUNC_TRACER
188
189     vogl_printf("Capturing %ss\n", get_gl_object_state_type_str(state_type));
190
191     uint total = 0;
192
193     if ((state_type == cGLSTVertexArray) && (m_context_info.is_compatibility_profile()))
194     {
195         // Save the default VAO.
196         vogl_gl_object_state *p = vogl_gl_object_state_factory(cGLSTVertexArray);
197         VOGL_VERIFY(p);
198
199         bool success = p->snapshot(m_context_info, remapper, 0, GL_NONE);
200         if (!success)
201         {
202             vogl_delete(p);
203             return false;
204         }
205
206         m_object_ptrs.push_back(p);
207
208         total++;
209     }
210
211     if (state_type == cGLSTSync)
212     {
213         m_object_ptrs.reserve(m_object_ptrs.size() + capture_params.m_syncs.size());
214
215         for (vogl_sync_hash_set::const_iterator it = capture_params.m_syncs.begin(); it != capture_params.m_syncs.end(); ++it)
216         {
217             uint64_t handle = it->first;
218
219             if (!GL_ENTRYPOINT(glIsSync)(vogl_handle_to_sync(handle)))
220             {
221                 VOGL_ASSERT_ALWAYS;
222                 continue;
223             }
224
225             vogl_gl_object_state *p = vogl_gl_object_state_factory(state_type);
226             VOGL_VERIFY(p);
227
228             bool success = p->snapshot(m_context_info, remapper, handle, GL_NONE);
229             if (!success)
230             {
231                 vogl_delete(p);
232                 return false;
233             }
234
235             m_object_ptrs.push_back(p);
236             total++;
237         }
238     }
239     else
240     {
241         vogl::vector<std::pair<GLuint, GLenum> > handles_to_capture;
242         handles_to_capture.reserve(4096);
243
244         switch (state_type)
245         {
246             case cGLSTARBProgram:
247             {
248                 for (vogl_handle_hash_map::const_iterator it = capture_params.m_arb_program_targets.begin(); it != capture_params.m_arb_program_targets.end(); ++it)
249                     handles_to_capture.push_back(*it);
250                 break;
251             }
252             case cGLSTBuffer:
253             {
254                 for (vogl_handle_hash_map::const_iterator it = capture_params.m_buffer_targets.begin(); it != capture_params.m_buffer_targets.end(); ++it)
255                     handles_to_capture.push_back(*it);
256                 break;
257             }
258             case cGLSTTexture:
259             {
260                 for (uint i = 0; i < capture_params.m_textures.size(); i++)
261                 {
262                     const vogl_handle_tracker::handle_def &def = capture_params.m_textures[i];
263                     if (def.is_valid())
264                         handles_to_capture.push_back(std::make_pair(def.get_inv_handle(), def.get_target()));
265                 }
266                 break;
267             }
268             case cGLSTRenderbuffer:
269             {
270                 for (uint i = 0; i < capture_params.m_rbos.size(); i++)
271                 {
272                     const vogl_handle_tracker::handle_def &def = capture_params.m_rbos[i];
273                     if (def.is_valid())
274                         handles_to_capture.push_back(std::make_pair(def.get_inv_handle(), def.get_target()));
275                 }
276
277                 break;
278             }
279             case cGLSTFramebuffer:
280             {
281                 for (vogl_handle_hash_set::const_iterator it = capture_params.m_framebuffers.begin(); it != capture_params.m_framebuffers.end(); ++it)
282                     handles_to_capture.push_back(std::make_pair(it->first, GL_NONE));
283
284                 break;
285             }
286             case cGLSTQuery:
287             {
288                 for (vogl_handle_hash_map::const_iterator it = capture_params.m_query_targets.begin(); it != capture_params.m_query_targets.end(); ++it)
289                     handles_to_capture.push_back(*it);
290                 break;
291             }
292             case cGLSTShader:
293             {
294                 for (uint i = 0; i < capture_params.m_objs.size(); i++)
295                 {
296                     const vogl_handle_tracker::handle_def &def = capture_params.m_objs[i];
297                     if ((def.is_valid()) && (def.get_target() == VOGL_SHADER_OBJECT))
298                         handles_to_capture.push_back(std::make_pair(def.get_inv_handle(), def.get_target()));
299                 }
300
301                 break;
302             }
303             case cGLSTProgram:
304             {
305                 for (uint i = 0; i < capture_params.m_objs.size(); i++)
306                 {
307                     const vogl_handle_tracker::handle_def &def = capture_params.m_objs[i];
308                     if ((def.is_valid()) && (def.get_target() == VOGL_PROGRAM_OBJECT))
309                     {
310                         GLuint handle = def.get_inv_handle();
311
312                         if (capture_params.m_filter_program_handles)
313                         {
314                             if (!capture_params.m_program_handles_filter.contains(handle))
315                                 continue;
316                         }
317
318                         handles_to_capture.push_back(std::make_pair(handle, def.get_target()));
319                     }
320                 }
321
322                 break;
323             }
324             case cGLSTSampler:
325             {
326                 for (vogl_handle_hash_set::const_iterator it = capture_params.m_samplers.begin(); it != capture_params.m_samplers.end(); ++it)
327                     handles_to_capture.push_back(std::make_pair(it->first, GL_NONE));
328
329                 break;
330             }
331             case cGLSTVertexArray:
332             {
333                 for (vogl_handle_hash_set::const_iterator it = capture_params.m_vaos.begin(); it != capture_params.m_vaos.end(); ++it)
334                     handles_to_capture.push_back(std::make_pair(it->first, GL_NONE));
335
336                 break;
337             }
338             default:
339             {
340                 VOGL_VERIFY(0);
341                 return false;
342             }
343         }
344
345         m_object_ptrs.reserve(m_object_ptrs.size() + handles_to_capture.size());
346
347         for (uint i = 0; i < handles_to_capture.size(); ++i)
348         {
349             GLuint handle = handles_to_capture[i].first;
350             GLenum target = handles_to_capture[i].second;
351
352             vogl_gl_object_state *p = vogl_gl_object_state_factory(state_type);
353             VOGL_VERIFY(p);
354
355             bool success = p->snapshot(m_context_info, remapper, handle, target);
356             if (!success)
357             {
358                 vogl_delete(p);
359                 return false;
360             }
361
362             if (state_type == cGLSTProgram)
363             {
364                 vogl_program_state *pProg = static_cast<vogl_program_state *>(p);
365
366                 const vogl_program_state *pLink_snapshot = capture_params.m_linked_programs.find_snapshot(handle);
367                 if (pLink_snapshot)
368                 {
369                     vogl_unique_ptr<vogl_program_state> pLink_snapshot_clone(vogl_new(vogl_program_state, *pLink_snapshot));
370
371                     pProg->set_link_time_snapshot(pLink_snapshot_clone);
372                 }
373                 else if (pProg->get_link_status())
374                 {
375                     vogl_error_printf("%s: GL program %u was snapshotted with a successful link status, but the link snapshot shadow doesn't contain this program!\n", VOGL_METHOD_NAME, handle);
376                 }
377             }
378             else if (state_type == cGLSTBuffer)
379             {
380                 // Determine if this buffer has been mapped. I don't expect this array to be very big (typically empty) so a simple search is fine.
381                 uint j;
382                 for (j = 0; j < capture_params.m_mapped_buffers.size(); j++)
383                     if (capture_params.m_mapped_buffers[j].m_buffer == handle)
384                         break;
385
386                 if (j < capture_params.m_mapped_buffers.size())
387                 {
388                     const vogl_mapped_buffer_desc &map_desc = capture_params.m_mapped_buffers[j];
389
390                     vogl_buffer_state *pBuf_state = static_cast<vogl_buffer_state *>(p);
391
392                     pBuf_state->set_mapped_buffer_snapshot_state(map_desc);
393                 }
394             }
395
396             m_object_ptrs.push_back(p);
397             total++;
398         }
399     }
400
401     VOGL_CHECK_GL_ERROR;
402
403     vogl_printf("Found %u %ss\n", total, get_gl_object_state_type_str(state_type));
404
405     return true;
406 }
407
408 static bool vogl_object_ptr_sorter(const vogl_gl_object_state *pLHS, vogl_gl_object_state *pRHS)
409 {
410     return pLHS->get_snapshot_handle() < pRHS->get_snapshot_handle();
411 }
412
413 void vogl_context_snapshot::get_all_objects_of_category(vogl_gl_object_state_type state_type, vogl_gl_object_state_ptr_vec &obj_ptr_vec) const
414 {
415     VOGL_FUNC_TRACER
416
417     obj_ptr_vec.resize(0);
418
419     for (uint i = 0; i < m_object_ptrs.size(); i++)
420         if (m_object_ptrs[i]->get_type() == state_type)
421             obj_ptr_vec.push_back(m_object_ptrs[i]);
422
423     obj_ptr_vec.sort(vogl_object_ptr_sorter);
424 }
425
426 bool vogl_context_snapshot::serialize(json_node &node, vogl_blob_manager &blob_manager, const vogl_ctypes *pCtypes) const
427 {
428     VOGL_FUNC_TRACER
429
430     if (!m_is_valid)
431         return false;
432
433     if (!m_context_desc.serialize(node.add_object("context_desc"), blob_manager))
434         return false;
435
436     if (m_context_info.is_valid() && !m_context_info.serialize(node.add_object("context_info"), blob_manager))
437         return false;
438
439     if (!m_general_state.serialize(node.add_object("general_state"), blob_manager))
440         return false;
441
442     if (!m_display_list_state.serialize(node.add_object("display_lists"), blob_manager, pCtypes))
443         return false;
444
445     if (m_texenv_state.is_valid() && !m_texenv_state.serialize(node.add_object("tex_env_gen_state"), blob_manager))
446         return false;
447
448     if (m_material_state.is_valid() && !m_material_state.serialize(node.add_object("material_state"), blob_manager))
449         return false;
450
451     if (m_light_state.is_valid() && !m_light_state.serialize(node.add_object("light_state"), blob_manager))
452         return false;
453
454     if (m_matrix_state.is_valid() && !m_matrix_state.serialize(node.add_array("matrix_state"), blob_manager))
455         return false;
456
457     if (m_polygon_stipple_state.is_valid() && !m_polygon_stipple_state.serialize(node.add_array("polygon_stipple"), blob_manager))
458         return false;
459
460     if (m_current_vertex_attrib_state.is_valid() && !m_current_vertex_attrib_state.serialize(node.add_array("current_vertex_attribs"), blob_manager))
461         return false;
462
463     if (m_arb_program_environment_state.is_valid() && !m_arb_program_environment_state.serialize(node.add_array("arb_program_environment_state"), blob_manager))
464         return false;
465
466     if (m_object_ptrs.size())
467     {
468         json_node &objects_node = node.add_object("state_objects");
469
470         vogl_gl_object_state_ptr_vec obj_ptrs;
471
472         for (vogl_gl_object_state_type state_type = static_cast<vogl_gl_object_state_type>(0); state_type < cGLSTTotalTypes; state_type = static_cast<vogl_gl_object_state_type>(state_type + 1))
473         {
474             get_all_objects_of_category(state_type, obj_ptrs);
475             if (obj_ptrs.is_empty())
476                 continue;
477
478             json_node &array_node = objects_node.add_array(get_gl_object_state_type_str(state_type));
479
480             for (uint i = 0; i < obj_ptrs.size(); i++)
481             {
482                 json_node &new_obj = array_node.add_object();
483                 if (!obj_ptrs[i]->serialize(new_obj, blob_manager))
484                     return false;
485             }
486         }
487     }
488
489     return true;
490 }
491
492 bool vogl_context_snapshot::deserialize(const json_node &node, const vogl_blob_manager &blob_manager, const vogl_ctypes *pCtypes)
493 {
494     VOGL_FUNC_TRACER
495
496     clear();
497
498     if ((!vogl_json_deserialize_obj(node, blob_manager, "context_desc", m_context_desc)) ||
499         (!vogl_json_deserialize_obj(node, blob_manager, "general_state", m_general_state)))
500     {
501         clear();
502         return false;
503     }
504
505     if (node.has_object("context_info") && !vogl_json_deserialize_obj(node, blob_manager, "context_info", m_context_info))
506     {
507         clear();
508         return false;
509     }
510
511     if (node.has_object("display_lists") && !m_display_list_state.deserialize(*node.find_child_object("display_lists"), blob_manager, pCtypes))
512     {
513         clear();
514         return false;
515     }
516
517     if (node.has_key("tex_env_gen_state") && !vogl_json_deserialize_obj(node, blob_manager, "tex_env_gen_state", m_texenv_state))
518     {
519         clear();
520         return false;
521     }
522
523     if (node.has_key("material_state") && !vogl_json_deserialize_obj(node, blob_manager, "material_state", m_material_state))
524     {
525         clear();
526         return false;
527     }
528
529     if (node.has_key("light_state") && !vogl_json_deserialize_obj(node, blob_manager, "light_state", m_light_state))
530     {
531         clear();
532         return false;
533     }
534
535     if (node.has_key("matrix_state") && !vogl_json_deserialize_array(node, blob_manager, "matrix_state", m_matrix_state))
536     {
537         clear();
538         return false;
539     }
540
541     if (node.has_key("polygon_stipple") && !vogl_json_deserialize_obj(node, blob_manager, "polygon_stipple", m_polygon_stipple_state))
542     {
543         clear();
544         return false;
545     }
546
547     if (node.has_key("current_vertex_attribs") && !vogl_json_deserialize_array(node, blob_manager, "current_vertex_attribs", m_current_vertex_attrib_state))
548     {
549         clear();
550         return false;
551     }
552
553     if (node.has_key("arb_program_environment_state") && !vogl_json_deserialize_obj(node, blob_manager, "arb_program_environment_state", m_arb_program_environment_state))
554     {
555         clear();
556         return false;
557     }
558
559     const json_node *pObjects_node = node.find_child_object("state_objects");
560     if (pObjects_node)
561     {
562         for (uint obj_iter = 0; obj_iter < pObjects_node->size(); obj_iter++)
563         {
564             const dynamic_string &obj_type_str = pObjects_node->get_key(obj_iter);
565
566             vogl_gl_object_state_type state_type = determine_gl_object_state_type_from_str(obj_type_str.get_ptr());
567             if (state_type == cGLSTInvalid)
568             {
569                 vogl_warning_printf("%s: Unknown object state type \"%s\", skipping node\n", VOGL_METHOD_NAME, obj_type_str.get_ptr());
570                 continue;
571             }
572
573             const json_node *pArray_node = pObjects_node->get_value_as_array(obj_iter);
574             if (!pArray_node)
575             {
576                 clear();
577                 return false;
578             }
579
580             m_object_ptrs.reserve(m_object_ptrs.size() + pArray_node->size());
581
582             for (uint i = 0; i < pArray_node->size(); i++)
583             {
584                 const json_node *pObj_node = pArray_node->get_value_as_object(i);
585                 if (!pObj_node)
586                 {
587                     clear();
588                     return false;
589                 }
590
591                 vogl_gl_object_state *pState_obj = vogl_gl_object_state_factory(state_type);
592                 if (!pState_obj)
593                 {
594                     clear();
595                     return false;
596                 }
597
598                 if (!pState_obj->deserialize(*pObj_node, blob_manager))
599                 {
600                     vogl_delete(pState_obj);
601
602                     clear();
603                     return false;
604                 }
605
606                 m_object_ptrs.push_back(pState_obj);
607             }
608         }
609     }
610
611     m_is_valid = true;
612
613     return true;
614 }
615
616 vogl_gl_state_snapshot::vogl_gl_state_snapshot()
617     : m_window_width(0),
618       m_window_height(0),
619       m_cur_trace_context(0),
620       m_frame_index(0),
621       m_gl_call_counter(0),
622       m_at_frame_boundary(false),
623       m_is_restorable(false),
624       m_captured_default_framebuffer(false),
625       m_is_valid(false)
626 {
627     VOGL_FUNC_TRACER
628
629     m_uuid.clear();
630 }
631
632 vogl_gl_state_snapshot::~vogl_gl_state_snapshot()
633 {
634     VOGL_FUNC_TRACER
635
636     destroy_contexts();
637 }
638
639 void vogl_gl_state_snapshot::clear()
640 {
641     VOGL_FUNC_TRACER
642
643     m_uuid.clear();
644     m_window_width = 0;
645     m_window_height = 0;
646     m_cur_trace_context = 0;
647     m_frame_index = 0;
648     m_gl_call_counter = 0;
649     m_at_frame_boundary = false;
650     m_is_restorable = false;
651
652     m_client_side_vertex_attrib_ptrs.clear();
653     m_client_side_array_ptrs.clear();
654     m_client_side_texcoord_ptrs.clear();
655
656     destroy_contexts();
657
658     m_default_framebuffer.clear();
659
660     m_captured_default_framebuffer = false;
661     m_is_valid = false;
662 }
663
664 // frame_index indicates the beginning of frame X, at a swap boundary
665 bool vogl_gl_state_snapshot::begin_capture(uint window_width, uint window_height, vogl_trace_ptr_value cur_context, uint frame_index, int64_t gl_call_counter, bool at_frame_boundary)
666 {
667     VOGL_FUNC_TRACER
668
669     clear();
670
671     m_uuid = gen_uuid();
672     m_window_width = window_width;
673     m_window_height = window_height;
674     m_cur_trace_context = cur_context;
675     m_frame_index = frame_index;
676     m_gl_call_counter = gl_call_counter;
677     m_at_frame_boundary = at_frame_boundary;
678     m_is_restorable = true;
679
680     m_is_valid = true;
681     m_captured_default_framebuffer = false;
682
683     return true;
684 }
685
686 void vogl_gl_state_snapshot::add_client_side_array_ptrs(const vogl_client_side_array_desc_vec &client_side_vertex_attrib_ptrs, const vogl_client_side_array_desc_vec &client_side_array_ptrs, const vogl_client_side_array_desc_vec &client_side_texcoord_ptrs)
687 {
688     VOGL_FUNC_TRACER
689
690     m_client_side_vertex_attrib_ptrs = client_side_vertex_attrib_ptrs;
691     m_client_side_array_ptrs = client_side_array_ptrs;
692     m_client_side_texcoord_ptrs = client_side_texcoord_ptrs;
693 }
694
695 // TODO: check if the context was ever made current yet (if not the context_info won't be valid), make sure this path works
696 bool vogl_gl_state_snapshot::capture_context(
697     const vogl_context_desc &desc, const vogl_context_info &info, vogl_handle_remapper &remapper,
698     const vogl_capture_context_params &capture_params)
699 {
700     VOGL_FUNC_TRACER
701
702     if (!m_captured_default_framebuffer)
703     {
704         // TODO: Move this!
705         vogl_default_framebuffer_attribs fb_attribs;
706         fb_attribs.clear();
707
708         bool status = false;
709         if (vogl_get_default_framebuffer_attribs(fb_attribs, 0))
710         {
711             if ((fb_attribs.m_width) && (fb_attribs.m_height))
712             {
713                 status = m_default_framebuffer.snapshot(info, fb_attribs);
714             }
715         }
716
717         if (!status)
718         {
719             vogl_error_printf("%s: Failed snapshotting default framebuffer!\n", VOGL_METHOD_NAME);
720         }
721
722         m_captured_default_framebuffer = true;
723     }
724
725     vogl_context_snapshot *pSnapshot = vogl_new(vogl_context_snapshot);
726
727     if (!pSnapshot->capture(desc, info, capture_params, remapper))
728     {
729         m_is_valid = false;
730
731         vogl_delete(pSnapshot);
732
733         return false;
734     }
735
736     if (!pSnapshot->remap_handles(remapper))
737         return false;
738
739     m_context_ptrs.push_back(pSnapshot);
740
741     return true;
742 }
743
744 bool vogl_gl_state_snapshot::end_capture()
745 {
746     VOGL_FUNC_TRACER
747
748     return m_is_valid;
749 }
750
751 bool vogl_gl_state_snapshot::serialize(json_node &node, vogl_blob_manager &blob_manager, const vogl_ctypes *pCtypes) const
752 {
753     VOGL_FUNC_TRACER
754
755     if (!m_is_valid)
756         return false;
757
758     m_uuid.json_serialize(node.add("uuid"));
759     node.add_key_value("window_width", m_window_width);
760     node.add_key_value("window_height", m_window_height);
761     node.add_key_value("cur_trace_context", m_cur_trace_context);
762     node.add_key_value("frame_index", m_frame_index);
763     node.add_key_value("gl_call_counter", m_gl_call_counter);
764     node.add_key_value("at_frame_boundary", m_at_frame_boundary);
765     node.add_key_value("is_restorable", m_is_restorable);
766
767     if (!vogl_json_serialize_vec(node, blob_manager, "client_side_vertex_attrib_ptrs", m_client_side_vertex_attrib_ptrs))
768         return false;
769     if (!vogl_json_serialize_vec(node, blob_manager, "client_side_array_ptrs", m_client_side_array_ptrs))
770         return false;
771     if (!vogl_json_serialize_vec(node, blob_manager, "client_side_texcoord_ptrs", m_client_side_texcoord_ptrs))
772         return false;
773
774     if (!vogl_json_serialize_ptr_vec(node, blob_manager, "context_snapshots", m_context_ptrs, pCtypes))
775         return false;
776
777     if (m_default_framebuffer.is_valid())
778     {
779         if (!m_default_framebuffer.serialize(node.add_object("default_framebuffer"), blob_manager))
780             return false;
781     }
782
783     return true;
784 }
785
786 bool vogl_gl_state_snapshot::deserialize(const json_node &node, const vogl_blob_manager &blob_manager, const vogl_ctypes *pCtypes)
787 {
788     VOGL_FUNC_TRACER
789
790     clear();
791
792     if (!m_uuid.json_deserialize(node, "uuid"))
793     {
794         // For old trace files that don't have uuid's
795         m_uuid = gen_uuid();
796     }
797
798     m_window_width = node.value_as_uint32("window_width");
799     m_window_height = node.value_as_uint32("window_height");
800
801     if ((!m_window_width) || (!m_window_height))
802     {
803         clear();
804         return false;
805     }
806
807     m_cur_trace_context = static_cast<vogl_trace_ptr_value>(node.value_as_uint64("cur_trace_context"));
808     m_frame_index = node.value_as_uint32("frame_index");
809     m_gl_call_counter = node.value_as_int64("gl_call_counter");
810     m_at_frame_boundary = node.value_as_int64("at_frame_boundary");
811     m_is_restorable = node.value_as_bool("is_restorable", true);
812
813     if (!vogl_json_deserialize_vec(node, blob_manager, "client_side_vertex_attrib_ptrs", m_client_side_vertex_attrib_ptrs))
814         return false;
815     if (!vogl_json_deserialize_vec(node, blob_manager, "client_side_array_ptrs", m_client_side_array_ptrs))
816         return false;
817     if (!vogl_json_deserialize_vec(node, blob_manager, "client_side_texcoord_ptrs", m_client_side_texcoord_ptrs))
818         return false;
819
820     if (!vogl_json_deserialize_ptr_vec(node, blob_manager, "context_snapshots", m_context_ptrs, pCtypes))
821         return false;
822
823     if  (node.has_object("default_framebuffer"))
824     {
825         if (!m_default_framebuffer.deserialize(*node.find_child_object("default_framebuffer"), blob_manager))
826             return false;
827     }
828
829     m_is_valid = true;
830
831     return true;
832 }
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852