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 if ((!m_desc.m_width) || (!m_desc.m_height) || (!m_desc.m_internal_format))
298 // Renderbuffer was only genned - no need to spit out warning
299 //vogl_warning_printf("%s: Unable to retrieve description renderbuffer %" PRIu64 "\n", VOGL_METHOD_NAME, static_cast<uint64_t>(handle));
303 vogl_scoped_state_saver framebuffer_state_saver(cGSTReadBuffer, cGSTDrawBuffer);
304 vogl_scoped_binding_state orig_framebuffers(GL_DRAW_FRAMEBUFFER, GL_READ_FRAMEBUFFER, GL_TEXTURE_2D, GL_TEXTURE_2D_MULTISAMPLE);
306 const GLenum tex_target = (m_desc.m_samples > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;
308 bool capture_status = false;
310 GLenum internal_fmt = m_desc.m_internal_format;
311 const vogl_internal_tex_format *pInternal_tex_fmt = vogl_find_internal_texture_format(internal_fmt);
312 if ((pInternal_tex_fmt) && (pInternal_tex_fmt->m_optimum_get_image_fmt != GL_NONE) && (pInternal_tex_fmt->m_optimum_get_image_type != GL_NONE))
315 GLuint tex_handle = 0;
316 GL_ENTRYPOINT(glGenTextures)(1, &tex_handle);
319 GL_ENTRYPOINT(glBindTexture)(tex_target, tex_handle);
322 if (m_desc.m_samples > 1)
324 GL_ENTRYPOINT(glTexImage2DMultisample)(tex_target,
333 GL_ENTRYPOINT(glTexImage2D)(tex_target,
339 pInternal_tex_fmt->m_optimum_get_image_fmt,
340 pInternal_tex_fmt->m_optimum_get_image_type,
344 if (!vogl_check_gl_error_internal())
346 GL_ENTRYPOINT(glTexParameteri)(tex_target, GL_TEXTURE_MAX_LEVEL, 0);
349 GLenum attachment = GL_COLOR_ATTACHMENT0;
350 GLenum draw_and_read_buf = GL_COLOR_ATTACHMENT0;
351 GLenum blit_type = GL_COLOR_BUFFER_BIT;
353 if ((m_desc.m_depth_size) && (m_desc.m_stencil_size))
355 attachment = GL_DEPTH_STENCIL_ATTACHMENT;
356 draw_and_read_buf = GL_NONE;
357 blit_type = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
359 else if (m_desc.m_depth_size)
361 attachment = GL_DEPTH_ATTACHMENT;
362 draw_and_read_buf = GL_NONE;
363 blit_type = GL_DEPTH_BUFFER_BIT;
365 else if (m_desc.m_stencil_size)
367 attachment = GL_STENCIL_ATTACHMENT;
368 draw_and_read_buf = GL_NONE;
369 blit_type = GL_STENCIL_BUFFER_BIT;
372 GLuint src_fbo_handle = 0, dst_fbo_handle = 0;
375 GL_ENTRYPOINT(glGenFramebuffers)(1, &src_fbo_handle);
378 GL_ENTRYPOINT(glBindFramebuffer)(GL_READ_FRAMEBUFFER, src_fbo_handle);
381 GL_ENTRYPOINT(glFramebufferRenderbuffer)(GL_READ_FRAMEBUFFER, attachment, GL_RENDERBUFFER, m_snapshot_handle);
384 GL_ENTRYPOINT(glReadBuffer)(draw_and_read_buf);
388 GL_ENTRYPOINT(glGenFramebuffers)(1, &dst_fbo_handle);
391 GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, dst_fbo_handle);
394 GL_ENTRYPOINT(glFramebufferTexture2D)(GL_DRAW_FRAMEBUFFER, attachment, tex_target, tex_handle, 0);
397 GL_ENTRYPOINT(glDrawBuffers)(1, &draw_and_read_buf);
400 GLenum read_status = GL_ENTRYPOINT(glCheckFramebufferStatus)(GL_READ_FRAMEBUFFER);
403 GLenum draw_status = GL_ENTRYPOINT(glCheckFramebufferStatus)(GL_DRAW_FRAMEBUFFER);
406 if ((read_status == GL_FRAMEBUFFER_COMPLETE) && (draw_status == GL_FRAMEBUFFER_COMPLETE))
408 GL_ENTRYPOINT(glBlitFramebuffer)(
409 0, 0, m_desc.m_width, m_desc.m_height,
410 0, 0, m_desc.m_width, m_desc.m_height,
414 if (!vogl_check_gl_error_internal())
416 vogl_handle_remapper def_handle_remapper;
417 if (m_texture.snapshot(context_info, def_handle_remapper, tex_handle, tex_target))
418 capture_status = true;
423 GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, 0);
426 GL_ENTRYPOINT(glDeleteFramebuffers)(1, &dst_fbo_handle);
429 GL_ENTRYPOINT(glBindFramebuffer)(GL_READ_FRAMEBUFFER, 0);
432 GL_ENTRYPOINT(glDeleteFramebuffers)(1, &src_fbo_handle);
436 GL_ENTRYPOINT(glBindTexture)(tex_target, 0);
439 GL_ENTRYPOINT(glDeleteTextures)(1, &tex_handle);
445 vogl_error_printf("%s: Failed blitting renderbuffer data to texture for renderbuffer %" PRIu64 "\n", VOGL_METHOD_NAME, static_cast<uint64_t>(handle));
454 bool vogl_renderbuffer_state::restore(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint64 &handle) const
458 VOGL_ASSERT(context_info.get_version() >= VOGL_GL_VERSION_3_0);
463 vogl_scoped_binding_state orig_renderbuffer(GL_RENDERBUFFER);
465 bool created_handle = false;
470 GL_ENTRYPOINT(glGenRenderbuffers)(1, &handle32);
471 if ((vogl_check_gl_error()) || (!handle32))
475 remapper.declare_handle(VOGL_NAMESPACE_RENDER_BUFFERS, m_snapshot_handle, handle, GL_NONE);
476 VOGL_ASSERT(remapper.remap_handle(VOGL_NAMESPACE_RENDER_BUFFERS, m_snapshot_handle) == handle);
478 created_handle = true;
481 GL_ENTRYPOINT(glBindRenderbuffer)(GL_RENDERBUFFER, static_cast<GLuint>(handle));
482 if (vogl_check_gl_error())
485 if ((m_desc.m_width) && (m_desc.m_height) && (m_desc.m_internal_format))
487 if (!m_desc.restore(context_info))
490 if (m_texture.is_valid())
492 GLenum attachment = GL_COLOR_ATTACHMENT0;
493 GLenum draw_and_read_buf = GL_COLOR_ATTACHMENT0;
494 GLenum blit_type = GL_COLOR_BUFFER_BIT;
496 if ((m_desc.m_depth_size) && (m_desc.m_stencil_size))
498 attachment = GL_DEPTH_STENCIL_ATTACHMENT;
499 draw_and_read_buf = GL_NONE;
500 blit_type = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
502 else if (m_desc.m_depth_size)
504 attachment = GL_DEPTH_ATTACHMENT;
505 draw_and_read_buf = GL_NONE;
506 blit_type = GL_DEPTH_BUFFER_BIT;
508 else if (m_desc.m_stencil_size)
510 attachment = GL_STENCIL_ATTACHMENT;
511 draw_and_read_buf = GL_NONE;
512 blit_type = GL_STENCIL_BUFFER_BIT;
515 bool restore_status = false;
517 GLuint64 tex_handle64 = 0;
518 vogl_handle_remapper def_handle_remapper;
519 if (m_texture.restore(context_info, def_handle_remapper, tex_handle64))
521 GLuint tex_handle = static_cast<GLuint>(tex_handle64);
523 const GLenum tex_target = (m_desc.m_samples > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;
525 GLuint src_fbo_handle = 0, dst_fbo_handle = 0;
528 GL_ENTRYPOINT(glGenFramebuffers)(1, &src_fbo_handle);
531 GL_ENTRYPOINT(glBindFramebuffer)(GL_READ_FRAMEBUFFER, src_fbo_handle);
534 GL_ENTRYPOINT(glFramebufferTexture2D)(GL_READ_FRAMEBUFFER, attachment, tex_target, tex_handle, 0);
537 GL_ENTRYPOINT(glReadBuffer)(draw_and_read_buf);
541 GL_ENTRYPOINT(glGenFramebuffers)(1, &dst_fbo_handle);
544 GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, dst_fbo_handle);
547 GL_ENTRYPOINT(glFramebufferRenderbuffer)(GL_DRAW_FRAMEBUFFER, attachment, GL_RENDERBUFFER, static_cast<GLuint>(handle));
550 GL_ENTRYPOINT(glDrawBuffers)(1, &draw_and_read_buf);
553 GLenum read_status = GL_ENTRYPOINT(glCheckFramebufferStatus)(GL_READ_FRAMEBUFFER);
556 GLenum draw_status = GL_ENTRYPOINT(glCheckFramebufferStatus)(GL_DRAW_FRAMEBUFFER);
559 if ((read_status = GL_FRAMEBUFFER_COMPLETE) && (draw_status == GL_FRAMEBUFFER_COMPLETE))
563 if (m_texture.get_num_samples() > 1)
565 uint base_level = m_texture.get_params().get_value<GLenum>(GL_TEXTURE_BASE_LEVEL);
567 if (base_level < m_texture.get_num_levels())
569 const vogl_state_vector &state_vec = m_texture.get_level_params(0, base_level);
572 if (state_vec.get_value<GLenum>(GL_TEXTURE_DEPTH_SIZE))
574 clear_mask |= GL_DEPTH_BUFFER_BIT;
576 if (state_vec.get_value<GLenum>(GL_TEXTURE_STENCIL_SIZE))
578 clear_mask |= GL_STENCIL_BUFFER_BIT;
580 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) +
581 state_vec.get_value<GLenum>(GL_TEXTURE_INTENSITY_SIZE) + state_vec.get_value<GLenum>(GL_TEXTURE_LUMINANCE_SIZE))
583 clear_mask |= GL_COLOR_BUFFER_BIT;
586 GL_ENTRYPOINT(glClearColor)(1.0f, 0.0f, 1.0f, 1.0f);
587 GL_ENTRYPOINT(glClearDepth)(.5f);
588 GL_ENTRYPOINT(glClearStencil)(128);
589 GL_ENTRYPOINT(glClear)(clear_mask);
597 GL_ENTRYPOINT(glBlitFramebuffer)(
598 0, 0, m_desc.m_width, m_desc.m_height,
599 0, 0, m_desc.m_width, m_desc.m_height,
603 if (!vogl_check_gl_error_internal())
605 restore_status = true;
611 GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, 0);
614 GL_ENTRYPOINT(glDeleteFramebuffers)(1, &dst_fbo_handle);
617 GL_ENTRYPOINT(glBindFramebuffer)(GL_READ_FRAMEBUFFER, 0);
620 GL_ENTRYPOINT(glDeleteFramebuffers)(1, &src_fbo_handle);
623 GL_ENTRYPOINT(glDeleteTextures)(1, &tex_handle);
629 vogl_error_printf("%s: Failed restoring contents of renderbuffer %u\n", VOGL_METHOD_NAME, static_cast<GLuint>(handle));
639 GL_ENTRYPOINT(glBindRenderbuffer)(GL_RENDERBUFFER, 0);
642 remapper.delete_handle_and_object(VOGL_NAMESPACE_RENDER_BUFFERS, m_snapshot_handle, handle);
644 //GLuint handle32 = static_cast<GLuint>(handle);
645 //GL_ENTRYPOINT(glDeleteRenderbuffers)(1, &handle32);
646 //VOGL_CHECK_GL_ERROR;
654 bool vogl_renderbuffer_state::remap_handles(vogl_handle_remapper &remapper)
661 m_snapshot_handle = static_cast<GLuint>(remapper.remap_handle(VOGL_NAMESPACE_RENDER_BUFFERS, m_snapshot_handle));
666 void vogl_renderbuffer_state::clear()
670 m_snapshot_handle = 0;
678 bool vogl_renderbuffer_state::serialize(json_node &node, vogl_blob_manager &blob_manager) const
682 VOGL_NOTE_UNUSED(blob_manager);
687 node.add_key_value("handle", m_snapshot_handle);
689 if (!m_desc.serialize(node))
692 if (m_texture.is_valid())
694 if (!m_texture.serialize(node.add_object("texture"), blob_manager))
701 bool vogl_renderbuffer_state::deserialize(const json_node &node, const vogl_blob_manager &blob_manager)
705 VOGL_NOTE_UNUSED(blob_manager);
709 m_snapshot_handle = node.value_as_int("handle");
711 if (!m_desc.deserialize(node))
714 if (node.has_object("texture"))
716 if (!m_texture.deserialize(*node.find_child_object("texture"), blob_manager))
725 bool vogl_renderbuffer_state::compare_restorable_state(const vogl_gl_object_state &rhs_obj) const
729 if ((!m_is_valid) || (!rhs_obj.is_valid()))
732 if (rhs_obj.get_type() != cGLSTRenderbuffer)
735 const vogl_renderbuffer_state &rhs = static_cast<const vogl_renderbuffer_state &>(rhs_obj);
740 return (m_desc == rhs.m_desc) && (m_texture.compare_restorable_state(rhs.m_texture));