This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/gpu/intern/gpu_framebuffer.cc

1111 lines
34 KiB
C++
Raw Normal View History

/*
* 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) 2005 Blender Foundation.
* All rights reserved.
*/
/** \file
* \ingroup gpu
*/
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
GPUFramebuffer: Refactor (Part 2) This refactor modernise the use of framebuffers. It also touches a lot of files so breaking down changes we have: - GPUTexture: Allow textures to be attached to more than one GPUFrameBuffer. This allows to create and configure more FBO without the need to attach and detach texture at drawing time. - GPUFrameBuffer: The wrapper starts to mimic opengl a bit closer. This allows to configure the framebuffer inside a context other than the one that will be rendering the framebuffer. We do the actual configuration when binding the FBO. We also Keep track of config validity and save drawbuffers state in the FBO. We remove the different bind/unbind functions. These make little sense now that we have separate contexts. - DRWFrameBuffer: We replace DRW_framebuffer functions by GPU_framebuffer ones to avoid another layer of abstraction. We move the DRW convenience functions to GPUFramebuffer instead and even add new ones. The MACRO GPU_framebuffer_ensure_config is pretty much all you need to create and config a GPUFramebuffer. - DRWTexture: Due to the removal of DRWFrameBuffer, we needed to create functions to create textures for thoses framebuffers. Pool textures are now using default texture parameters for the texture type asked. - DRWManager: Make sure no framebuffer object is bound when doing cache filling. - GPUViewport: Add new color_only_fb and depth_only_fb along with FB API usage update. This let draw engines render to color/depth only target and without the need to attach/detach textures. - WM_window: Assert when a framebuffer is bound when changing context. This balance the fact we are not track ogl context inside GPUFramebuffer. - Eevee, Clay, Mode engines: Update to new API. This comes with a lot of code simplification. This also come with some cleanups in some engine codes.
2018-03-25 17:46:48 +02:00
#include "BLI_math_base.h"
#include "BLI_utildefines.h"
#include "GPU_batch.h"
#include "GPU_extensions.h"
#include "GPU_shader.h"
#include "GPU_texture.h"
#include "gpu_context_private.hh"
#include "gpu_private.h"
#include "gpu_framebuffer_private.hh"
using namespace blender::gpu;
GPUFramebuffer: Refactor (Part 2) This refactor modernise the use of framebuffers. It also touches a lot of files so breaking down changes we have: - GPUTexture: Allow textures to be attached to more than one GPUFrameBuffer. This allows to create and configure more FBO without the need to attach and detach texture at drawing time. - GPUFrameBuffer: The wrapper starts to mimic opengl a bit closer. This allows to configure the framebuffer inside a context other than the one that will be rendering the framebuffer. We do the actual configuration when binding the FBO. We also Keep track of config validity and save drawbuffers state in the FBO. We remove the different bind/unbind functions. These make little sense now that we have separate contexts. - DRWFrameBuffer: We replace DRW_framebuffer functions by GPU_framebuffer ones to avoid another layer of abstraction. We move the DRW convenience functions to GPUFramebuffer instead and even add new ones. The MACRO GPU_framebuffer_ensure_config is pretty much all you need to create and config a GPUFramebuffer. - DRWTexture: Due to the removal of DRWFrameBuffer, we needed to create functions to create textures for thoses framebuffers. Pool textures are now using default texture parameters for the texture type asked. - DRWManager: Make sure no framebuffer object is bound when doing cache filling. - GPUViewport: Add new color_only_fb and depth_only_fb along with FB API usage update. This let draw engines render to color/depth only target and without the need to attach/detach textures. - WM_window: Assert when a framebuffer is bound when changing context. This balance the fact we are not track ogl context inside GPUFramebuffer. - Eevee, Clay, Mode engines: Update to new API. This comes with a lot of code simplification. This also come with some cleanups in some engine codes.
2018-03-25 17:46:48 +02:00
static GLenum convert_attachment_type_to_gl(GPUAttachmentType type)
{
2020-07-26 22:55:09 +02:00
#define ATTACHMENT(type) \
case GPU_FB_##type: { \
return GL_##type; \
} \
((void)0)
switch (type) {
ATTACHMENT(DEPTH_ATTACHMENT);
ATTACHMENT(DEPTH_STENCIL_ATTACHMENT);
ATTACHMENT(COLOR_ATTACHMENT0);
ATTACHMENT(COLOR_ATTACHMENT1);
ATTACHMENT(COLOR_ATTACHMENT2);
ATTACHMENT(COLOR_ATTACHMENT3);
ATTACHMENT(COLOR_ATTACHMENT4);
ATTACHMENT(COLOR_ATTACHMENT5);
default:
BLI_assert(0);
return GL_COLOR_ATTACHMENT0;
}
GPUFramebuffer: Refactor (Part 2) This refactor modernise the use of framebuffers. It also touches a lot of files so breaking down changes we have: - GPUTexture: Allow textures to be attached to more than one GPUFrameBuffer. This allows to create and configure more FBO without the need to attach and detach texture at drawing time. - GPUFrameBuffer: The wrapper starts to mimic opengl a bit closer. This allows to configure the framebuffer inside a context other than the one that will be rendering the framebuffer. We do the actual configuration when binding the FBO. We also Keep track of config validity and save drawbuffers state in the FBO. We remove the different bind/unbind functions. These make little sense now that we have separate contexts. - DRWFrameBuffer: We replace DRW_framebuffer functions by GPU_framebuffer ones to avoid another layer of abstraction. We move the DRW convenience functions to GPUFramebuffer instead and even add new ones. The MACRO GPU_framebuffer_ensure_config is pretty much all you need to create and config a GPUFramebuffer. - DRWTexture: Due to the removal of DRWFrameBuffer, we needed to create functions to create textures for thoses framebuffers. Pool textures are now using default texture parameters for the texture type asked. - DRWManager: Make sure no framebuffer object is bound when doing cache filling. - GPUViewport: Add new color_only_fb and depth_only_fb along with FB API usage update. This let draw engines render to color/depth only target and without the need to attach/detach textures. - WM_window: Assert when a framebuffer is bound when changing context. This balance the fact we are not track ogl context inside GPUFramebuffer. - Eevee, Clay, Mode engines: Update to new API. This comes with a lot of code simplification. This also come with some cleanups in some engine codes.
2018-03-25 17:46:48 +02:00
}
static GPUAttachmentType attachment_type_from_tex(GPUTexture *tex, int slot)
{
switch (GPU_texture_format(tex)) {
case GPU_DEPTH_COMPONENT32F:
case GPU_DEPTH_COMPONENT24:
case GPU_DEPTH_COMPONENT16:
return GPU_FB_DEPTH_ATTACHMENT;
case GPU_DEPTH24_STENCIL8:
case GPU_DEPTH32F_STENCIL8:
return GPU_FB_DEPTH_STENCIL_ATTACHMENT;
default:
2020-07-25 18:40:19 +02:00
return static_cast<GPUAttachmentType>(GPU_FB_COLOR_ATTACHMENT0 + slot);
}
GPUFramebuffer: Refactor (Part 2) This refactor modernise the use of framebuffers. It also touches a lot of files so breaking down changes we have: - GPUTexture: Allow textures to be attached to more than one GPUFrameBuffer. This allows to create and configure more FBO without the need to attach and detach texture at drawing time. - GPUFrameBuffer: The wrapper starts to mimic opengl a bit closer. This allows to configure the framebuffer inside a context other than the one that will be rendering the framebuffer. We do the actual configuration when binding the FBO. We also Keep track of config validity and save drawbuffers state in the FBO. We remove the different bind/unbind functions. These make little sense now that we have separate contexts. - DRWFrameBuffer: We replace DRW_framebuffer functions by GPU_framebuffer ones to avoid another layer of abstraction. We move the DRW convenience functions to GPUFramebuffer instead and even add new ones. The MACRO GPU_framebuffer_ensure_config is pretty much all you need to create and config a GPUFramebuffer. - DRWTexture: Due to the removal of DRWFrameBuffer, we needed to create functions to create textures for thoses framebuffers. Pool textures are now using default texture parameters for the texture type asked. - DRWManager: Make sure no framebuffer object is bound when doing cache filling. - GPUViewport: Add new color_only_fb and depth_only_fb along with FB API usage update. This let draw engines render to color/depth only target and without the need to attach/detach textures. - WM_window: Assert when a framebuffer is bound when changing context. This balance the fact we are not track ogl context inside GPUFramebuffer. - Eevee, Clay, Mode engines: Update to new API. This comes with a lot of code simplification. This also come with some cleanups in some engine codes.
2018-03-25 17:46:48 +02:00
}
static GLenum convert_buffer_bits_to_gl(eGPUFrameBufferBits bits)
{
GLbitfield mask = 0;
mask |= (bits & GPU_DEPTH_BIT) ? GL_DEPTH_BUFFER_BIT : 0;
mask |= (bits & GPU_STENCIL_BIT) ? GL_STENCIL_BUFFER_BIT : 0;
mask |= (bits & GPU_COLOR_BIT) ? GL_COLOR_BUFFER_BIT : 0;
return mask;
}
static void gpu_print_framebuffer_error(GLenum status, char err_out[256])
{
const char *format = "GPUFrameBuffer: framebuffer status %s\n";
const char *err = "unknown";
2019-06-18 18:11:16 +02:00
#define FORMAT_STATUS(X) \
case GL_FRAMEBUFFER_##X: { \
err = "GL_FRAMEBUFFER_" #X; \
break; \
} \
((void)0)
switch (status) {
/* success */
2019-06-18 18:11:16 +02:00
FORMAT_STATUS(COMPLETE);
/* errors shared by OpenGL desktop & ES */
FORMAT_STATUS(INCOMPLETE_ATTACHMENT);
FORMAT_STATUS(INCOMPLETE_MISSING_ATTACHMENT);
FORMAT_STATUS(UNSUPPORTED);
#if 0 /* for OpenGL ES only */
2019-06-18 18:11:16 +02:00
FORMAT_STATUS(INCOMPLETE_DIMENSIONS);
#else /* for desktop GL only */
2019-06-18 18:11:16 +02:00
FORMAT_STATUS(INCOMPLETE_DRAW_BUFFER);
FORMAT_STATUS(INCOMPLETE_READ_BUFFER);
FORMAT_STATUS(INCOMPLETE_MULTISAMPLE);
FORMAT_STATUS(UNDEFINED);
#endif
}
2019-06-18 18:11:16 +02:00
#undef FORMAT_STATUS
if (err_out) {
BLI_snprintf(err_out, 256, format, err);
}
else {
fprintf(stderr, format, err);
}
}
GPUFrameBuffer *GPU_framebuffer_active_get(void)
{
GPUContext *ctx = GPU_context_active_get();
return reinterpret_cast<GPUFrameBuffer *>(ctx ? ctx->active_fb : NULL);
}
/* GPUFrameBuffer */
GPUFrameBuffer *GPU_framebuffer_create(void)
{
/* We generate the FB object later at first use in order to
* create the framebuffer in the right opengl context. */
return (GPUFrameBuffer *)new FrameBuffer();
GPUFramebuffer: Refactor (Part 2) This refactor modernise the use of framebuffers. It also touches a lot of files so breaking down changes we have: - GPUTexture: Allow textures to be attached to more than one GPUFrameBuffer. This allows to create and configure more FBO without the need to attach and detach texture at drawing time. - GPUFrameBuffer: The wrapper starts to mimic opengl a bit closer. This allows to configure the framebuffer inside a context other than the one that will be rendering the framebuffer. We do the actual configuration when binding the FBO. We also Keep track of config validity and save drawbuffers state in the FBO. We remove the different bind/unbind functions. These make little sense now that we have separate contexts. - DRWFrameBuffer: We replace DRW_framebuffer functions by GPU_framebuffer ones to avoid another layer of abstraction. We move the DRW convenience functions to GPUFramebuffer instead and even add new ones. The MACRO GPU_framebuffer_ensure_config is pretty much all you need to create and config a GPUFramebuffer. - DRWTexture: Due to the removal of DRWFrameBuffer, we needed to create functions to create textures for thoses framebuffers. Pool textures are now using default texture parameters for the texture type asked. - DRWManager: Make sure no framebuffer object is bound when doing cache filling. - GPUViewport: Add new color_only_fb and depth_only_fb along with FB API usage update. This let draw engines render to color/depth only target and without the need to attach/detach textures. - WM_window: Assert when a framebuffer is bound when changing context. This balance the fact we are not track ogl context inside GPUFramebuffer. - Eevee, Clay, Mode engines: Update to new API. This comes with a lot of code simplification. This also come with some cleanups in some engine codes.
2018-03-25 17:46:48 +02:00
}
static void gpu_framebuffer_init(FrameBuffer *fb)
GPUFramebuffer: Refactor (Part 2) This refactor modernise the use of framebuffers. It also touches a lot of files so breaking down changes we have: - GPUTexture: Allow textures to be attached to more than one GPUFrameBuffer. This allows to create and configure more FBO without the need to attach and detach texture at drawing time. - GPUFrameBuffer: The wrapper starts to mimic opengl a bit closer. This allows to configure the framebuffer inside a context other than the one that will be rendering the framebuffer. We do the actual configuration when binding the FBO. We also Keep track of config validity and save drawbuffers state in the FBO. We remove the different bind/unbind functions. These make little sense now that we have separate contexts. - DRWFrameBuffer: We replace DRW_framebuffer functions by GPU_framebuffer ones to avoid another layer of abstraction. We move the DRW convenience functions to GPUFramebuffer instead and even add new ones. The MACRO GPU_framebuffer_ensure_config is pretty much all you need to create and config a GPUFramebuffer. - DRWTexture: Due to the removal of DRWFrameBuffer, we needed to create functions to create textures for thoses framebuffers. Pool textures are now using default texture parameters for the texture type asked. - DRWManager: Make sure no framebuffer object is bound when doing cache filling. - GPUViewport: Add new color_only_fb and depth_only_fb along with FB API usage update. This let draw engines render to color/depth only target and without the need to attach/detach textures. - WM_window: Assert when a framebuffer is bound when changing context. This balance the fact we are not track ogl context inside GPUFramebuffer. - Eevee, Clay, Mode engines: Update to new API. This comes with a lot of code simplification. This also come with some cleanups in some engine codes.
2018-03-25 17:46:48 +02:00
{
fb->object = GPU_fbo_alloc();
fb->ctx = GPU_context_active_get();
/* Not really needed for now. */
// gpu_context_add_framebuffer(fb->ctx, fb);
}
void GPU_framebuffer_free(GPUFrameBuffer *gpu_fb)
{
FrameBuffer *fb = reinterpret_cast<FrameBuffer *>(gpu_fb);
2020-07-25 18:40:19 +02:00
for (int i_type = 0; i_type < GPU_FB_MAX_ATTACHEMENT; i_type++) {
GPUAttachmentType type = static_cast<GPUAttachmentType>(i_type);
if (fb->attachments[type].tex != NULL) {
GPU_framebuffer_texture_detach(gpu_fb, fb->attachments[type].tex);
}
}
if (fb->object != 0) {
/* This restores the framebuffer if it was bound */
GPU_fbo_free(fb->object, fb->ctx);
/* Not really needed for now. */
// gpu_context_remove_framebuffer(fb->ctx, fb);
}
/* TODO(fclem) check if bound in its associated context context. */
if (GPU_framebuffer_active_get() == gpu_fb) {
GPU_context_active_get()->active_fb = NULL;
}
delete fb;
}
GPUFramebuffer: Refactor (Part 2) This refactor modernise the use of framebuffers. It also touches a lot of files so breaking down changes we have: - GPUTexture: Allow textures to be attached to more than one GPUFrameBuffer. This allows to create and configure more FBO without the need to attach and detach texture at drawing time. - GPUFrameBuffer: The wrapper starts to mimic opengl a bit closer. This allows to configure the framebuffer inside a context other than the one that will be rendering the framebuffer. We do the actual configuration when binding the FBO. We also Keep track of config validity and save drawbuffers state in the FBO. We remove the different bind/unbind functions. These make little sense now that we have separate contexts. - DRWFrameBuffer: We replace DRW_framebuffer functions by GPU_framebuffer ones to avoid another layer of abstraction. We move the DRW convenience functions to GPUFramebuffer instead and even add new ones. The MACRO GPU_framebuffer_ensure_config is pretty much all you need to create and config a GPUFramebuffer. - DRWTexture: Due to the removal of DRWFrameBuffer, we needed to create functions to create textures for thoses framebuffers. Pool textures are now using default texture parameters for the texture type asked. - DRWManager: Make sure no framebuffer object is bound when doing cache filling. - GPUViewport: Add new color_only_fb and depth_only_fb along with FB API usage update. This let draw engines render to color/depth only target and without the need to attach/detach textures. - WM_window: Assert when a framebuffer is bound when changing context. This balance the fact we are not track ogl context inside GPUFramebuffer. - Eevee, Clay, Mode engines: Update to new API. This comes with a lot of code simplification. This also come with some cleanups in some engine codes.
2018-03-25 17:46:48 +02:00
/* ---------- Attach ----------- */
static void gpu_framebuffer_texture_attach_ex(
FrameBuffer *fb, GPUTexture *tex, int slot, int layer, int mip)
GPUFramebuffer: Refactor (Part 2) This refactor modernise the use of framebuffers. It also touches a lot of files so breaking down changes we have: - GPUTexture: Allow textures to be attached to more than one GPUFrameBuffer. This allows to create and configure more FBO without the need to attach and detach texture at drawing time. - GPUFrameBuffer: The wrapper starts to mimic opengl a bit closer. This allows to configure the framebuffer inside a context other than the one that will be rendering the framebuffer. We do the actual configuration when binding the FBO. We also Keep track of config validity and save drawbuffers state in the FBO. We remove the different bind/unbind functions. These make little sense now that we have separate contexts. - DRWFrameBuffer: We replace DRW_framebuffer functions by GPU_framebuffer ones to avoid another layer of abstraction. We move the DRW convenience functions to GPUFramebuffer instead and even add new ones. The MACRO GPU_framebuffer_ensure_config is pretty much all you need to create and config a GPUFramebuffer. - DRWTexture: Due to the removal of DRWFrameBuffer, we needed to create functions to create textures for thoses framebuffers. Pool textures are now using default texture parameters for the texture type asked. - DRWManager: Make sure no framebuffer object is bound when doing cache filling. - GPUViewport: Add new color_only_fb and depth_only_fb along with FB API usage update. This let draw engines render to color/depth only target and without the need to attach/detach textures. - WM_window: Assert when a framebuffer is bound when changing context. This balance the fact we are not track ogl context inside GPUFramebuffer. - Eevee, Clay, Mode engines: Update to new API. This comes with a lot of code simplification. This also come with some cleanups in some engine codes.
2018-03-25 17:46:48 +02:00
{
if (slot >= GPU_FB_MAX_COLOR_ATTACHMENT) {
fprintf(stderr,
"Attaching to index %d framebuffer slot unsupported. "
"Use at most %d\n",
slot,
GPU_FB_MAX_COLOR_ATTACHMENT);
return;
}
GPUFrameBuffer *gpufb = reinterpret_cast<GPUFrameBuffer *>(fb);
GPUAttachmentType type = attachment_type_from_tex(tex, slot);
GPUAttachment *attachment = &fb->attachments[type];
if ((attachment->tex == tex) && (attachment->mip == mip) && (attachment->layer == layer)) {
return; /* Exact same texture already bound here. */
}
if (attachment->tex != NULL) {
GPU_framebuffer_texture_detach(gpufb, attachment->tex);
}
if (attachment->tex == NULL) {
GPU_texture_attach_framebuffer(tex, gpufb, type);
}
attachment->tex = tex;
attachment->mip = mip;
attachment->layer = layer;
GPU_FB_ATTACHEMENT_SET_DIRTY(fb->dirty_flag, type);
}
void GPU_framebuffer_texture_attach(GPUFrameBuffer *gpu_fb, GPUTexture *tex, int slot, int mip)
{
FrameBuffer *fb = reinterpret_cast<FrameBuffer *>(gpu_fb);
gpu_framebuffer_texture_attach_ex(fb, tex, slot, -1, mip);
}
void GPU_framebuffer_texture_layer_attach(
GPUFrameBuffer *gpu_fb, GPUTexture *tex, int slot, int layer, int mip)
{
FrameBuffer *fb = reinterpret_cast<FrameBuffer *>(gpu_fb);
/* NOTE: We could support 1D ARRAY texture. */
BLI_assert(GPU_texture_target(tex) == GL_TEXTURE_2D_ARRAY);
gpu_framebuffer_texture_attach_ex(fb, tex, slot, layer, mip);
}
void GPU_framebuffer_texture_cubeface_attach(
GPUFrameBuffer *gpu_fb, GPUTexture *tex, int slot, int face, int mip)
{
FrameBuffer *fb = reinterpret_cast<FrameBuffer *>(gpu_fb);
BLI_assert(GPU_texture_cube(tex));
gpu_framebuffer_texture_attach_ex(fb, tex, slot, face, mip);
GPUFramebuffer: Refactor (Part 2) This refactor modernise the use of framebuffers. It also touches a lot of files so breaking down changes we have: - GPUTexture: Allow textures to be attached to more than one GPUFrameBuffer. This allows to create and configure more FBO without the need to attach and detach texture at drawing time. - GPUFrameBuffer: The wrapper starts to mimic opengl a bit closer. This allows to configure the framebuffer inside a context other than the one that will be rendering the framebuffer. We do the actual configuration when binding the FBO. We also Keep track of config validity and save drawbuffers state in the FBO. We remove the different bind/unbind functions. These make little sense now that we have separate contexts. - DRWFrameBuffer: We replace DRW_framebuffer functions by GPU_framebuffer ones to avoid another layer of abstraction. We move the DRW convenience functions to GPUFramebuffer instead and even add new ones. The MACRO GPU_framebuffer_ensure_config is pretty much all you need to create and config a GPUFramebuffer. - DRWTexture: Due to the removal of DRWFrameBuffer, we needed to create functions to create textures for thoses framebuffers. Pool textures are now using default texture parameters for the texture type asked. - DRWManager: Make sure no framebuffer object is bound when doing cache filling. - GPUViewport: Add new color_only_fb and depth_only_fb along with FB API usage update. This let draw engines render to color/depth only target and without the need to attach/detach textures. - WM_window: Assert when a framebuffer is bound when changing context. This balance the fact we are not track ogl context inside GPUFramebuffer. - Eevee, Clay, Mode engines: Update to new API. This comes with a lot of code simplification. This also come with some cleanups in some engine codes.
2018-03-25 17:46:48 +02:00
}
GPUFramebuffer: Refactor (Part 2) This refactor modernise the use of framebuffers. It also touches a lot of files so breaking down changes we have: - GPUTexture: Allow textures to be attached to more than one GPUFrameBuffer. This allows to create and configure more FBO without the need to attach and detach texture at drawing time. - GPUFrameBuffer: The wrapper starts to mimic opengl a bit closer. This allows to configure the framebuffer inside a context other than the one that will be rendering the framebuffer. We do the actual configuration when binding the FBO. We also Keep track of config validity and save drawbuffers state in the FBO. We remove the different bind/unbind functions. These make little sense now that we have separate contexts. - DRWFrameBuffer: We replace DRW_framebuffer functions by GPU_framebuffer ones to avoid another layer of abstraction. We move the DRW convenience functions to GPUFramebuffer instead and even add new ones. The MACRO GPU_framebuffer_ensure_config is pretty much all you need to create and config a GPUFramebuffer. - DRWTexture: Due to the removal of DRWFrameBuffer, we needed to create functions to create textures for thoses framebuffers. Pool textures are now using default texture parameters for the texture type asked. - DRWManager: Make sure no framebuffer object is bound when doing cache filling. - GPUViewport: Add new color_only_fb and depth_only_fb along with FB API usage update. This let draw engines render to color/depth only target and without the need to attach/detach textures. - WM_window: Assert when a framebuffer is bound when changing context. This balance the fact we are not track ogl context inside GPUFramebuffer. - Eevee, Clay, Mode engines: Update to new API. This comes with a lot of code simplification. This also come with some cleanups in some engine codes.
2018-03-25 17:46:48 +02:00
/* ---------- Detach ----------- */
void GPU_framebuffer_texture_detach_slot(GPUFrameBuffer *gpu_fb, GPUTexture *tex, int type)
GPUFramebuffer: Refactor (Part 2) This refactor modernise the use of framebuffers. It also touches a lot of files so breaking down changes we have: - GPUTexture: Allow textures to be attached to more than one GPUFrameBuffer. This allows to create and configure more FBO without the need to attach and detach texture at drawing time. - GPUFrameBuffer: The wrapper starts to mimic opengl a bit closer. This allows to configure the framebuffer inside a context other than the one that will be rendering the framebuffer. We do the actual configuration when binding the FBO. We also Keep track of config validity and save drawbuffers state in the FBO. We remove the different bind/unbind functions. These make little sense now that we have separate contexts. - DRWFrameBuffer: We replace DRW_framebuffer functions by GPU_framebuffer ones to avoid another layer of abstraction. We move the DRW convenience functions to GPUFramebuffer instead and even add new ones. The MACRO GPU_framebuffer_ensure_config is pretty much all you need to create and config a GPUFramebuffer. - DRWTexture: Due to the removal of DRWFrameBuffer, we needed to create functions to create textures for thoses framebuffers. Pool textures are now using default texture parameters for the texture type asked. - DRWManager: Make sure no framebuffer object is bound when doing cache filling. - GPUViewport: Add new color_only_fb and depth_only_fb along with FB API usage update. This let draw engines render to color/depth only target and without the need to attach/detach textures. - WM_window: Assert when a framebuffer is bound when changing context. This balance the fact we are not track ogl context inside GPUFramebuffer. - Eevee, Clay, Mode engines: Update to new API. This comes with a lot of code simplification. This also come with some cleanups in some engine codes.
2018-03-25 17:46:48 +02:00
{
FrameBuffer *fb = reinterpret_cast<FrameBuffer *>(gpu_fb);
GPUAttachment *attachment = &fb->attachments[type];
if (attachment->tex != tex) {
fprintf(stderr,
"Warning, attempting to detach Texture %p from framebuffer %p "
"but texture is not attached.\n",
tex,
fb);
return;
}
attachment->tex = NULL;
GPU_FB_ATTACHEMENT_SET_DIRTY(fb->dirty_flag, type);
GPUFramebuffer: Refactor (Part 2) This refactor modernise the use of framebuffers. It also touches a lot of files so breaking down changes we have: - GPUTexture: Allow textures to be attached to more than one GPUFrameBuffer. This allows to create and configure more FBO without the need to attach and detach texture at drawing time. - GPUFrameBuffer: The wrapper starts to mimic opengl a bit closer. This allows to configure the framebuffer inside a context other than the one that will be rendering the framebuffer. We do the actual configuration when binding the FBO. We also Keep track of config validity and save drawbuffers state in the FBO. We remove the different bind/unbind functions. These make little sense now that we have separate contexts. - DRWFrameBuffer: We replace DRW_framebuffer functions by GPU_framebuffer ones to avoid another layer of abstraction. We move the DRW convenience functions to GPUFramebuffer instead and even add new ones. The MACRO GPU_framebuffer_ensure_config is pretty much all you need to create and config a GPUFramebuffer. - DRWTexture: Due to the removal of DRWFrameBuffer, we needed to create functions to create textures for thoses framebuffers. Pool textures are now using default texture parameters for the texture type asked. - DRWManager: Make sure no framebuffer object is bound when doing cache filling. - GPUViewport: Add new color_only_fb and depth_only_fb along with FB API usage update. This let draw engines render to color/depth only target and without the need to attach/detach textures. - WM_window: Assert when a framebuffer is bound when changing context. This balance the fact we are not track ogl context inside GPUFramebuffer. - Eevee, Clay, Mode engines: Update to new API. This comes with a lot of code simplification. This also come with some cleanups in some engine codes.
2018-03-25 17:46:48 +02:00
}
void GPU_framebuffer_texture_detach(GPUFrameBuffer *gpu_fb, GPUTexture *tex)
GPUFramebuffer: Refactor (Part 2) This refactor modernise the use of framebuffers. It also touches a lot of files so breaking down changes we have: - GPUTexture: Allow textures to be attached to more than one GPUFrameBuffer. This allows to create and configure more FBO without the need to attach and detach texture at drawing time. - GPUFrameBuffer: The wrapper starts to mimic opengl a bit closer. This allows to configure the framebuffer inside a context other than the one that will be rendering the framebuffer. We do the actual configuration when binding the FBO. We also Keep track of config validity and save drawbuffers state in the FBO. We remove the different bind/unbind functions. These make little sense now that we have separate contexts. - DRWFrameBuffer: We replace DRW_framebuffer functions by GPU_framebuffer ones to avoid another layer of abstraction. We move the DRW convenience functions to GPUFramebuffer instead and even add new ones. The MACRO GPU_framebuffer_ensure_config is pretty much all you need to create and config a GPUFramebuffer. - DRWTexture: Due to the removal of DRWFrameBuffer, we needed to create functions to create textures for thoses framebuffers. Pool textures are now using default texture parameters for the texture type asked. - DRWManager: Make sure no framebuffer object is bound when doing cache filling. - GPUViewport: Add new color_only_fb and depth_only_fb along with FB API usage update. This let draw engines render to color/depth only target and without the need to attach/detach textures. - WM_window: Assert when a framebuffer is bound when changing context. This balance the fact we are not track ogl context inside GPUFramebuffer. - Eevee, Clay, Mode engines: Update to new API. This comes with a lot of code simplification. This also come with some cleanups in some engine codes.
2018-03-25 17:46:48 +02:00
{
GPUAttachmentType type = (GPUAttachmentType)GPU_texture_detach_framebuffer(tex, gpu_fb);
GPU_framebuffer_texture_detach_slot(gpu_fb, tex, type);
}
GPUFramebuffer: Refactor (Part 2) This refactor modernise the use of framebuffers. It also touches a lot of files so breaking down changes we have: - GPUTexture: Allow textures to be attached to more than one GPUFrameBuffer. This allows to create and configure more FBO without the need to attach and detach texture at drawing time. - GPUFrameBuffer: The wrapper starts to mimic opengl a bit closer. This allows to configure the framebuffer inside a context other than the one that will be rendering the framebuffer. We do the actual configuration when binding the FBO. We also Keep track of config validity and save drawbuffers state in the FBO. We remove the different bind/unbind functions. These make little sense now that we have separate contexts. - DRWFrameBuffer: We replace DRW_framebuffer functions by GPU_framebuffer ones to avoid another layer of abstraction. We move the DRW convenience functions to GPUFramebuffer instead and even add new ones. The MACRO GPU_framebuffer_ensure_config is pretty much all you need to create and config a GPUFramebuffer. - DRWTexture: Due to the removal of DRWFrameBuffer, we needed to create functions to create textures for thoses framebuffers. Pool textures are now using default texture parameters for the texture type asked. - DRWManager: Make sure no framebuffer object is bound when doing cache filling. - GPUViewport: Add new color_only_fb and depth_only_fb along with FB API usage update. This let draw engines render to color/depth only target and without the need to attach/detach textures. - WM_window: Assert when a framebuffer is bound when changing context. This balance the fact we are not track ogl context inside GPUFramebuffer. - Eevee, Clay, Mode engines: Update to new API. This comes with a lot of code simplification. This also come with some cleanups in some engine codes.
2018-03-25 17:46:48 +02:00
/* ---------- Config (Attach & Detach) ----------- */
/**
* First GPUAttachment in *config is always the depth/depth_stencil buffer.
* Following GPUAttachments are color buffers.
* Setting GPUAttachment.mip to -1 will leave the texture in this slot.
* Setting GPUAttachment.tex to NULL will detach the texture in this slot.
2019-03-19 15:17:46 +11:00
*/
void GPU_framebuffer_config_array(GPUFrameBuffer *gpu_fb,
const GPUAttachment *config,
int config_len)
{
FrameBuffer *fb = reinterpret_cast<FrameBuffer *>(gpu_fb);
if (config[0].tex) {
BLI_assert(GPU_texture_depth(config[0].tex));
gpu_framebuffer_texture_attach_ex(fb, config[0].tex, 0, config[0].layer, config[0].mip);
}
else if (config[0].mip == -1) {
/* Leave texture attached */
}
else if (fb->attachments[GPU_FB_DEPTH_ATTACHMENT].tex != NULL) {
GPU_framebuffer_texture_detach(gpu_fb, fb->attachments[GPU_FB_DEPTH_ATTACHMENT].tex);
}
else if (fb->attachments[GPU_FB_DEPTH_STENCIL_ATTACHMENT].tex != NULL) {
GPU_framebuffer_texture_detach(gpu_fb, fb->attachments[GPU_FB_DEPTH_STENCIL_ATTACHMENT].tex);
}
int slot = 0;
for (int i = 1; i < config_len; i++, slot++) {
if (config[i].tex != NULL) {
BLI_assert(GPU_texture_depth(config[i].tex) == false);
gpu_framebuffer_texture_attach_ex(fb, config[i].tex, slot, config[i].layer, config[i].mip);
}
else if (config[i].mip != -1) {
GPUTexture *tex = fb->color_tex(slot);
if (tex != NULL) {
GPU_framebuffer_texture_detach(gpu_fb, tex);
}
}
}
GPUFramebuffer: Refactor (Part 2) This refactor modernise the use of framebuffers. It also touches a lot of files so breaking down changes we have: - GPUTexture: Allow textures to be attached to more than one GPUFrameBuffer. This allows to create and configure more FBO without the need to attach and detach texture at drawing time. - GPUFrameBuffer: The wrapper starts to mimic opengl a bit closer. This allows to configure the framebuffer inside a context other than the one that will be rendering the framebuffer. We do the actual configuration when binding the FBO. We also Keep track of config validity and save drawbuffers state in the FBO. We remove the different bind/unbind functions. These make little sense now that we have separate contexts. - DRWFrameBuffer: We replace DRW_framebuffer functions by GPU_framebuffer ones to avoid another layer of abstraction. We move the DRW convenience functions to GPUFramebuffer instead and even add new ones. The MACRO GPU_framebuffer_ensure_config is pretty much all you need to create and config a GPUFramebuffer. - DRWTexture: Due to the removal of DRWFrameBuffer, we needed to create functions to create textures for thoses framebuffers. Pool textures are now using default texture parameters for the texture type asked. - DRWManager: Make sure no framebuffer object is bound when doing cache filling. - GPUViewport: Add new color_only_fb and depth_only_fb along with FB API usage update. This let draw engines render to color/depth only target and without the need to attach/detach textures. - WM_window: Assert when a framebuffer is bound when changing context. This balance the fact we are not track ogl context inside GPUFramebuffer. - Eevee, Clay, Mode engines: Update to new API. This comes with a lot of code simplification. This also come with some cleanups in some engine codes.
2018-03-25 17:46:48 +02:00
}
GPUFramebuffer: Refactor (Part 2) This refactor modernise the use of framebuffers. It also touches a lot of files so breaking down changes we have: - GPUTexture: Allow textures to be attached to more than one GPUFrameBuffer. This allows to create and configure more FBO without the need to attach and detach texture at drawing time. - GPUFrameBuffer: The wrapper starts to mimic opengl a bit closer. This allows to configure the framebuffer inside a context other than the one that will be rendering the framebuffer. We do the actual configuration when binding the FBO. We also Keep track of config validity and save drawbuffers state in the FBO. We remove the different bind/unbind functions. These make little sense now that we have separate contexts. - DRWFrameBuffer: We replace DRW_framebuffer functions by GPU_framebuffer ones to avoid another layer of abstraction. We move the DRW convenience functions to GPUFramebuffer instead and even add new ones. The MACRO GPU_framebuffer_ensure_config is pretty much all you need to create and config a GPUFramebuffer. - DRWTexture: Due to the removal of DRWFrameBuffer, we needed to create functions to create textures for thoses framebuffers. Pool textures are now using default texture parameters for the texture type asked. - DRWManager: Make sure no framebuffer object is bound when doing cache filling. - GPUViewport: Add new color_only_fb and depth_only_fb along with FB API usage update. This let draw engines render to color/depth only target and without the need to attach/detach textures. - WM_window: Assert when a framebuffer is bound when changing context. This balance the fact we are not track ogl context inside GPUFramebuffer. - Eevee, Clay, Mode engines: Update to new API. This comes with a lot of code simplification. This also come with some cleanups in some engine codes.
2018-03-25 17:46:48 +02:00
/* ---------- Bind / Restore ----------- */
GPUFramebuffer: Refactor (Part 2) This refactor modernise the use of framebuffers. It also touches a lot of files so breaking down changes we have: - GPUTexture: Allow textures to be attached to more than one GPUFrameBuffer. This allows to create and configure more FBO without the need to attach and detach texture at drawing time. - GPUFrameBuffer: The wrapper starts to mimic opengl a bit closer. This allows to configure the framebuffer inside a context other than the one that will be rendering the framebuffer. We do the actual configuration when binding the FBO. We also Keep track of config validity and save drawbuffers state in the FBO. We remove the different bind/unbind functions. These make little sense now that we have separate contexts. - DRWFrameBuffer: We replace DRW_framebuffer functions by GPU_framebuffer ones to avoid another layer of abstraction. We move the DRW convenience functions to GPUFramebuffer instead and even add new ones. The MACRO GPU_framebuffer_ensure_config is pretty much all you need to create and config a GPUFramebuffer. - DRWTexture: Due to the removal of DRWFrameBuffer, we needed to create functions to create textures for thoses framebuffers. Pool textures are now using default texture parameters for the texture type asked. - DRWManager: Make sure no framebuffer object is bound when doing cache filling. - GPUViewport: Add new color_only_fb and depth_only_fb along with FB API usage update. This let draw engines render to color/depth only target and without the need to attach/detach textures. - WM_window: Assert when a framebuffer is bound when changing context. This balance the fact we are not track ogl context inside GPUFramebuffer. - Eevee, Clay, Mode engines: Update to new API. This comes with a lot of code simplification. This also come with some cleanups in some engine codes.
2018-03-25 17:46:48 +02:00
static void gpu_framebuffer_attachment_attach(GPUAttachment *attach, GPUAttachmentType attach_type)
{
int tex_bind = GPU_texture_opengl_bindcode(attach->tex);
GLenum gl_attachment = convert_attachment_type_to_gl(attach_type);
if (attach->layer > -1) {
if (GPU_texture_cube(attach->tex)) {
glFramebufferTexture2D(GL_FRAMEBUFFER,
gl_attachment,
GL_TEXTURE_CUBE_MAP_POSITIVE_X + attach->layer,
tex_bind,
attach->mip);
}
else {
glFramebufferTextureLayer(
GL_FRAMEBUFFER, gl_attachment, tex_bind, attach->mip, attach->layer);
}
}
else {
glFramebufferTexture(GL_FRAMEBUFFER, gl_attachment, tex_bind, attach->mip);
}
GPUFramebuffer: Refactor (Part 2) This refactor modernise the use of framebuffers. It also touches a lot of files so breaking down changes we have: - GPUTexture: Allow textures to be attached to more than one GPUFrameBuffer. This allows to create and configure more FBO without the need to attach and detach texture at drawing time. - GPUFrameBuffer: The wrapper starts to mimic opengl a bit closer. This allows to configure the framebuffer inside a context other than the one that will be rendering the framebuffer. We do the actual configuration when binding the FBO. We also Keep track of config validity and save drawbuffers state in the FBO. We remove the different bind/unbind functions. These make little sense now that we have separate contexts. - DRWFrameBuffer: We replace DRW_framebuffer functions by GPU_framebuffer ones to avoid another layer of abstraction. We move the DRW convenience functions to GPUFramebuffer instead and even add new ones. The MACRO GPU_framebuffer_ensure_config is pretty much all you need to create and config a GPUFramebuffer. - DRWTexture: Due to the removal of DRWFrameBuffer, we needed to create functions to create textures for thoses framebuffers. Pool textures are now using default texture parameters for the texture type asked. - DRWManager: Make sure no framebuffer object is bound when doing cache filling. - GPUViewport: Add new color_only_fb and depth_only_fb along with FB API usage update. This let draw engines render to color/depth only target and without the need to attach/detach textures. - WM_window: Assert when a framebuffer is bound when changing context. This balance the fact we are not track ogl context inside GPUFramebuffer. - Eevee, Clay, Mode engines: Update to new API. This comes with a lot of code simplification. This also come with some cleanups in some engine codes.
2018-03-25 17:46:48 +02:00
}
static void gpu_framebuffer_attachment_detach(GPUAttachment *UNUSED(attachment),
GPUAttachmentType attach_type)
GPUFramebuffer: Refactor (Part 2) This refactor modernise the use of framebuffers. It also touches a lot of files so breaking down changes we have: - GPUTexture: Allow textures to be attached to more than one GPUFrameBuffer. This allows to create and configure more FBO without the need to attach and detach texture at drawing time. - GPUFrameBuffer: The wrapper starts to mimic opengl a bit closer. This allows to configure the framebuffer inside a context other than the one that will be rendering the framebuffer. We do the actual configuration when binding the FBO. We also Keep track of config validity and save drawbuffers state in the FBO. We remove the different bind/unbind functions. These make little sense now that we have separate contexts. - DRWFrameBuffer: We replace DRW_framebuffer functions by GPU_framebuffer ones to avoid another layer of abstraction. We move the DRW convenience functions to GPUFramebuffer instead and even add new ones. The MACRO GPU_framebuffer_ensure_config is pretty much all you need to create and config a GPUFramebuffer. - DRWTexture: Due to the removal of DRWFrameBuffer, we needed to create functions to create textures for thoses framebuffers. Pool textures are now using default texture parameters for the texture type asked. - DRWManager: Make sure no framebuffer object is bound when doing cache filling. - GPUViewport: Add new color_only_fb and depth_only_fb along with FB API usage update. This let draw engines render to color/depth only target and without the need to attach/detach textures. - WM_window: Assert when a framebuffer is bound when changing context. This balance the fact we are not track ogl context inside GPUFramebuffer. - Eevee, Clay, Mode engines: Update to new API. This comes with a lot of code simplification. This also come with some cleanups in some engine codes.
2018-03-25 17:46:48 +02:00
{
GLenum gl_attachment = convert_attachment_type_to_gl(attach_type);
glFramebufferTexture(GL_FRAMEBUFFER, gl_attachment, 0, 0);
}
static void gpu_framebuffer_update_attachments(FrameBuffer *fb)
{
GLenum gl_attachments[GPU_FB_MAX_COLOR_ATTACHMENT];
int numslots = 0;
BLI_assert(GPU_context_active_get()->active_fb == fb);
/* Update attachments */
2020-07-25 18:40:19 +02:00
FOREACH_ATTACHMENT_RANGE(type, 0, GPU_FB_MAX_ATTACHEMENT)
{
if (type >= GPU_FB_COLOR_ATTACHMENT0) {
if (fb->attachments[type].tex) {
gl_attachments[numslots] = convert_attachment_type_to_gl(type);
}
else {
gl_attachments[numslots] = GL_NONE;
}
numslots++;
}
if (GPU_FB_ATTACHEMENT_IS_DIRTY(fb->dirty_flag, type) == false) {
continue;
}
if (fb->attachments[type].tex != NULL) {
gpu_framebuffer_attachment_attach(&fb->attachments[type], type);
fb->multisample = (GPU_texture_samples(fb->attachments[type].tex) > 0);
fb->width = GPU_texture_width(fb->attachments[type].tex);
fb->height = GPU_texture_height(fb->attachments[type].tex);
}
else {
gpu_framebuffer_attachment_detach(&fb->attachments[type], type);
}
}
fb->dirty_flag = 0;
/* Update draw buffers (color targets)
* This state is saved in the FBO */
2019-04-22 09:32:37 +10:00
if (numslots) {
glDrawBuffers(numslots, gl_attachments);
2019-04-22 09:32:37 +10:00
}
else {
glDrawBuffer(GL_NONE);
2019-04-22 09:32:37 +10:00
}
}
/**
* Hack to solve the problem of some bugged AMD GPUs (see `GPU_unused_fb_slot_workaround`).
* If there is an empty color slot between the color slots,
* all textures after this slot are apparently skipped/discarded.
2019-03-19 15:17:46 +11:00
*/
static void gpu_framebuffer_update_attachments_and_fill_empty_slots(FrameBuffer *fb)
{
GLenum gl_attachments[GPU_FB_MAX_COLOR_ATTACHMENT];
int dummy_tex = 0;
BLI_assert(GPU_context_active_get()->active_fb == fb);
/* Update attachments */
for (int i_type = GPU_FB_MAX_ATTACHEMENT - 1; i_type >= 0; --i_type) {
2020-07-25 18:40:19 +02:00
GPUAttachmentType type = static_cast<GPUAttachmentType>(i_type);
GPUTexture *tex = fb->attachments[type].tex;
if (type >= GPU_FB_COLOR_ATTACHMENT0) {
int slot = type - GPU_FB_COLOR_ATTACHMENT0;
if (tex != NULL || (dummy_tex != 0)) {
gl_attachments[slot] = convert_attachment_type_to_gl(type);
if (dummy_tex == 0) {
dummy_tex = GPU_texture_opengl_bindcode(tex);
}
}
else {
gl_attachments[slot] = GL_NONE;
}
}
else {
dummy_tex = 0;
}
if ((dummy_tex != 0) && tex == NULL) {
/* Fill empty slot */
glFramebufferTexture(GL_FRAMEBUFFER, convert_attachment_type_to_gl(type), dummy_tex, 0);
}
else if (GPU_FB_ATTACHEMENT_IS_DIRTY(fb->dirty_flag, type)) {
if (tex != NULL) {
gpu_framebuffer_attachment_attach(&fb->attachments[type], type);
fb->multisample = (GPU_texture_samples(tex) > 0);
fb->width = GPU_texture_width(tex);
fb->height = GPU_texture_height(tex);
}
else {
gpu_framebuffer_attachment_detach(&fb->attachments[type], type);
}
}
}
fb->dirty_flag = 0;
/* Update draw buffers (color targets)
* This state is saved in the FBO */
glDrawBuffers(GPU_FB_MAX_COLOR_ATTACHMENT, gl_attachments);
}
#define FRAMEBUFFER_STACK_DEPTH 16
static struct {
GPUFrameBuffer *framebuffers[FRAMEBUFFER_STACK_DEPTH];
uint top;
2018-12-30 15:14:00 +11:00
} FrameBufferStack = {{0}};
static void gpuPushFrameBuffer(GPUFrameBuffer *fb)
{
BLI_assert(FrameBufferStack.top < FRAMEBUFFER_STACK_DEPTH);
FrameBufferStack.framebuffers[FrameBufferStack.top] = fb;
FrameBufferStack.top++;
}
static GPUFrameBuffer *gpuPopFrameBuffer(void)
{
BLI_assert(FrameBufferStack.top > 0);
FrameBufferStack.top--;
return FrameBufferStack.framebuffers[FrameBufferStack.top];
}
#undef FRAMEBUFFER_STACK_DEPTH
void GPU_framebuffer_bind(GPUFrameBuffer *gpu_fb)
{
FrameBuffer *fb = reinterpret_cast<FrameBuffer *>(gpu_fb);
2019-04-22 09:32:37 +10:00
if (fb->object == 0) {
gpu_framebuffer_init(fb);
2019-04-22 09:32:37 +10:00
}
if (GPU_framebuffer_active_get() != gpu_fb) {
glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
glEnable(GL_FRAMEBUFFER_SRGB);
GPUTexture *first_target = fb->attachments[GPU_FB_COLOR_ATTACHMENT0].tex;
const bool is_srgb_target = (first_target &&
(GPU_texture_format(first_target) == GPU_SRGB8_A8));
GPU_shader_set_framebuffer_srgb_target(is_srgb_target);
2019-04-22 09:32:37 +10:00
}
GPU_context_active_get()->active_fb = fb;
if (fb->dirty_flag != 0) {
if (GPU_unused_fb_slot_workaround()) {
/* XXX: Please AMD, fix this. */
gpu_framebuffer_update_attachments_and_fill_empty_slots(fb);
}
else {
gpu_framebuffer_update_attachments(fb);
}
}
/* TODO manually check for errors? */
GPUFramebuffer: Refactor (Part 2) This refactor modernise the use of framebuffers. It also touches a lot of files so breaking down changes we have: - GPUTexture: Allow textures to be attached to more than one GPUFrameBuffer. This allows to create and configure more FBO without the need to attach and detach texture at drawing time. - GPUFrameBuffer: The wrapper starts to mimic opengl a bit closer. This allows to configure the framebuffer inside a context other than the one that will be rendering the framebuffer. We do the actual configuration when binding the FBO. We also Keep track of config validity and save drawbuffers state in the FBO. We remove the different bind/unbind functions. These make little sense now that we have separate contexts. - DRWFrameBuffer: We replace DRW_framebuffer functions by GPU_framebuffer ones to avoid another layer of abstraction. We move the DRW convenience functions to GPUFramebuffer instead and even add new ones. The MACRO GPU_framebuffer_ensure_config is pretty much all you need to create and config a GPUFramebuffer. - DRWTexture: Due to the removal of DRWFrameBuffer, we needed to create functions to create textures for thoses framebuffers. Pool textures are now using default texture parameters for the texture type asked. - DRWManager: Make sure no framebuffer object is bound when doing cache filling. - GPUViewport: Add new color_only_fb and depth_only_fb along with FB API usage update. This let draw engines render to color/depth only target and without the need to attach/detach textures. - WM_window: Assert when a framebuffer is bound when changing context. This balance the fact we are not track ogl context inside GPUFramebuffer. - Eevee, Clay, Mode engines: Update to new API. This comes with a lot of code simplification. This also come with some cleanups in some engine codes.
2018-03-25 17:46:48 +02:00
#if 0
char err_out[256];
if (!GPU_framebuffer_check_valid(fb, err_out)) {
printf("Invalid %s\n", err_out);
}
GPUFramebuffer: Refactor (Part 2) This refactor modernise the use of framebuffers. It also touches a lot of files so breaking down changes we have: - GPUTexture: Allow textures to be attached to more than one GPUFrameBuffer. This allows to create and configure more FBO without the need to attach and detach texture at drawing time. - GPUFrameBuffer: The wrapper starts to mimic opengl a bit closer. This allows to configure the framebuffer inside a context other than the one that will be rendering the framebuffer. We do the actual configuration when binding the FBO. We also Keep track of config validity and save drawbuffers state in the FBO. We remove the different bind/unbind functions. These make little sense now that we have separate contexts. - DRWFrameBuffer: We replace DRW_framebuffer functions by GPU_framebuffer ones to avoid another layer of abstraction. We move the DRW convenience functions to GPUFramebuffer instead and even add new ones. The MACRO GPU_framebuffer_ensure_config is pretty much all you need to create and config a GPUFramebuffer. - DRWTexture: Due to the removal of DRWFrameBuffer, we needed to create functions to create textures for thoses framebuffers. Pool textures are now using default texture parameters for the texture type asked. - DRWManager: Make sure no framebuffer object is bound when doing cache filling. - GPUViewport: Add new color_only_fb and depth_only_fb along with FB API usage update. This let draw engines render to color/depth only target and without the need to attach/detach textures. - WM_window: Assert when a framebuffer is bound when changing context. This balance the fact we are not track ogl context inside GPUFramebuffer. - Eevee, Clay, Mode engines: Update to new API. This comes with a lot of code simplification. This also come with some cleanups in some engine codes.
2018-03-25 17:46:48 +02:00
#endif
GPU_viewport(0, 0, fb->width, fb->height);
}
/* Workaround for binding a srgb framebuffer without doing the srgb transform. */
void GPU_framebuffer_bind_no_srgb(GPUFrameBuffer *gpu_fb)
{
FrameBuffer *fb = reinterpret_cast<FrameBuffer *>(gpu_fb);
GPU_framebuffer_bind(gpu_fb);
glDisable(GL_FRAMEBUFFER_SRGB);
GPUTexture *first_target = fb->attachments[GPU_FB_COLOR_ATTACHMENT0].tex;
const bool is_srgb_target = (first_target && (GPU_texture_format(first_target) == GPU_SRGB8_A8));
GPU_shader_set_framebuffer_srgb_target(!is_srgb_target);
}
GPUFramebuffer: Refactor (Part 2) This refactor modernise the use of framebuffers. It also touches a lot of files so breaking down changes we have: - GPUTexture: Allow textures to be attached to more than one GPUFrameBuffer. This allows to create and configure more FBO without the need to attach and detach texture at drawing time. - GPUFrameBuffer: The wrapper starts to mimic opengl a bit closer. This allows to configure the framebuffer inside a context other than the one that will be rendering the framebuffer. We do the actual configuration when binding the FBO. We also Keep track of config validity and save drawbuffers state in the FBO. We remove the different bind/unbind functions. These make little sense now that we have separate contexts. - DRWFrameBuffer: We replace DRW_framebuffer functions by GPU_framebuffer ones to avoid another layer of abstraction. We move the DRW convenience functions to GPUFramebuffer instead and even add new ones. The MACRO GPU_framebuffer_ensure_config is pretty much all you need to create and config a GPUFramebuffer. - DRWTexture: Due to the removal of DRWFrameBuffer, we needed to create functions to create textures for thoses framebuffers. Pool textures are now using default texture parameters for the texture type asked. - DRWManager: Make sure no framebuffer object is bound when doing cache filling. - GPUViewport: Add new color_only_fb and depth_only_fb along with FB API usage update. This let draw engines render to color/depth only target and without the need to attach/detach textures. - WM_window: Assert when a framebuffer is bound when changing context. This balance the fact we are not track ogl context inside GPUFramebuffer. - Eevee, Clay, Mode engines: Update to new API. This comes with a lot of code simplification. This also come with some cleanups in some engine codes.
2018-03-25 17:46:48 +02:00
void GPU_framebuffer_restore(void)
{
if (GPU_framebuffer_active_get() != NULL) {
glBindFramebuffer(GL_FRAMEBUFFER, GPU_framebuffer_default());
GPU_context_active_get()->active_fb = NULL;
glDisable(GL_FRAMEBUFFER_SRGB);
GPU_shader_set_framebuffer_srgb_target(false);
}
}
bool GPU_framebuffer_bound(GPUFrameBuffer *gpu_fb)
{
FrameBuffer *fb = reinterpret_cast<FrameBuffer *>(gpu_fb);
return (gpu_fb == GPU_framebuffer_active_get()) && (fb->object != 0);
}
bool GPU_framebuffer_check_valid(GPUFrameBuffer *gpu_fb, char err_out[256])
{
if (!GPU_framebuffer_bound(gpu_fb)) {
GPU_framebuffer_bind(gpu_fb);
2019-04-22 09:32:37 +10:00
}
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
GPU_framebuffer_restore();
gpu_print_framebuffer_error(status, err_out);
return false;
}
return true;
}
GPUFramebuffer: Refactor (Part 2) This refactor modernise the use of framebuffers. It also touches a lot of files so breaking down changes we have: - GPUTexture: Allow textures to be attached to more than one GPUFrameBuffer. This allows to create and configure more FBO without the need to attach and detach texture at drawing time. - GPUFrameBuffer: The wrapper starts to mimic opengl a bit closer. This allows to configure the framebuffer inside a context other than the one that will be rendering the framebuffer. We do the actual configuration when binding the FBO. We also Keep track of config validity and save drawbuffers state in the FBO. We remove the different bind/unbind functions. These make little sense now that we have separate contexts. - DRWFrameBuffer: We replace DRW_framebuffer functions by GPU_framebuffer ones to avoid another layer of abstraction. We move the DRW convenience functions to GPUFramebuffer instead and even add new ones. The MACRO GPU_framebuffer_ensure_config is pretty much all you need to create and config a GPUFramebuffer. - DRWTexture: Due to the removal of DRWFrameBuffer, we needed to create functions to create textures for thoses framebuffers. Pool textures are now using default texture parameters for the texture type asked. - DRWManager: Make sure no framebuffer object is bound when doing cache filling. - GPUViewport: Add new color_only_fb and depth_only_fb along with FB API usage update. This let draw engines render to color/depth only target and without the need to attach/detach textures. - WM_window: Assert when a framebuffer is bound when changing context. This balance the fact we are not track ogl context inside GPUFramebuffer. - Eevee, Clay, Mode engines: Update to new API. This comes with a lot of code simplification. This also come with some cleanups in some engine codes.
2018-03-25 17:46:48 +02:00
/* ---------- Framebuffer Operations ----------- */
#define CHECK_FRAMEBUFFER_IS_BOUND(_fb) \
BLI_assert(GPU_framebuffer_bound(_fb)); \
2019-04-20 11:28:21 +02:00
UNUSED_VARS_NDEBUG(_fb); \
((void)0)
/* Needs to be done after binding. */
void GPU_framebuffer_viewport_set(GPUFrameBuffer *gpu_fb, int x, int y, int w, int h)
{
CHECK_FRAMEBUFFER_IS_BOUND(gpu_fb);
GPU_viewport(x, y, w, h);
}
void GPU_framebuffer_clear(GPUFrameBuffer *gpu_fb,
eGPUFrameBufferBits buffers,
const float clear_col[4],
float clear_depth,
uint clear_stencil)
{
CHECK_FRAMEBUFFER_IS_BOUND(gpu_fb);
/* 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);
}
GPU_context_active_get()->state_manager->apply_state();
GLbitfield mask = convert_buffer_bits_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);
}
}
/* Clear all textures bound to this framebuffer with a different color. */
void GPU_framebuffer_multi_clear(GPUFrameBuffer *gpu_fb, const float (*clear_cols)[4])
{
CHECK_FRAMEBUFFER_IS_BOUND(gpu_fb);
FrameBuffer *fb = reinterpret_cast<FrameBuffer *>(gpu_fb);
/* Save and restore the state. */
eGPUWriteMask write_mask = GPU_write_mask_get();
GPU_color_mask(true, true, true, true);
2020-07-25 18:40:19 +02:00
int i_type = GPU_FB_COLOR_ATTACHMENT0;
for (int i = 0; i_type < GPU_FB_MAX_ATTACHEMENT; i++, i_type++) {
GPUAttachmentType type = static_cast<GPUAttachmentType>(i_type);
if (fb->attachments[type].tex != NULL) {
glClearBufferfv(GL_COLOR, i, clear_cols[i]);
}
}
GPU_write_mask(write_mask);
}
void GPU_framebuffer_read_depth(GPUFrameBuffer *gpu_fb, int x, int y, int w, int h, float *data)
GPUFramebuffer: Refactor (Part 2) This refactor modernise the use of framebuffers. It also touches a lot of files so breaking down changes we have: - GPUTexture: Allow textures to be attached to more than one GPUFrameBuffer. This allows to create and configure more FBO without the need to attach and detach texture at drawing time. - GPUFrameBuffer: The wrapper starts to mimic opengl a bit closer. This allows to configure the framebuffer inside a context other than the one that will be rendering the framebuffer. We do the actual configuration when binding the FBO. We also Keep track of config validity and save drawbuffers state in the FBO. We remove the different bind/unbind functions. These make little sense now that we have separate contexts. - DRWFrameBuffer: We replace DRW_framebuffer functions by GPU_framebuffer ones to avoid another layer of abstraction. We move the DRW convenience functions to GPUFramebuffer instead and even add new ones. The MACRO GPU_framebuffer_ensure_config is pretty much all you need to create and config a GPUFramebuffer. - DRWTexture: Due to the removal of DRWFrameBuffer, we needed to create functions to create textures for thoses framebuffers. Pool textures are now using default texture parameters for the texture type asked. - DRWManager: Make sure no framebuffer object is bound when doing cache filling. - GPUViewport: Add new color_only_fb and depth_only_fb along with FB API usage update. This let draw engines render to color/depth only target and without the need to attach/detach textures. - WM_window: Assert when a framebuffer is bound when changing context. This balance the fact we are not track ogl context inside GPUFramebuffer. - Eevee, Clay, Mode engines: Update to new API. This comes with a lot of code simplification. This also come with some cleanups in some engine codes.
2018-03-25 17:46:48 +02:00
{
CHECK_FRAMEBUFFER_IS_BOUND(gpu_fb);
GPUFramebuffer: Refactor (Part 2) This refactor modernise the use of framebuffers. It also touches a lot of files so breaking down changes we have: - GPUTexture: Allow textures to be attached to more than one GPUFrameBuffer. This allows to create and configure more FBO without the need to attach and detach texture at drawing time. - GPUFrameBuffer: The wrapper starts to mimic opengl a bit closer. This allows to configure the framebuffer inside a context other than the one that will be rendering the framebuffer. We do the actual configuration when binding the FBO. We also Keep track of config validity and save drawbuffers state in the FBO. We remove the different bind/unbind functions. These make little sense now that we have separate contexts. - DRWFrameBuffer: We replace DRW_framebuffer functions by GPU_framebuffer ones to avoid another layer of abstraction. We move the DRW convenience functions to GPUFramebuffer instead and even add new ones. The MACRO GPU_framebuffer_ensure_config is pretty much all you need to create and config a GPUFramebuffer. - DRWTexture: Due to the removal of DRWFrameBuffer, we needed to create functions to create textures for thoses framebuffers. Pool textures are now using default texture parameters for the texture type asked. - DRWManager: Make sure no framebuffer object is bound when doing cache filling. - GPUViewport: Add new color_only_fb and depth_only_fb along with FB API usage update. This let draw engines render to color/depth only target and without the need to attach/detach textures. - WM_window: Assert when a framebuffer is bound when changing context. This balance the fact we are not track ogl context inside GPUFramebuffer. - Eevee, Clay, Mode engines: Update to new API. This comes with a lot of code simplification. This also come with some cleanups in some engine codes.
2018-03-25 17:46:48 +02:00
GLenum type = GL_DEPTH_COMPONENT;
glReadBuffer(GL_COLOR_ATTACHMENT0); /* This is OK! */
glReadPixels(x, y, w, h, type, GL_FLOAT, data);
GPUFramebuffer: Refactor (Part 2) This refactor modernise the use of framebuffers. It also touches a lot of files so breaking down changes we have: - GPUTexture: Allow textures to be attached to more than one GPUFrameBuffer. This allows to create and configure more FBO without the need to attach and detach texture at drawing time. - GPUFrameBuffer: The wrapper starts to mimic opengl a bit closer. This allows to configure the framebuffer inside a context other than the one that will be rendering the framebuffer. We do the actual configuration when binding the FBO. We also Keep track of config validity and save drawbuffers state in the FBO. We remove the different bind/unbind functions. These make little sense now that we have separate contexts. - DRWFrameBuffer: We replace DRW_framebuffer functions by GPU_framebuffer ones to avoid another layer of abstraction. We move the DRW convenience functions to GPUFramebuffer instead and even add new ones. The MACRO GPU_framebuffer_ensure_config is pretty much all you need to create and config a GPUFramebuffer. - DRWTexture: Due to the removal of DRWFrameBuffer, we needed to create functions to create textures for thoses framebuffers. Pool textures are now using default texture parameters for the texture type asked. - DRWManager: Make sure no framebuffer object is bound when doing cache filling. - GPUViewport: Add new color_only_fb and depth_only_fb along with FB API usage update. This let draw engines render to color/depth only target and without the need to attach/detach textures. - WM_window: Assert when a framebuffer is bound when changing context. This balance the fact we are not track ogl context inside GPUFramebuffer. - Eevee, Clay, Mode engines: Update to new API. This comes with a lot of code simplification. This also come with some cleanups in some engine codes.
2018-03-25 17:46:48 +02:00
}
static GLenum gpu_get_gl_datatype(eGPUDataFormat format)
{
switch (format) {
case GPU_DATA_FLOAT:
return GL_FLOAT;
case GPU_DATA_INT:
return GL_INT;
case GPU_DATA_UNSIGNED_INT:
return GL_UNSIGNED_INT;
case GPU_DATA_UNSIGNED_BYTE:
return GL_UNSIGNED_BYTE;
case GPU_DATA_UNSIGNED_INT_24_8:
return GL_UNSIGNED_INT_24_8;
case GPU_DATA_10_11_11_REV:
return GL_UNSIGNED_INT_10F_11F_11F_REV;
default:
BLI_assert(!"Unhandled data format");
return GL_FLOAT;
}
}
static GLenum gpu_get_gl_channel_type(int channels)
{
switch (channels) {
case 1:
return GL_RED;
case 2:
return GL_RG;
case 3:
return GL_RGB;
case 4:
return GL_RGBA;
default:
BLI_assert(!"Wrong number of read channels");
return GL_RED;
}
}
static void gpu_framebuffer_read_color_ex(
int x, int y, int w, int h, int channels, GLenum readfb, eGPUDataFormat format, float *data)
{
GLenum type = gpu_get_gl_channel_type(channels);
GLenum gl_format = gpu_get_gl_datatype(format);
/* TODO: needed for selection buffers to work properly, this should be handled better. */
if (type == GL_RED && gl_format == GL_UNSIGNED_INT) {
type = GL_RED_INTEGER;
}
glReadBuffer(readfb);
glReadPixels(x, y, w, h, type, gl_format, data);
}
void GPU_framebuffer_read_color(GPUFrameBuffer *gpu_fb,
int x,
int y,
int w,
int h,
int channels,
int slot,
eGPUDataFormat format,
void *data)
{
CHECK_FRAMEBUFFER_IS_BOUND(gpu_fb);
2020-07-25 18:40:19 +02:00
gpu_framebuffer_read_color_ex(
x, y, w, h, channels, GL_COLOR_ATTACHMENT0 + slot, format, (float *)data);
GPUFramebuffer: Refactor (Part 2) This refactor modernise the use of framebuffers. It also touches a lot of files so breaking down changes we have: - GPUTexture: Allow textures to be attached to more than one GPUFrameBuffer. This allows to create and configure more FBO without the need to attach and detach texture at drawing time. - GPUFrameBuffer: The wrapper starts to mimic opengl a bit closer. This allows to configure the framebuffer inside a context other than the one that will be rendering the framebuffer. We do the actual configuration when binding the FBO. We also Keep track of config validity and save drawbuffers state in the FBO. We remove the different bind/unbind functions. These make little sense now that we have separate contexts. - DRWFrameBuffer: We replace DRW_framebuffer functions by GPU_framebuffer ones to avoid another layer of abstraction. We move the DRW convenience functions to GPUFramebuffer instead and even add new ones. The MACRO GPU_framebuffer_ensure_config is pretty much all you need to create and config a GPUFramebuffer. - DRWTexture: Due to the removal of DRWFrameBuffer, we needed to create functions to create textures for thoses framebuffers. Pool textures are now using default texture parameters for the texture type asked. - DRWManager: Make sure no framebuffer object is bound when doing cache filling. - GPUViewport: Add new color_only_fb and depth_only_fb along with FB API usage update. This let draw engines render to color/depth only target and without the need to attach/detach textures. - WM_window: Assert when a framebuffer is bound when changing context. This balance the fact we are not track ogl context inside GPUFramebuffer. - Eevee, Clay, Mode engines: Update to new API. This comes with a lot of code simplification. This also come with some cleanups in some engine codes.
2018-03-25 17:46:48 +02:00
}
/* read_slot and write_slot are only used for color buffers. */
void GPU_framebuffer_blit(GPUFrameBuffer *gpufb_read,
int read_slot,
GPUFrameBuffer *gpufb_write,
int write_slot,
eGPUFrameBufferBits blit_buffers)
{
FrameBuffer *fb_read = reinterpret_cast<FrameBuffer *>(gpufb_read);
FrameBuffer *fb_write = reinterpret_cast<FrameBuffer *>(gpufb_write);
BLI_assert(blit_buffers != 0);
FrameBuffer *prev_fb = GPU_context_active_get()->active_fb;
/* Framebuffers must be up to date. This simplify this function. */
if (fb_read->dirty_flag != 0 || fb_read->object == 0) {
GPU_framebuffer_bind(gpufb_read);
}
if (fb_write->dirty_flag != 0 || fb_write->object == 0) {
GPU_framebuffer_bind(gpufb_write);
}
const bool do_color = (blit_buffers & GPU_COLOR_BIT);
const bool do_depth = (blit_buffers & GPU_DEPTH_BIT);
const bool do_stencil = (blit_buffers & GPU_STENCIL_BIT);
GPUTexture *read_tex = ((do_depth || do_stencil) ? fb_read->depth_tex() :
fb_read->color_tex(read_slot));
GPUTexture *write_tex = ((do_depth || do_stencil) ? fb_write->depth_tex() :
fb_write->color_tex(read_slot));
if (do_depth) {
BLI_assert(GPU_texture_depth(read_tex) && GPU_texture_depth(write_tex));
BLI_assert(GPU_texture_format(read_tex) == GPU_texture_format(write_tex));
}
if (do_stencil) {
BLI_assert(GPU_texture_stencil(read_tex) && GPU_texture_stencil(write_tex));
BLI_assert(GPU_texture_format(read_tex) == GPU_texture_format(write_tex));
}
if (GPU_texture_samples(write_tex) != 0 || GPU_texture_samples(read_tex) != 0) {
/* Can only blit multisample textures to another texture of the same size. */
BLI_assert((fb_read->width == fb_write->width) && (fb_read->height == fb_write->height));
}
glBindFramebuffer(GL_READ_FRAMEBUFFER, fb_read->object);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb_write->object);
if (do_color) {
glReadBuffer(GL_COLOR_ATTACHMENT0 + read_slot);
glDrawBuffer(GL_COLOR_ATTACHMENT0 + write_slot);
/* XXX we messed with the glDrawBuffer, this will reset the
* glDrawBuffers the next time we bind fb_write. */
fb_write->dirty_flag = GPU_FB_DIRTY_DRAWBUFFER;
}
GLbitfield mask = convert_buffer_bits_to_gl(blit_buffers);
GPU_context_active_get()->state_manager->apply_state();
glBlitFramebuffer(0,
0,
fb_read->width,
fb_read->height,
0,
0,
fb_write->width,
fb_write->height,
mask,
GL_NEAREST);
/* Restore previous framebuffer */
if (fb_write == prev_fb) {
GPU_framebuffer_bind(gpufb_write); /* To update drawbuffers */
}
else if (prev_fb) {
glBindFramebuffer(GL_FRAMEBUFFER, prev_fb->object);
GPU_context_active_get()->active_fb = prev_fb;
}
else {
glBindFramebuffer(GL_FRAMEBUFFER, GPU_framebuffer_default());
GPU_context_active_get()->active_fb = NULL;
}
}
/**
* Use this if you need to custom down-sample your texture and use the previous mip level as
* input. This function only takes care of the correct texture handling. It execute the callback
* for each texture level.
2019-03-19 15:17:46 +11:00
*/
void GPU_framebuffer_recursive_downsample(GPUFrameBuffer *gpu_fb,
int max_lvl,
void (*callback)(void *userData, int level),
void *userData)
{
GPUContext *ctx = GPU_context_active_get();
FrameBuffer *fb = reinterpret_cast<FrameBuffer *>(gpu_fb);
/* Framebuffer must be up to date and bound. This simplify this function. */
if (ctx->active_fb != fb || fb->dirty_flag != 0 || fb->object == 0) {
GPU_framebuffer_bind(gpu_fb);
}
/* HACK: We make the framebuffer appear not bound in order to
* not trigger any error in GPU_texture_bind(). */
FrameBuffer *prev_fb = ctx->active_fb;
ctx->active_fb = NULL;
int levels = floor(log2(max_ii(fb->width, fb->height)));
max_lvl = min_ii(max_lvl, levels);
int i;
int current_dim[2] = {fb->width, fb->height};
for (i = 1; i < max_lvl + 1; i++) {
/* calculate next viewport size */
current_dim[0] = max_ii(current_dim[0] / 2, 1);
current_dim[1] = max_ii(current_dim[1] / 2, 1);
2020-07-25 18:40:19 +02:00
for (int i_type = 0; i_type < GPU_FB_MAX_ATTACHEMENT; i_type++) {
GPUAttachmentType type = static_cast<GPUAttachmentType>(i_type);
if (fb->attachments[type].tex != NULL) {
/* Some Intel HDXXX have issue with rendering to a mipmap that is below
* the texture GL_TEXTURE_MAX_LEVEL. So even if it not correct, in this case
* we allow GL_TEXTURE_MAX_LEVEL to be one level lower. In practice it does work! */
int next_lvl = (GPU_mip_render_workaround()) ? i : i - 1;
/* bind next level for rendering but first restrict fetches only to previous level */
GPUTexture *tex = fb->attachments[type].tex;
GPU_texture_bind(tex, 0);
glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_BASE_LEVEL, i - 1);
glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_MAX_LEVEL, next_lvl);
GPU_texture_unbind(tex);
/* copy attachment and replace miplevel. */
GPUAttachment attachment = fb->attachments[type];
attachment.mip = i;
gpu_framebuffer_attachment_attach(&attachment, type);
}
}
BLI_assert(GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_FRAMEBUFFER));
GPU_viewport(0, 0, current_dim[0], current_dim[1]);
callback(userData, i);
2019-04-22 09:32:37 +10:00
if (current_dim[0] == 1 && current_dim[1] == 1) {
break;
2019-04-22 09:32:37 +10:00
}
}
2020-07-25 18:40:19 +02:00
for (int i_type = 0; i_type < GPU_FB_MAX_ATTACHEMENT; i_type++) {
GPUAttachmentType type = static_cast<GPUAttachmentType>(i_type);
if (fb->attachments[type].tex != NULL) {
/* reset mipmap level range */
GPUTexture *tex = fb->attachments[type].tex;
GPU_texture_bind(tex, 0);
glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_MAX_LEVEL, i - 1);
GPU_texture_unbind(tex);
/* Reattach original level */
/* NOTE: This is not necessary but this makes the FBO config
* remain in sync with the GPUFrameBuffer config. */
gpu_framebuffer_attachment_attach(&fb->attachments[type], type);
}
}
ctx->active_fb = prev_fb;
}
/* GPUOffScreen */
#define MAX_CTX_FB_LEN 3
struct GPUOffScreen {
struct {
GPUContext *ctx;
GPUFrameBuffer *fb;
} framebuffers[MAX_CTX_FB_LEN];
GPUTexture *color;
GPUTexture *depth;
/** Saved state of the previously bound framebuffer. */
/* TODO(fclem) This is quite hacky and a proper fix would be to
* put these states directly inside the GPUFrambuffer.
* But we don't have a GPUFramebuffer for the default framebuffer yet. */
int saved_viewport[4];
int saved_scissor[4];
};
/* Returns the correct framebuffer for the current context. */
static GPUFrameBuffer *gpu_offscreen_fb_get(GPUOffScreen *ofs)
{
GPUContext *ctx = GPU_context_active_get();
BLI_assert(ctx);
for (int i = 0; i < MAX_CTX_FB_LEN; i++) {
if (ofs->framebuffers[i].fb == NULL) {
ofs->framebuffers[i].ctx = ctx;
2020-07-25 18:40:19 +02:00
GPU_framebuffer_ensure_config(&ofs->framebuffers[i].fb,
{
GPU_ATTACHMENT_TEXTURE(ofs->depth),
GPU_ATTACHMENT_TEXTURE(ofs->color),
});
}
if (ofs->framebuffers[i].ctx == ctx) {
return ofs->framebuffers[i].fb;
}
}
/* List is full, this should never happen or
* it might just slow things down if it happens
2019-07-07 15:38:41 +10:00
* regularly. In this case we just empty the list
* and start over. This is most likely never going
* to happen under normal usage. */
BLI_assert(0);
printf(
"Warning: GPUOffscreen used in more than 3 GPUContext. "
"This may create performance drop.\n");
for (int i = 0; i < MAX_CTX_FB_LEN; i++) {
GPU_framebuffer_free(ofs->framebuffers[i].fb);
ofs->framebuffers[i].fb = NULL;
}
return gpu_offscreen_fb_get(ofs);
}
GPUOffScreen *GPU_offscreen_create(
int width, int height, bool depth, bool high_bitdepth, char err_out[256])
{
2020-07-25 18:40:19 +02:00
GPUOffScreen *ofs = (GPUOffScreen *)MEM_callocN(sizeof(GPUOffScreen), __func__);
/* Sometimes areas can have 0 height or width and this will
* create a 1D texture which we don't want. */
height = max_ii(1, height);
width = max_ii(1, width);
ofs->color = GPU_texture_create_2d(
width, height, (high_bitdepth) ? GPU_RGBA16F : GPU_RGBA8, NULL, err_out);
if (depth) {
ofs->depth = GPU_texture_create_2d(width, height, GPU_DEPTH24_STENCIL8, NULL, err_out);
}
if ((depth && !ofs->depth) || !ofs->color) {
GPU_offscreen_free(ofs);
return NULL;
}
int viewport[4];
GPU_viewport_size_get_i(viewport);
GPUFrameBuffer *fb = gpu_offscreen_fb_get(ofs);
GPUFramebuffer: Refactor (Part 2) This refactor modernise the use of framebuffers. It also touches a lot of files so breaking down changes we have: - GPUTexture: Allow textures to be attached to more than one GPUFrameBuffer. This allows to create and configure more FBO without the need to attach and detach texture at drawing time. - GPUFrameBuffer: The wrapper starts to mimic opengl a bit closer. This allows to configure the framebuffer inside a context other than the one that will be rendering the framebuffer. We do the actual configuration when binding the FBO. We also Keep track of config validity and save drawbuffers state in the FBO. We remove the different bind/unbind functions. These make little sense now that we have separate contexts. - DRWFrameBuffer: We replace DRW_framebuffer functions by GPU_framebuffer ones to avoid another layer of abstraction. We move the DRW convenience functions to GPUFramebuffer instead and even add new ones. The MACRO GPU_framebuffer_ensure_config is pretty much all you need to create and config a GPUFramebuffer. - DRWTexture: Due to the removal of DRWFrameBuffer, we needed to create functions to create textures for thoses framebuffers. Pool textures are now using default texture parameters for the texture type asked. - DRWManager: Make sure no framebuffer object is bound when doing cache filling. - GPUViewport: Add new color_only_fb and depth_only_fb along with FB API usage update. This let draw engines render to color/depth only target and without the need to attach/detach textures. - WM_window: Assert when a framebuffer is bound when changing context. This balance the fact we are not track ogl context inside GPUFramebuffer. - Eevee, Clay, Mode engines: Update to new API. This comes with a lot of code simplification. This also come with some cleanups in some engine codes.
2018-03-25 17:46:48 +02:00
/* check validity at the very end! */
if (!GPU_framebuffer_check_valid(fb, err_out)) {
GPU_offscreen_free(ofs);
GPU_viewport(UNPACK4(viewport));
return NULL;
}
GPU_framebuffer_restore();
GPU_viewport(UNPACK4(viewport));
return ofs;
}
void GPU_offscreen_free(GPUOffScreen *ofs)
{
for (int i = 0; i < MAX_CTX_FB_LEN; i++) {
if (ofs->framebuffers[i].fb) {
GPU_framebuffer_free(ofs->framebuffers[i].fb);
}
2019-04-22 09:32:37 +10:00
}
if (ofs->color) {
GPU_texture_free(ofs->color);
2019-04-22 09:32:37 +10:00
}
if (ofs->depth) {
GPU_texture_free(ofs->depth);
2019-04-22 09:32:37 +10:00
}
MEM_freeN(ofs);
}
void GPU_offscreen_bind(GPUOffScreen *ofs, bool save)
{
if (save) {
GPU_scissor_get(ofs->saved_scissor);
GPU_viewport_size_get_i(ofs->saved_viewport);
GPUFrameBuffer *fb = GPU_framebuffer_active_get();
gpuPushFrameBuffer(reinterpret_cast<GPUFrameBuffer *>(fb));
}
GPUFrameBuffer *ofs_fb = gpu_offscreen_fb_get(ofs);
GPU_framebuffer_bind(ofs_fb);
glDisable(GL_FRAMEBUFFER_SRGB);
2020-07-17 19:21:33 +02:00
GPU_scissor_test(false);
GPU_shader_set_framebuffer_srgb_target(false);
}
void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore)
{
GPUFrameBuffer *fb = NULL;
if (restore) {
GPU_scissor(UNPACK4(ofs->saved_scissor));
GPU_viewport(UNPACK4(ofs->saved_viewport));
fb = gpuPopFrameBuffer();
}
if (fb) {
GPU_framebuffer_bind(fb);
}
else {
GPU_framebuffer_restore();
}
}
void GPU_offscreen_draw_to_screen(GPUOffScreen *ofs, int x, int y)
{
const int w = GPU_texture_width(ofs->color);
const int h = GPU_texture_height(ofs->color);
GPU_context_active_get()->state_manager->apply_state();
FrameBuffer *ofs_fb = reinterpret_cast<FrameBuffer *>(gpu_offscreen_fb_get(ofs));
glBindFramebuffer(GL_READ_FRAMEBUFFER, ofs_fb->object);
GLenum status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER);
if (status == GL_FRAMEBUFFER_COMPLETE) {
glBlitFramebuffer(0, 0, w, h, x, y, x + w, y + h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
}
else {
gpu_print_framebuffer_error(status, NULL);
}
glBindFramebuffer(GL_READ_FRAMEBUFFER, GPU_framebuffer_default());
}
void GPU_offscreen_read_pixels(GPUOffScreen *ofs, eGPUDataFormat type, void *pixels)
{
const int w = GPU_texture_width(ofs->color);
const int h = GPU_texture_height(ofs->color);
BLI_assert(ELEM(type, GPU_DATA_UNSIGNED_BYTE, GPU_DATA_FLOAT));
GLenum gl_type = (type == GPU_DATA_FLOAT) ? GL_FLOAT : GL_UNSIGNED_BYTE;
glReadPixels(0, 0, w, h, GL_RGBA, gl_type, pixels);
}
int GPU_offscreen_width(const GPUOffScreen *ofs)
{
return GPU_texture_width(ofs->color);
}
int GPU_offscreen_height(const GPUOffScreen *ofs)
{
return GPU_texture_height(ofs->color);
}
GPUTexture *GPU_offscreen_color_texture(const GPUOffScreen *ofs)
{
return ofs->color;
}
/* only to be used by viewport code! */
void GPU_offscreen_viewport_data_get(GPUOffScreen *ofs,
GPUFrameBuffer **r_fb,
GPUTexture **r_color,
GPUTexture **r_depth)
{
*r_fb = gpu_offscreen_fb_get(ofs);
*r_color = ofs->color;
*r_depth = ofs->depth;
}
void GPU_clear_color(float red, float green, float blue, float alpha)
{
BLI_assert((GPU_write_mask_get() & GPU_WRITE_COLOR) != 0);
GPU_context_active_get()->state_manager->apply_state();
glClearColor(red, green, blue, alpha);
glClear(GL_COLOR_BUFFER_BIT);
}
void GPU_clear_depth(float depth)
{
BLI_assert((GPU_write_mask_get() & GPU_WRITE_DEPTH) != 0);
GPU_context_active_get()->state_manager->apply_state();
glClearDepth(depth);
glClear(GL_DEPTH_BUFFER_BIT);
}
void GPU_frontbuffer_read_pixels(
int x, int y, int w, int h, int channels, eGPUDataFormat format, void *data)
{
2020-07-25 18:40:19 +02:00
gpu_framebuffer_read_color_ex(x, y, w, h, channels, GL_FRONT, format, (float *)data);
}
/* For stereo rendering. */
void GPU_backbuffer_bind(eGPUBackBuffer buffer)
{
if (buffer == GPU_BACKBUFFER) {
glDrawBuffer(GL_BACK);
}
else if (buffer == GPU_BACKBUFFER_LEFT) {
glDrawBuffer(GL_BACK_LEFT);
}
else if (buffer == GPU_BACKBUFFER_RIGHT) {
glDrawBuffer(GL_BACK_RIGHT);
}
}