Module: Mesa Branch: gallium-mesa-7.4 Commit: ae22ad765843c19d4c853277416a6d52d9918c83 URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=ae22ad765843c19d4c853277416a6d52d9918c83
Author: Alan Hourihane <al...@vmware.com> Date: Mon Jun 15 15:59:57 2009 +0100 add patches from bug 21997 --- src/gallium/auxiliary/util/u_linear.c | 63 +++++--- src/gallium/auxiliary/util/u_linear.h | 11 ++- src/gallium/include/pipe/p_defines.h | 10 ++ src/gallium/include/pipe/p_screen.h | 17 ++ src/gallium/include/pipe/p_state.h | 22 +++ src/mesa/state_tracker/st_cb_readpixels.c | 252 ++++++++++++++++++++++++++++- 6 files changed, 346 insertions(+), 29 deletions(-) diff --git a/src/gallium/auxiliary/util/u_linear.c b/src/gallium/auxiliary/util/u_linear.c index ff7645a..34a7ff3 100644 --- a/src/gallium/auxiliary/util/u_linear.c +++ b/src/gallium/auxiliary/util/u_linear.c @@ -6,23 +6,27 @@ void pipe_linear_to_tile(size_t src_stride, void *src_ptr, struct pipe_tile_info *t, void *dst_ptr) { - unsigned x, y, z; - char *ptr; + unsigned x, y, offset; + char *ptr, *dst; + unsigned rows = t->rows, cols = t->cols; size_t bytes = t->cols * t->block.size; assert(pipe_linear_check_tile(t)); /* lets write lineary to the tiled buffer */ - for (y = 0; y < t->tiles_y; y++) { - for (x = 0; x < t->tiles_x; x++) { - /* this inner loop could be replace with SSE magic */ - ptr = (char*)src_ptr + src_stride * t->rows * y + bytes * x; - for (z = 0; z < t->rows; z++) { - memcpy(dst_ptr, ptr, bytes); - dst_ptr = (char *)dst_ptr + bytes; - ptr += src_stride; - } + for (x = t->left; x < t->right; x += cols) { + cols = t->cols - x % t->cols; + if (x + cols > t->right) + cols = t->right - x; + ptr = (char*)src_ptr + (x - t->left) * t->block.size; + offset = x / t->cols * t->tile.size + (x % t->cols) * t->block.size; + for (y = t->top; y < t->bottom; y++) { + dst = (char*)dst_ptr + offset + + y / t->rows * t->stride * t->rows + + (y % t->rows) * bytes; + memcpy(dst, ptr, cols * t->block.size); + ptr += src_stride; } } } @@ -30,20 +34,24 @@ pipe_linear_to_tile(size_t src_stride, void *src_ptr, void pipe_linear_from_tile(struct pipe_tile_info *t, void *src_ptr, size_t dst_stride, void *dst_ptr) { - unsigned x, y, z; - char *ptr; + unsigned x, y, offset; + unsigned rows = t->rows, cols = t->cols; + char *ptr, *src; size_t bytes = t->cols * t->block.size; - /* lets read lineary from the tiled buffer */ - for (y = 0; y < t->tiles_y; y++) { - for (x = 0; x < t->tiles_x; x++) { - /* this inner loop could be replace with SSE magic */ - ptr = (char*)dst_ptr + dst_stride * t->rows * y + bytes * x; - for (z = 0; z < t->rows; z++) { - memcpy(ptr, src_ptr, bytes); - src_ptr = (char *)src_ptr + bytes; - ptr += dst_stride; - } + /* lets write lineary to the tiled buffer */ + for (x = t->left; x < t->right; x += cols) { + cols = t->cols - x % t->cols; + if (x + cols > t->right) + cols = t->right - x; + ptr = (char*)dst_ptr + (x - t->left) * t->block.size; + offset = x / t->cols * t->tile.size + (x % t->cols) * t->block.size; + for (y = t->top; y < t->bottom; y++) { + src = (char*)src_ptr + offset + + y / t->rows * t->stride * t->rows + + (y % t->rows) * bytes; + memcpy(ptr, src, cols * t->block.size); + ptr += dst_stride; } } } @@ -52,7 +60,9 @@ void pipe_linear_fill_info(struct pipe_tile_info *t, struct pipe_format_block *block, unsigned tile_width, unsigned tile_height, - unsigned tiles_x, unsigned tiles_y) + unsigned tiles_x, unsigned tiles_y, + unsigned left, unsigned top, + unsigned right, unsigned bottom) { t->block = *block; @@ -66,4 +76,9 @@ pipe_linear_fill_info(struct pipe_tile_info *t, t->tiles_y = tiles_y; t->stride = t->cols * t->tiles_x * t->block.size; t->size = t->tiles_x * t->tiles_y * t->tile.size; + + t->left = left; + t->top = top; + t->right = right; + t->bottom = bottom; } diff --git a/src/gallium/auxiliary/util/u_linear.h b/src/gallium/auxiliary/util/u_linear.h index e337cfd..c213d37 100644 --- a/src/gallium/auxiliary/util/u_linear.h +++ b/src/gallium/auxiliary/util/u_linear.h @@ -12,6 +12,12 @@ struct pipe_tile_info unsigned tiles_x; unsigned tiles_y; + /* The region to be converted */ + unsigned left; + unsigned top; + unsigned right; + unsigned bottom; + /* size of each tile expressed in blocks */ unsigned cols; unsigned rows; @@ -37,11 +43,14 @@ void pipe_linear_from_tile(struct pipe_tile_info *t, void *src_ptr, * @tile_height the height of the tile in pixels * @tiles_x number of tiles in x axis * @tiles_y number of tiles in y axis + * @[left,top,right,bottom] the region to be converted, in pixels */ void pipe_linear_fill_info(struct pipe_tile_info *t, struct pipe_format_block *block, unsigned tile_width, unsigned tile_height, - unsigned tiles_x, unsigned tiles_y); + unsigned tiles_x, unsigned tiles_y, + unsigned left, unsigned top, + unsigned right, unsigned bottom); static INLINE boolean pipe_linear_check_tile(struct pipe_tile_info *t) { diff --git a/src/gallium/include/pipe/p_defines.h b/src/gallium/include/pipe/p_defines.h index a900ed0..ff60c20 100644 --- a/src/gallium/include/pipe/p_defines.h +++ b/src/gallium/include/pipe/p_defines.h @@ -194,6 +194,16 @@ enum pipe_texture_target { /** + * Transfer object usage flags + */ +enum pipe_transfer_usage { + PIPE_TRANSFER_READ, + PIPE_TRANSFER_WRITE, + PIPE_TRANSFER_READ_WRITE /**< Read/modify/write */ +}; + + +/** * Buffer usage flags */ #define PIPE_BUFFER_USAGE_CPU_READ (1 << 0) diff --git a/src/gallium/include/pipe/p_screen.h b/src/gallium/include/pipe/p_screen.h index 492667c..f34cff9 100644 --- a/src/gallium/include/pipe/p_screen.h +++ b/src/gallium/include/pipe/p_screen.h @@ -40,6 +40,7 @@ #include "pipe/p_compiler.h" #include "pipe/p_state.h" +#include "pipe/p_defines.h" @@ -129,6 +130,22 @@ struct pipe_screen { void (*surface_unmap)( struct pipe_screen *, struct pipe_surface *surface ); + /** Get a transfer object for transferring data to/from a texture */ + struct pipe_transfer *(*get_tex_transfer)(struct pipe_screen *, + struct pipe_texture *texture, + unsigned face, unsigned level, + unsigned zslice, + enum pipe_transfer_usage usage, + unsigned x, unsigned y, + unsigned w, unsigned h); + + void (*tex_transfer_destroy)(struct pipe_transfer *); + + void *(*transfer_map)( struct pipe_screen *, + struct pipe_transfer *transfer ); + + void (*transfer_unmap)( struct pipe_screen *, + struct pipe_transfer *transfer ); }; diff --git a/src/gallium/include/pipe/p_state.h b/src/gallium/include/pipe/p_state.h index 13fa9ba..ac60240 100644 --- a/src/gallium/include/pipe/p_state.h +++ b/src/gallium/include/pipe/p_state.h @@ -299,6 +299,28 @@ struct pipe_surface /** + * Transfer object. For data transfer to/from a texture. + */ +struct pipe_transfer +{ + enum pipe_format format; /**< PIPE_FORMAT_x */ + unsigned x; /**< x offset from start of texture image */ + unsigned y; /**< y offset from start of texture image */ + unsigned width; /**< logical width in pixels */ + unsigned height; /**< logical height in pixels */ + struct pipe_format_block block; + unsigned nblocksx; /**< allocated width in blocks */ + unsigned nblocksy; /**< allocated height in blocks */ + unsigned stride; /**< stride in bytes between rows of blocks */ + unsigned usage; /**< PIPE_TRANSFER_* */ + + struct pipe_texture *texture; /**< texture to transfer to/from */ + unsigned face; + unsigned level; + unsigned zslice; +}; + +/** * Texture object. */ struct pipe_texture diff --git a/src/mesa/state_tracker/st_cb_readpixels.c b/src/mesa/state_tracker/st_cb_readpixels.c index 646eaff..f3e60dd 100644 --- a/src/mesa/state_tracker/st_cb_readpixels.c +++ b/src/mesa/state_tracker/st_cb_readpixels.c @@ -45,6 +45,7 @@ #include "st_context.h" #include "st_cb_bitmap.h" #include "st_cb_readpixels.h" +#include "st_cb_bufferobjects.h" #include "st_cb_fbo.h" #include "st_format.h" #include "st_public.h" @@ -167,6 +168,238 @@ st_get_color_read_renderbuffer(GLcontext *ctx) * \return GL_TRUE for success, GL_FALSE for failure */ static GLboolean +st_accelerated_readpixels(GLcontext *ctx, struct st_renderbuffer *strb, + GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *pack, + GLvoid *dest) +{ + struct pipe_context *pipe = ctx->st->pipe; + struct pipe_screen *screen = pipe->screen; + GLfloat temp[MAX_WIDTH][4]; + const GLubyte *map; + GLubyte *dst; + GLint row, col, dy, dstStride; + struct gl_pixelstore_attrib clippedPacking = *pack; + struct pipe_transfer *trans; + struct st_buffer_object *st_obj = st_buffer_object(pack->BufferObj); + boolean do_flip = (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP); + + enum combination { + A8R8G8B8_UNORM_TO_RGBA_UBYTE, + A8R8G8B8_UNORM_TO_RGB_UBYTE, + A8R8G8B8_UNORM_TO_BGRA_UINT, + A8R8G8B8_UNORM_TO_FLOAT + } combo; + + if (ctx->_ImageTransferState) + return GL_FALSE; + + if (strb->format != PIPE_FORMAT_A8R8G8B8_UNORM) + return GL_FALSE; + + if (format == GL_RGBA && + ((type == GL_UNSIGNED_BYTE) || (type == GL_UNSIGNED_INT_8_8_8_8))) { + combo = A8R8G8B8_UNORM_TO_RGBA_UBYTE; + } + else if (format == GL_RGB && type == GL_UNSIGNED_BYTE) { + combo = A8R8G8B8_UNORM_TO_RGB_UBYTE; + } + else if (format == GL_BGRA && type == GL_UNSIGNED_INT_8_8_8_8_REV) { + combo = A8R8G8B8_UNORM_TO_BGRA_UINT; + } + else if (type == GL_FLOAT) { + combo = A8R8G8B8_UNORM_TO_FLOAT; + } + else { + return GL_FALSE; + } + + /* Try issue a copy to PBO if possible */ + if (st_obj && ( + (combo == A8R8G8B8_UNORM_TO_RGBA_UBYTE) || + (combo == A8R8G8B8_UNORM_TO_BGRA_UINT))) { + struct pipe_surface *surface = NULL; + struct pipe_surface *surf = NULL; + struct pipe_texture template; + struct pipe_texture *tex; + GLuint stride = (width * 4); + + surf = screen->get_tex_surface(screen, strb->texture, 0, 0, 0, + PIPE_BUFFER_USAGE_GPU_READ); + if (!surf) { + return GL_FALSE; + } + + template.target = PIPE_TEXTURE_2D; + template.compressed = 0; + template.format = st_choose_format(pipe, GL_RGBA, PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_RENDER_TARGET); + if (template.format != PIPE_FORMAT_NONE) { + pipe_surface_reference(&surf, NULL); + return GL_FALSE; + } + pf_get_block(template.format, &template.block); + template.width[0] = width; + template.height[0] = height; + template.depth[0] = 1; + template.last_level = 0; + template.tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET; + + tex = pipe->screen->texture_blanket( pipe->screen, + &template, + &stride, + st_obj->buffer ); + if (!tex) { + pipe_surface_reference(&surf, NULL); + return GL_FALSE; + } + + surface = pipe->screen->get_tex_surface( pipe->screen, + tex, 0, 0, 0, + PIPE_BUFFER_USAGE_GPU_WRITE ); + + if (!surface) { + pipe_texture_reference(&tex, NULL); + pipe_surface_reference(&surf, NULL); + return GL_FALSE; + } + + pipe->surface_copy(pipe, + do_flip, + /* dest */ + surface, + 0, 0, + /* src */ + surf, + x, y, + /* size */ + width, height); + + pipe_surface_reference(&surface, NULL); + pipe_texture_reference(&tex, NULL); + pipe_surface_reference(&surf, NULL); + + return GL_TRUE; + } + + if (!screen->get_tex_transfer || + !screen->tex_transfer_destroy || + !screen->transfer_map || + !screen->transfer_unmap) { + return GL_FALSE; + } + + if (do_flip) { + y = strb->texture->height[0] - y - height; + } + + trans = screen->get_tex_transfer(screen, strb->texture, + 0, 0, 0, + PIPE_TRANSFER_READ, x, y, + width, height); + if (!trans) { + return GL_FALSE; + } + + map = screen->transfer_map(screen, trans); + if (!map) { + screen->tex_transfer_destroy(trans); + return GL_FALSE; + } + + if (do_flip) { + y = height - 1; + dy = -1; + } + else { + y = 0; + dy = 1; + } + + dest = _mesa_map_readpix_pbo(ctx, &clippedPacking, dest); + if (!dest) + return GL_FALSE; + + dst = _mesa_image_address2d(pack, dest, width, height, + format, type, 0, 0); + dstStride = _mesa_image_row_stride(pack, width, format, type); + + switch (combo) { + case A8R8G8B8_UNORM_TO_RGBA_UBYTE: + for (row = 0; row < height; row++) { + const GLubyte *src = map + y * trans->stride; + for (col = 0; col < width; col++) { + GLuint pixel = ((GLuint *) src)[col]; + dst[col*4+0] = (pixel >> 16) & 0xff; + dst[col*4+1] = (pixel >> 8) & 0xff; + dst[col*4+2] = (pixel >> 0) & 0xff; + dst[col*4+3] = (pixel >> 24) & 0xff; + } + dst += dstStride; + y += dy; + } + break; + case A8R8G8B8_UNORM_TO_RGB_UBYTE: + for (row = 0; row < height; row++) { + const GLubyte *src = map + y * trans->stride; + for (col = 0; col < width; col++) { + GLuint pixel = ((GLuint *) src)[col]; + dst[col*3+0] = (pixel >> 16) & 0xff; + dst[col*3+1] = (pixel >> 8) & 0xff; + dst[col*3+2] = (pixel >> 0) & 0xff; + } + dst += dstStride; + y += dy; + } + break; + case A8R8G8B8_UNORM_TO_BGRA_UINT: + for (row = 0; row < height; row++) { + const GLubyte *src = map + y * trans->stride; + memcpy(dst, src, 4 * width); + dst += dstStride; + y += dy; + } + break; + case A8R8G8B8_UNORM_TO_FLOAT: + if (format == GL_RGBA) { + /* write tile(row) directly into user's buffer */ + for (row = 0; row < height; row++) { + const GLubyte *src = map + y * trans->stride; + pipe_tile_raw_to_rgba(strb->format, src, width, 1, dst, dstStride); + dst += dstStride; + y += dy; + } + } + else { + for (row = 0; row < height; row++) { + const GLubyte *src = map + y * trans->stride; + pipe_tile_raw_to_rgba(strb->format, src, width, 1, temp, dstStride); + _mesa_pack_rgba_span_float(ctx, width, temp, format, type, dst, + &clippedPacking, 0); + dst += dstStride; + y += dy; + } + } + break; + default: + ; /* nothing */ + } + + _mesa_unmap_readpix_pbo(ctx, &clippedPacking); + + screen->transfer_unmap(screen, trans); + screen->tex_transfer_destroy(trans); + + return GL_TRUE; +} + + +/** + * Try to do glReadPixels in a fast manner for common cases. + * \return GL_TRUE for success, GL_FALSE for failure + */ +static GLboolean st_fast_readpixels(GLcontext *ctx, struct st_renderbuffer *strb, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, @@ -313,15 +546,17 @@ st_readpixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height, return; } - dest = _mesa_map_readpix_pbo(ctx, &clippedPacking, dest); - if (!dest) - return; - /* make sure rendering has completed */ st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL); if (format == GL_STENCIL_INDEX) { + dest = _mesa_map_readpix_pbo(ctx, &clippedPacking, dest); + if (!dest) + return; + st_read_stencil_pixels(ctx, x, y, width, height, type, pack, dest); + + _mesa_unmap_readpix_pbo(ctx, &clippedPacking); return; } else if (format == GL_DEPTH_COMPONENT) { @@ -335,6 +570,15 @@ st_readpixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height, if (!strb) return; + /* try an accelerated readpixels before anything else */ + if (st_accelerated_readpixels(ctx, strb, x, y, width, height, + format, type, pack, dest)) + return; + + dest = _mesa_map_readpix_pbo(ctx, &clippedPacking, dest); + if (!dest) + return; + /* try a fast-path readpixels before anything else */ if (st_fast_readpixels(ctx, strb, x, y, width, height, format, type, pack, dest)) { _______________________________________________ mesa-commit mailing list mesa-commit@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-commit