Fix T61768 Eevee Offscreen rendering

The issue was caused by a bad usage of GPUOffscreen.

The Framebuffer was created using a window framebuffer and used
in a viewport callback when another GPUContext was bound.

This change allows up to 3 framebuffers per GPUOffscreen.

Most common case will be using 2 framebuffers (one for init and
one for drawing) but in the case of more (bad usage) it will just
degrade performance a bit.
This commit is contained in:
Clément Foucault 2019-06-13 21:31:46 +02:00
parent 1688a57a8e
commit 5e626e7664

@ -801,12 +801,55 @@ void GPU_framebuffer_recursive_downsample(GPUFrameBuffer *fb,
/* GPUOffScreen */
#define MAX_CTX_FB_LEN 3
struct GPUOffScreen {
GPUFrameBuffer *fb;
struct {
GPUContext *ctx;
GPUFrameBuffer *fb;
} framebuffers[MAX_CTX_FB_LEN];
GPUTexture *color;
GPUTexture *depth;
};
/* 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;
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
* regulary. 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, int samples, bool depth, bool high_bitdepth, char err_out[256])
{
@ -834,11 +877,10 @@ GPUOffScreen *GPU_offscreen_create(
gpuPushAttr(GPU_VIEWPORT_BIT);
GPU_framebuffer_ensure_config(
&ofs->fb, {GPU_ATTACHMENT_TEXTURE(ofs->depth), GPU_ATTACHMENT_TEXTURE(ofs->color)});
GPUFrameBuffer *fb = gpu_offscreen_fb_get(ofs);
/* check validity at the very end! */
if (!GPU_framebuffer_check_valid(ofs->fb, err_out)) {
if (!GPU_framebuffer_check_valid(fb, err_out)) {
GPU_offscreen_free(ofs);
gpuPopAttr();
return NULL;
@ -853,8 +895,10 @@ GPUOffScreen *GPU_offscreen_create(
void GPU_offscreen_free(GPUOffScreen *ofs)
{
if (ofs->fb) {
GPU_framebuffer_free(ofs->fb);
for (int i = 0; i < MAX_CTX_FB_LEN; i++) {
if (ofs->framebuffers[i].fb) {
GPU_framebuffer_free(ofs->framebuffers[i].fb);
}
}
if (ofs->color) {
GPU_texture_free(ofs->color);
@ -874,7 +918,8 @@ void GPU_offscreen_bind(GPUOffScreen *ofs, bool save)
gpuPushFrameBuffer(fb);
}
glDisable(GL_SCISSOR_TEST);
GPU_framebuffer_bind(ofs->fb);
GPUFrameBuffer *ofs_fb = gpu_offscreen_fb_get(ofs);
GPU_framebuffer_bind(ofs_fb);
}
void GPU_offscreen_unbind(GPUOffScreen *UNUSED(ofs), bool restore)
@ -899,7 +944,9 @@ 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);
glBindFramebuffer(GL_READ_FRAMEBUFFER, ofs->fb->object);
GPUFrameBuffer *ofs_fb = gpu_offscreen_fb_get(ofs);
glBindFramebuffer(GL_READ_FRAMEBUFFER, ofs_fb->object);
GLenum status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER);
if (status == GL_FRAMEBUFFER_COMPLETE) {
@ -950,7 +997,8 @@ void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels)
glReadPixels(0, 0, w, h, GL_RGBA, type, pixels);
/* restore the original frame-bufer */
glBindFramebuffer(GL_FRAMEBUFFER, ofs->fb->object);
GPUFrameBuffer *ofs_fb = gpu_offscreen_fb_get(ofs);
glBindFramebuffer(GL_FRAMEBUFFER, ofs_fb->object);
finally:
/* cleanup */
@ -983,7 +1031,7 @@ void GPU_offscreen_viewport_data_get(GPUOffScreen *ofs,
GPUTexture **r_color,
GPUTexture **r_depth)
{
*r_fb = ofs->fb;
*r_fb = gpu_offscreen_fb_get(ofs);
*r_color = ofs->color;
*r_depth = ofs->depth;
}