1 /**************************************************************************
3 * Copyright 2013-2014 RAD Game Tools and Valve Software
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 **************************************************************************/
26 // File: vogl_renderbuffer_state.cpp
27 #include "vogl_common.h"
28 #include "vogl_renderbuffer_state.h"
29 #include "vogl_texture_format.h"
31 vogl_renderbuffer_desc::vogl_renderbuffer_desc()
38 vogl_renderbuffer_desc::~vogl_renderbuffer_desc()
43 void vogl_renderbuffer_desc::clear()
49 m_internal_format = 0;
58 bool vogl_renderbuffer_desc::snapshot(const vogl_context_info &context_info)
62 VOGL_ASSERT(context_info.get_version() >= VOGL_GL_VERSION_3_0);
63 VOGL_NOTE_UNUSED(context_info);
67 #define GET_STATE(e, x) \
70 GL_ENTRYPOINT(glGetRenderbufferParameteriv)(GL_RENDERBUFFER, e, reinterpret_cast<int *>(&x)); \
71 VOGL_CHECK_GL_ERROR; \
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);
88 bool vogl_renderbuffer_desc::restore(const vogl_context_info &context_info) const
92 VOGL_NOTE_UNUSED(context_info);
97 VOGL_ASSERT(context_info.get_version() >= VOGL_GL_VERSION_3_0);
101 GL_ENTRYPOINT(glRenderbufferStorageMultisample)(GL_RENDERBUFFER, m_samples, m_internal_format, m_width, m_height);
103 bool prev_gl_error = vogl_check_gl_error();
104 VOGL_ASSERT(!prev_gl_error);
106 return !prev_gl_error;
109 bool vogl_renderbuffer_desc::serialize(json_node &node) const
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);
127 bool vogl_renderbuffer_desc::deserialize(const json_node &node)
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");
143 const char *pFmt = node.value_as_string_ptr("internal_format");
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)
154 if (enum_val > cUINT32_MAX)
159 m_internal_format = static_cast<GLenum>(enum_val);
164 bool vogl_renderbuffer_desc::operator==(const vogl_renderbuffer_desc &rhs) const
174 COMP(m_internal_format);
180 COMP(m_stencil_size);
186 bool vogl_renderbuffer_desc::get_int(GLenum enum_val, int *pVals, uint n) const
197 case GL_RENDERBUFFER_WIDTH:
202 case GL_RENDERBUFFER_HEIGHT:
207 case GL_RENDERBUFFER_SAMPLES:
212 case GL_RENDERBUFFER_INTERNAL_FORMAT:
214 result = m_internal_format;
217 case GL_RENDERBUFFER_RED_SIZE:
222 case GL_RENDERBUFFER_GREEN_SIZE:
224 result = m_green_size;
227 case GL_RENDERBUFFER_BLUE_SIZE:
229 result = m_blue_size;
232 case GL_RENDERBUFFER_ALPHA_SIZE:
234 result = m_alpha_size;
237 case GL_RENDERBUFFER_DEPTH_SIZE:
239 result = m_depth_size;
242 case GL_RENDERBUFFER_STENCIL_SIZE:
244 result = m_stencil_size;
259 vogl_renderbuffer_state::vogl_renderbuffer_state()
260 : m_snapshot_handle(0),
266 vogl_renderbuffer_state::~vogl_renderbuffer_state()
273 bool vogl_renderbuffer_state::snapshot(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint64 handle, GLenum target)
277 VOGL_NOTE_UNUSED(remapper);
278 VOGL_ASSERT(context_info.get_version() >= VOGL_GL_VERSION_3_0);
280 VOGL_NOTE_UNUSED(target);
284 VOGL_ASSERT(handle <= cUINT32_MAX);
286 m_snapshot_handle = static_cast<GLuint>(handle);
288 vogl_scoped_binding_state orig_renderbuffer(GL_RENDERBUFFER);
290 GL_ENTRYPOINT(glBindRenderbuffer)(GL_RENDERBUFFER, m_snapshot_handle);
293 if (!m_desc.snapshot(context_info))
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);
299 const GLenum tex_target = (m_desc.m_samples > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;
301 bool capture_status = false;
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))
308 GLuint tex_handle = 0;
309 GL_ENTRYPOINT(glGenTextures)(1, &tex_handle);
312 GL_ENTRYPOINT(glBindTexture)(tex_target, tex_handle);
315 if (m_desc.m_samples > 1)
317 GL_ENTRYPOINT(glTexImage2DMultisample)(tex_target,
326 GL_ENTRYPOINT(glTexImage2D)(tex_target,
332 pInternal_tex_fmt->m_optimum_get_image_fmt,
333 pInternal_tex_fmt->m_optimum_get_image_type,
337 if (!vogl_check_gl_error_internal())
339 GL_ENTRYPOINT(glTexParameteri)(tex_target, GL_TEXTURE_MAX_LEVEL, 0);
342 GLenum attachment = GL_COLOR_ATTACHMENT0;
343 GLenum draw_and_read_buf = GL_COLOR_ATTACHMENT0;
344 GLenum blit_type = GL_COLOR_BUFFER_BIT;
346 if ((m_desc.m_depth_size) && (m_desc.m_stencil_size))
348 attachment = GL_DEPTH_STENCIL_ATTACHMENT;
349 draw_and_read_buf = GL_NONE;
350 blit_type = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
352 else if (m_desc.m_depth_size)
354 attachment = GL_DEPTH_ATTACHMENT;
355 draw_and_read_buf = GL_NONE;
356 blit_type = GL_DEPTH_BUFFER_BIT;
358 else if (m_desc.m_stencil_size)
360 attachment = GL_STENCIL_ATTACHMENT;
361 draw_and_read_buf = GL_NONE;
362 blit_type = GL_STENCIL_BUFFER_BIT;
365 GLuint src_fbo_handle = 0, dst_fbo_handle = 0;
368 GL_ENTRYPOINT(glGenFramebuffers)(1, &src_fbo_handle);
371 GL_ENTRYPOINT(glBindFramebuffer)(GL_READ_FRAMEBUFFER, src_fbo_handle);
374 GL_ENTRYPOINT(glFramebufferRenderbuffer)(GL_READ_FRAMEBUFFER, attachment, GL_RENDERBUFFER, m_snapshot_handle);
377 GL_ENTRYPOINT(glReadBuffer)(draw_and_read_buf);
381 GL_ENTRYPOINT(glGenFramebuffers)(1, &dst_fbo_handle);
384 GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, dst_fbo_handle);
387 GL_ENTRYPOINT(glFramebufferTexture2D)(GL_DRAW_FRAMEBUFFER, attachment, tex_target, tex_handle, 0);
390 GL_ENTRYPOINT(glDrawBuffers)(1, &draw_and_read_buf);
393 GLenum read_status = GL_ENTRYPOINT(glCheckFramebufferStatus)(GL_READ_FRAMEBUFFER);
396 GLenum draw_status = GL_ENTRYPOINT(glCheckFramebufferStatus)(GL_DRAW_FRAMEBUFFER);
399 if ((read_status == GL_FRAMEBUFFER_COMPLETE) && (draw_status == GL_FRAMEBUFFER_COMPLETE))
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,
407 if (!vogl_check_gl_error_internal())
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;
416 GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, 0);
419 GL_ENTRYPOINT(glDeleteFramebuffers)(1, &dst_fbo_handle);
422 GL_ENTRYPOINT(glBindFramebuffer)(GL_READ_FRAMEBUFFER, 0);
425 GL_ENTRYPOINT(glDeleteFramebuffers)(1, &src_fbo_handle);
429 GL_ENTRYPOINT(glBindTexture)(tex_target, 0);
432 GL_ENTRYPOINT(glDeleteTextures)(1, &tex_handle);
438 vogl_error_printf("%s: Failed blitting renderbuffer data to texture for renderbuffer %" PRIu64 "\n", VOGL_METHOD_NAME, static_cast<uint64_t>(handle));
446 bool vogl_renderbuffer_state::restore(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint64 &handle) const
450 VOGL_ASSERT(context_info.get_version() >= VOGL_GL_VERSION_3_0);
455 vogl_scoped_binding_state orig_renderbuffer(GL_RENDERBUFFER);
457 bool created_handle = false;
462 GL_ENTRYPOINT(glGenRenderbuffers)(1, &handle32);
463 if ((vogl_check_gl_error()) || (!handle32))
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);
470 created_handle = true;
473 GL_ENTRYPOINT(glBindRenderbuffer)(GL_RENDERBUFFER, static_cast<GLuint>(handle));
474 if (vogl_check_gl_error())
477 if (!m_desc.restore(context_info))
480 if (m_texture.is_valid())
482 GLenum attachment = GL_COLOR_ATTACHMENT0;
483 GLenum draw_and_read_buf = GL_COLOR_ATTACHMENT0;
484 GLenum blit_type = GL_COLOR_BUFFER_BIT;
486 if ((m_desc.m_depth_size) && (m_desc.m_stencil_size))
488 attachment = GL_DEPTH_STENCIL_ATTACHMENT;
489 draw_and_read_buf = GL_NONE;
490 blit_type = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
492 else if (m_desc.m_depth_size)
494 attachment = GL_DEPTH_ATTACHMENT;
495 draw_and_read_buf = GL_NONE;
496 blit_type = GL_DEPTH_BUFFER_BIT;
498 else if (m_desc.m_stencil_size)
500 attachment = GL_STENCIL_ATTACHMENT;
501 draw_and_read_buf = GL_NONE;
502 blit_type = GL_STENCIL_BUFFER_BIT;
505 bool restore_status = false;
507 GLuint64 tex_handle64 = 0;
508 vogl_handle_remapper def_handle_remapper;
509 if (m_texture.restore(context_info, def_handle_remapper, tex_handle64))
511 GLuint tex_handle = static_cast<GLuint>(tex_handle64);
513 const GLenum tex_target = (m_desc.m_samples > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;
515 GLuint src_fbo_handle = 0, dst_fbo_handle = 0;
518 GL_ENTRYPOINT(glGenFramebuffers)(1, &src_fbo_handle);
521 GL_ENTRYPOINT(glBindFramebuffer)(GL_READ_FRAMEBUFFER, src_fbo_handle);
524 GL_ENTRYPOINT(glFramebufferTexture2D)(GL_READ_FRAMEBUFFER, attachment, tex_target, tex_handle, 0);
527 GL_ENTRYPOINT(glReadBuffer)(draw_and_read_buf);
531 GL_ENTRYPOINT(glGenFramebuffers)(1, &dst_fbo_handle);
534 GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, dst_fbo_handle);
537 GL_ENTRYPOINT(glFramebufferRenderbuffer)(GL_DRAW_FRAMEBUFFER, attachment, GL_RENDERBUFFER, static_cast<GLuint>(handle));
540 GL_ENTRYPOINT(glDrawBuffers)(1, &draw_and_read_buf);
543 GLenum read_status = GL_ENTRYPOINT(glCheckFramebufferStatus)(GL_READ_FRAMEBUFFER);
546 GLenum draw_status = GL_ENTRYPOINT(glCheckFramebufferStatus)(GL_DRAW_FRAMEBUFFER);
549 if ((read_status = GL_FRAMEBUFFER_COMPLETE) && (draw_status == GL_FRAMEBUFFER_COMPLETE))
553 if (m_texture.get_num_samples() > 1)
555 uint base_level = m_texture.get_params().get_value<GLenum>(GL_TEXTURE_BASE_LEVEL);
557 if (base_level < m_texture.get_num_levels())
559 const vogl_state_vector &state_vec = m_texture.get_level_params(0, base_level);
562 if (state_vec.get_value<GLenum>(GL_TEXTURE_DEPTH_SIZE))
564 clear_mask |= GL_DEPTH_BUFFER_BIT;
566 if (state_vec.get_value<GLenum>(GL_TEXTURE_STENCIL_SIZE))
568 clear_mask |= GL_STENCIL_BUFFER_BIT;
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))
573 clear_mask |= GL_COLOR_BUFFER_BIT;
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);
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,
593 if (!vogl_check_gl_error_internal())
595 restore_status = true;
601 GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, 0);
604 GL_ENTRYPOINT(glDeleteFramebuffers)(1, &dst_fbo_handle);
607 GL_ENTRYPOINT(glBindFramebuffer)(GL_READ_FRAMEBUFFER, 0);
610 GL_ENTRYPOINT(glDeleteFramebuffers)(1, &src_fbo_handle);
613 GL_ENTRYPOINT(glDeleteTextures)(1, &tex_handle);
619 vogl_error_printf("%s: Failed restoring contents of renderbuffer %u\n", VOGL_METHOD_NAME, static_cast<GLuint>(handle));
628 GL_ENTRYPOINT(glBindRenderbuffer)(GL_RENDERBUFFER, 0);
631 remapper.delete_handle_and_object(VOGL_NAMESPACE_RENDER_BUFFERS, m_snapshot_handle, handle);
633 //GLuint handle32 = static_cast<GLuint>(handle);
634 //GL_ENTRYPOINT(glDeleteRenderbuffers)(1, &handle32);
635 //VOGL_CHECK_GL_ERROR;
643 bool vogl_renderbuffer_state::remap_handles(vogl_handle_remapper &remapper)
650 m_snapshot_handle = static_cast<GLuint>(remapper.remap_handle(VOGL_NAMESPACE_RENDER_BUFFERS, m_snapshot_handle));
655 void vogl_renderbuffer_state::clear()
659 m_snapshot_handle = 0;
667 bool vogl_renderbuffer_state::serialize(json_node &node, vogl_blob_manager &blob_manager) const
671 VOGL_NOTE_UNUSED(blob_manager);
676 node.add_key_value("handle", m_snapshot_handle);
678 if (!m_desc.serialize(node))
681 if (m_texture.is_valid())
683 if (!m_texture.serialize(node.add_object("texture"), blob_manager))
690 bool vogl_renderbuffer_state::deserialize(const json_node &node, const vogl_blob_manager &blob_manager)
694 VOGL_NOTE_UNUSED(blob_manager);
698 m_snapshot_handle = node.value_as_int("handle");
700 if (!m_desc.deserialize(node))
703 if (node.has_object("texture"))
705 if (!m_texture.deserialize(*node.find_child_object("texture"), blob_manager))
714 bool vogl_renderbuffer_state::compare_restorable_state(const vogl_gl_object_state &rhs_obj) const
718 if ((!m_is_valid) || (!rhs_obj.is_valid()))
721 if (rhs_obj.get_type() != cGLSTRenderbuffer)
724 const vogl_renderbuffer_state &rhs = static_cast<const vogl_renderbuffer_state &>(rhs_obj);
729 return (m_desc == rhs.m_desc) && (m_texture.compare_restorable_state(rhs.m_texture));