cogl-framebuffer: Add _cogl_blit_framebuffer

This adds the _cogl_blit_framebuffer internal function which is a
wrapper around glBlitFramebuffer. The API is changed from the GL
version of the function to reflect the limitations provided by the
GL_ANGLE_framebuffer_blit extension (eg, no scaling or mirroring).
This commit is contained in:
Neil Roberts 2011-02-05 11:19:52 +00:00
parent 392cfb493a
commit 9d242b62a9
2 changed files with 99 additions and 0 deletions

View File

@ -288,5 +288,58 @@ void
_cogl_push_framebuffers (CoglFramebuffer *draw_buffer, _cogl_push_framebuffers (CoglFramebuffer *draw_buffer,
CoglFramebuffer *read_buffer); CoglFramebuffer *read_buffer);
/*
* _cogl_blit_framebuffer:
* @src_x: Source x position
* @src_y: Source y position
* @dst_x: Destination x position
* @dst_y: Destination y position
* @width: Width of region to copy
* @height: Height of region to copy
*
* This blits a region of the color buffer of the current draw buffer
* to the current read buffer. The draw and read buffers can be set up
* using _cogl_push_framebuffers(). This function should only be
* called if the COGL_FEATURE_OFFSCREEN_BLIT feature is
* advertised. The two buffers must both be offscreen and have the
* same format.
*
* Note that this function differs a lot from the glBlitFramebuffer
* function provided by the GL_EXT_framebuffer_blit extension. Notably
* it doesn't support having different sizes for the source and
* destination rectangle. This isn't supported by the corresponding
* GL_ANGLE_framebuffer_blit extension on GLES2.0 and it doesn't seem
* like a particularly useful feature. If the application wanted to
* 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
* ignored.
*
* The function also doesn't support specifying the buffers to copy
* and instead only the color buffer is copied. When copying the depth
* or stencil buffers the extension on GLES2.0 only supports copying
* the full buffer which would be awkward to document with this
* API. If we wanted to support that feature it may be better to have
* a separate function to copy the entire buffer for a given mask.
*/
void
_cogl_blit_framebuffer (unsigned int src_x,
unsigned int src_y,
unsigned int dst_x,
unsigned int dst_y,
unsigned int width,
unsigned int height);
#endif /* __COGL_FRAMEBUFFER_PRIVATE_H */ #endif /* __COGL_FRAMEBUFFER_PRIVATE_H */

View File

@ -54,6 +54,8 @@
#endif #endif
#define glBlitFramebuffer ctx->drv.pf_glBlitFramebuffer
#ifndef GL_FRAMEBUFFER #ifndef GL_FRAMEBUFFER
#define GL_FRAMEBUFFER 0x8D40 #define GL_FRAMEBUFFER 0x8D40
#endif #endif
@ -1429,3 +1431,47 @@ _cogl_framebuffer_try_fast_read_pixel (CoglFramebuffer *framebuffer,
return FALSE; return FALSE;
} }
void
_cogl_blit_framebuffer (unsigned int src_x,
unsigned int src_y,
unsigned int dst_x,
unsigned int dst_y,
unsigned int width,
unsigned int height)
{
CoglFramebuffer *draw_buffer;
CoglFramebuffer *read_buffer;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
draw_buffer = _cogl_get_draw_buffer ();
read_buffer = _cogl_get_read_buffer ();
g_return_if_fail (cogl_features_available (COGL_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 (draw_buffer));
g_return_if_fail (cogl_is_offscreen (read_buffer));
/* The buffers must be the same format */
g_return_if_fail (draw_buffer->format == read_buffer->format);
/* Make sure the current framebuffers are bound. We explicitly avoid
flushing the clip state so we can bind our own empty state */
_cogl_framebuffer_flush_state (_cogl_get_draw_buffer (),
_cogl_get_read_buffer (),
COGL_FRAMEBUFFER_FLUSH_SKIP_CLIP_STATE);
/* Flush any empty clip stack because glBlitFramebuffer is affected
by the scissor and we want to hide this feature for the Cogl API
because it's not obvious to an app how the clip state will affect
the scissor */
_cogl_clip_stack_flush (NULL);
glBlitFramebuffer (src_x, src_y,
src_x + width, src_y + height,
dst_x, dst_y,
dst_x + width, dst_y + height,
GL_COLOR_BUFFER_BIT,
GL_NEAREST);
}