]> git.cworth.org Git - vogl/blob - src/voglcommon/vogl_renderbuffer_state.cpp
Initial vogl checkin
[vogl] / src / voglcommon / vogl_renderbuffer_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_renderbuffer_state.cpp
27 #include "vogl_common.h"
28 #include "vogl_renderbuffer_state.h"
29 #include "vogl_texture_format.h"
30
31 vogl_renderbuffer_desc::vogl_renderbuffer_desc()
32 {
33     VOGL_FUNC_TRACER
34
35     clear();
36 }
37
38 vogl_renderbuffer_desc::~vogl_renderbuffer_desc()
39 {
40     VOGL_FUNC_TRACER
41 }
42
43 void vogl_renderbuffer_desc::clear()
44 {
45     VOGL_FUNC_TRACER
46     m_width = 0;
47     m_height = 0;
48     m_samples = 0;
49     m_internal_format = 0;
50     m_red_size = 0;
51     m_green_size = 0;
52     m_blue_size = 0;
53     m_alpha_size = 0;
54     m_depth_size = 0;
55     m_stencil_size = 0;
56 }
57
58 bool vogl_renderbuffer_desc::snapshot(const vogl_context_info &context_info)
59 {
60     VOGL_FUNC_TRACER
61
62     VOGL_ASSERT(context_info.get_version() >= VOGL_GL_VERSION_3_0);
63     VOGL_NOTE_UNUSED(context_info);
64
65     VOGL_CHECK_GL_ERROR;
66
67 #define GET_STATE(e, x)                                                                               \
68     do                                                                                                \
69     {                                                                                                 \
70         GL_ENTRYPOINT(glGetRenderbufferParameteriv)(GL_RENDERBUFFER, e, reinterpret_cast<int *>(&x)); \
71         VOGL_CHECK_GL_ERROR;                                                                           \
72     } while (0)
73     GET_STATE(GL_RENDERBUFFER_WIDTH, m_width);
74     GET_STATE(GL_RENDERBUFFER_HEIGHT, m_height);
75     GET_STATE(GL_RENDERBUFFER_SAMPLES, m_samples);
76     GET_STATE(GL_RENDERBUFFER_INTERNAL_FORMAT, m_internal_format);
77     GET_STATE(GL_RENDERBUFFER_RED_SIZE, m_red_size);
78     GET_STATE(GL_RENDERBUFFER_GREEN_SIZE, m_green_size);
79     GET_STATE(GL_RENDERBUFFER_BLUE_SIZE, m_blue_size);
80     GET_STATE(GL_RENDERBUFFER_ALPHA_SIZE, m_alpha_size);
81     GET_STATE(GL_RENDERBUFFER_DEPTH_SIZE, m_depth_size);
82     GET_STATE(GL_RENDERBUFFER_STENCIL_SIZE, m_stencil_size);
83 #undef GET_STATE
84
85     return true;
86 }
87
88 bool vogl_renderbuffer_desc::restore(const vogl_context_info &context_info) const
89 {
90     VOGL_FUNC_TRACER
91
92     VOGL_NOTE_UNUSED(context_info);
93
94     if (!m_width)
95         return false;
96
97     VOGL_ASSERT(context_info.get_version() >= VOGL_GL_VERSION_3_0);
98
99     VOGL_CHECK_GL_ERROR;
100
101     GL_ENTRYPOINT(glRenderbufferStorageMultisample)(GL_RENDERBUFFER, m_samples, m_internal_format, m_width, m_height);
102
103     bool prev_gl_error = vogl_check_gl_error();
104     VOGL_ASSERT(!prev_gl_error);
105
106     return !prev_gl_error;
107 }
108
109 bool vogl_renderbuffer_desc::serialize(json_node &node) const
110 {
111     VOGL_FUNC_TRACER
112
113     node.add_key_value("width", m_width);
114     node.add_key_value("height", m_height);
115     node.add_key_value("internal_format", g_gl_enums.find_name(m_internal_format, "gl"));
116     node.add_key_value("samples", m_samples);
117     node.add_key_value("red_size", m_red_size);
118     node.add_key_value("green_size", m_green_size);
119     node.add_key_value("blue_size", m_blue_size);
120     node.add_key_value("alpha_size", m_alpha_size);
121     node.add_key_value("depth_size", m_depth_size);
122     node.add_key_value("stencil_size", m_stencil_size);
123
124     return true;
125 }
126
127 bool vogl_renderbuffer_desc::deserialize(const json_node &node)
128 {
129     VOGL_FUNC_TRACER
130
131     clear();
132
133     m_width = node.value_as_int("width");
134     m_height = node.value_as_int("height");
135     m_samples = node.value_as_int("samples");
136     m_red_size = node.value_as_int("red_size");
137     m_green_size = node.value_as_int("green_size");
138     m_blue_size = node.value_as_int("blue_size");
139     m_alpha_size = node.value_as_int("alpha_size");
140     m_depth_size = node.value_as_int("depth_size");
141     m_stencil_size = node.value_as_int("stencil_size");
142
143     const char *pFmt = node.value_as_string_ptr("internal_format");
144     if (!pFmt)
145     {
146         VOGL_ASSERT_ALWAYS;
147         return false;
148     }
149
150     uint64_t enum_val = g_gl_enums.find_enum(pFmt);
151     VOGL_ASSERT(enum_val != gl_enums::cUnknownEnum);
152     if (enum_val == gl_enums::cUnknownEnum)
153         return false;
154     if (enum_val > cUINT32_MAX)
155     {
156         VOGL_ASSERT_ALWAYS;
157         return false;
158     }
159     m_internal_format = static_cast<GLenum>(enum_val);
160
161     return true;
162 }
163
164 bool vogl_renderbuffer_desc::operator==(const vogl_renderbuffer_desc &rhs) const
165 {
166     VOGL_FUNC_TRACER
167
168 #define COMP(x)     \
169     if (x != rhs.x) \
170         return false;
171     COMP(m_width);
172     COMP(m_height);
173     COMP(m_samples);
174     COMP(m_internal_format);
175     COMP(m_red_size);
176     COMP(m_green_size);
177     COMP(m_blue_size);
178     COMP(m_alpha_size);
179     COMP(m_depth_size);
180     COMP(m_stencil_size);
181
182 #undef COMP
183     return true;
184 }
185
186 bool vogl_renderbuffer_desc::get_int(GLenum enum_val, int *pVals, uint n) const
187 {
188     VOGL_FUNC_TRACER
189
190     int result = 0;
191
192     if (n < 1)
193         return false;
194
195     switch (enum_val)
196     {
197         case GL_RENDERBUFFER_WIDTH:
198         {
199             result = m_width;
200             break;
201         }
202         case GL_RENDERBUFFER_HEIGHT:
203         {
204             result = m_height;
205             break;
206         }
207         case GL_RENDERBUFFER_SAMPLES:
208         {
209             result = m_samples;
210             break;
211         }
212         case GL_RENDERBUFFER_INTERNAL_FORMAT:
213         {
214             result = m_internal_format;
215             break;
216         }
217         case GL_RENDERBUFFER_RED_SIZE:
218         {
219             result = m_red_size;
220             break;
221         }
222         case GL_RENDERBUFFER_GREEN_SIZE:
223         {
224             result = m_green_size;
225             break;
226         }
227         case GL_RENDERBUFFER_BLUE_SIZE:
228         {
229             result = m_blue_size;
230             break;
231         }
232         case GL_RENDERBUFFER_ALPHA_SIZE:
233         {
234             result = m_alpha_size;
235             break;
236         }
237         case GL_RENDERBUFFER_DEPTH_SIZE:
238         {
239             result = m_depth_size;
240             break;
241         }
242         case GL_RENDERBUFFER_STENCIL_SIZE:
243         {
244             result = m_stencil_size;
245             break;
246         }
247         default:
248         {
249             VOGL_ASSERT_ALWAYS;
250             *pVals = 0;
251             return false;
252         }
253     }
254
255     *pVals = result;
256     return true;
257 }
258
259 vogl_renderbuffer_state::vogl_renderbuffer_state()
260     : m_snapshot_handle(0),
261       m_is_valid(false)
262 {
263     VOGL_FUNC_TRACER
264 }
265
266 vogl_renderbuffer_state::~vogl_renderbuffer_state()
267 {
268     VOGL_FUNC_TRACER
269
270     clear();
271 }
272
273 bool vogl_renderbuffer_state::snapshot(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint64 handle, GLenum target)
274 {
275     VOGL_FUNC_TRACER
276
277     VOGL_NOTE_UNUSED(remapper);
278     VOGL_ASSERT(context_info.get_version() >= VOGL_GL_VERSION_3_0);
279     VOGL_CHECK_GL_ERROR;
280     VOGL_NOTE_UNUSED(target);
281
282     clear();
283
284     VOGL_ASSERT(handle <= cUINT32_MAX);
285
286     m_snapshot_handle = static_cast<GLuint>(handle);
287
288     vogl_scoped_binding_state orig_renderbuffer(GL_RENDERBUFFER);
289
290     GL_ENTRYPOINT(glBindRenderbuffer)(GL_RENDERBUFFER, m_snapshot_handle);
291     VOGL_CHECK_GL_ERROR;
292
293     if (!m_desc.snapshot(context_info))
294         return false;
295
296     vogl_scoped_state_saver framebuffer_state_saver(cGSTReadBuffer, cGSTDrawBuffer);
297     vogl_scoped_binding_state orig_framebuffers(GL_DRAW_FRAMEBUFFER, GL_READ_FRAMEBUFFER, GL_TEXTURE_2D, GL_TEXTURE_2D_MULTISAMPLE);
298
299     const GLenum tex_target = (m_desc.m_samples > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;
300
301     bool capture_status = false;
302
303     GLenum internal_fmt = m_desc.m_internal_format;
304     const vogl_internal_tex_format *pInternal_tex_fmt = vogl_find_internal_texture_format(internal_fmt);
305     if ((pInternal_tex_fmt) && (pInternal_tex_fmt->m_optimum_get_image_fmt != GL_NONE) && (pInternal_tex_fmt->m_optimum_get_image_type != GL_NONE))
306     {
307         // Create texture
308         GLuint tex_handle = 0;
309         GL_ENTRYPOINT(glGenTextures)(1, &tex_handle);
310         VOGL_CHECK_GL_ERROR;
311
312         GL_ENTRYPOINT(glBindTexture)(tex_target, tex_handle);
313         VOGL_CHECK_GL_ERROR;
314
315         if (m_desc.m_samples > 1)
316         {
317             GL_ENTRYPOINT(glTexImage2DMultisample)(tex_target,
318                 m_desc.m_samples,
319                 internal_fmt,
320                 m_desc.m_width,
321                 m_desc.m_height,
322                 GL_TRUE);
323         }
324         else
325         {
326             GL_ENTRYPOINT(glTexImage2D)(tex_target,
327                 0,
328                 internal_fmt,
329                 m_desc.m_width,
330                 m_desc.m_height,
331                 0,
332                 pInternal_tex_fmt->m_optimum_get_image_fmt,
333                 pInternal_tex_fmt->m_optimum_get_image_type,
334                 NULL);
335         }
336
337         if (!vogl_check_gl_error_internal())
338         {
339             GL_ENTRYPOINT(glTexParameteri)(tex_target, GL_TEXTURE_MAX_LEVEL, 0);
340             VOGL_CHECK_GL_ERROR;
341
342             GLenum attachment = GL_COLOR_ATTACHMENT0;
343             GLenum draw_and_read_buf = GL_COLOR_ATTACHMENT0;
344             GLenum blit_type = GL_COLOR_BUFFER_BIT;
345
346             if ((m_desc.m_depth_size) && (m_desc.m_stencil_size))
347             {
348                 attachment = GL_DEPTH_STENCIL_ATTACHMENT;
349                 draw_and_read_buf = GL_NONE;
350                 blit_type = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
351             }
352             else if (m_desc.m_depth_size)
353             {
354                 attachment = GL_DEPTH_ATTACHMENT;
355                 draw_and_read_buf = GL_NONE;
356                 blit_type = GL_DEPTH_BUFFER_BIT;
357             }
358             else if (m_desc.m_stencil_size)
359             {
360                 attachment = GL_STENCIL_ATTACHMENT;
361                 draw_and_read_buf = GL_NONE;
362                 blit_type = GL_STENCIL_BUFFER_BIT;
363             }
364
365             GLuint src_fbo_handle = 0, dst_fbo_handle = 0;
366
367             // Source FBO
368             GL_ENTRYPOINT(glGenFramebuffers)(1, &src_fbo_handle);
369             VOGL_CHECK_GL_ERROR;
370
371             GL_ENTRYPOINT(glBindFramebuffer)(GL_READ_FRAMEBUFFER, src_fbo_handle);
372             VOGL_CHECK_GL_ERROR;
373
374             GL_ENTRYPOINT(glFramebufferRenderbuffer)(GL_READ_FRAMEBUFFER, attachment, GL_RENDERBUFFER, m_snapshot_handle);
375             VOGL_CHECK_GL_ERROR;
376
377             GL_ENTRYPOINT(glReadBuffer)(draw_and_read_buf);
378             VOGL_CHECK_GL_ERROR;
379
380             // Dest FBO
381             GL_ENTRYPOINT(glGenFramebuffers)(1, &dst_fbo_handle);
382             VOGL_CHECK_GL_ERROR;
383
384             GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, dst_fbo_handle);
385             VOGL_CHECK_GL_ERROR;
386
387             GL_ENTRYPOINT(glFramebufferTexture2D)(GL_DRAW_FRAMEBUFFER, attachment, tex_target, tex_handle, 0);
388             VOGL_CHECK_GL_ERROR;
389
390             GL_ENTRYPOINT(glDrawBuffers)(1, &draw_and_read_buf);
391             VOGL_CHECK_GL_ERROR;
392
393             GLenum read_status = GL_ENTRYPOINT(glCheckFramebufferStatus)(GL_READ_FRAMEBUFFER);
394             VOGL_CHECK_GL_ERROR;
395
396             GLenum draw_status = GL_ENTRYPOINT(glCheckFramebufferStatus)(GL_DRAW_FRAMEBUFFER);
397             VOGL_CHECK_GL_ERROR;
398
399             if ((read_status == GL_FRAMEBUFFER_COMPLETE) && (draw_status == GL_FRAMEBUFFER_COMPLETE))
400             {
401                 GL_ENTRYPOINT(glBlitFramebuffer)(
402                     0, 0, m_desc.m_width, m_desc.m_height,
403                     0, 0, m_desc.m_width, m_desc.m_height,
404                     blit_type,
405                     GL_NEAREST);
406
407                 if (!vogl_check_gl_error_internal())
408                 {
409                     vogl_handle_remapper def_handle_remapper;
410                     if (m_texture.snapshot(context_info, def_handle_remapper, tex_handle, tex_target))
411                         capture_status = true;
412                 }
413             }
414
415             // Delete FBO
416             GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, 0);
417             VOGL_CHECK_GL_ERROR;
418
419             GL_ENTRYPOINT(glDeleteFramebuffers)(1, &dst_fbo_handle);
420             VOGL_CHECK_GL_ERROR;
421
422             GL_ENTRYPOINT(glBindFramebuffer)(GL_READ_FRAMEBUFFER, 0);
423             VOGL_CHECK_GL_ERROR;
424
425             GL_ENTRYPOINT(glDeleteFramebuffers)(1, &src_fbo_handle);
426             VOGL_CHECK_GL_ERROR;
427         }
428
429         GL_ENTRYPOINT(glBindTexture)(tex_target, 0);
430         VOGL_CHECK_GL_ERROR;
431
432         GL_ENTRYPOINT(glDeleteTextures)(1, &tex_handle);
433         VOGL_CHECK_GL_ERROR;
434     }
435
436     if (!capture_status)
437     {
438         vogl_error_printf("%s: Failed blitting renderbuffer data to texture for renderbuffer %" PRIu64 "\n", VOGL_METHOD_NAME, static_cast<uint64_t>(handle));
439     }
440
441     m_is_valid = true;
442
443     return true;
444 }
445
446 bool vogl_renderbuffer_state::restore(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint64 &handle) const
447 {
448     VOGL_FUNC_TRACER
449
450     VOGL_ASSERT(context_info.get_version() >= VOGL_GL_VERSION_3_0);
451
452     if (!m_is_valid)
453         return false;
454
455     vogl_scoped_binding_state orig_renderbuffer(GL_RENDERBUFFER);
456
457     bool created_handle = false;
458
459     if (!handle)
460     {
461         GLuint handle32 = 0;
462         GL_ENTRYPOINT(glGenRenderbuffers)(1, &handle32);
463         if ((vogl_check_gl_error()) || (!handle32))
464             return false;
465         handle = handle32;
466
467         remapper.declare_handle(VOGL_NAMESPACE_RENDER_BUFFERS, m_snapshot_handle, handle, GL_NONE);
468         VOGL_ASSERT(remapper.remap_handle(VOGL_NAMESPACE_RENDER_BUFFERS, m_snapshot_handle) == handle);
469
470         created_handle = true;
471     }
472
473     GL_ENTRYPOINT(glBindRenderbuffer)(GL_RENDERBUFFER, static_cast<GLuint>(handle));
474     if (vogl_check_gl_error())
475         goto handle_error;
476
477     if (!m_desc.restore(context_info))
478         goto handle_error;
479
480     if (m_texture.is_valid())
481     {
482         GLenum attachment = GL_COLOR_ATTACHMENT0;
483         GLenum draw_and_read_buf = GL_COLOR_ATTACHMENT0;
484         GLenum blit_type = GL_COLOR_BUFFER_BIT;
485
486         if ((m_desc.m_depth_size) && (m_desc.m_stencil_size))
487         {
488             attachment = GL_DEPTH_STENCIL_ATTACHMENT;
489             draw_and_read_buf = GL_NONE;
490             blit_type = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
491         }
492         else if (m_desc.m_depth_size)
493         {
494             attachment = GL_DEPTH_ATTACHMENT;
495             draw_and_read_buf = GL_NONE;
496             blit_type = GL_DEPTH_BUFFER_BIT;
497         }
498         else if (m_desc.m_stencil_size)
499         {
500             attachment = GL_STENCIL_ATTACHMENT;
501             draw_and_read_buf = GL_NONE;
502             blit_type = GL_STENCIL_BUFFER_BIT;
503         }
504
505         bool restore_status = false;
506
507         GLuint64 tex_handle64 = 0;
508         vogl_handle_remapper def_handle_remapper;
509         if (m_texture.restore(context_info, def_handle_remapper, tex_handle64))
510         {
511             GLuint tex_handle = static_cast<GLuint>(tex_handle64);
512
513             const GLenum tex_target = (m_desc.m_samples > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;
514
515             GLuint src_fbo_handle = 0, dst_fbo_handle = 0;
516
517             // Source FBO
518             GL_ENTRYPOINT(glGenFramebuffers)(1, &src_fbo_handle);
519             VOGL_CHECK_GL_ERROR;
520
521             GL_ENTRYPOINT(glBindFramebuffer)(GL_READ_FRAMEBUFFER, src_fbo_handle);
522             VOGL_CHECK_GL_ERROR;
523
524             GL_ENTRYPOINT(glFramebufferTexture2D)(GL_READ_FRAMEBUFFER, attachment, tex_target, tex_handle, 0);
525             VOGL_CHECK_GL_ERROR;
526
527             GL_ENTRYPOINT(glReadBuffer)(draw_and_read_buf);
528             VOGL_CHECK_GL_ERROR;
529
530             // Dest FBO
531             GL_ENTRYPOINT(glGenFramebuffers)(1, &dst_fbo_handle);
532             VOGL_CHECK_GL_ERROR;
533
534             GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, dst_fbo_handle);
535             VOGL_CHECK_GL_ERROR;
536
537             GL_ENTRYPOINT(glFramebufferRenderbuffer)(GL_DRAW_FRAMEBUFFER, attachment, GL_RENDERBUFFER, static_cast<GLuint>(handle));
538             VOGL_CHECK_GL_ERROR;
539
540             GL_ENTRYPOINT(glDrawBuffers)(1, &draw_and_read_buf);
541             VOGL_CHECK_GL_ERROR;
542
543             GLenum read_status = GL_ENTRYPOINT(glCheckFramebufferStatus)(GL_READ_FRAMEBUFFER);
544             VOGL_CHECK_GL_ERROR;
545
546             GLenum draw_status = GL_ENTRYPOINT(glCheckFramebufferStatus)(GL_DRAW_FRAMEBUFFER);
547             VOGL_CHECK_GL_ERROR;
548
549             if ((read_status = GL_FRAMEBUFFER_COMPLETE) && (draw_status == GL_FRAMEBUFFER_COMPLETE))
550             {
551 #if 0
552                 // HACK HACK HACK
553                 if (m_texture.get_num_samples() > 1)
554                 {
555                     uint base_level = m_texture.get_params().get_value<GLenum>(GL_TEXTURE_BASE_LEVEL);
556
557                     if (base_level < m_texture.get_num_levels())
558                     {
559                         const vogl_state_vector &state_vec = m_texture.get_level_params(0, base_level);
560
561                         uint clear_mask = 0;
562                         if (state_vec.get_value<GLenum>(GL_TEXTURE_DEPTH_SIZE))
563                         {
564                             clear_mask |= GL_DEPTH_BUFFER_BIT;
565                         }
566                         if (state_vec.get_value<GLenum>(GL_TEXTURE_STENCIL_SIZE))
567                         {
568                             clear_mask |= GL_STENCIL_BUFFER_BIT;
569                         }
570                         if (state_vec.get_value<GLenum>(GL_TEXTURE_RED_SIZE) + state_vec.get_value<GLenum>(GL_TEXTURE_GREEN_SIZE) + state_vec.get_value<GLenum>(GL_TEXTURE_BLUE_SIZE) + state_vec.get_value<GLenum>(GL_TEXTURE_ALPHA_SIZE) +
571                             state_vec.get_value<GLenum>(GL_TEXTURE_INTENSITY_SIZE) + state_vec.get_value<GLenum>(GL_TEXTURE_LUMINANCE_SIZE))
572                         {
573                             clear_mask |= GL_COLOR_BUFFER_BIT;
574                         }
575
576                         GL_ENTRYPOINT(glClearColor)(1.0f, 0.0f, 1.0f, 1.0f);
577                         GL_ENTRYPOINT(glClearDepth)(.5f);
578                         GL_ENTRYPOINT(glClearStencil)(128);
579                         GL_ENTRYPOINT(glClear)(clear_mask);
580
581                         VOGL_CHECK_GL_ERROR;
582                     }
583                 }
584                 else
585 #endif
586                 {
587                     GL_ENTRYPOINT(glBlitFramebuffer)(
588                         0, 0, m_desc.m_width, m_desc.m_height,
589                         0, 0, m_desc.m_width, m_desc.m_height,
590                         blit_type,
591                         GL_NEAREST);
592
593                     if (!vogl_check_gl_error_internal())
594                     {
595                         restore_status = true;
596                     }
597                 }
598             }
599
600             // Delete FBO
601             GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, 0);
602             VOGL_CHECK_GL_ERROR;
603
604             GL_ENTRYPOINT(glDeleteFramebuffers)(1, &dst_fbo_handle);
605             VOGL_CHECK_GL_ERROR;
606
607             GL_ENTRYPOINT(glBindFramebuffer)(GL_READ_FRAMEBUFFER, 0);
608             VOGL_CHECK_GL_ERROR;
609
610             GL_ENTRYPOINT(glDeleteFramebuffers)(1, &src_fbo_handle);
611             VOGL_CHECK_GL_ERROR;
612
613             GL_ENTRYPOINT(glDeleteTextures)(1, &tex_handle);
614             VOGL_CHECK_GL_ERROR;
615         }
616
617         if (!restore_status)
618         {
619             vogl_error_printf("%s: Failed restoring contents of renderbuffer %u\n", VOGL_METHOD_NAME, static_cast<GLuint>(handle));
620         }
621     }
622
623     return true;
624
625 handle_error:
626     if (created_handle)
627     {
628         GL_ENTRYPOINT(glBindRenderbuffer)(GL_RENDERBUFFER, 0);
629         VOGL_CHECK_GL_ERROR;
630
631         remapper.delete_handle_and_object(VOGL_NAMESPACE_RENDER_BUFFERS, m_snapshot_handle, handle);
632
633         //GLuint handle32 = static_cast<GLuint>(handle);
634         //GL_ENTRYPOINT(glDeleteRenderbuffers)(1, &handle32);
635         //VOGL_CHECK_GL_ERROR;
636
637         handle = 0;
638     }
639
640     return false;
641 }
642
643 bool vogl_renderbuffer_state::remap_handles(vogl_handle_remapper &remapper)
644 {
645     VOGL_FUNC_TRACER
646
647     if (!m_is_valid)
648         return false;
649
650     m_snapshot_handle = static_cast<GLuint>(remapper.remap_handle(VOGL_NAMESPACE_RENDER_BUFFERS, m_snapshot_handle));
651
652     return true;
653 }
654
655 void vogl_renderbuffer_state::clear()
656 {
657     VOGL_FUNC_TRACER
658
659     m_snapshot_handle = 0;
660
661     m_desc.clear();
662     m_texture.clear();
663
664     m_is_valid = false;
665 }
666
667 bool vogl_renderbuffer_state::serialize(json_node &node, vogl_blob_manager &blob_manager) const
668 {
669     VOGL_FUNC_TRACER
670
671     VOGL_NOTE_UNUSED(blob_manager);
672
673     if (!m_is_valid)
674         return false;
675
676     node.add_key_value("handle", m_snapshot_handle);
677
678     if (!m_desc.serialize(node))
679         return false;
680
681     if (m_texture.is_valid())
682     {
683         if (!m_texture.serialize(node.add_object("texture"), blob_manager))
684             return false;
685     }
686
687     return true;
688 }
689
690 bool vogl_renderbuffer_state::deserialize(const json_node &node, const vogl_blob_manager &blob_manager)
691 {
692     VOGL_FUNC_TRACER
693
694     VOGL_NOTE_UNUSED(blob_manager);
695
696     clear();
697
698     m_snapshot_handle = node.value_as_int("handle");
699
700     if (!m_desc.deserialize(node))
701         return false;
702
703     if (node.has_object("texture"))
704     {
705         if (!m_texture.deserialize(*node.find_child_object("texture"), blob_manager))
706             return false;
707     }
708
709     m_is_valid = true;
710
711     return true;
712 }
713
714 bool vogl_renderbuffer_state::compare_restorable_state(const vogl_gl_object_state &rhs_obj) const
715 {
716     VOGL_FUNC_TRACER
717
718     if ((!m_is_valid) || (!rhs_obj.is_valid()))
719         return false;
720
721     if (rhs_obj.get_type() != cGLSTRenderbuffer)
722         return false;
723
724     const vogl_renderbuffer_state &rhs = static_cast<const vogl_renderbuffer_state &>(rhs_obj);
725
726     if (this == &rhs)
727         return true;
728
729     return (m_desc == rhs.m_desc) && (m_texture.compare_restorable_state(rhs.m_texture));
730 }
731