From e4b2234d9918e9d3357ac3c7ca3898599725d3da Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Mon, 6 May 2019 15:08:29 +0300 Subject: [PATCH 05/12] cogl: Allow glBlitFramebuffer between onscreen/offscreen Depends on "cogl: Replace ANGLE with GLES3 and NV framebuffer_blit" Allow blitting between onscreen and offscreen framebuffers by doing the y-flip as necessary. This was not possible with ANGLE, but now with ANGLE gone, glBlitFramebuffer supports flipping the copied image. This will be useful in follow-up work to copy from onscreen primary GPU framebuffer to an offscreen secondary GPU framebuffer. https://gitlab.gnome.org/GNOME/mutter/merge_requests/615 (cherry picked from commit 45289b3d65e308117f1bc8fe6a4c88c1baaacca7) --- cogl/cogl/cogl-framebuffer-private.h | 14 +++---- cogl/cogl/cogl-framebuffer.c | 46 ++++++++++++++++++----- cogl/cogl/driver/gl/cogl-framebuffer-gl.c | 5 +-- 3 files changed, 43 insertions(+), 22 deletions(-) diff --git a/cogl/cogl/cogl-framebuffer-private.h b/cogl/cogl/cogl-framebuffer-private.h index b06fbaee1..f68153d8b 100644 --- a/cogl/cogl/cogl-framebuffer-private.h +++ b/cogl/cogl/cogl-framebuffer-private.h @@ -381,7 +381,11 @@ _cogl_push_framebuffers (CoglFramebuffer *draw_buffer, * This blits a region of the color buffer of the source buffer * to the destination buffer. This function should only be * called if the COGL_PRIVATE_FEATURE_OFFSCREEN_BLIT feature is - * advertised. The two buffers must both be offscreen. + * advertised. + * + * The source and destination rectangles are defined in offscreen + * framebuffer orientation. When copying between an offscreen and + * onscreen framebuffers, the image is y-flipped accordingly. * * The two buffers must have the same value types (e.g. floating-point, * unsigned int, signed int, or fixed-point), but color formats do not @@ -396,14 +400,6 @@ _cogl_push_framebuffers (CoglFramebuffer *draw_buffer, * scale the results it may make more sense to draw a primitive * instead. * - * We can only really support blitting between two offscreen buffers - * for this function on GLES2.0. This is because we effectively render - * upside down to offscreen buffers to maintain Cogl's representation - * of the texture coordinate system where 0,0 is the top left of the - * texture. If we were to blit from an offscreen to an onscreen buffer - * then we would need to mirror the blit along the x-axis but the GLES - * extension does not support this. - * * The GL function is documented to be affected by the scissor. This * function therefore ensure that an empty clip stack is flushed * before performing the blit which means the scissor is effectively diff --git a/cogl/cogl/cogl-framebuffer.c b/cogl/cogl/cogl-framebuffer.c index 0bc225945..90976a611 100644 --- a/cogl/cogl/cogl-framebuffer.c +++ b/cogl/cogl/cogl-framebuffer.c @@ -1460,15 +1460,12 @@ _cogl_blit_framebuffer (CoglFramebuffer *src, int height) { CoglContext *ctx = src->context; + int src_x1, src_y1, src_x2, src_y2; + int dst_x1, dst_y1, dst_x2, dst_y2; _COGL_RETURN_IF_FAIL (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_OFFSCREEN_BLIT)); - /* We can only support blitting between offscreen buffers because - otherwise we would need to mirror the image and GLES2.0 doesn't - support this */ - _COGL_RETURN_IF_FAIL (cogl_is_offscreen (src)); - _COGL_RETURN_IF_FAIL (cogl_is_offscreen (dest)); /* The buffers must use the same premult convention */ _COGL_RETURN_IF_FAIL ((src->internal_format & COGL_PREMULT_BIT) == (dest->internal_format & COGL_PREMULT_BIT)); @@ -1492,10 +1489,41 @@ _cogl_blit_framebuffer (CoglFramebuffer *src, * as changed */ ctx->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_CLIP; - ctx->glBlitFramebuffer (src_x, src_y, - src_x + width, src_y + height, - dst_x, dst_y, - dst_x + width, dst_y + height, + /* Offscreens we do the normal way, onscreens need an y-flip. Even if + * we consider offscreens to be rendered upside-down, the offscreen + * orientation is in this function's API. */ + if (cogl_is_offscreen (src)) + { + src_x1 = src_x; + src_y1 = src_y; + src_x2 = src_x + width; + src_y2 = src_y + height; + } + else + { + src_x1 = src_x; + src_y1 = cogl_framebuffer_get_height (src) - src_y; + src_x2 = src_x + width; + src_y2 = src_y1 - height; + } + + if (cogl_is_offscreen (dest)) + { + dst_x1 = dst_x; + dst_y1 = dst_y; + dst_x2 = dst_x + width; + dst_y2 = dst_y + height; + } + else + { + dst_x1 = dst_x; + dst_y1 = cogl_framebuffer_get_height (dest) - dst_y; + dst_x2 = dst_x + width; + dst_y2 = dst_y1 - height; + } + + ctx->glBlitFramebuffer (src_x1, src_y1, src_x2, src_y2, + dst_x1, dst_y1, dst_x2, dst_y2, GL_COLOR_BUFFER_BIT, GL_NEAREST); } diff --git a/cogl/cogl/driver/gl/cogl-framebuffer-gl.c b/cogl/cogl/driver/gl/cogl-framebuffer-gl.c index 5402a7075..83e1d263a 100644 --- a/cogl/cogl/driver/gl/cogl-framebuffer-gl.c +++ b/cogl/cogl/driver/gl/cogl-framebuffer-gl.c @@ -400,12 +400,9 @@ _cogl_framebuffer_gl_flush_state (CoglFramebuffer *draw_buffer, else { /* NB: Currently we only take advantage of binding separate - * read/write buffers for offscreen framebuffer blit - * purposes. */ + * read/write buffers for framebuffer blit purposes. */ _COGL_RETURN_IF_FAIL (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_OFFSCREEN_BLIT)); - _COGL_RETURN_IF_FAIL (draw_buffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN); - _COGL_RETURN_IF_FAIL (read_buffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN); _cogl_framebuffer_gl_bind (draw_buffer, GL_DRAW_FRAMEBUFFER); _cogl_framebuffer_gl_bind (read_buffer, GL_READ_FRAMEBUFFER); -- 2.21.0