]> git.cworth.org Git - vogl/blob - src/voglcommon/vogl_gl_state_snapshot.cpp
Initial vogl checkin
[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
379             m_object_ptrs.push_back(p);
380             total++;
381         }
382     }
383
384     VOGL_CHECK_GL_ERROR;
385
386     vogl_printf("Found %u %ss\n", total, get_gl_object_state_type_str(state_type));
387
388     return true;
389 }
390
391 static bool vogl_object_ptr_sorter(const vogl_gl_object_state *pLHS, vogl_gl_object_state *pRHS)
392 {
393     return pLHS->get_snapshot_handle() < pRHS->get_snapshot_handle();
394 }
395
396 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
397 {
398     VOGL_FUNC_TRACER
399
400     obj_ptr_vec.resize(0);
401
402     for (uint i = 0; i < m_object_ptrs.size(); i++)
403         if (m_object_ptrs[i]->get_type() == state_type)
404             obj_ptr_vec.push_back(m_object_ptrs[i]);
405
406     obj_ptr_vec.sort(vogl_object_ptr_sorter);
407 }
408
409 bool vogl_context_snapshot::serialize(json_node &node, vogl_blob_manager &blob_manager, const vogl_ctypes *pCtypes) const
410 {
411     VOGL_FUNC_TRACER
412
413     if (!m_is_valid)
414         return false;
415
416     if (!m_context_desc.serialize(node.add_object("context_desc"), blob_manager))
417         return false;
418
419     if (m_context_info.is_valid() && !m_context_info.serialize(node.add_object("context_info"), blob_manager))
420         return false;
421
422     if (!m_general_state.serialize(node.add_object("general_state"), blob_manager))
423         return false;
424
425     if (!m_display_list_state.serialize(node.add_object("display_lists"), blob_manager, pCtypes))
426         return false;
427
428     if (m_texenv_state.is_valid() && !m_texenv_state.serialize(node.add_object("tex_env_gen_state"), blob_manager))
429         return false;
430
431     if (m_material_state.is_valid() && !m_material_state.serialize(node.add_object("material_state"), blob_manager))
432         return false;
433
434     if (m_light_state.is_valid() && !m_light_state.serialize(node.add_object("light_state"), blob_manager))
435         return false;
436
437     if (m_matrix_state.is_valid() && !m_matrix_state.serialize(node.add_array("matrix_state"), blob_manager))
438         return false;
439
440     if (m_polygon_stipple_state.is_valid() && !m_polygon_stipple_state.serialize(node.add_array("polygon_stipple"), blob_manager))
441         return false;
442
443     if (m_current_vertex_attrib_state.is_valid() && !m_current_vertex_attrib_state.serialize(node.add_array("current_vertex_attribs"), blob_manager))
444         return false;
445
446     if (m_arb_program_environment_state.is_valid() && !m_arb_program_environment_state.serialize(node.add_array("arb_program_environment_state"), blob_manager))
447         return false;
448
449     if (m_object_ptrs.size())
450     {
451         json_node &objects_node = node.add_object("state_objects");
452
453         vogl_gl_object_state_ptr_vec obj_ptrs;
454
455         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))
456         {
457             get_all_objects_of_category(state_type, obj_ptrs);
458             if (obj_ptrs.is_empty())
459                 continue;
460
461             json_node &array_node = objects_node.add_array(get_gl_object_state_type_str(state_type));
462
463             for (uint i = 0; i < obj_ptrs.size(); i++)
464             {
465                 json_node &new_obj = array_node.add_object();
466                 if (!obj_ptrs[i]->serialize(new_obj, blob_manager))
467                     return false;
468             }
469         }
470     }
471
472     return true;
473 }
474
475 bool vogl_context_snapshot::deserialize(const json_node &node, const vogl_blob_manager &blob_manager, const vogl_ctypes *pCtypes)
476 {
477     VOGL_FUNC_TRACER
478
479     clear();
480
481     if ((!vogl_json_deserialize_obj(node, blob_manager, "context_desc", m_context_desc)) ||
482         (!vogl_json_deserialize_obj(node, blob_manager, "general_state", m_general_state)))
483     {
484         clear();
485         return false;
486     }
487
488     if (node.has_object("context_info") && !vogl_json_deserialize_obj(node, blob_manager, "context_info", m_context_info))
489     {
490         clear();
491         return false;
492     }
493
494     if (node.has_object("display_lists") && !m_display_list_state.deserialize(*node.find_child_object("display_lists"), blob_manager, pCtypes))
495     {
496         clear();
497         return false;
498     }
499
500     if (node.has_key("tex_env_gen_state") && !vogl_json_deserialize_obj(node, blob_manager, "tex_env_gen_state", m_texenv_state))
501     {
502         clear();
503         return false;
504     }
505
506     if (node.has_key("material_state") && !vogl_json_deserialize_obj(node, blob_manager, "material_state", m_material_state))
507     {
508         clear();
509         return false;
510     }
511
512     if (node.has_key("light_state") && !vogl_json_deserialize_obj(node, blob_manager, "light_state", m_light_state))
513     {
514         clear();
515         return false;
516     }
517
518     if (node.has_key("matrix_state") && !vogl_json_deserialize_array(node, blob_manager, "matrix_state", m_matrix_state))
519     {
520         clear();
521         return false;
522     }
523
524     if (node.has_key("polygon_stipple") && !vogl_json_deserialize_obj(node, blob_manager, "polygon_stipple", m_polygon_stipple_state))
525     {
526         clear();
527         return false;
528     }
529
530     if (node.has_key("current_vertex_attribs") && !vogl_json_deserialize_array(node, blob_manager, "current_vertex_attribs", m_current_vertex_attrib_state))
531     {
532         clear();
533         return false;
534     }
535
536     if (node.has_key("arb_program_environment_state") && !vogl_json_deserialize_obj(node, blob_manager, "arb_program_environment_state", m_arb_program_environment_state))
537     {
538         clear();
539         return false;
540     }
541
542     const json_node *pObjects_node = node.find_child_object("state_objects");
543     if (pObjects_node)
544     {
545         for (uint obj_iter = 0; obj_iter < pObjects_node->size(); obj_iter++)
546         {
547             const dynamic_string &obj_type_str = pObjects_node->get_key(obj_iter);
548
549             vogl_gl_object_state_type state_type = determine_gl_object_state_type_from_str(obj_type_str.get_ptr());
550             if (state_type == cGLSTInvalid)
551             {
552                 vogl_warning_printf("%s: Unknown object state type \"%s\", skipping node\n", VOGL_METHOD_NAME, obj_type_str.get_ptr());
553                 continue;
554             }
555
556             const json_node *pArray_node = pObjects_node->get_value_as_array(obj_iter);
557             if (!pArray_node)
558             {
559                 clear();
560                 return false;
561             }
562
563             m_object_ptrs.reserve(m_object_ptrs.size() + pArray_node->size());
564
565             for (uint i = 0; i < pArray_node->size(); i++)
566             {
567                 const json_node *pObj_node = pArray_node->get_value_as_object(i);
568                 if (!pObj_node)
569                 {
570                     clear();
571                     return false;
572                 }
573
574                 vogl_gl_object_state *pState_obj = vogl_gl_object_state_factory(state_type);
575                 if (!pState_obj)
576                 {
577                     clear();
578                     return false;
579                 }
580
581                 if (!pState_obj->deserialize(*pObj_node, blob_manager))
582                 {
583                     vogl_delete(pState_obj);
584
585                     clear();
586                     return false;
587                 }
588
589                 m_object_ptrs.push_back(pState_obj);
590             }
591         }
592     }
593
594     m_is_valid = true;
595
596     return true;
597 }
598
599 vogl_gl_state_snapshot::vogl_gl_state_snapshot()
600     : m_window_width(0),
601       m_window_height(0),
602       m_cur_trace_context(0),
603       m_frame_index(0),
604       m_gl_call_counter(0),
605       m_at_frame_boundary(false),
606       m_is_restorable(false),
607       m_captured_default_framebuffer(false),
608       m_is_valid(false)
609 {
610     VOGL_FUNC_TRACER
611
612     m_uuid.clear();
613 }
614
615 vogl_gl_state_snapshot::~vogl_gl_state_snapshot()
616 {
617     VOGL_FUNC_TRACER
618
619     destroy_contexts();
620 }
621
622 void vogl_gl_state_snapshot::clear()
623 {
624     VOGL_FUNC_TRACER
625
626     m_uuid.clear();
627     m_window_width = 0;
628     m_window_height = 0;
629     m_cur_trace_context = 0;
630     m_frame_index = 0;
631     m_gl_call_counter = 0;
632     m_at_frame_boundary = false;
633     m_is_restorable = false;
634
635     m_client_side_vertex_attrib_ptrs.clear();
636     m_client_side_array_ptrs.clear();
637     m_client_side_texcoord_ptrs.clear();
638
639     destroy_contexts();
640
641     m_default_framebuffer.clear();
642
643     m_captured_default_framebuffer = false;
644     m_is_valid = false;
645 }
646
647 // frame_index indicates the beginning of frame X, at a swap boundary
648 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)
649 {
650     VOGL_FUNC_TRACER
651
652     clear();
653
654     m_uuid = gen_uuid();
655     m_window_width = window_width;
656     m_window_height = window_height;
657     m_cur_trace_context = cur_context;
658     m_frame_index = frame_index;
659     m_gl_call_counter = gl_call_counter;
660     m_at_frame_boundary = at_frame_boundary;
661     m_is_restorable = true;
662
663     m_is_valid = true;
664     m_captured_default_framebuffer = false;
665
666     return true;
667 }
668
669 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)
670 {
671     VOGL_FUNC_TRACER
672
673     m_client_side_vertex_attrib_ptrs = client_side_vertex_attrib_ptrs;
674     m_client_side_array_ptrs = client_side_array_ptrs;
675     m_client_side_texcoord_ptrs = client_side_texcoord_ptrs;
676 }
677
678 // TODO: check if the context was ever made current yet (if not the context_info won't be valid), make sure this path works
679 bool vogl_gl_state_snapshot::capture_context(
680     const vogl_context_desc &desc, const vogl_context_info &info, vogl_handle_remapper &remapper,
681     const vogl_capture_context_params &capture_params)
682 {
683     VOGL_FUNC_TRACER
684
685     if (!m_captured_default_framebuffer)
686     {
687         // TODO: Move this!
688         vogl_default_framebuffer_attribs fb_attribs;
689         fb_attribs.clear();
690
691         bool status = false;
692         if (vogl_get_default_framebuffer_attribs(fb_attribs, 0))
693         {
694             if ((fb_attribs.m_width) && (fb_attribs.m_height))
695             {
696                 status = m_default_framebuffer.snapshot(info, fb_attribs);
697             }
698         }
699
700         if (!status)
701         {
702             vogl_error_printf("%s: Failed snapshotting default framebuffer!\n", VOGL_METHOD_NAME);
703         }
704
705         m_captured_default_framebuffer = false;
706     }
707
708     vogl_context_snapshot *pSnapshot = vogl_new(vogl_context_snapshot);
709
710     if (!pSnapshot->capture(desc, info, capture_params, remapper))
711     {
712         m_is_valid = false;
713
714         vogl_delete(pSnapshot);
715
716         return false;
717     }
718
719     if (!pSnapshot->remap_handles(remapper))
720         return false;
721
722     m_context_ptrs.push_back(pSnapshot);
723
724     return true;
725 }
726
727 bool vogl_gl_state_snapshot::end_capture()
728 {
729     VOGL_FUNC_TRACER
730
731     return m_is_valid;
732 }
733
734 bool vogl_gl_state_snapshot::serialize(json_node &node, vogl_blob_manager &blob_manager, const vogl_ctypes *pCtypes) const
735 {
736     VOGL_FUNC_TRACER
737
738     if (!m_is_valid)
739         return false;
740
741     m_uuid.json_serialize(node.add("uuid"));
742     node.add_key_value("window_width", m_window_width);
743     node.add_key_value("window_height", m_window_height);
744     node.add_key_value("cur_trace_context", m_cur_trace_context);
745     node.add_key_value("frame_index", m_frame_index);
746     node.add_key_value("gl_call_counter", m_gl_call_counter);
747     node.add_key_value("at_frame_boundary", m_at_frame_boundary);
748     node.add_key_value("is_restorable", m_is_restorable);
749
750     if (!vogl_json_serialize_vec(node, blob_manager, "client_side_vertex_attrib_ptrs", m_client_side_vertex_attrib_ptrs))
751         return false;
752     if (!vogl_json_serialize_vec(node, blob_manager, "client_side_array_ptrs", m_client_side_array_ptrs))
753         return false;
754     if (!vogl_json_serialize_vec(node, blob_manager, "client_side_texcoord_ptrs", m_client_side_texcoord_ptrs))
755         return false;
756
757     if (!vogl_json_serialize_ptr_vec(node, blob_manager, "context_snapshots", m_context_ptrs, pCtypes))
758         return false;
759
760     if (m_default_framebuffer.is_valid())
761     {
762         if (!m_default_framebuffer.serialize(node.add_object("default_framebuffer"), blob_manager))
763             return false;
764     }
765
766     return true;
767 }
768
769 bool vogl_gl_state_snapshot::deserialize(const json_node &node, const vogl_blob_manager &blob_manager, const vogl_ctypes *pCtypes)
770 {
771     VOGL_FUNC_TRACER
772
773     clear();
774
775     if (!m_uuid.json_deserialize(node, "uuid"))
776     {
777         // For old trace files that don't have uuid's
778         m_uuid = gen_uuid();
779     }
780
781     m_window_width = node.value_as_uint32("window_width");
782     m_window_height = node.value_as_uint32("window_height");
783
784     if ((!m_window_width) || (!m_window_height))
785     {
786         clear();
787         return false;
788     }
789
790     m_cur_trace_context = static_cast<vogl_trace_ptr_value>(node.value_as_uint64("cur_trace_context"));
791     m_frame_index = node.value_as_uint32("frame_index");
792     m_gl_call_counter = node.value_as_int64("gl_call_counter");
793     m_at_frame_boundary = node.value_as_int64("at_frame_boundary");
794     m_is_restorable = node.value_as_bool("is_restorable", true);
795
796     if (!vogl_json_deserialize_vec(node, blob_manager, "client_side_vertex_attrib_ptrs", m_client_side_vertex_attrib_ptrs))
797         return false;
798     if (!vogl_json_deserialize_vec(node, blob_manager, "client_side_array_ptrs", m_client_side_array_ptrs))
799         return false;
800     if (!vogl_json_deserialize_vec(node, blob_manager, "client_side_texcoord_ptrs", m_client_side_texcoord_ptrs))
801         return false;
802
803     if (!vogl_json_deserialize_ptr_vec(node, blob_manager, "context_snapshots", m_context_ptrs, pCtypes))
804         return false;
805
806     if  (node.has_object("default_framebuffer"))
807     {
808         if (!m_default_framebuffer.deserialize(*node.find_child_object("default_framebuffer"), blob_manager))
809             return false;
810     }
811
812     m_is_valid = true;
813
814     return true;
815 }
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835