Add a public cogl_framebuffer_read_pixels_into_bitmap
This adds a public function to read pixels from a framebuffer into a CoglBitmap. This replaces the internal function _cogl_read_pixels_with_rowstride because a CoglBitmap contains a rowstride so it can be used for the same purpose. A CoglBitmap already has public API to make one that points to a CoglPixelBuffer so this function can be used to read pixels into a PBO. It also avoids the need to push the framebuffer on to the context's stack so it provides a function which can be used in the 2.0 API after the stack is removed. Reviewed-by: Robert Bragg <robert@linux.intel.com>
This commit is contained in:
parent
2501899044
commit
10a38bb14f
@ -244,14 +244,6 @@ _cogl_framebuffer_flush_journal (CoglFramebuffer *framebuffer);
|
|||||||
void
|
void
|
||||||
_cogl_framebuffer_flush_dependency_journals (CoglFramebuffer *framebuffer);
|
_cogl_framebuffer_flush_dependency_journals (CoglFramebuffer *framebuffer);
|
||||||
|
|
||||||
gboolean
|
|
||||||
_cogl_framebuffer_try_fast_read_pixel (CoglFramebuffer *framebuffer,
|
|
||||||
int x,
|
|
||||||
int y,
|
|
||||||
CoglReadPixelsFlags source,
|
|
||||||
CoglPixelFormat format,
|
|
||||||
guint8 *pixel);
|
|
||||||
|
|
||||||
void
|
void
|
||||||
_cogl_framebuffer_flush_state (CoglFramebuffer *draw_buffer,
|
_cogl_framebuffer_flush_state (CoglFramebuffer *draw_buffer,
|
||||||
CoglFramebuffer *read_buffer,
|
CoglFramebuffer *read_buffer,
|
||||||
|
@ -25,6 +25,8 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "cogl-debug.h"
|
#include "cogl-debug.h"
|
||||||
#include "cogl-internal.h"
|
#include "cogl-internal.h"
|
||||||
#include "cogl-context-private.h"
|
#include "cogl-context-private.h"
|
||||||
@ -43,6 +45,7 @@
|
|||||||
#include "cogl-primitive-private.h"
|
#include "cogl-primitive-private.h"
|
||||||
#include "cogl-offscreen.h"
|
#include "cogl-offscreen.h"
|
||||||
#include "cogl1-context.h"
|
#include "cogl1-context.h"
|
||||||
|
#include "cogl-private.h"
|
||||||
|
|
||||||
#ifndef GL_FRAMEBUFFER
|
#ifndef GL_FRAMEBUFFER
|
||||||
#define GL_FRAMEBUFFER 0x8D40
|
#define GL_FRAMEBUFFER 0x8D40
|
||||||
@ -1860,15 +1863,15 @@ cogl_framebuffer_get_context (CoglFramebuffer *framebuffer)
|
|||||||
return framebuffer->context;
|
return framebuffer->context;
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
static gboolean
|
||||||
_cogl_framebuffer_try_fast_read_pixel (CoglFramebuffer *framebuffer,
|
_cogl_framebuffer_try_fast_read_pixel (CoglFramebuffer *framebuffer,
|
||||||
int x,
|
int x,
|
||||||
int y,
|
int y,
|
||||||
CoglReadPixelsFlags source,
|
CoglReadPixelsFlags source,
|
||||||
CoglPixelFormat format,
|
CoglBitmap *bitmap)
|
||||||
guint8 *pixel)
|
|
||||||
{
|
{
|
||||||
gboolean found_intersection;
|
gboolean found_intersection;
|
||||||
|
CoglPixelFormat format;
|
||||||
|
|
||||||
if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_FAST_READ_PIXEL)))
|
if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_FAST_READ_PIXEL)))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -1876,12 +1879,14 @@ _cogl_framebuffer_try_fast_read_pixel (CoglFramebuffer *framebuffer,
|
|||||||
if (source != COGL_READ_PIXELS_COLOR_BUFFER)
|
if (source != COGL_READ_PIXELS_COLOR_BUFFER)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
format = _cogl_bitmap_get_format (bitmap);
|
||||||
|
|
||||||
if (format != COGL_PIXEL_FORMAT_RGBA_8888_PRE &&
|
if (format != COGL_PIXEL_FORMAT_RGBA_8888_PRE &&
|
||||||
format != COGL_PIXEL_FORMAT_RGBA_8888)
|
format != COGL_PIXEL_FORMAT_RGBA_8888)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (!_cogl_journal_try_read_pixel (framebuffer->journal,
|
if (!_cogl_journal_try_read_pixel (framebuffer->journal,
|
||||||
x, y, format, pixel,
|
x, y, bitmap,
|
||||||
&found_intersection))
|
&found_intersection))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
@ -1906,23 +1911,268 @@ _cogl_framebuffer_try_fast_read_pixel (CoglFramebuffer *framebuffer,
|
|||||||
y >= framebuffer->clear_clip_y0 &&
|
y >= framebuffer->clear_clip_y0 &&
|
||||||
y < framebuffer->clear_clip_y1)
|
y < framebuffer->clear_clip_y1)
|
||||||
{
|
{
|
||||||
|
guint8 *pixel;
|
||||||
|
|
||||||
/* we currently only care about cases where the premultiplied or
|
/* we currently only care about cases where the premultiplied or
|
||||||
* unpremultipled colors are equivalent... */
|
* unpremultipled colors are equivalent... */
|
||||||
if (framebuffer->clear_color_alpha != 1.0)
|
if (framebuffer->clear_color_alpha != 1.0)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
pixel = _cogl_bitmap_map (bitmap,
|
||||||
|
COGL_BUFFER_ACCESS_WRITE,
|
||||||
|
COGL_BUFFER_MAP_HINT_DISCARD);
|
||||||
|
if (pixel == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
pixel[0] = framebuffer->clear_color_red * 255.0;
|
pixel[0] = framebuffer->clear_color_red * 255.0;
|
||||||
pixel[1] = framebuffer->clear_color_green * 255.0;
|
pixel[1] = framebuffer->clear_color_green * 255.0;
|
||||||
pixel[2] = framebuffer->clear_color_blue * 255.0;
|
pixel[2] = framebuffer->clear_color_blue * 255.0;
|
||||||
pixel[3] = framebuffer->clear_color_alpha * 255.0;
|
pixel[3] = framebuffer->clear_color_alpha * 255.0;
|
||||||
|
|
||||||
|
_cogl_bitmap_unmap (bitmap);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
CoglReadPixelsFlags source,
|
||||||
|
CoglBitmap *bitmap)
|
||||||
|
{
|
||||||
|
CoglContext *ctx;
|
||||||
|
int framebuffer_height;
|
||||||
|
CoglPixelFormat format;
|
||||||
|
CoglPixelFormat required_format;
|
||||||
|
GLenum gl_intformat;
|
||||||
|
GLenum gl_format;
|
||||||
|
GLenum gl_type;
|
||||||
|
gboolean pack_invert_set;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
|
||||||
|
_COGL_RETURN_VAL_IF_FAIL (source == COGL_READ_PIXELS_COLOR_BUFFER, FALSE);
|
||||||
|
_COGL_RETURN_VAL_IF_FAIL (_cogl_is_framebuffer (framebuffer), FALSE);
|
||||||
|
|
||||||
|
ctx = cogl_framebuffer_get_context (framebuffer);
|
||||||
|
|
||||||
|
width = _cogl_bitmap_get_width (bitmap);
|
||||||
|
height = _cogl_bitmap_get_height (bitmap);
|
||||||
|
|
||||||
|
if (width == 1 && height == 1 && !framebuffer->clear_clip_dirty)
|
||||||
|
{
|
||||||
|
/* If everything drawn so far for this frame is still in the
|
||||||
|
* Journal then if all of the rectangles only have a flat
|
||||||
|
* opaque color we have a fast-path for reading a single pixel
|
||||||
|
* that avoids the relatively high cost of flushing primitives
|
||||||
|
* to be drawn on the GPU (considering how simple the geometry
|
||||||
|
* is in this case) and then blocking on the long GPU pipelines
|
||||||
|
* for the result.
|
||||||
|
*/
|
||||||
|
if (_cogl_framebuffer_try_fast_read_pixel (framebuffer,
|
||||||
|
x, y, source, bitmap))
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make sure any batched primitives get emitted to the GL driver
|
||||||
|
* before issuing our read pixels...
|
||||||
|
*/
|
||||||
|
_cogl_framebuffer_flush_journal (framebuffer);
|
||||||
|
|
||||||
|
_cogl_framebuffer_flush_state (framebuffer,
|
||||||
|
framebuffer,
|
||||||
|
COGL_FRAMEBUFFER_STATE_BIND);
|
||||||
|
|
||||||
|
framebuffer_height = cogl_framebuffer_get_height (framebuffer);
|
||||||
|
|
||||||
|
/* The y co-ordinate should be given in OpenGL's coordinate system
|
||||||
|
* so 0 is the bottom row
|
||||||
|
*
|
||||||
|
* NB: all offscreen rendering is done upside down so no conversion
|
||||||
|
* is necissary in this case.
|
||||||
|
*/
|
||||||
|
if (!cogl_is_offscreen (framebuffer))
|
||||||
|
y = framebuffer_height - y - height;
|
||||||
|
|
||||||
|
format = _cogl_bitmap_get_format (bitmap);
|
||||||
|
|
||||||
|
required_format = ctx->texture_driver->pixel_format_to_gl (format,
|
||||||
|
&gl_intformat,
|
||||||
|
&gl_format,
|
||||||
|
&gl_type);
|
||||||
|
|
||||||
|
/* NB: All offscreen rendering is done upside down so there is no need
|
||||||
|
* to flip in this case... */
|
||||||
|
if ((ctx->private_feature_flags & COGL_PRIVATE_FEATURE_MESA_PACK_INVERT) &&
|
||||||
|
!cogl_is_offscreen (framebuffer))
|
||||||
|
{
|
||||||
|
GE (ctx, glPixelStorei (GL_PACK_INVERT_MESA, TRUE));
|
||||||
|
pack_invert_set = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pack_invert_set = FALSE;
|
||||||
|
|
||||||
|
/* Under GLES only GL_RGBA with GL_UNSIGNED_BYTE as well as an
|
||||||
|
implementation specific format under
|
||||||
|
GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES and
|
||||||
|
GL_IMPLEMENTATION_COLOR_READ_TYPE_OES is supported. We could try
|
||||||
|
to be more clever and check if the requested type matches that
|
||||||
|
but we would need some reliable functions to convert from GL
|
||||||
|
types to Cogl types. For now, lets just always read in
|
||||||
|
GL_RGBA/GL_UNSIGNED_BYTE and convert if necessary. We also need
|
||||||
|
to use this intermediate buffer if the rowstride has padding
|
||||||
|
because GLES does not support setting GL_ROW_LENGTH */
|
||||||
|
if ((ctx->driver != COGL_DRIVER_GL &&
|
||||||
|
(gl_format != GL_RGBA || gl_type != GL_UNSIGNED_BYTE ||
|
||||||
|
_cogl_bitmap_get_rowstride (bitmap) != 4 * width)) ||
|
||||||
|
(required_format & ~COGL_PREMULT_BIT) != (format & ~COGL_PREMULT_BIT))
|
||||||
|
{
|
||||||
|
CoglBitmap *tmp_bmp;
|
||||||
|
guint8 *tmp_data;
|
||||||
|
CoglPixelFormat read_format;
|
||||||
|
int bpp, rowstride;
|
||||||
|
int succeeded;
|
||||||
|
|
||||||
|
if (ctx->driver == COGL_DRIVER_GL)
|
||||||
|
read_format = required_format;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
read_format = COGL_PIXEL_FORMAT_RGBA_8888;
|
||||||
|
gl_format = GL_RGBA;
|
||||||
|
gl_type = GL_UNSIGNED_BYTE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (read_format))
|
||||||
|
read_format = ((read_format & ~COGL_PREMULT_BIT) |
|
||||||
|
(framebuffer->format & COGL_PREMULT_BIT));
|
||||||
|
|
||||||
|
bpp = _cogl_pixel_format_get_bytes_per_pixel (read_format);
|
||||||
|
rowstride = (width * bpp + 3) & ~3;
|
||||||
|
tmp_data = g_malloc (rowstride * height);
|
||||||
|
|
||||||
|
tmp_bmp = _cogl_bitmap_new_from_data (tmp_data,
|
||||||
|
read_format,
|
||||||
|
width, height, rowstride,
|
||||||
|
(CoglBitmapDestroyNotify) g_free,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
ctx->texture_driver->prep_gl_for_pixels_download (rowstride, bpp);
|
||||||
|
|
||||||
|
GE( ctx, glReadPixels (x, y, width, height,
|
||||||
|
gl_format, gl_type,
|
||||||
|
tmp_data) );
|
||||||
|
|
||||||
|
succeeded = _cogl_bitmap_convert_into_bitmap (tmp_bmp, bitmap);
|
||||||
|
|
||||||
|
cogl_object_unref (tmp_bmp);
|
||||||
|
|
||||||
|
if (!succeeded)
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CoglBitmap *shared_bmp;
|
||||||
|
CoglPixelFormat bmp_format;
|
||||||
|
int bpp, rowstride;
|
||||||
|
gboolean succeeded = FALSE;
|
||||||
|
guint8 *pixels;
|
||||||
|
|
||||||
|
rowstride = _cogl_bitmap_get_rowstride (bitmap);
|
||||||
|
|
||||||
|
/* We match the premultiplied state of the target buffer to the
|
||||||
|
* premultiplied state of the framebuffer so that it will get
|
||||||
|
* converted to the right format below */
|
||||||
|
if (COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (format))
|
||||||
|
bmp_format = ((format & ~COGL_PREMULT_BIT) |
|
||||||
|
(framebuffer->format & COGL_PREMULT_BIT));
|
||||||
|
else
|
||||||
|
bmp_format = format;
|
||||||
|
|
||||||
|
if (bmp_format != format)
|
||||||
|
shared_bmp = _cogl_bitmap_new_shared (bitmap,
|
||||||
|
bmp_format,
|
||||||
|
width, height,
|
||||||
|
rowstride);
|
||||||
|
else
|
||||||
|
shared_bmp = cogl_object_ref (bitmap);
|
||||||
|
|
||||||
|
bpp = _cogl_pixel_format_get_bytes_per_pixel (bmp_format);
|
||||||
|
|
||||||
|
ctx->texture_driver->prep_gl_for_pixels_download (rowstride, bpp);
|
||||||
|
|
||||||
|
pixels = _cogl_bitmap_bind (shared_bmp,
|
||||||
|
COGL_BUFFER_ACCESS_WRITE,
|
||||||
|
0 /* hints */);
|
||||||
|
|
||||||
|
GE( ctx, glReadPixels (x, y,
|
||||||
|
width, height,
|
||||||
|
gl_format, gl_type,
|
||||||
|
pixels) );
|
||||||
|
|
||||||
|
_cogl_bitmap_unbind (shared_bmp);
|
||||||
|
|
||||||
|
/* Convert to the premult format specified by the caller
|
||||||
|
in-place. This will do nothing if the premult status is already
|
||||||
|
correct. */
|
||||||
|
if (_cogl_bitmap_convert_premult_status (shared_bmp, format))
|
||||||
|
succeeded = TRUE;
|
||||||
|
|
||||||
|
cogl_object_unref (shared_bmp);
|
||||||
|
|
||||||
|
if (!succeeded)
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Currently this function owns the pack_invert state and we don't want this
|
||||||
|
* to interfere with other Cogl components so all other code can assume that
|
||||||
|
* we leave the pack_invert state off. */
|
||||||
|
if (pack_invert_set)
|
||||||
|
GE (ctx, glPixelStorei (GL_PACK_INVERT_MESA, FALSE));
|
||||||
|
|
||||||
|
/* NB: All offscreen rendering is done upside down so there is no need
|
||||||
|
* to flip in this case... */
|
||||||
|
if (!cogl_is_offscreen (framebuffer) && !pack_invert_set)
|
||||||
|
{
|
||||||
|
guint8 *temprow;
|
||||||
|
int rowstride;
|
||||||
|
guint8 *pixels;
|
||||||
|
|
||||||
|
rowstride = _cogl_bitmap_get_rowstride (bitmap);
|
||||||
|
pixels = _cogl_bitmap_map (bitmap,
|
||||||
|
COGL_BUFFER_ACCESS_READ |
|
||||||
|
COGL_BUFFER_ACCESS_WRITE,
|
||||||
|
0 /* hints */);
|
||||||
|
|
||||||
|
if (pixels == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
temprow = g_alloca (rowstride * sizeof (guint8));
|
||||||
|
|
||||||
|
/* vertically flip the buffer in-place */
|
||||||
|
for (y = 0; y < height / 2; y++)
|
||||||
|
{
|
||||||
|
if (y != height - y - 1) /* skip center row */
|
||||||
|
{
|
||||||
|
memcpy (temprow,
|
||||||
|
pixels + y * rowstride, rowstride);
|
||||||
|
memcpy (pixels + y * rowstride,
|
||||||
|
pixels + (height - y - 1) * rowstride, rowstride);
|
||||||
|
memcpy (pixels + (height - y - 1) * rowstride,
|
||||||
|
temprow,
|
||||||
|
rowstride);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_cogl_bitmap_unmap (bitmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_cogl_blit_framebuffer (unsigned int src_x,
|
_cogl_blit_framebuffer (unsigned int src_x,
|
||||||
unsigned int src_y,
|
unsigned int src_y,
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
|
|
||||||
#include <cogl/cogl-pipeline.h>
|
#include <cogl/cogl-pipeline.h>
|
||||||
#include <cogl/cogl-indices.h>
|
#include <cogl/cogl-indices.h>
|
||||||
|
#include <cogl/cogl-bitmap.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
@ -1245,6 +1246,39 @@ cogl_framebuffer_discard_buffers (CoglFramebuffer *framebuffer,
|
|||||||
void
|
void
|
||||||
cogl_framebuffer_finish (CoglFramebuffer *framebuffer);
|
cogl_framebuffer_finish (CoglFramebuffer *framebuffer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cogl_framebuffer_read_pixels_into_bitmap:
|
||||||
|
* @framebuffer: A #CoglFramebuffer
|
||||||
|
* @x: The x position to read from
|
||||||
|
* @y: The y position to read from
|
||||||
|
* @source: Identifies which auxillary buffer you want to read
|
||||||
|
* (only COGL_READ_PIXELS_COLOR_BUFFER supported currently)
|
||||||
|
* @bitmap: The bitmap to store the results in.
|
||||||
|
*
|
||||||
|
* This reads a rectangle of pixels from the given framebuffer where
|
||||||
|
* position (0, 0) is the top left. The pixel at (x, y) is the first
|
||||||
|
* read, and a rectangle of pixels with the same size as the bitmap is
|
||||||
|
* read right and downwards from that point.
|
||||||
|
*
|
||||||
|
* Currently Cogl assumes that the framebuffer is in a premultiplied
|
||||||
|
* format so if the format of @bitmap is non-premultiplied it will
|
||||||
|
* convert it. To read the pixel values without any conversion you
|
||||||
|
* should either specify a format that doesn't use an alpha channel or
|
||||||
|
* use one of the formats ending in PRE.
|
||||||
|
*
|
||||||
|
* Return value: %TRUE if the read succeeded or %FALSE otherwise. The
|
||||||
|
* function is only likely to fail if the bitmap points to a pixel
|
||||||
|
* buffer and it could not be mapped.
|
||||||
|
* Since: 1.10
|
||||||
|
* Stability: unstable
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
CoglReadPixelsFlags source,
|
||||||
|
CoglBitmap *bitmap);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cogl_get_draw_framebuffer:
|
* cogl_get_draw_framebuffer:
|
||||||
*
|
*
|
||||||
|
@ -105,8 +105,7 @@ gboolean
|
|||||||
_cogl_journal_try_read_pixel (CoglJournal *journal,
|
_cogl_journal_try_read_pixel (CoglJournal *journal,
|
||||||
int x,
|
int x,
|
||||||
int y,
|
int y,
|
||||||
CoglPixelFormat format,
|
CoglBitmap *bitmap,
|
||||||
guint8 *pixel,
|
|
||||||
gboolean *found_intersection);
|
gboolean *found_intersection);
|
||||||
|
|
||||||
#endif /* __COGL_JOURNAL_PRIVATE_H */
|
#endif /* __COGL_JOURNAL_PRIVATE_H */
|
||||||
|
@ -1791,10 +1791,10 @@ gboolean
|
|||||||
_cogl_journal_try_read_pixel (CoglJournal *journal,
|
_cogl_journal_try_read_pixel (CoglJournal *journal,
|
||||||
int x,
|
int x,
|
||||||
int y,
|
int y,
|
||||||
CoglPixelFormat format,
|
CoglBitmap *bitmap,
|
||||||
guint8 *pixel,
|
|
||||||
gboolean *found_intersection)
|
gboolean *found_intersection)
|
||||||
{
|
{
|
||||||
|
CoglPixelFormat format;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
_COGL_GET_CONTEXT (ctx, FALSE);
|
_COGL_GET_CONTEXT (ctx, FALSE);
|
||||||
@ -1810,6 +1810,8 @@ _cogl_journal_try_read_pixel (CoglJournal *journal,
|
|||||||
if (journal->fast_read_pixel_count > 50)
|
if (journal->fast_read_pixel_count > 50)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
format = _cogl_bitmap_get_format (bitmap);
|
||||||
|
|
||||||
if (format != COGL_PIXEL_FORMAT_RGBA_8888_PRE &&
|
if (format != COGL_PIXEL_FORMAT_RGBA_8888_PRE &&
|
||||||
format != COGL_PIXEL_FORMAT_RGBA_8888)
|
format != COGL_PIXEL_FORMAT_RGBA_8888)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -1832,6 +1834,7 @@ _cogl_journal_try_read_pixel (CoglJournal *journal,
|
|||||||
float *vertices = (float *)color + 1;
|
float *vertices = (float *)color + 1;
|
||||||
float poly[16];
|
float poly[16];
|
||||||
CoglFramebuffer *framebuffer = journal->framebuffer;
|
CoglFramebuffer *framebuffer = journal->framebuffer;
|
||||||
|
guint8 *pixel;
|
||||||
|
|
||||||
entry_to_screen_polygon (framebuffer, entry, vertices, poly);
|
entry_to_screen_polygon (framebuffer, entry, vertices, poly);
|
||||||
|
|
||||||
@ -1870,11 +1873,19 @@ _cogl_journal_try_read_pixel (CoglJournal *journal,
|
|||||||
if (color[3] != 0xff)
|
if (color[3] != 0xff)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
pixel = _cogl_bitmap_map (bitmap,
|
||||||
|
COGL_BUFFER_ACCESS_WRITE,
|
||||||
|
COGL_BUFFER_MAP_HINT_DISCARD);
|
||||||
|
if (pixel == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
pixel[0] = color[0];
|
pixel[0] = color[0];
|
||||||
pixel[1] = color[1];
|
pixel[1] = color[1];
|
||||||
pixel[2] = color[2];
|
pixel[2] = color[2];
|
||||||
pixel[3] = color[3];
|
pixel[3] = color[3];
|
||||||
|
|
||||||
|
_cogl_bitmap_unmap (bitmap);
|
||||||
|
|
||||||
goto success;
|
goto success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,16 +44,6 @@ _cogl_check_extension (const char *name, const char *ext);
|
|||||||
void
|
void
|
||||||
_cogl_clear (const CoglColor *color, unsigned long buffers);
|
_cogl_clear (const CoglColor *color, unsigned long buffers);
|
||||||
|
|
||||||
void
|
|
||||||
_cogl_read_pixels_with_rowstride (int x,
|
|
||||||
int y,
|
|
||||||
int width,
|
|
||||||
int height,
|
|
||||||
CoglReadPixelsFlags source,
|
|
||||||
CoglPixelFormat format,
|
|
||||||
guint8 *pixels,
|
|
||||||
int rowstride);
|
|
||||||
|
|
||||||
void
|
void
|
||||||
_cogl_init (void);
|
_cogl_init (void);
|
||||||
|
|
||||||
|
@ -1015,6 +1015,7 @@ get_texture_bits_via_offscreen (CoglTexture *texture,
|
|||||||
{
|
{
|
||||||
CoglOffscreen *offscreen;
|
CoglOffscreen *offscreen;
|
||||||
CoglFramebuffer *framebuffer;
|
CoglFramebuffer *framebuffer;
|
||||||
|
CoglBitmap *bitmap;
|
||||||
|
|
||||||
_COGL_GET_CONTEXT (ctx, FALSE);
|
_COGL_GET_CONTEXT (ctx, FALSE);
|
||||||
|
|
||||||
@ -1031,19 +1032,17 @@ get_texture_bits_via_offscreen (CoglTexture *texture,
|
|||||||
|
|
||||||
framebuffer = COGL_FRAMEBUFFER (offscreen);
|
framebuffer = COGL_FRAMEBUFFER (offscreen);
|
||||||
|
|
||||||
if (!cogl_framebuffer_allocate (framebuffer, NULL))
|
bitmap = _cogl_bitmap_new_from_data (dst_bits,
|
||||||
{
|
dst_format,
|
||||||
cogl_object_unref (framebuffer);
|
width, height,
|
||||||
return FALSE;
|
dst_rowstride,
|
||||||
}
|
NULL, /* destroy_fn */
|
||||||
|
NULL /* destroy_fn_data */);
|
||||||
cogl_push_framebuffer (framebuffer);
|
cogl_framebuffer_read_pixels_into_bitmap (framebuffer,
|
||||||
|
x, y,
|
||||||
_cogl_read_pixels_with_rowstride (x, y, width, height,
|
|
||||||
COGL_READ_PIXELS_COLOR_BUFFER,
|
COGL_READ_PIXELS_COLOR_BUFFER,
|
||||||
dst_format, dst_bits, dst_rowstride);
|
bitmap);
|
||||||
|
cogl_object_unref (bitmap);
|
||||||
cogl_pop_framebuffer ();
|
|
||||||
|
|
||||||
cogl_object_unref (framebuffer);
|
cogl_object_unref (framebuffer);
|
||||||
|
|
||||||
|
200
cogl/cogl.c
200
cogl/cogl.c
@ -368,189 +368,6 @@ cogl_flush (void)
|
|||||||
_cogl_framebuffer_flush_journal (l->data);
|
_cogl_framebuffer_flush_journal (l->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
_cogl_read_pixels_with_rowstride (int x,
|
|
||||||
int y,
|
|
||||||
int width,
|
|
||||||
int height,
|
|
||||||
CoglReadPixelsFlags source,
|
|
||||||
CoglPixelFormat format,
|
|
||||||
guint8 *pixels,
|
|
||||||
int rowstride)
|
|
||||||
{
|
|
||||||
CoglFramebuffer *framebuffer = _cogl_get_read_framebuffer ();
|
|
||||||
int framebuffer_height;
|
|
||||||
int bpp;
|
|
||||||
CoglBitmap *bmp;
|
|
||||||
GLenum gl_intformat;
|
|
||||||
GLenum gl_format;
|
|
||||||
GLenum gl_type;
|
|
||||||
CoglPixelFormat bmp_format;
|
|
||||||
gboolean pack_invert_set;
|
|
||||||
|
|
||||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
||||||
|
|
||||||
_COGL_RETURN_IF_FAIL (source == COGL_READ_PIXELS_COLOR_BUFFER);
|
|
||||||
|
|
||||||
if (width == 1 && height == 1 && !framebuffer->clear_clip_dirty)
|
|
||||||
{
|
|
||||||
/* If everything drawn so far for this frame is still in the
|
|
||||||
* Journal then if all of the rectangles only have a flat
|
|
||||||
* opaque color we have a fast-path for reading a single pixel
|
|
||||||
* that avoids the relatively high cost of flushing primitives
|
|
||||||
* to be drawn on the GPU (considering how simple the geometry
|
|
||||||
* is in this case) and then blocking on the long GPU pipelines
|
|
||||||
* for the result.
|
|
||||||
*/
|
|
||||||
if (_cogl_framebuffer_try_fast_read_pixel (framebuffer,
|
|
||||||
x, y, source, format,
|
|
||||||
pixels))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* make sure any batched primitives get emitted to the GL driver
|
|
||||||
* before issuing our read pixels...
|
|
||||||
*
|
|
||||||
* XXX: Note we currently use cogl_flush to ensure *all* journals
|
|
||||||
* are flushed here and not _cogl_journal_flush because we don't
|
|
||||||
* track the dependencies between framebuffers so we don't know if
|
|
||||||
* the current framebuffer depends on the contents of other
|
|
||||||
* framebuffers which could also have associated journal entries.
|
|
||||||
*/
|
|
||||||
cogl_flush ();
|
|
||||||
|
|
||||||
_cogl_framebuffer_flush_state (cogl_get_draw_framebuffer (),
|
|
||||||
framebuffer,
|
|
||||||
COGL_FRAMEBUFFER_STATE_BIND);
|
|
||||||
|
|
||||||
framebuffer_height = cogl_framebuffer_get_height (framebuffer);
|
|
||||||
|
|
||||||
/* The y co-ordinate should be given in OpenGL's coordinate system
|
|
||||||
* so 0 is the bottom row
|
|
||||||
*
|
|
||||||
* NB: all offscreen rendering is done upside down so no conversion
|
|
||||||
* is necissary in this case.
|
|
||||||
*/
|
|
||||||
if (!cogl_is_offscreen (framebuffer))
|
|
||||||
y = framebuffer_height - y - height;
|
|
||||||
|
|
||||||
/* Initialise the CoglBitmap */
|
|
||||||
bpp = _cogl_pixel_format_get_bytes_per_pixel (format);
|
|
||||||
bmp_format = format;
|
|
||||||
|
|
||||||
if (COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (format & COGL_A_BIT))
|
|
||||||
{
|
|
||||||
/* We match the premultiplied state of the target buffer to the
|
|
||||||
* premultiplied state of the framebuffer so that it will get
|
|
||||||
* converted to the right format below */
|
|
||||||
|
|
||||||
if ((framebuffer->format & COGL_PREMULT_BIT))
|
|
||||||
bmp_format |= COGL_PREMULT_BIT;
|
|
||||||
else
|
|
||||||
bmp_format &= ~COGL_PREMULT_BIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
bmp = _cogl_bitmap_new_from_data (pixels,
|
|
||||||
bmp_format, width, height, rowstride,
|
|
||||||
NULL, NULL);
|
|
||||||
|
|
||||||
ctx->texture_driver->pixel_format_to_gl (format,
|
|
||||||
&gl_intformat,
|
|
||||||
&gl_format,
|
|
||||||
&gl_type);
|
|
||||||
|
|
||||||
/* NB: All offscreen rendering is done upside down so there is no need
|
|
||||||
* to flip in this case... */
|
|
||||||
if ((ctx->private_feature_flags & COGL_PRIVATE_FEATURE_MESA_PACK_INVERT) &&
|
|
||||||
!cogl_is_offscreen (framebuffer))
|
|
||||||
{
|
|
||||||
GE (ctx, glPixelStorei (GL_PACK_INVERT_MESA, TRUE));
|
|
||||||
pack_invert_set = TRUE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
pack_invert_set = FALSE;
|
|
||||||
|
|
||||||
/* Under GLES only GL_RGBA with GL_UNSIGNED_BYTE as well as an
|
|
||||||
implementation specific format under
|
|
||||||
GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES and
|
|
||||||
GL_IMPLEMENTATION_COLOR_READ_TYPE_OES is supported. We could try
|
|
||||||
to be more clever and check if the requested type matches that
|
|
||||||
but we would need some reliable functions to convert from GL
|
|
||||||
types to Cogl types. For now, lets just always read in
|
|
||||||
GL_RGBA/GL_UNSIGNED_BYTE and convert if necessary. We also need
|
|
||||||
to use this intermediate buffer if the rowstride has padding
|
|
||||||
because GLES does not support setting GL_ROW_LENGTH */
|
|
||||||
if (ctx->driver != COGL_DRIVER_GL &&
|
|
||||||
(gl_format != GL_RGBA || gl_type != GL_UNSIGNED_BYTE ||
|
|
||||||
rowstride != 4 * width))
|
|
||||||
{
|
|
||||||
CoglBitmap *tmp_bmp;
|
|
||||||
guint8 *tmp_data = g_malloc (width * height * 4);
|
|
||||||
|
|
||||||
tmp_bmp = _cogl_bitmap_new_from_data (tmp_data,
|
|
||||||
COGL_PIXEL_FORMAT_RGBA_8888 |
|
|
||||||
(bmp_format & COGL_PREMULT_BIT),
|
|
||||||
width, height, 4 * width,
|
|
||||||
(CoglBitmapDestroyNotify) g_free,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
ctx->texture_driver->prep_gl_for_pixels_download (4 * width, 4);
|
|
||||||
|
|
||||||
GE( ctx, glReadPixels (x, y, width, height,
|
|
||||||
GL_RGBA, GL_UNSIGNED_BYTE,
|
|
||||||
tmp_data) );
|
|
||||||
|
|
||||||
if (!_cogl_bitmap_convert_into_bitmap (tmp_bmp, bmp))
|
|
||||||
{
|
|
||||||
/* FIXME: there's no way to report an error here so we'll
|
|
||||||
just have to leave the data initialised */
|
|
||||||
}
|
|
||||||
|
|
||||||
cogl_object_unref (tmp_bmp);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ctx->texture_driver->prep_gl_for_pixels_download (rowstride, bpp);
|
|
||||||
|
|
||||||
GE( ctx, glReadPixels (x, y, width, height, gl_format, gl_type, pixels) );
|
|
||||||
|
|
||||||
/* Convert to the premult format specified by the caller
|
|
||||||
in-place. This will do nothing if the premult status is already
|
|
||||||
correct. */
|
|
||||||
_cogl_bitmap_convert_premult_status (bmp, format);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Currently this function owns the pack_invert state and we don't want this
|
|
||||||
* to interfere with other Cogl components so all other code can assume that
|
|
||||||
* we leave the pack_invert state off. */
|
|
||||||
if (pack_invert_set)
|
|
||||||
GE (ctx, glPixelStorei (GL_PACK_INVERT_MESA, FALSE));
|
|
||||||
|
|
||||||
/* NB: All offscreen rendering is done upside down so there is no need
|
|
||||||
* to flip in this case... */
|
|
||||||
if (!cogl_is_offscreen (framebuffer) && !pack_invert_set)
|
|
||||||
{
|
|
||||||
guint8 *temprow = g_alloca (rowstride * sizeof (guint8));
|
|
||||||
|
|
||||||
/* vertically flip the buffer in-place */
|
|
||||||
for (y = 0; y < height / 2; y++)
|
|
||||||
{
|
|
||||||
if (y != height - y - 1) /* skip center row */
|
|
||||||
{
|
|
||||||
memcpy (temprow,
|
|
||||||
pixels + y * rowstride, rowstride);
|
|
||||||
memcpy (pixels + y * rowstride,
|
|
||||||
pixels + (height - y - 1) * rowstride, rowstride);
|
|
||||||
memcpy (pixels + (height - y - 1) * rowstride,
|
|
||||||
temprow,
|
|
||||||
rowstride);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cogl_object_unref (bmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
cogl_read_pixels (int x,
|
cogl_read_pixels (int x,
|
||||||
int y,
|
int y,
|
||||||
@ -561,10 +378,19 @@ cogl_read_pixels (int x,
|
|||||||
guint8 *pixels)
|
guint8 *pixels)
|
||||||
{
|
{
|
||||||
int bpp = _cogl_pixel_format_get_bytes_per_pixel (format);
|
int bpp = _cogl_pixel_format_get_bytes_per_pixel (format);
|
||||||
_cogl_read_pixels_with_rowstride (x, y, width, height,
|
CoglBitmap *bitmap;
|
||||||
source, format, pixels,
|
|
||||||
/* rowstride */
|
bitmap = _cogl_bitmap_new_from_data (pixels,
|
||||||
bpp * width);
|
format,
|
||||||
|
width, height,
|
||||||
|
bpp * width, /* rowstride */
|
||||||
|
NULL, /* destroy_fn */
|
||||||
|
NULL /* destroy_fn_data */);
|
||||||
|
cogl_framebuffer_read_pixels_into_bitmap (_cogl_get_read_framebuffer (),
|
||||||
|
x, y,
|
||||||
|
source,
|
||||||
|
bitmap);
|
||||||
|
cogl_object_unref (bitmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -406,6 +406,7 @@ cogl_framebuffer_set_point_samples_per_pixel
|
|||||||
cogl_framebuffer_get_context
|
cogl_framebuffer_get_context
|
||||||
cogl_framebuffer_clear
|
cogl_framebuffer_clear
|
||||||
cogl_framebuffer_clear4f
|
cogl_framebuffer_clear4f
|
||||||
|
cogl_framebuffer_read_pixels_into_bitmap
|
||||||
|
|
||||||
<SUBSECTION>
|
<SUBSECTION>
|
||||||
cogl_framebuffer_draw_primitive
|
cogl_framebuffer_draw_primitive
|
||||||
|
Loading…
Reference in New Issue
Block a user