| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or | 
					
						
							|  |  |  |  * modify it under the terms of the GNU General Public License | 
					
						
							|  |  |  |  * as published by the Free Software Foundation; either version 2 | 
					
						
							|  |  |  |  * of the License, or (at your option) any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  * GNU General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |  * along with this program; if not, write to the Free Software Foundation, | 
					
						
							|  |  |  |  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The Original Code is Copyright (C) 2020 Blender Foundation. | 
					
						
							|  |  |  |  * All rights reserved. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** \file
 | 
					
						
							|  |  |  |  * \ingroup gpu | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "BKE_global.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-07 19:35:56 +02:00
										 |  |  | #include "GPU_capabilities.h"
 | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "gl_backend.hh"
 | 
					
						
							| 
									
										
										
										
											2020-09-09 00:47:59 +02:00
										 |  |  | #include "gl_debug.hh"
 | 
					
						
							| 
									
										
										
										
											2020-08-29 15:17:13 +02:00
										 |  |  | #include "gl_state.hh"
 | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  | #include "gl_texture.hh"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-09 00:47:59 +02:00
										 |  |  | #include "gl_framebuffer.hh"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  | namespace blender::gpu { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* -------------------------------------------------------------------- */ | 
					
						
							|  |  |  | /** \name Creation & Deletion
 | 
					
						
							|  |  |  |  * \{ */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | GLFrameBuffer::GLFrameBuffer(const char *name) : FrameBuffer(name) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-09-02 09:58:26 +10:00
										 |  |  |   /* Just-In-Time init. See #GLFrameBuffer::init(). */ | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  |   immutable_ = false; | 
					
						
							|  |  |  |   fbo_id_ = 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | GLFrameBuffer::GLFrameBuffer( | 
					
						
							|  |  |  |     const char *name, GLContext *ctx, GLenum target, GLuint fbo, int w, int h) | 
					
						
							|  |  |  |     : FrameBuffer(name) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   context_ = ctx; | 
					
						
							| 
									
										
										
										
											2020-08-29 15:17:13 +02:00
										 |  |  |   state_manager_ = static_cast<GLStateManager *>(ctx->state_manager); | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  |   immutable_ = true; | 
					
						
							|  |  |  |   fbo_id_ = fbo; | 
					
						
							|  |  |  |   gl_attachments_[0] = target; | 
					
						
							| 
									
										
										
										
											2020-09-02 09:58:26 +10:00
										 |  |  |   /* Never update an internal frame-buffer. */ | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  |   dirty_attachments_ = false; | 
					
						
							|  |  |  |   width_ = w; | 
					
						
							|  |  |  |   height_ = h; | 
					
						
							|  |  |  |   srgb_ = false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-29 15:17:13 +02:00
										 |  |  |   viewport_[0] = scissor_[0] = 0; | 
					
						
							|  |  |  |   viewport_[1] = scissor_[1] = 0; | 
					
						
							|  |  |  |   viewport_[2] = scissor_[2] = w; | 
					
						
							|  |  |  |   viewport_[3] = scissor_[3] = h; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-09 00:47:59 +02:00
										 |  |  |   if (fbo_id_) { | 
					
						
							|  |  |  |     debug::object_label(GL_FRAMEBUFFER, fbo_id_, name_); | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | GLFrameBuffer::~GLFrameBuffer() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-11-06 17:49:09 +01:00
										 |  |  |   if (context_ == nullptr) { | 
					
						
							| 
									
										
										
										
											2020-09-01 18:41:23 +02:00
										 |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-08 15:49:16 +02:00
										 |  |  |   /* Context might be partially freed. This happens when destroying the window frame-buffers. */ | 
					
						
							|  |  |  |   if (context_ == Context::get()) { | 
					
						
							| 
									
										
										
										
											2020-09-01 18:41:23 +02:00
										 |  |  |     glDeleteFramebuffers(1, &fbo_id_); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     context_->fbo_free(fbo_id_); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-09-02 09:58:26 +10:00
										 |  |  |   /* Restore default frame-buffer if this frame-buffer was bound. */ | 
					
						
							| 
									
										
										
										
											2020-09-01 18:41:23 +02:00
										 |  |  |   if (context_->active_fb == this && context_->back_left != this) { | 
					
						
							| 
									
										
										
										
											2020-09-02 09:58:26 +10:00
										 |  |  |     /* If this assert triggers it means the frame-buffer is being freed while in use by another
 | 
					
						
							| 
									
										
										
										
											2020-09-01 18:41:23 +02:00
										 |  |  |      * context which, by the way, is TOTALLY UNSAFE!!!  */ | 
					
						
							| 
									
										
										
										
											2020-09-08 15:49:16 +02:00
										 |  |  |     BLI_assert(context_ == Context::get()); | 
					
						
							| 
									
										
										
										
											2020-09-01 18:41:23 +02:00
										 |  |  |     GPU_framebuffer_restore(); | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-06 13:18:48 +01:00
										 |  |  | void GLFrameBuffer::init() | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-09-08 04:12:12 +02:00
										 |  |  |   context_ = GLContext::get(); | 
					
						
							| 
									
										
										
										
											2020-08-29 15:17:13 +02:00
										 |  |  |   state_manager_ = static_cast<GLStateManager *>(context_->state_manager); | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  |   glGenFramebuffers(1, &fbo_id_); | 
					
						
							| 
									
										
										
										
											2020-09-09 00:47:59 +02:00
										 |  |  |   /* Binding before setting the label is needed on some drivers.
 | 
					
						
							|  |  |  |    * This is not an issue since we call this function only before binding. */ | 
					
						
							|  |  |  |   glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_); | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-09 00:47:59 +02:00
										 |  |  |   debug::object_label(GL_FRAMEBUFFER, fbo_id_, name_); | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** \} */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* -------------------------------------------------------------------- */ | 
					
						
							|  |  |  | /** \name Config
 | 
					
						
							|  |  |  |  * \{ */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* This is a rather slow operation. Don't check in normal cases. */ | 
					
						
							|  |  |  | bool GLFrameBuffer::check(char err_out[256]) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   this->bind(true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define FORMAT_STATUS(X) \
 | 
					
						
							|  |  |  |   case X: { \ | 
					
						
							|  |  |  |     err = #X; \ | 
					
						
							|  |  |  |     break; \ | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const char *err; | 
					
						
							|  |  |  |   switch (status) { | 
					
						
							|  |  |  |     FORMAT_STATUS(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT); | 
					
						
							|  |  |  |     FORMAT_STATUS(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT); | 
					
						
							|  |  |  |     FORMAT_STATUS(GL_FRAMEBUFFER_UNSUPPORTED); | 
					
						
							|  |  |  |     FORMAT_STATUS(GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER); | 
					
						
							|  |  |  |     FORMAT_STATUS(GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER); | 
					
						
							|  |  |  |     FORMAT_STATUS(GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE); | 
					
						
							|  |  |  |     FORMAT_STATUS(GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS); | 
					
						
							|  |  |  |     FORMAT_STATUS(GL_FRAMEBUFFER_UNDEFINED); | 
					
						
							|  |  |  |     case GL_FRAMEBUFFER_COMPLETE: | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       err = "unknown"; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #undef FORMAT_STATUS
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-03 17:09:35 +01:00
										 |  |  |   const char *format = "GPUFrameBuffer: %s status %s\n"; | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (err_out) { | 
					
						
							| 
									
										
										
										
											2021-02-03 17:09:35 +01:00
										 |  |  |     BLI_snprintf(err_out, 256, format, this->name_, err); | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							| 
									
										
										
										
											2021-02-03 17:09:35 +01:00
										 |  |  |     fprintf(stderr, format, this->name_, err); | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-06 13:18:48 +01:00
										 |  |  | void GLFrameBuffer::update_attachments() | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-09-02 09:58:26 +10:00
										 |  |  |   /* Default frame-buffers cannot have attachments. */ | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  |   BLI_assert(immutable_ == false); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* First color texture OR the depth texture if no color is attached.
 | 
					
						
							| 
									
										
										
										
											2020-09-02 09:58:26 +10:00
										 |  |  |    * Used to determine frame-buffer color-space and dimensions. */ | 
					
						
							| 
									
										
										
										
											2020-09-02 10:04:50 +10:00
										 |  |  |   GPUAttachmentType first_attachment = GPU_FB_MAX_ATTACHMENT; | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  |   /* NOTE: Inverse iteration to get the first color texture. */ | 
					
						
							| 
									
										
										
										
											2020-09-02 10:04:50 +10:00
										 |  |  |   for (GPUAttachmentType type = GPU_FB_MAX_ATTACHMENT - 1; type >= 0; --type) { | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  |     GPUAttachment &attach = attachments_[type]; | 
					
						
							|  |  |  |     GLenum gl_attachment = to_gl(type); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (type >= GPU_FB_COLOR_ATTACHMENT0) { | 
					
						
							|  |  |  |       gl_attachments_[type - GPU_FB_COLOR_ATTACHMENT0] = (attach.tex) ? gl_attachment : GL_NONE; | 
					
						
							|  |  |  |       first_attachment = (attach.tex) ? type : first_attachment; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-09-02 10:04:50 +10:00
										 |  |  |     else if (first_attachment == GPU_FB_MAX_ATTACHMENT) { | 
					
						
							| 
									
										
										
										
											2020-09-02 09:58:26 +10:00
										 |  |  |       /* Only use depth texture to get information if there is no color attachment. */ | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  |       first_attachment = (attach.tex) ? type : first_attachment; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-06 17:49:09 +01:00
										 |  |  |     if (attach.tex == nullptr) { | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  |       glFramebufferTexture(GL_FRAMEBUFFER, gl_attachment, 0, 0); | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-09-08 03:22:35 +02:00
										 |  |  |     GLuint gl_tex = static_cast<GLTexture *>(unwrap(attach.tex))->tex_id_; | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  |     if (attach.layer > -1 && GPU_texture_cube(attach.tex) && !GPU_texture_array(attach.tex)) { | 
					
						
							|  |  |  |       /* Could be avoided if ARB_direct_state_access is required. In this case
 | 
					
						
							| 
									
										
										
										
											2020-09-02 09:58:26 +10:00
										 |  |  |        * #glFramebufferTextureLayer would bind the correct face. */ | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  |       GLenum gl_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + attach.layer; | 
					
						
							|  |  |  |       glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attachment, gl_target, gl_tex, attach.mip); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (attach.layer > -1) { | 
					
						
							|  |  |  |       glFramebufferTextureLayer(GL_FRAMEBUFFER, gl_attachment, gl_tex, attach.mip, attach.layer); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							| 
									
										
										
										
											2020-09-02 09:58:26 +10:00
										 |  |  |       /* The whole texture level is attached. The frame-buffer is potentially layered. */ | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  |       glFramebufferTexture(GL_FRAMEBUFFER, gl_attachment, gl_tex, attach.mip); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     /* We found one depth buffer type. Stop here, otherwise we would
 | 
					
						
							|  |  |  |      * override it by setting GPU_FB_DEPTH_ATTACHMENT */ | 
					
						
							|  |  |  |     if (type == GPU_FB_DEPTH_STENCIL_ATTACHMENT) { | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-07 18:52:30 +02:00
										 |  |  |   if (GLContext::unused_fb_slot_workaround) { | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  |     /* Fill normally un-occupied slots to avoid rendering artifacts on some hardware. */ | 
					
						
							|  |  |  |     GLuint gl_tex = 0; | 
					
						
							|  |  |  |     /* NOTE: Inverse iteration to get the first color texture. */ | 
					
						
							|  |  |  |     for (int i = ARRAY_SIZE(gl_attachments_) - 1; i >= 0; --i) { | 
					
						
							|  |  |  |       GPUAttachmentType type = GPU_FB_COLOR_ATTACHMENT0 + i; | 
					
						
							|  |  |  |       GPUAttachment &attach = attachments_[type]; | 
					
						
							| 
									
										
										
										
											2020-11-06 17:49:09 +01:00
										 |  |  |       if (attach.tex != nullptr) { | 
					
						
							| 
									
										
										
										
											2020-09-08 03:22:35 +02:00
										 |  |  |         gl_tex = static_cast<GLTexture *>(unwrap(attach.tex))->tex_id_; | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  |       } | 
					
						
							|  |  |  |       else if (gl_tex != 0) { | 
					
						
							|  |  |  |         GLenum gl_attachment = to_gl(type); | 
					
						
							|  |  |  |         gl_attachments_[i] = gl_attachment; | 
					
						
							|  |  |  |         glFramebufferTexture(GL_FRAMEBUFFER, gl_attachment, gl_tex, 0); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-02 10:04:50 +10:00
										 |  |  |   if (first_attachment != GPU_FB_MAX_ATTACHMENT) { | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  |     GPUAttachment &attach = attachments_[first_attachment]; | 
					
						
							|  |  |  |     int size[3]; | 
					
						
							|  |  |  |     GPU_texture_get_mipmap_size(attach.tex, attach.mip, size); | 
					
						
							| 
									
										
										
										
											2020-08-29 14:03:15 +02:00
										 |  |  |     this->size_set(size[0], size[1]); | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  |     srgb_ = (GPU_texture_format(attach.tex) == GPU_SRGB8_A8); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   dirty_attachments_ = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   glDrawBuffers(ARRAY_SIZE(gl_attachments_), gl_attachments_); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (G.debug & G_DEBUG_GPU) { | 
					
						
							| 
									
										
										
										
											2020-11-06 17:49:09 +01:00
										 |  |  |     BLI_assert(this->check(nullptr)); | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-06 13:18:48 +01:00
										 |  |  | void GLFrameBuffer::apply_state() | 
					
						
							| 
									
										
										
										
											2020-08-29 15:17:13 +02:00
										 |  |  | { | 
					
						
							|  |  |  |   if (dirty_state_ == false) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   glViewport(UNPACK4(viewport_)); | 
					
						
							|  |  |  |   glScissor(UNPACK4(scissor_)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (scissor_test_) { | 
					
						
							|  |  |  |     glEnable(GL_SCISSOR_TEST); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     glDisable(GL_SCISSOR_TEST); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   dirty_state_ = false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  | /** \} */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* -------------------------------------------------------------------- */ | 
					
						
							|  |  |  | /** \name Binding
 | 
					
						
							|  |  |  |  * \{ */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void GLFrameBuffer::bind(bool enabled_srgb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (!immutable_ && fbo_id_ == 0) { | 
					
						
							|  |  |  |     this->init(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-08 04:12:12 +02:00
										 |  |  |   if (context_ != GLContext::get()) { | 
					
						
							| 
									
										
										
										
											2020-09-02 09:58:26 +10:00
										 |  |  |     BLI_assert(!"Trying to use the same frame-buffer in multiple context"); | 
					
						
							| 
									
										
										
										
											2020-08-29 15:17:13 +02:00
										 |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (context_->active_fb != this) { | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  |     glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_); | 
					
						
							| 
									
										
										
										
											2020-09-02 09:58:26 +10:00
										 |  |  |     /* Internal frame-buffers have only one color output and needs to be set every time. */ | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  |     if (immutable_ && fbo_id_ == 0) { | 
					
						
							|  |  |  |       glDrawBuffer(gl_attachments_[0]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (dirty_attachments_) { | 
					
						
							|  |  |  |     this->update_attachments(); | 
					
						
							| 
									
										
										
										
											2020-08-29 15:17:13 +02:00
										 |  |  |     this->viewport_reset(); | 
					
						
							|  |  |  |     this->scissor_reset(); | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-14 18:15:50 +02:00
										 |  |  |   if (context_->active_fb != this || enabled_srgb_ != enabled_srgb) { | 
					
						
							|  |  |  |     enabled_srgb_ = enabled_srgb; | 
					
						
							| 
									
										
										
										
											2020-11-03 14:23:03 +01:00
										 |  |  |     if (enabled_srgb && srgb_) { | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  |       glEnable(GL_FRAMEBUFFER_SRGB); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       glDisable(GL_FRAMEBUFFER_SRGB); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     GPU_shader_set_framebuffer_srgb_target(enabled_srgb && srgb_); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-10-14 18:15:50 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (context_->active_fb != this) { | 
					
						
							|  |  |  |     context_->active_fb = this; | 
					
						
							|  |  |  |     state_manager_->active_fb = this; | 
					
						
							|  |  |  |     dirty_state_ = true; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** \} */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* -------------------------------------------------------------------- */ | 
					
						
							|  |  |  | /** \name Operations.
 | 
					
						
							|  |  |  |  * \{ */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void GLFrameBuffer::clear(eGPUFrameBufferBits buffers, | 
					
						
							|  |  |  |                           const float clear_col[4], | 
					
						
							|  |  |  |                           float clear_depth, | 
					
						
							|  |  |  |                           uint clear_stencil) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-09-08 04:12:12 +02:00
										 |  |  |   BLI_assert(GLContext::get() == context_); | 
					
						
							| 
									
										
										
										
											2020-08-29 15:17:13 +02:00
										 |  |  |   BLI_assert(context_->active_fb == this); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  |   /* Save and restore the state. */ | 
					
						
							|  |  |  |   eGPUWriteMask write_mask = GPU_write_mask_get(); | 
					
						
							|  |  |  |   uint stencil_mask = GPU_stencil_mask_get(); | 
					
						
							|  |  |  |   eGPUStencilTest stencil_test = GPU_stencil_test_get(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (buffers & GPU_COLOR_BIT) { | 
					
						
							|  |  |  |     GPU_color_mask(true, true, true, true); | 
					
						
							|  |  |  |     glClearColor(clear_col[0], clear_col[1], clear_col[2], clear_col[3]); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (buffers & GPU_DEPTH_BIT) { | 
					
						
							|  |  |  |     GPU_depth_mask(true); | 
					
						
							|  |  |  |     glClearDepth(clear_depth); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (buffers & GPU_STENCIL_BIT) { | 
					
						
							|  |  |  |     GPU_stencil_write_mask_set(0xFFu); | 
					
						
							|  |  |  |     GPU_stencil_test(GPU_STENCIL_ALWAYS); | 
					
						
							|  |  |  |     glClearStencil(clear_stencil); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   context_->state_manager->apply_state(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GLbitfield mask = to_gl(buffers); | 
					
						
							|  |  |  |   glClear(mask); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (buffers & (GPU_COLOR_BIT | GPU_DEPTH_BIT)) { | 
					
						
							|  |  |  |     GPU_write_mask(write_mask); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (buffers & GPU_STENCIL_BIT) { | 
					
						
							|  |  |  |     GPU_stencil_write_mask_set(stencil_mask); | 
					
						
							|  |  |  |     GPU_stencil_test(stencil_test); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-03 21:52:30 +02:00
										 |  |  | void GLFrameBuffer::clear_attachment(GPUAttachmentType type, | 
					
						
							|  |  |  |                                      eGPUDataFormat data_format, | 
					
						
							|  |  |  |                                      const void *clear_value) | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-09-08 04:12:12 +02:00
										 |  |  |   BLI_assert(GLContext::get() == context_); | 
					
						
							| 
									
										
										
										
											2020-08-29 15:17:13 +02:00
										 |  |  |   BLI_assert(context_->active_fb == this); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  |   /* Save and restore the state. */ | 
					
						
							|  |  |  |   eGPUWriteMask write_mask = GPU_write_mask_get(); | 
					
						
							|  |  |  |   GPU_color_mask(true, true, true, true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   context_->state_manager->apply_state(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-03 21:52:30 +02:00
										 |  |  |   if (type == GPU_FB_DEPTH_STENCIL_ATTACHMENT) { | 
					
						
							| 
									
										
										
										
											2021-02-17 12:38:21 -03:00
										 |  |  |     BLI_assert(data_format == GPU_DATA_UINT_24_8); | 
					
						
							| 
									
										
										
										
											2020-09-03 21:52:30 +02:00
										 |  |  |     float depth = ((*(uint32_t *)clear_value) & 0x00FFFFFFu) / (float)0x00FFFFFFu; | 
					
						
							|  |  |  |     int stencil = ((*(uint32_t *)clear_value) >> 24); | 
					
						
							|  |  |  |     glClearBufferfi(GL_DEPTH_STENCIL, 0, depth, stencil); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else if (type == GPU_FB_DEPTH_ATTACHMENT) { | 
					
						
							|  |  |  |     if (data_format == GPU_DATA_FLOAT) { | 
					
						
							|  |  |  |       glClearBufferfv(GL_DEPTH, 0, (GLfloat *)clear_value); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-02-17 12:38:21 -03:00
										 |  |  |     else if (data_format == GPU_DATA_UINT) { | 
					
						
							| 
									
										
										
										
											2020-09-03 21:52:30 +02:00
										 |  |  |       float depth = *(uint32_t *)clear_value / (float)0xFFFFFFFFu; | 
					
						
							|  |  |  |       glClearBufferfv(GL_DEPTH, 0, &depth); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       BLI_assert(!"Unhandled data format"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     int slot = type - GPU_FB_COLOR_ATTACHMENT0; | 
					
						
							|  |  |  |     switch (data_format) { | 
					
						
							|  |  |  |       case GPU_DATA_FLOAT: | 
					
						
							|  |  |  |         glClearBufferfv(GL_COLOR, slot, (GLfloat *)clear_value); | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2021-02-17 12:38:21 -03:00
										 |  |  |       case GPU_DATA_UINT: | 
					
						
							| 
									
										
										
										
											2020-09-03 21:52:30 +02:00
										 |  |  |         glClearBufferuiv(GL_COLOR, slot, (GLuint *)clear_value); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case GPU_DATA_INT: | 
					
						
							|  |  |  |         glClearBufferiv(GL_COLOR, slot, (GLint *)clear_value); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       default: | 
					
						
							|  |  |  |         BLI_assert(!"Unhandled data format"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GPU_write_mask(write_mask); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void GLFrameBuffer::clear_multi(const float (*clear_cols)[4]) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-09-02 09:58:26 +10:00
										 |  |  |   /* WATCH: This can easily access clear_cols out of bounds it clear_cols is not big enough for
 | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  |    * all attachments. | 
					
						
							| 
									
										
										
										
											2020-09-19 14:32:41 +10:00
										 |  |  |    * TODO(fclem): fix this insecurity? */ | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  |   int type = GPU_FB_COLOR_ATTACHMENT0; | 
					
						
							| 
									
										
										
										
											2020-09-02 10:04:50 +10:00
										 |  |  |   for (int i = 0; type < GPU_FB_MAX_ATTACHMENT; i++, type++) { | 
					
						
							| 
									
										
										
										
											2020-11-06 17:49:09 +01:00
										 |  |  |     if (attachments_[type].tex != nullptr) { | 
					
						
							| 
									
										
										
										
											2020-09-03 21:52:30 +02:00
										 |  |  |       this->clear_attachment(GPU_FB_COLOR_ATTACHMENT0 + i, GPU_DATA_FLOAT, clear_cols[i]); | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void GLFrameBuffer::read(eGPUFrameBufferBits plane, | 
					
						
							|  |  |  |                          eGPUDataFormat data_format, | 
					
						
							|  |  |  |                          const int area[4], | 
					
						
							|  |  |  |                          int channel_len, | 
					
						
							|  |  |  |                          int slot, | 
					
						
							|  |  |  |                          void *r_data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   GLenum format, type, mode; | 
					
						
							|  |  |  |   mode = gl_attachments_[slot]; | 
					
						
							|  |  |  |   type = to_gl(data_format); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   switch (plane) { | 
					
						
							|  |  |  |     case GPU_DEPTH_BIT: | 
					
						
							|  |  |  |       format = GL_DEPTH_COMPONENT; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case GPU_COLOR_BIT: | 
					
						
							|  |  |  |       format = channel_len_to_gl(channel_len); | 
					
						
							|  |  |  |       /* TODO: needed for selection buffers to work properly, this should be handled better. */ | 
					
						
							|  |  |  |       if (format == GL_RED && type == GL_UNSIGNED_INT) { | 
					
						
							|  |  |  |         format = GL_RED_INTEGER; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case GPU_STENCIL_BIT: | 
					
						
							|  |  |  |       fprintf(stderr, "GPUFramebuffer: Error: Trying to read stencil bit. Unsupported."); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     default: | 
					
						
							| 
									
										
										
										
											2020-09-02 09:58:26 +10:00
										 |  |  |       fprintf(stderr, "GPUFramebuffer: Error: Trying to read more than one frame-buffer plane."); | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  |       return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_id_); | 
					
						
							|  |  |  |   glReadBuffer(mode); | 
					
						
							|  |  |  |   glReadPixels(UNPACK4(area), format, type, r_data); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-02 09:58:26 +10:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Copy \a src at the give offset inside \a dst. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  | void GLFrameBuffer::blit_to( | 
					
						
							|  |  |  |     eGPUFrameBufferBits planes, int src_slot, FrameBuffer *dst_, int dst_slot, int x, int y) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   GLFrameBuffer *src = this; | 
					
						
							|  |  |  |   GLFrameBuffer *dst = static_cast<GLFrameBuffer *>(dst_); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-02 09:58:26 +10:00
										 |  |  |   /* Frame-buffers must be up to date. This simplify this function. */ | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  |   if (src->dirty_attachments_) { | 
					
						
							|  |  |  |     src->bind(true); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (dst->dirty_attachments_) { | 
					
						
							|  |  |  |     dst->bind(true); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   glBindFramebuffer(GL_READ_FRAMEBUFFER, src->fbo_id_); | 
					
						
							|  |  |  |   glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst->fbo_id_); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (planes & GPU_COLOR_BIT) { | 
					
						
							|  |  |  |     BLI_assert(src->immutable_ == false || src_slot == 0); | 
					
						
							|  |  |  |     BLI_assert(dst->immutable_ == false || dst_slot == 0); | 
					
						
							|  |  |  |     BLI_assert(src->gl_attachments_[src_slot] != GL_NONE); | 
					
						
							|  |  |  |     BLI_assert(dst->gl_attachments_[dst_slot] != GL_NONE); | 
					
						
							|  |  |  |     glReadBuffer(src->gl_attachments_[src_slot]); | 
					
						
							|  |  |  |     glDrawBuffer(dst->gl_attachments_[dst_slot]); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-29 15:17:13 +02:00
										 |  |  |   context_->state_manager->apply_state(); | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   int w = src->width_; | 
					
						
							|  |  |  |   int h = src->height_; | 
					
						
							|  |  |  |   GLbitfield mask = to_gl(planes); | 
					
						
							|  |  |  |   glBlitFramebuffer(0, 0, w, h, x, y, x + w, y + h, mask, GL_NEAREST); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!dst->immutable_) { | 
					
						
							|  |  |  |     /* Restore the draw buffers. */ | 
					
						
							|  |  |  |     glDrawBuffers(ARRAY_SIZE(dst->gl_attachments_), dst->gl_attachments_); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-10-07 14:03:27 +02:00
										 |  |  |   /* Ensure previous buffer is restored. */ | 
					
						
							|  |  |  |   context_->active_fb = dst; | 
					
						
							| 
									
										
										
										
											2020-08-29 01:13:54 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** \} */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-02 09:58:26 +10:00
										 |  |  | }  // namespace blender::gpu
 |