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_default_framebuffer_state.cpp
27 #include "vogl_default_framebuffer_state.h"
29 #include "vogl_console.h"
30 #include "vogl_data_stream_serializer.h"
31 #include "vogl_dynamic_stream.h"
33 #include "vogl_common.h"
34 #include "vogl_texture_format.h"
36 static const GLenum g_def_framebuffer_enums[] =
45 bool vogl_get_default_framebuffer_attribs(vogl_default_framebuffer_attribs &attribs, uint screen)
47 GLXDrawable pDrawable = GL_ENTRYPOINT(glXGetCurrentDrawable)();
48 Display *pDisplay = GL_ENTRYPOINT(glXGetCurrentDisplay)();
49 if ((!pDrawable) || (!pDisplay))
52 GLuint fbconfig_id = 0;
53 GL_ENTRYPOINT(glXQueryDrawable)(pDisplay, pDrawable, GLX_FBCONFIG_ID, &fbconfig_id);
55 GLint attrib_list[3] = { GLX_FBCONFIG_ID, static_cast<GLint>(fbconfig_id), None };
57 GLXFBConfig *pConfigs = GL_ENTRYPOINT(glXChooseFBConfig)(pDisplay, screen, attrib_list, &nelements);
59 GLint red_size = 8, green_size = 8, blue_size = 8, alpha_size = 8;
60 GLint doublebuffer = 1, stereo = 0, depth_size = 24, stencil_size = 8;
61 GLint drawable_type = GLX_WINDOW_BIT;
62 GLint render_type = GLX_RGBA_BIT;
63 GLint samples = 0, sample_buffers = 0;
65 if ((pConfigs) && (nelements > 0))
67 GLXFBConfig config = pConfigs[0];
69 GL_ENTRYPOINT(glXGetFBConfigAttrib)(pDisplay, config, GLX_DRAWABLE_TYPE, &drawable_type); // what does a drawable type of 7 mean?
70 GL_ENTRYPOINT(glXGetFBConfigAttrib)(pDisplay, config, GLX_RENDER_TYPE, &render_type);
71 GL_ENTRYPOINT(glXGetFBConfigAttrib)(pDisplay, config, GLX_RED_SIZE, &red_size);
72 GL_ENTRYPOINT(glXGetFBConfigAttrib)(pDisplay, config, GLX_GREEN_SIZE, &green_size);
73 GL_ENTRYPOINT(glXGetFBConfigAttrib)(pDisplay, config, GLX_BLUE_SIZE, &blue_size);
74 GL_ENTRYPOINT(glXGetFBConfigAttrib)(pDisplay, config, GLX_ALPHA_SIZE, &alpha_size);
75 GL_ENTRYPOINT(glXGetFBConfigAttrib)(pDisplay, config, GLX_DOUBLEBUFFER, &doublebuffer);
76 GL_ENTRYPOINT(glXGetFBConfigAttrib)(pDisplay, config, GLX_STEREO, &stereo);
77 GL_ENTRYPOINT(glXGetFBConfigAttrib)(pDisplay, config, GLX_DEPTH_SIZE, &depth_size);
78 GL_ENTRYPOINT(glXGetFBConfigAttrib)(pDisplay, config, GLX_STENCIL_SIZE, &stencil_size);
79 GL_ENTRYPOINT(glXGetFBConfigAttrib)(pDisplay, config, GLX_SAMPLES, &samples);
80 GL_ENTRYPOINT(glXGetFBConfigAttrib)(pDisplay, config, GLX_SAMPLE_BUFFERS, &sample_buffers);
83 attribs.m_r_size = red_size;
84 attribs.m_g_size = green_size;
85 attribs.m_b_size = blue_size;
86 attribs.m_a_size = alpha_size;
87 attribs.m_depth_size = depth_size;
88 attribs.m_stencil_size = stencil_size;
89 attribs.m_samples = samples;
90 attribs.m_double_buffered = (doublebuffer != 0);
92 GL_ENTRYPOINT(glXQueryDrawable)(pDisplay, pDrawable, GLX_WIDTH, &attribs.m_width);
93 GL_ENTRYPOINT(glXQueryDrawable)(pDisplay, pDrawable, GLX_HEIGHT, &attribs.m_height);
98 vogl_default_framebuffer_state::vogl_default_framebuffer_state() :
103 vogl_default_framebuffer_state::~vogl_default_framebuffer_state()
107 bool vogl_default_framebuffer_state::snapshot(const vogl_context_info &context_info, const vogl_default_framebuffer_attribs &fb_attribs)
109 VOGL_NOTE_UNUSED(context_info);
113 m_fb_attribs = fb_attribs;
115 // Create compatible GL texture
116 // Attach this texture to an FBO
117 // Blit default framebuffer to this FBO
118 // Capture this texture's state
120 vogl_scoped_state_saver framebuffer_state_saver(cGSTReadBuffer, cGSTDrawBuffer);
122 vogl_scoped_binding_state orig_framebuffers(GL_DRAW_FRAMEBUFFER, GL_READ_FRAMEBUFFER, GL_TEXTURE_2D, GL_TEXTURE_2D_MULTISAMPLE);
124 GL_ENTRYPOINT(glBindFramebuffer)(GL_READ_FRAMEBUFFER, 0);
127 // TODO: Test multisampled default framebuffers
128 const GLenum tex_target = (fb_attribs.m_samples > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;
130 for (uint i = 0; i < cDefFramebufferTotal; i++)
132 GLenum internal_fmt, pixel_fmt, pixel_type;
134 // TODO: This uses fixed pixel formats, and assumes there's always a depth/stencil buffer.
135 if (i == cDefFramebufferDepthStencil)
137 if ((fb_attribs.m_depth_size + fb_attribs.m_stencil_size) == 0)
140 GL_ENTRYPOINT(glReadBuffer)(fb_attribs.m_double_buffered ? GL_BACK_LEFT : GL_FRONT_LEFT);
142 internal_fmt = GL_DEPTH_STENCIL;
143 pixel_fmt = GL_DEPTH_STENCIL;
144 pixel_type = GL_UNSIGNED_INT_24_8;
148 if ((fb_attribs.m_r_size + fb_attribs.m_g_size + fb_attribs.m_b_size + fb_attribs.m_a_size) == 0)
151 GL_ENTRYPOINT(glReadBuffer)(g_def_framebuffer_enums[i]);
153 internal_fmt = GL_RGBA;
155 pixel_type = GL_UNSIGNED_INT_8_8_8_8_REV;
158 if (vogl_check_gl_error_internal(true))
162 GLuint tex_handle = 0;
163 GL_ENTRYPOINT(glGenTextures)(1, &tex_handle);
166 GL_ENTRYPOINT(glBindTexture)(tex_target, tex_handle);
169 if (fb_attribs.m_samples > 1)
171 GL_ENTRYPOINT(glTexImage2DMultisample)(tex_target,
172 fb_attribs.m_samples,
180 GL_ENTRYPOINT(glTexImage2D)(tex_target,
191 if (vogl_check_gl_error_internal())
193 GL_ENTRYPOINT(glBindTexture)(tex_target, 0);
196 GL_ENTRYPOINT(glDeleteTextures)(1, &tex_handle);
202 GL_ENTRYPOINT(glTexParameteri)(tex_target, GL_TEXTURE_MAX_LEVEL, 0);
206 GLuint fbo_handle = 0;
207 GL_ENTRYPOINT(glGenFramebuffers)(1, &fbo_handle);
210 GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, fbo_handle);
213 GL_ENTRYPOINT(glFramebufferTexture2D)(GL_DRAW_FRAMEBUFFER, (i == cDefFramebufferDepthStencil) ? GL_DEPTH_STENCIL_ATTACHMENT : GL_COLOR_ATTACHMENT0, tex_target, tex_handle, 0);
216 GLenum draw_buf = (i == cDefFramebufferDepthStencil) ? GL_NONE : GL_COLOR_ATTACHMENT0;
217 GL_ENTRYPOINT(glDrawBuffers)(1, &draw_buf);
220 GLenum cur_status = GL_ENTRYPOINT(glCheckFramebufferStatus)(GL_DRAW_FRAMEBUFFER);
225 if (cur_status == GL_FRAMEBUFFER_COMPLETE)
227 GL_ENTRYPOINT(glBlitFramebuffer)(
228 0, 0, fb_attribs.m_width, fb_attribs.m_height,
229 0, 0, fb_attribs.m_width, fb_attribs.m_height,
230 (i == cDefFramebufferDepthStencil) ? (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT) : GL_COLOR_BUFFER_BIT,
233 if (vogl_check_gl_error_internal())
241 vogl_handle_remapper def_handle_remapper;
242 status = m_textures[i].snapshot(context_info, def_handle_remapper, tex_handle, tex_target);
246 vogl_error_printf("%s: Failed snapshotting texture for default framebuffer %s\n", VOGL_METHOD_NAME, g_gl_enums.find_gl_name(g_def_framebuffer_enums[i]));
251 vogl_warning_printf("%s: Failed blitting framebuffer %u\n", VOGL_METHOD_NAME, i);
255 GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, 0);
258 GL_ENTRYPOINT(glDeleteFramebuffers)(1, &fbo_handle);
261 GL_ENTRYPOINT(glDrawBuffer)(GL_FRONT_LEFT);
264 GL_ENTRYPOINT(glBindTexture)(tex_target, 0);
267 GL_ENTRYPOINT(glDeleteTextures)(1, &tex_handle);
276 bool vogl_default_framebuffer_state::restore(const vogl_context_info &context_info) const
278 VOGL_NOTE_UNUSED(context_info);
283 // TODO: Test multisampled default framebuffers
284 // TODO: Check to ensure the stored fb is compatible with the current framebuffer
285 const GLenum tex_target = (m_fb_attribs.m_samples > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;
287 vogl_scoped_state_saver framebuffer_state_saver(cGSTReadBuffer, cGSTDrawBuffer);
289 vogl_scoped_binding_state orig_framebuffers(GL_DRAW_FRAMEBUFFER, GL_READ_FRAMEBUFFER, GL_TEXTURE_2D, GL_TEXTURE_2D_MULTISAMPLE);
291 GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, 0);
294 for (uint i = 0; i < cDefFramebufferTotal; i++)
296 if (!m_textures[i].is_valid())
299 GL_ENTRYPOINT(glDrawBuffer)((i == cDefFramebufferDepthStencil) ? GL_NONE : g_def_framebuffer_enums[i]);
300 if (vogl_check_gl_error_internal(true))
303 GLuint64 tex_handle64 = 0;
305 vogl_handle_remapper def_handle_remapper;
306 if (!m_textures[i].restore(context_info, def_handle_remapper, tex_handle64))
308 vogl_error_printf("%s: Failed restoring texture %u\n", VOGL_METHOD_NAME, i);
312 GLuint tex_handle = static_cast<GLuint>(tex_handle64);
315 GLuint fbo_handle = 0;
316 GL_ENTRYPOINT(glGenFramebuffers)(1, &fbo_handle);
319 GL_ENTRYPOINT(glBindFramebuffer)(GL_READ_FRAMEBUFFER, fbo_handle);
322 GL_ENTRYPOINT(glFramebufferTexture2D)(GL_READ_FRAMEBUFFER, (i == cDefFramebufferDepthStencil) ? GL_DEPTH_STENCIL_ATTACHMENT : GL_COLOR_ATTACHMENT0, tex_target, tex_handle, 0);
325 GL_ENTRYPOINT(glReadBuffer)((i == cDefFramebufferDepthStencil) ? GL_NONE : GL_COLOR_ATTACHMENT0);
328 GLenum cur_status = GL_ENTRYPOINT(glCheckFramebufferStatus)(GL_READ_FRAMEBUFFER);
333 if (cur_status == GL_FRAMEBUFFER_COMPLETE)
335 GL_ENTRYPOINT(glBlitFramebuffer)(
336 0, 0, m_fb_attribs.m_width, m_fb_attribs.m_height,
337 0, 0, m_fb_attribs.m_width, m_fb_attribs.m_height,
338 (i == cDefFramebufferDepthStencil) ? (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT) : GL_COLOR_BUFFER_BIT,
341 if (vogl_check_gl_error_internal())
349 vogl_warning_printf("%s: Failed blitting framebuffer %u\n", VOGL_METHOD_NAME, i);
353 GL_ENTRYPOINT(glBindFramebuffer)(GL_READ_FRAMEBUFFER, 0);
356 GL_ENTRYPOINT(glDeleteFramebuffers)(1, &fbo_handle);
359 GL_ENTRYPOINT(glReadBuffer)(GL_FRONT_LEFT);
362 GL_ENTRYPOINT(glBindTexture)(tex_target, 0);
365 GL_ENTRYPOINT(glDeleteTextures)(1, &tex_handle);
372 void vogl_default_framebuffer_state::clear()
374 m_fb_attribs.clear();
376 for (uint i = 0; i < cDefFramebufferTotal; i++)
377 m_textures[i].clear();
382 bool vogl_default_framebuffer_state::serialize(json_node &node, vogl_blob_manager &blob_manager) const
387 if (!m_fb_attribs.serialize(node.add_object("attribs")))
390 json_node &framebuffers_array = node.add_array("framebuffers");
391 for (uint i = 0; i < cDefFramebufferTotal; i++)
393 json_node &object_node = framebuffers_array.add_object();
394 if (m_textures[i].is_valid())
396 if (!m_textures[i].serialize(object_node, blob_manager))
404 bool vogl_default_framebuffer_state::deserialize(const json_node &node, const vogl_blob_manager &blob_manager)
408 if (!node.has_object("attribs"))
411 if (!m_fb_attribs.deserialize(*node.find_child_object("attribs")))
414 const json_node *pFramebuffers_array = node.find_child_array("framebuffers");
415 if (pFramebuffers_array)
417 for (uint i = 0; i < math::minimum<uint>(cDefFramebufferTotal, pFramebuffers_array->size()); i++)
419 if ((pFramebuffers_array->is_child_object(i)) && (pFramebuffers_array->get_child(i)->size()))
421 if (!m_textures[i].deserialize(*pFramebuffers_array->get_child(i), blob_manager))