mesa: add common format-independent memcpy-based ReadPixels path
I'll need the _mesa_readpixels_needs_slow_path function for the blit-based version, but it's also useful to have this memcpy-based path in one place and not scattered across several functions. v2: add "const" to function parameters Reviewed-by: Brian Paul <brianp@vmware.com> Tested-by: Brian Paul <brianp@vmware.com>
This commit is contained in:
parent
f8855a4214
commit
d702c67ba5
|
@ -923,10 +923,10 @@ _mesa_get_color_read_type(struct gl_context *ctx)
|
|||
* Returns the read renderbuffer for the specified format.
|
||||
*/
|
||||
struct gl_renderbuffer *
|
||||
_mesa_get_read_renderbuffer_for_format(struct gl_context *ctx,
|
||||
_mesa_get_read_renderbuffer_for_format(const struct gl_context *ctx,
|
||||
GLenum format)
|
||||
{
|
||||
struct gl_framebuffer *rfb = ctx->ReadBuffer;
|
||||
const struct gl_framebuffer *rfb = ctx->ReadBuffer;
|
||||
|
||||
if (_mesa_is_color_format(format)) {
|
||||
return rfb->Attachment[rfb->_ColorReadBufferIndex].Renderbuffer;
|
||||
|
|
|
@ -98,7 +98,7 @@ extern GLenum
|
|||
_mesa_get_color_read_format(struct gl_context *ctx);
|
||||
|
||||
extern struct gl_renderbuffer *
|
||||
_mesa_get_read_renderbuffer_for_format(struct gl_context *ctx,
|
||||
_mesa_get_read_renderbuffer_for_format(const struct gl_context *ctx,
|
||||
GLenum format);
|
||||
|
||||
extern void
|
||||
|
|
|
@ -108,11 +108,145 @@ get_readpixels_transfer_ops(const struct gl_context *ctx, gl_format texFormat,
|
|||
|
||||
|
||||
/**
|
||||
* Tries to implement glReadPixels() of GL_DEPTH_COMPONENT using memcpy of the
|
||||
* mapping.
|
||||
* Return true if memcpy cannot be used for ReadPixels.
|
||||
*
|
||||
* If uses_blit is true, the function returns true if a simple 3D engine blit
|
||||
* cannot be used for ReadPixels packing.
|
||||
*
|
||||
* NOTE: This doesn't take swizzling and format conversions between
|
||||
* the readbuffer and the pixel pack buffer into account.
|
||||
*/
|
||||
GLboolean
|
||||
_mesa_readpixels_needs_slow_path(const struct gl_context *ctx, GLenum format,
|
||||
GLenum type, GLboolean uses_blit)
|
||||
{
|
||||
struct gl_renderbuffer *rb =
|
||||
_mesa_get_read_renderbuffer_for_format(ctx, format);
|
||||
GLenum srcType;
|
||||
|
||||
ASSERT(rb);
|
||||
|
||||
/* There are different rules depending on the base format. */
|
||||
switch (format) {
|
||||
case GL_DEPTH_STENCIL:
|
||||
return !_mesa_has_depthstencil_combined(ctx->ReadBuffer) ||
|
||||
ctx->Pixel.DepthScale != 1.0f || ctx->Pixel.DepthBias != 0.0f ||
|
||||
ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset ||
|
||||
ctx->Pixel.MapStencilFlag;
|
||||
|
||||
case GL_DEPTH_COMPONENT:
|
||||
return ctx->Pixel.DepthScale != 1.0f || ctx->Pixel.DepthBias != 0.0f;
|
||||
|
||||
case GL_STENCIL_INDEX:
|
||||
return ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset ||
|
||||
ctx->Pixel.MapStencilFlag;
|
||||
|
||||
default:
|
||||
/* Color formats. */
|
||||
if (need_rgb_to_luminance_conversion(rb->Format, format)) {
|
||||
return GL_TRUE;
|
||||
}
|
||||
|
||||
/* Conversion between signed and unsigned integers needs masking
|
||||
* (it isn't just memcpy). */
|
||||
srcType = _mesa_get_format_datatype(rb->Format);
|
||||
|
||||
if ((srcType == GL_INT &&
|
||||
(type == GL_UNSIGNED_INT ||
|
||||
type == GL_UNSIGNED_SHORT ||
|
||||
type == GL_UNSIGNED_BYTE)) ||
|
||||
(srcType == GL_UNSIGNED_INT &&
|
||||
(type == GL_INT ||
|
||||
type == GL_SHORT ||
|
||||
type == GL_BYTE))) {
|
||||
return GL_TRUE;
|
||||
}
|
||||
|
||||
/* And finally, see if there are any transfer ops. */
|
||||
return get_readpixels_transfer_ops(ctx, rb->Format, format, type,
|
||||
uses_blit) != 0;
|
||||
}
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
static GLboolean
|
||||
readpixels_can_use_memcpy(const struct gl_context *ctx, GLenum format, GLenum type,
|
||||
const struct gl_pixelstore_attrib *packing)
|
||||
{
|
||||
struct gl_renderbuffer *rb =
|
||||
_mesa_get_read_renderbuffer_for_format(ctx, format);
|
||||
|
||||
ASSERT(rb);
|
||||
|
||||
if (_mesa_readpixels_needs_slow_path(ctx, format, type, GL_FALSE)) {
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
/* The base internal format and the base Mesa format must match. */
|
||||
if (rb->_BaseFormat != _mesa_get_format_base_format(rb->Format)) {
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
/* The Mesa format must match the input format and type. */
|
||||
if (!_mesa_format_matches_format_and_type(rb->Format, format, type,
|
||||
packing->SwapBytes)) {
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
return GL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
static GLboolean
|
||||
readpixels_memcpy(struct gl_context *ctx,
|
||||
GLint x, GLint y,
|
||||
GLsizei width, GLsizei height,
|
||||
GLenum format, GLenum type,
|
||||
GLvoid *pixels,
|
||||
const struct gl_pixelstore_attrib *packing)
|
||||
{
|
||||
struct gl_renderbuffer *rb =
|
||||
_mesa_get_read_renderbuffer_for_format(ctx, format);
|
||||
GLubyte *dst, *map;
|
||||
int dstStride, stride, j, texelBytes;
|
||||
|
||||
/* Fail if memcpy cannot be used. */
|
||||
if (!readpixels_can_use_memcpy(ctx, format, type, packing)) {
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
dstStride = _mesa_image_row_stride(packing, width, format, type);
|
||||
dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
|
||||
format, type, 0, 0);
|
||||
|
||||
ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
|
||||
&map, &stride);
|
||||
if (!map) {
|
||||
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
|
||||
return GL_TRUE; /* don't bother trying the slow path */
|
||||
}
|
||||
|
||||
texelBytes = _mesa_get_format_bytes(rb->Format);
|
||||
|
||||
/* memcpy*/
|
||||
for (j = 0; j < height; j++) {
|
||||
memcpy(dst, map, width * texelBytes);
|
||||
dst += dstStride;
|
||||
map += stride;
|
||||
}
|
||||
|
||||
ctx->Driver.UnmapRenderbuffer(ctx, rb);
|
||||
return GL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Optimized path for conversion of depth values to GL_DEPTH_COMPONENT,
|
||||
* GL_UNSIGNED_INT.
|
||||
*/
|
||||
static GLboolean
|
||||
fast_read_depth_pixels( struct gl_context *ctx,
|
||||
read_uint_depth_pixels( struct gl_context *ctx,
|
||||
GLint x, GLint y,
|
||||
GLsizei width, GLsizei height,
|
||||
GLenum type, GLvoid *pixels,
|
||||
|
@ -132,10 +266,6 @@ fast_read_depth_pixels( struct gl_context *ctx,
|
|||
if (_mesa_get_format_datatype(rb->Format) != GL_UNSIGNED_NORMALIZED)
|
||||
return GL_FALSE;
|
||||
|
||||
if (!((type == GL_UNSIGNED_SHORT && rb->Format == MESA_FORMAT_Z16) ||
|
||||
type == GL_UNSIGNED_INT))
|
||||
return GL_FALSE;
|
||||
|
||||
ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
|
||||
&map, &stride);
|
||||
|
||||
|
@ -149,12 +279,7 @@ fast_read_depth_pixels( struct gl_context *ctx,
|
|||
GL_DEPTH_COMPONENT, type, 0, 0);
|
||||
|
||||
for (j = 0; j < height; j++) {
|
||||
if (type == GL_UNSIGNED_INT) {
|
||||
_mesa_unpack_uint_z_row(rb->Format, width, map, (GLuint *)dst);
|
||||
} else {
|
||||
ASSERT(type == GL_UNSIGNED_SHORT && rb->Format == MESA_FORMAT_Z16);
|
||||
memcpy(dst, map, width * 2);
|
||||
}
|
||||
_mesa_unpack_uint_z_row(rb->Format, width, map, (GLuint *)dst);
|
||||
|
||||
map += stride;
|
||||
dst += dstStride;
|
||||
|
@ -190,8 +315,10 @@ read_depth_pixels( struct gl_context *ctx,
|
|||
ASSERT(x + width <= (GLint) rb->Width);
|
||||
ASSERT(y + height <= (GLint) rb->Height);
|
||||
|
||||
if (fast_read_depth_pixels(ctx, x, y, width, height, type, pixels, packing))
|
||||
if (type == GL_UNSIGNED_INT &&
|
||||
read_uint_depth_pixels(ctx, x, y, width, height, type, pixels, packing)) {
|
||||
return;
|
||||
}
|
||||
|
||||
dstStride = _mesa_image_row_stride(packing, width, GL_DEPTH_COMPONENT, type);
|
||||
dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
|
||||
|
@ -279,20 +406,20 @@ read_stencil_pixels( struct gl_context *ctx,
|
|||
|
||||
|
||||
/**
|
||||
* Try to do glReadPixels of RGBA data using a simple memcpy or swizzle.
|
||||
* Try to do glReadPixels of RGBA data using swizzle.
|
||||
* \return GL_TRUE if successful, GL_FALSE otherwise (use the slow path)
|
||||
*/
|
||||
static GLboolean
|
||||
fast_read_rgba_pixels_memcpy( struct gl_context *ctx,
|
||||
GLint x, GLint y,
|
||||
GLsizei width, GLsizei height,
|
||||
GLenum format, GLenum type,
|
||||
GLvoid *pixels,
|
||||
const struct gl_pixelstore_attrib *packing)
|
||||
read_rgba_pixels_swizzle(struct gl_context *ctx,
|
||||
GLint x, GLint y,
|
||||
GLsizei width, GLsizei height,
|
||||
GLenum format, GLenum type,
|
||||
GLvoid *pixels,
|
||||
const struct gl_pixelstore_attrib *packing)
|
||||
{
|
||||
struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
|
||||
GLubyte *dst, *map;
|
||||
int dstStride, stride, j, texelBytes;
|
||||
int dstStride, stride, j;
|
||||
GLboolean swizzle_rb = GL_FALSE, copy_xrgb = GL_FALSE;
|
||||
|
||||
/* XXX we could check for other swizzle/special cases here as needed */
|
||||
|
@ -308,9 +435,9 @@ fast_read_rgba_pixels_memcpy( struct gl_context *ctx,
|
|||
!ctx->Pack.SwapBytes) {
|
||||
copy_xrgb = GL_TRUE;
|
||||
}
|
||||
else if (!_mesa_format_matches_format_and_type(rb->Format, format, type,
|
||||
ctx->Pack.SwapBytes))
|
||||
else {
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
dstStride = _mesa_image_row_stride(packing, width, format, type);
|
||||
dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
|
||||
|
@ -323,8 +450,6 @@ fast_read_rgba_pixels_memcpy( struct gl_context *ctx,
|
|||
return GL_TRUE; /* don't bother trying the slow path */
|
||||
}
|
||||
|
||||
texelBytes = _mesa_get_format_bytes(rb->Format);
|
||||
|
||||
if (swizzle_rb) {
|
||||
/* swap R/B */
|
||||
for (j = 0; j < height; j++) {
|
||||
|
@ -350,13 +475,6 @@ fast_read_rgba_pixels_memcpy( struct gl_context *ctx,
|
|||
dst += dstStride;
|
||||
map += stride;
|
||||
}
|
||||
} else {
|
||||
/* just memcpy */
|
||||
for (j = 0; j < height; j++) {
|
||||
memcpy(dst, map, width * texelBytes);
|
||||
dst += dstStride;
|
||||
map += stride;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->Driver.UnmapRenderbuffer(ctx, rb);
|
||||
|
@ -447,7 +565,7 @@ read_rgba_pixels( struct gl_context *ctx,
|
|||
|
||||
/* Try the optimized paths first. */
|
||||
if (!transferOps &&
|
||||
fast_read_rgba_pixels_memcpy(ctx, x, y, width, height,
|
||||
read_rgba_pixels_swizzle(ctx, x, y, width, height,
|
||||
format, type, pixels, packing)) {
|
||||
return;
|
||||
}
|
||||
|
@ -703,6 +821,14 @@ _mesa_readpixels(struct gl_context *ctx,
|
|||
pixels = _mesa_map_pbo_dest(ctx, &clippedPacking, pixels);
|
||||
|
||||
if (pixels) {
|
||||
/* Try memcpy first. */
|
||||
if (readpixels_memcpy(ctx, x, y, width, height, format, type,
|
||||
pixels, packing)) {
|
||||
_mesa_unmap_pbo_dest(ctx, &clippedPacking);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Otherwise take the slow path. */
|
||||
switch (format) {
|
||||
case GL_STENCIL_INDEX:
|
||||
read_stencil_pixels(ctx, x, y, width, height, type, pixels,
|
||||
|
|
|
@ -33,6 +33,10 @@ struct gl_context;
|
|||
struct gl_pixelstore_attrib;
|
||||
|
||||
|
||||
extern GLboolean
|
||||
_mesa_readpixels_needs_slow_path(const struct gl_context *ctx, GLenum format,
|
||||
GLenum type, GLboolean uses_blit);
|
||||
|
||||
extern void
|
||||
_mesa_readpixels(struct gl_context *ctx,
|
||||
GLint x, GLint y, GLsizei width, GLsizei height,
|
||||
|
|
Loading…
Reference in New Issue