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
This commit is contained in:
Pekka Paalanen 2019-05-06 15:08:29 +03:00 committed by Jonas Ådahl
parent 6df34eb4b7
commit 45289b3d65
3 changed files with 43 additions and 22 deletions

View File

@ -378,7 +378,11 @@ _cogl_push_framebuffers (CoglFramebuffer *draw_buffer,
* This blits a region of the color buffer of the source buffer * This blits a region of the color buffer of the source buffer
* to the destination buffer. This function should only be * to the destination buffer. This function should only be
* called if the COGL_PRIVATE_FEATURE_OFFSCREEN_BLIT feature is * 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, * 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 * unsigned int, signed int, or fixed-point), but color formats do not
@ -393,14 +397,6 @@ _cogl_push_framebuffers (CoglFramebuffer *draw_buffer,
* scale the results it may make more sense to draw a primitive * scale the results it may make more sense to draw a primitive
* instead. * 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 * The GL function is documented to be affected by the scissor. This
* function therefore ensure that an empty clip stack is flushed * function therefore ensure that an empty clip stack is flushed
* before performing the blit which means the scissor is effectively * before performing the blit which means the scissor is effectively

View File

@ -1352,15 +1352,12 @@ _cogl_blit_framebuffer (CoglFramebuffer *src,
int height) int height)
{ {
CoglContext *ctx = src->context; CoglContext *ctx = src->context;
int src_x1, src_y1, src_x2, src_y2;
int dst_x1, dst_y1, dst_x2, dst_y2;
g_return_if_fail (_cogl_has_private_feature g_return_if_fail (_cogl_has_private_feature
(ctx, COGL_PRIVATE_FEATURE_OFFSCREEN_BLIT)); (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 */
g_return_if_fail (cogl_is_offscreen (src));
g_return_if_fail (cogl_is_offscreen (dest));
/* The buffers must use the same premult convention */ /* The buffers must use the same premult convention */
g_return_if_fail ((src->internal_format & COGL_PREMULT_BIT) == g_return_if_fail ((src->internal_format & COGL_PREMULT_BIT) ==
(dest->internal_format & COGL_PREMULT_BIT)); (dest->internal_format & COGL_PREMULT_BIT));
@ -1384,10 +1381,41 @@ _cogl_blit_framebuffer (CoglFramebuffer *src,
* as changed */ * as changed */
ctx->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_CLIP; ctx->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_CLIP;
ctx->glBlitFramebuffer (src_x, src_y, /* Offscreens we do the normal way, onscreens need an y-flip. Even if
src_x + width, src_y + height, * we consider offscreens to be rendered upside-down, the offscreen
dst_x, dst_y, * orientation is in this function's API. */
dst_x + width, dst_y + height, 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_COLOR_BUFFER_BIT,
GL_NEAREST); GL_NEAREST);
} }

View File

@ -385,12 +385,9 @@ _cogl_framebuffer_gl_flush_state (CoglFramebuffer *draw_buffer,
else else
{ {
/* NB: Currently we only take advantage of binding separate /* NB: Currently we only take advantage of binding separate
* read/write buffers for offscreen framebuffer blit * read/write buffers for framebuffer blit purposes. */
* purposes. */
g_return_if_fail (_cogl_has_private_feature g_return_if_fail (_cogl_has_private_feature
(ctx, COGL_PRIVATE_FEATURE_OFFSCREEN_BLIT)); (ctx, COGL_PRIVATE_FEATURE_OFFSCREEN_BLIT));
g_return_if_fail (draw_buffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN);
g_return_if_fail (read_buffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN);
_cogl_framebuffer_gl_bind (draw_buffer, GL_DRAW_FRAMEBUFFER); _cogl_framebuffer_gl_bind (draw_buffer, GL_DRAW_FRAMEBUFFER);
_cogl_framebuffer_gl_bind (read_buffer, GL_READ_FRAMEBUFFER); _cogl_framebuffer_gl_bind (read_buffer, GL_READ_FRAMEBUFFER);