summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlan Hourihane <alanh@vmware.com>2009-06-15 15:59:57 +0100
committerAlan Hourihane <alanh@vmware.com>2009-06-15 15:59:57 +0100
commitae22ad765843c19d4c853277416a6d52d9918c83 (patch)
tree2aa135bc5e18d5143a8ca23d09466033e71a68aa /src
parent29b822e4cf9626d3f0b8105375a2c0954e653e12 (diff)
add patches from bug 21997
Diffstat (limited to 'src')
-rw-r--r--src/gallium/auxiliary/util/u_linear.c63
-rw-r--r--src/gallium/auxiliary/util/u_linear.h11
-rw-r--r--src/gallium/include/pipe/p_defines.h10
-rw-r--r--src/gallium/include/pipe/p_screen.h17
-rw-r--r--src/gallium/include/pipe/p_state.h22
-rw-r--r--src/mesa/state_tracker/st_cb_readpixels.c252
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 ff7645ac91a..34a7ff34f88 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 e337cfd7702..c213d370810 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 a900ed0dc4d..ff60c20f91e 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 492667c93ac..f34cff93cec 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 13fa9ba848c..ac6024012fd 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 646eaff1903..f3e60dd6ae1 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)) {