diff --git a/cogl/cogl-framebuffer-private.h b/cogl/cogl-framebuffer-private.h index 6685d3102..0081a2f90 100644 --- a/cogl/cogl-framebuffer-private.h +++ b/cogl/cogl-framebuffer-private.h @@ -244,14 +244,6 @@ _cogl_framebuffer_flush_journal (CoglFramebuffer *framebuffer); void _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 _cogl_framebuffer_flush_state (CoglFramebuffer *draw_buffer, CoglFramebuffer *read_buffer, diff --git a/cogl/cogl-framebuffer.c b/cogl/cogl-framebuffer.c index 5a549abd3..e3f123978 100644 --- a/cogl/cogl-framebuffer.c +++ b/cogl/cogl-framebuffer.c @@ -25,6 +25,8 @@ #include "config.h" #endif +#include + #include "cogl-debug.h" #include "cogl-internal.h" #include "cogl-context-private.h" @@ -43,6 +45,7 @@ #include "cogl-primitive-private.h" #include "cogl-offscreen.h" #include "cogl1-context.h" +#include "cogl-private.h" #ifndef GL_FRAMEBUFFER #define GL_FRAMEBUFFER 0x8D40 @@ -1860,15 +1863,15 @@ cogl_framebuffer_get_context (CoglFramebuffer *framebuffer) return framebuffer->context; } -gboolean +static gboolean _cogl_framebuffer_try_fast_read_pixel (CoglFramebuffer *framebuffer, int x, int y, CoglReadPixelsFlags source, - CoglPixelFormat format, - guint8 *pixel) + CoglBitmap *bitmap) { gboolean found_intersection; + CoglPixelFormat format; if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_FAST_READ_PIXEL))) return FALSE; @@ -1876,12 +1879,14 @@ _cogl_framebuffer_try_fast_read_pixel (CoglFramebuffer *framebuffer, if (source != COGL_READ_PIXELS_COLOR_BUFFER) return FALSE; + format = _cogl_bitmap_get_format (bitmap); + if (format != COGL_PIXEL_FORMAT_RGBA_8888_PRE && format != COGL_PIXEL_FORMAT_RGBA_8888) return FALSE; if (!_cogl_journal_try_read_pixel (framebuffer->journal, - x, y, format, pixel, + x, y, bitmap, &found_intersection)) return FALSE; @@ -1906,23 +1911,268 @@ _cogl_framebuffer_try_fast_read_pixel (CoglFramebuffer *framebuffer, y >= framebuffer->clear_clip_y0 && y < framebuffer->clear_clip_y1) { + guint8 *pixel; /* we currently only care about cases where the premultiplied or * unpremultipled colors are equivalent... */ if (framebuffer->clear_color_alpha != 1.0) 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[1] = framebuffer->clear_color_green * 255.0; pixel[2] = framebuffer->clear_color_blue * 255.0; pixel[3] = framebuffer->clear_color_alpha * 255.0; + _cogl_bitmap_unmap (bitmap); + return TRUE; } 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 _cogl_blit_framebuffer (unsigned int src_x, unsigned int src_y, diff --git a/cogl/cogl-framebuffer.h b/cogl/cogl-framebuffer.h index 1fbd23d42..0dfdc48ed 100644 --- a/cogl/cogl-framebuffer.h +++ b/cogl/cogl-framebuffer.h @@ -46,6 +46,7 @@ #include #include +#include G_BEGIN_DECLS @@ -1245,6 +1246,39 @@ cogl_framebuffer_discard_buffers (CoglFramebuffer *framebuffer, void 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: * diff --git a/cogl/cogl-journal-private.h b/cogl/cogl-journal-private.h index c561a1078..e3dbaa8ae 100644 --- a/cogl/cogl-journal-private.h +++ b/cogl/cogl-journal-private.h @@ -105,8 +105,7 @@ gboolean _cogl_journal_try_read_pixel (CoglJournal *journal, int x, int y, - CoglPixelFormat format, - guint8 *pixel, + CoglBitmap *bitmap, gboolean *found_intersection); #endif /* __COGL_JOURNAL_PRIVATE_H */ diff --git a/cogl/cogl-journal.c b/cogl/cogl-journal.c index bec9e6dcd..a5811294e 100644 --- a/cogl/cogl-journal.c +++ b/cogl/cogl-journal.c @@ -1791,10 +1791,10 @@ gboolean _cogl_journal_try_read_pixel (CoglJournal *journal, int x, int y, - CoglPixelFormat format, - guint8 *pixel, + CoglBitmap *bitmap, gboolean *found_intersection) { + CoglPixelFormat format; int i; _COGL_GET_CONTEXT (ctx, FALSE); @@ -1810,6 +1810,8 @@ _cogl_journal_try_read_pixel (CoglJournal *journal, if (journal->fast_read_pixel_count > 50) return FALSE; + format = _cogl_bitmap_get_format (bitmap); + if (format != COGL_PIXEL_FORMAT_RGBA_8888_PRE && format != COGL_PIXEL_FORMAT_RGBA_8888) return FALSE; @@ -1832,6 +1834,7 @@ _cogl_journal_try_read_pixel (CoglJournal *journal, float *vertices = (float *)color + 1; float poly[16]; CoglFramebuffer *framebuffer = journal->framebuffer; + guint8 *pixel; entry_to_screen_polygon (framebuffer, entry, vertices, poly); @@ -1870,11 +1873,19 @@ _cogl_journal_try_read_pixel (CoglJournal *journal, if (color[3] != 0xff) 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[1] = color[1]; pixel[2] = color[2]; pixel[3] = color[3]; + _cogl_bitmap_unmap (bitmap); + goto success; } diff --git a/cogl/cogl-private.h b/cogl/cogl-private.h index 41275fe4d..6130c113f 100644 --- a/cogl/cogl-private.h +++ b/cogl/cogl-private.h @@ -44,16 +44,6 @@ _cogl_check_extension (const char *name, const char *ext); void _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 _cogl_init (void); diff --git a/cogl/cogl-texture.c b/cogl/cogl-texture.c index 38e923299..254c2ff81 100644 --- a/cogl/cogl-texture.c +++ b/cogl/cogl-texture.c @@ -1015,6 +1015,7 @@ get_texture_bits_via_offscreen (CoglTexture *texture, { CoglOffscreen *offscreen; CoglFramebuffer *framebuffer; + CoglBitmap *bitmap; _COGL_GET_CONTEXT (ctx, FALSE); @@ -1031,19 +1032,17 @@ get_texture_bits_via_offscreen (CoglTexture *texture, framebuffer = COGL_FRAMEBUFFER (offscreen); - if (!cogl_framebuffer_allocate (framebuffer, NULL)) - { - cogl_object_unref (framebuffer); - return FALSE; - } - - cogl_push_framebuffer (framebuffer); - - _cogl_read_pixels_with_rowstride (x, y, width, height, - COGL_READ_PIXELS_COLOR_BUFFER, - dst_format, dst_bits, dst_rowstride); - - cogl_pop_framebuffer (); + bitmap = _cogl_bitmap_new_from_data (dst_bits, + dst_format, + width, height, + dst_rowstride, + NULL, /* destroy_fn */ + NULL /* destroy_fn_data */); + cogl_framebuffer_read_pixels_into_bitmap (framebuffer, + x, y, + COGL_READ_PIXELS_COLOR_BUFFER, + bitmap); + cogl_object_unref (bitmap); cogl_object_unref (framebuffer); diff --git a/cogl/cogl.c b/cogl/cogl.c index dffd5f774..bfd7ab5ec 100644 --- a/cogl/cogl.c +++ b/cogl/cogl.c @@ -368,189 +368,6 @@ cogl_flush (void) _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 cogl_read_pixels (int x, int y, @@ -561,10 +378,19 @@ cogl_read_pixels (int x, guint8 *pixels) { int bpp = _cogl_pixel_format_get_bytes_per_pixel (format); - _cogl_read_pixels_with_rowstride (x, y, width, height, - source, format, pixels, - /* rowstride */ - bpp * width); + CoglBitmap *bitmap; + + bitmap = _cogl_bitmap_new_from_data (pixels, + 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 diff --git a/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt b/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt index 787e7d5be..1cb8ae777 100644 --- a/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt +++ b/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt @@ -406,6 +406,7 @@ cogl_framebuffer_set_point_samples_per_pixel cogl_framebuffer_get_context cogl_framebuffer_clear cogl_framebuffer_clear4f +cogl_framebuffer_read_pixels_into_bitmap cogl_framebuffer_draw_primitive