summaryrefslogtreecommitdiff
path: root/src/gallium/drivers/llvmpipe/lp_texture.c
diff options
context:
space:
mode:
authorBrian Paul <brianp@vmware.com>2010-04-16 09:10:54 -0600
committerBrian Paul <brianp@vmware.com>2010-04-16 09:25:44 -0600
commit0639765b2850739af1678f10fc0c5706d5827776 (patch)
treedd83a7abaeae23f39f780dad327840b0e12e297b /src/gallium/drivers/llvmpipe/lp_texture.c
parent97831efdb02ad68c70602a5b3a68c024e49e5715 (diff)
Merge the lp-surface-tiling branch into master.
This branch implemented dual representations of texture/drawing surfaces: one in the conventional linear layout and the other the tiled layout which is used by the fragment shader pipe. Per-tile flags indicate the layout of each image tile. In many situations this lets us avoid converting image data between the two layouts. Squashed commit of the following: commit 563a7e3cc552fdcfcaf9ac0d4b1683c3ba2ae732 Author: Brian Paul <brianp@vmware.com> Date: Thu Apr 8 14:48:21 2010 -0600 llvmpipe: convert points/lines to triangles with draw module This isn't the most efficient way to render points/lines but it allows us to run more tests. commit a8aa763e8a717533f2b13bb6ea53cbccbede68c9 Author: Brian Paul <brianp@vmware.com> Date: Thu Apr 8 14:47:28 2010 -0600 llvmpipe: call llvmpipe_get_texture_tile() for depth/stencil The returned pointer isn't used, but the tile status/layout info gets updated. Helps to fix glReadPixels(DEPTH / STENCIL). commit 463bc64af266194acbea71cd52e26a79b8c8a260 Author: Brian Paul <brianp@vmware.com> Date: Thu Apr 8 10:58:48 2010 -0600 llvmpipe: add store_color to debug cmd_names list commit 784cc73fb334a9d7b7c93cbd8a1445cdf742ff58 Author: Brian Paul <brianp@vmware.com> Date: Thu Apr 8 10:57:43 2010 -0600 llvmpipe: fix debug build commit 792c93171ec075664f55720ffed397ac2834a4fc Author: Brian Paul <brianp@vmware.com> Date: Thu Apr 8 10:49:01 2010 -0600 llvmpipe: fix cube mapping commit 882b1035db88c3dd8aebe28dc971ac30a9ee39e3 Author: Brian Paul <brianp@vmware.com> Date: Thu Apr 8 09:53:30 2010 -0600 llvmpipe: remove some older/unused code commit b807d32b23145301e8842824664d9f06b9c5502e Author: Brian Paul <brianp@vmware.com> Date: Thu Apr 8 09:29:50 2010 -0600 llvmpipe: silence warning commit 7b337e64fec92836ccdf9d96216289dd58418e35 Author: Brian Paul <brianp@vmware.com> Date: Wed Apr 7 17:06:08 2010 -0600 llvmpipe: clean-up, comments in lp_surface_copy() commit c52fa36f249cc652fa8d5fdd94d6574127c08c41 Author: Brian Paul <brianp@vmware.com> Date: Wed Apr 7 16:51:42 2010 -0600 llvmpipe: overhaul tiled/linear memory management Now we keep per-tile layout info (linear vs. tiled (or neither or both) and convert from one layout to the other on demand. commit 4a50ccfd470547c9be0704005818a87014e9c0e9 Author: Brian Paul <brianp@vmware.com> Date: Wed Apr 7 16:51:27 2010 -0600 llvmpipe: added tile read/write counters commit b7d0ea9c687ac8773b083791623826fa604adf21 Author: Brian Paul <brianp@vmware.com> Date: Mon Apr 5 14:54:04 2010 -0600 llvmpipe: rename some functions commit ee45c6e5b95cbd3c8cccc9aa4d45d8aef11e20c4 Author: Brian Paul <brianp@vmware.com> Date: Mon Apr 5 14:42:15 2010 -0600 llvmpipe: re-org some get block/tile pointer code commit 26ce97c16c0b6520ff1538803baa772d8c3b1280 Author: Brian Paul <brianp@vmware.com> Date: Mon Apr 5 14:34:13 2010 -0600 llvmpipe: disable bad assertions commit 5c670481248c4d46f87f13bf3af5655925e7002d Author: Brian Paul <brianp@vmware.com> Date: Fri Apr 2 16:36:11 2010 -0600 llvmpipe: add a special-case optimization to lp_surface_copy() Be more efficient when copying tiled image to linear image. Before, the fallback path was always converting the whole source image to linear. Now we can convert just a sub region. commit faa684645e64d6024b3a11e4e08da825e8220b2e Author: Brian Paul <brianp@vmware.com> Date: Fri Apr 2 16:15:16 2010 -0600 llvmpipe: assorted texture and tile/line conversion code change s The tiled/linear conversion functions take x/y positions now to allow converting only sub-regions. More texture-related helper functions. commit baad81ec5318d44bfac1e37c7643afc0836607bb Author: Brian Paul <brianp@vmware.com> Date: Tue Mar 30 13:18:40 2010 -0600 llvmpipe: convert tiled->linear upon PIPE_FLUSH_SWAPBUFFERS If we know we're about to do a swapbuffers we should immediately convert the tiled color tiles to linear instead of later in llvmpipe_texture_unmap() since we can take advantage of threading/ parallelism here. commit 928dd41256811daeddb7506a49a34dbad04beaf8 Author: Brian Paul <brianp@vmware.com> Date: Tue Mar 30 09:16:58 2010 -0600 llvmpipe: polish-up the llvmpipe_flush() code commit dd6014abcf86c517d159b8175e0eaeb167ea2ef6 Author: Brian Paul <brianp@vmware.com> Date: Tue Mar 30 09:15:17 2010 -0600 llvmpipe: SETUP_x enum clean-up commit 0b1ce6da2b28a41f3389685ab93e10b43c950f5d Author: Brian Paul <brianp@vmware.com> Date: Fri Mar 26 10:43:37 2010 -0600 llvmpipe: remove unused vars commit 4562663480f88162ed4452cb05569eecb67f9f39 Author: Brian Paul <brianp@vmware.com> Date: Fri Mar 26 10:31:55 2010 -0600 llvmpipe: cope with non-existant color/depth buffers The fragment jit functions always grab these pointers, even if they're not used. commit df4329edbaf204ed501f1eac0698b8198178f9af Author: Brian Paul <brianp@vmware.com> Date: Thu Mar 25 15:20:15 2010 -0600 llvmpipe: do all render target surface mapping/unmapping in the rast code commit 3d0c25d5ba8b8f61e8366d4c97324e45d526ff41 Author: Brian Paul <brianp@vmware.com> Date: Thu Mar 25 14:31:21 2010 -0600 llvmpipe: map z/stencil buffer on demand like color buffers Plus lots of code clean-up and loose ends taken care of. commit c3b6fddd788aef09b4b84b843b7b1272231151e8 Author: Brian Paul <brianp@vmware.com> Date: Thu Mar 25 13:15:03 2010 -0600 llvmpipe: remove unused write_zstencil field commit 63374d97836926a6357e9d6dd24a509a8e155c56 Author: Brian Paul <brianp@vmware.com> Date: Thu Mar 25 09:45:59 2010 -0600 llvmpipe: add missing lp_rast_end() call Fixes crash on window resize when LP_NUM_THREADS=0. commit 92fe9952161cc06f6edc58778e9e5a8b9ea447dc Author: Brian Paul <brianp@vmware.com> Date: Wed Mar 24 10:15:19 2010 -0600 llvmpipe: add tiled/linear conversion for 16-bit Z images commit 6605fa28c147f30df351da0e4413cab33e4db5da Author: Brian Paul <brianp@vmware.com> Date: Tue Mar 23 16:06:41 2010 -0600 llvmpipe: implement tiled/linear conversion for Z/stencil images commit 804528d84ffa292ef9d49d3666cdd3fa099ff3ff Author: Brian Paul <brianp@vmware.com> Date: Tue Mar 23 16:05:45 2010 -0600 llvmpipe: added texture stride comment commit 66a88c012edf670c4ac887a912f02dcff93266dd Author: Brian Paul <brianp@vmware.com> Date: Tue Mar 23 16:04:07 2010 -0600 llvmpipe: remove unused vars commit e2ca8d1328316dc8b36d5f688c16d109e49a6870 Author: Brian Paul <brianp@vmware.com> Date: Mon Mar 22 18:53:11 2010 -0600 llvmpipe: checkpoint WIP: overhaul texture/surface mapping Conversion between tiled and linear surfaces is working everywhere now. The LP_TEXTURE_READ/READ_WRITE/WRITE_ALL flags let us avoid unnecessary image layout conversions. Still some loose ends, temporary/debug code, etc. Need to implement tiled/linear conversion for depth/stencil images. commit f2730a03839ee8984c1f537b7cbebba24961397a Author: Brian Paul <brianp@vmware.com> Date: Mon Mar 22 14:41:58 2010 -0600 llvmpipe: rename/repurpose lp_rast_store_color() commit e192a47552c5d20d2caef452ca7697e2cd852c9b Author: Brian Paul <brianp@vmware.com> Date: Mon Mar 22 14:38:51 2010 -0600 llvmpipe: remove lp_rast_load_color() commit 3cff0bde4b4ab980e1c3e812700419091527c76b Author: Brian Paul <brianp@vmware.com> Date: Mon Mar 22 14:11:38 2010 -0600 llvmpipe: remove/consolidate texture image code commit 3a2f08b6a550c69ef5e874f482be30252cbf8bfa Author: Brian Paul <brianp@vmware.com> Date: Fri Mar 19 17:03:14 2010 -0600 llvmpipe: checkpoint WIP: directly render to tiled texture buffers We're now directly writing colors into the tiled texture image buffers. This is a checkpoint commit with lots of dead code and temporary hacks. Everything will get cleaned up eventually. commit c5ca987e03870849514d4e3c99af143722a09695 Author: Brian Paul <brianp@vmware.com> Date: Fri Mar 19 16:41:14 2010 -0600 llvmpipe: refactor code, create tile_pixel_offset() commit 2133e8273e937cbac09cd7264d6ce53af9764ddb Author: Brian Paul <brianp@vmware.com> Date: Fri Mar 19 14:55:11 2010 -0600 llvmpipe: pass LP_TEXTURE_LINEAR/TILED flags around commit b9b9d4b82b01f4588721fdc8444740f859b4a021 Author: Brian Paul <brianp@vmware.com> Date: Fri Mar 19 14:51:05 2010 -0600 llvmpipe: checkpoint WIP: hanlde co-existing tiled/linear texture data Cube maps are temporarily broken, maybe other things. commit 4cd322e6889940b5f155fcb69041b685b9ef9273 Author: Brian Paul <brianp@vmware.com> Date: Fri Mar 19 11:34:43 2010 -0600 progs/demos: add other modes/patterns to dissolve demo
Diffstat (limited to 'src/gallium/drivers/llvmpipe/lp_texture.c')
-rw-r--r--src/gallium/drivers/llvmpipe/lp_texture.c648
1 files changed, 601 insertions, 47 deletions
diff --git a/src/gallium/drivers/llvmpipe/lp_texture.c b/src/gallium/drivers/llvmpipe/lp_texture.c
index 61210de890..7e4e4d5f0b 100644
--- a/src/gallium/drivers/llvmpipe/lp_texture.c
+++ b/src/gallium/drivers/llvmpipe/lp_texture.c
@@ -30,64 +30,101 @@
* Michel Dänzer <michel@tungstengraphics.com>
*/
+#include <stdio.h>
+
#include "pipe/p_context.h"
#include "pipe/p_defines.h"
-#include "util/u_inlines.h"
+#include "util/u_inlines.h"
#include "util/u_format.h"
#include "util/u_math.h"
#include "util/u_memory.h"
#include "util/u_transfer.h"
#include "lp_context.h"
-#include "lp_screen.h"
#include "lp_flush.h"
+#include "lp_screen.h"
+#include "lp_tile_image.h"
#include "lp_texture.h"
#include "lp_setup.h"
#include "lp_tile_size.h"
+
#include "state_tracker/sw_winsys.h"
+static INLINE boolean
+resource_is_texture(const struct pipe_resource *resource)
+{
+ const unsigned tex_binds = (PIPE_BIND_DISPLAY_TARGET |
+ PIPE_BIND_SCANOUT |
+ PIPE_BIND_SHARED |
+ PIPE_BIND_DEPTH_STENCIL |
+ PIPE_BIND_SAMPLER_VIEW);
+ const struct llvmpipe_resource *lpt = llvmpipe_resource_const(resource);
+
+ return (lpt->base.bind & tex_binds) ? TRUE : FALSE;
+}
+
+
+
+/**
+ * Allocate storage for llvmpipe_texture::layout array.
+ * The number of elements is width_in_tiles * height_in_tiles.
+ */
+static enum lp_texture_layout *
+alloc_layout_array(unsigned width, unsigned height)
+{
+ const unsigned tx = align(width, TILE_SIZE) / TILE_SIZE;
+ const unsigned ty = align(height, TILE_SIZE) / TILE_SIZE;
+
+ assert(tx * ty > 0);
+ assert(LP_TEX_LAYOUT_NONE == 0); /* calloc'ing LP_TEX_LAYOUT_NONE here */
+
+ return (enum lp_texture_layout *)
+ calloc(tx * ty, sizeof(enum lp_texture_layout));
+}
+
+
+
/**
* Conventional allocation path for non-display textures:
- * Simple, maximally packed layout.
+ * Just compute row strides here. Storage is allocated on demand later.
*/
static boolean
-llvmpipe_resource_layout(struct llvmpipe_screen *screen,
+llvmpipe_texture_layout(struct llvmpipe_screen *screen,
struct llvmpipe_resource *lpt)
{
struct pipe_resource *pt = &lpt->base;
unsigned level;
unsigned width = pt->width0;
unsigned height = pt->height0;
- unsigned depth = pt->depth0;
- unsigned buffer_size = 0;
+
+ assert(LP_MAX_TEXTURE_2D_LEVELS <= LP_MAX_TEXTURE_LEVELS);
+ assert(LP_MAX_TEXTURE_3D_LEVELS <= LP_MAX_TEXTURE_LEVELS);
for (level = 0; level <= pt->last_level; level++) {
- unsigned nblocksx, nblocksy;
+ const unsigned num_faces = lpt->base.target == PIPE_TEXTURE_CUBE ? 6 : 1;
+ unsigned nblocksx, face;
/* Allocate storage for whole quads. This is particularly important
* for depth surfaces, which are currently stored in a swizzled format.
*/
nblocksx = util_format_get_nblocksx(pt->format, align(width, TILE_SIZE));
- nblocksy = util_format_get_nblocksy(pt->format, align(height, TILE_SIZE));
- lpt->stride[level] = align(nblocksx * util_format_get_blocksize(pt->format), 16);
+ lpt->stride[level] =
+ align(nblocksx * util_format_get_blocksize(pt->format), 16);
- lpt->level_offset[level] = buffer_size;
+ lpt->tiles_per_row[level] = align(width, TILE_SIZE) / TILE_SIZE;
- buffer_size += (nblocksy *
- ((pt->target == PIPE_TEXTURE_CUBE) ? 6 : depth) *
- lpt->stride[level]);
+ for (face = 0; face < num_faces; face++) {
+ lpt->layout[face][level] = alloc_layout_array(width, height);
+ }
width = u_minify(width, 1);
height = u_minify(height, 1);
- depth = u_minify(depth, 1);
}
- lpt->data = align_malloc(buffer_size, 16);
-
- return lpt->data != NULL;
+ return TRUE;
}
@@ -104,6 +141,10 @@ llvmpipe_displaytarget_layout(struct llvmpipe_screen *screen,
unsigned width = align(lpt->base.width0, TILE_SIZE);
unsigned height = align(lpt->base.height0, TILE_SIZE);
+ lpt->tiles_per_row[0] = align(width, TILE_SIZE) / TILE_SIZE;
+
+ lpt->layout[0][0] = alloc_layout_array(width, height);
+
lpt->dt = winsys->displaytarget_create(winsys,
lpt->base.bind,
lpt->base.format,
@@ -117,8 +158,9 @@ llvmpipe_displaytarget_layout(struct llvmpipe_screen *screen,
static struct pipe_resource *
llvmpipe_resource_create(struct pipe_screen *_screen,
- const struct pipe_resource *templat)
+ const struct pipe_resource *templat)
{
+ static unsigned id_counter = 0;
struct llvmpipe_screen *screen = llvmpipe_screen(_screen);
struct llvmpipe_resource *lpt = CALLOC_STRUCT(llvmpipe_resource);
if (!lpt)
@@ -128,17 +170,38 @@ llvmpipe_resource_create(struct pipe_screen *_screen,
pipe_reference_init(&lpt->base.reference, 1);
lpt->base.screen = &screen->base;
+ assert(lpt->base.bind);
+
if (lpt->base.bind & (PIPE_BIND_DISPLAY_TARGET |
PIPE_BIND_SCANOUT |
PIPE_BIND_SHARED)) {
+ /* displayable surface */
if (!llvmpipe_displaytarget_layout(screen, lpt))
goto fail;
+ assert(lpt->layout[0][0][0] == LP_TEX_LAYOUT_NONE);
+ }
+ else if (lpt->base.bind & (PIPE_BIND_SAMPLER_VIEW |
+ PIPE_BIND_DEPTH_STENCIL)) {
+ /* texture map */
+ if (!llvmpipe_texture_layout(screen, lpt))
+ goto fail;
+ assert(lpt->layout[0][0][0] == LP_TEX_LAYOUT_NONE);
}
else {
- if (!llvmpipe_resource_layout(screen, lpt))
+ /* other data (vertex buffer, const buffer, etc) */
+ const enum pipe_format format = templat->format;
+ const uint w = templat->width0 / util_format_get_blockheight(format);
+ const uint h = templat->height0 / util_format_get_blockwidth(format);
+ const uint d = templat->depth0;
+ const uint bpp = util_format_get_blocksize(format);
+ const uint bytes = w * h * d * bpp;
+ lpt->data = align_malloc(bytes, 16);
+ if (!lpt->data)
goto fail;
}
+ lpt->id = id_counter++;
+
return &lpt->base;
fail:
@@ -159,8 +222,37 @@ llvmpipe_resource_destroy(struct pipe_screen *pscreen,
struct sw_winsys *winsys = screen->winsys;
winsys->displaytarget_destroy(winsys, lpt->dt);
}
- else if (!lpt->userBuffer) {
+ else if (resource_is_texture(pt)) {
/* regular texture */
+ const uint num_faces = pt->target == PIPE_TEXTURE_CUBE ? 6 : 1;
+ uint level, face;
+
+ /* free linear image data */
+ for (level = 0; level < Elements(lpt->linear); level++) {
+ if (lpt->linear[level].data) {
+ align_free(lpt->linear[level].data);
+ lpt->linear[level].data = NULL;
+ }
+ }
+
+ /* free tiled image data */
+ for (level = 0; level < Elements(lpt->tiled); level++) {
+ if (lpt->tiled[level].data) {
+ align_free(lpt->tiled[level].data);
+ lpt->tiled[level].data = NULL;
+ }
+ }
+
+ /* free layout flag arrays */
+ for (level = 0; level < Elements(lpt->tiled); level++) {
+ for (face = 0; face < num_faces; face++) {
+ free(lpt->layout[face][level]);
+ lpt->layout[face][level] = NULL;
+ }
+ }
+ }
+ else if (!lpt->userBuffer) {
+ assert(lpt->data);
align_free(lpt->data);
}
@@ -169,63 +261,88 @@ llvmpipe_resource_destroy(struct pipe_screen *pscreen,
/**
- * Map a texture. Without any synchronization.
+ * Map a texture for read/write (rendering). Without any synchronization.
*/
void *
llvmpipe_resource_map(struct pipe_resource *texture,
- unsigned usage,
unsigned face,
unsigned level,
- unsigned zslice)
+ unsigned zslice,
+ enum lp_texture_usage tex_usage,
+ enum lp_texture_layout layout)
{
struct llvmpipe_resource *lpt = llvmpipe_resource(texture);
uint8_t *map;
+ assert(face < 6);
+ assert(level < LP_MAX_TEXTURE_LEVELS);
+
+ assert(tex_usage == LP_TEX_USAGE_READ ||
+ tex_usage == LP_TEX_USAGE_READ_WRITE ||
+ tex_usage == LP_TEX_USAGE_WRITE_ALL);
+
+ assert(layout == LP_TEX_LAYOUT_NONE ||
+ layout == LP_TEX_LAYOUT_TILED ||
+ layout == LP_TEX_LAYOUT_LINEAR);
+
if (lpt->dt) {
/* display target */
struct llvmpipe_screen *screen = llvmpipe_screen(texture->screen);
struct sw_winsys *winsys = screen->winsys;
+ unsigned dt_usage;
+
+ if (tex_usage == LP_TEX_USAGE_READ) {
+ dt_usage = PIPE_TRANSFER_READ;
+ }
+ else {
+ dt_usage = PIPE_TRANSFER_READ_WRITE;
+ }
assert(face == 0);
assert(level == 0);
assert(zslice == 0);
/* FIXME: keep map count? */
- map = winsys->displaytarget_map(winsys, lpt->dt, usage);
- }
- else {
- /* regular texture */
- unsigned offset;
- unsigned stride;
+ map = winsys->displaytarget_map(winsys, lpt->dt, dt_usage);
- map = lpt->data;
+ /* install this linear image in texture data structure */
+ lpt->linear[level].data = map;
- assert(level < LP_MAX_TEXTURE_2D_LEVELS);
+ map = llvmpipe_get_texture_image(lpt, face, level, tex_usage, layout);
+ assert(map);
- offset = lpt->level_offset[level];
- stride = lpt->stride[level];
+ return map;
+ }
+ else if (resource_is_texture(texture)) {
+ /* regular texture */
+ const unsigned tex_height = u_minify(texture->height0, level);
+ const unsigned nblocksy =
+ util_format_get_nblocksy(texture->format, tex_height);
+ const unsigned stride = lpt->stride[level];
+ unsigned offset = 0;
- /* XXX shouldn't that rather be
- tex_height = align(u_minify(texture->height0, level), 2)
- to account for alignment done in llvmpipe_resource_layout ?
- */
if (texture->target == PIPE_TEXTURE_CUBE) {
- unsigned tex_height = u_minify(texture->height0, level);
- offset += face * util_format_get_nblocksy(texture->format, tex_height) * stride;
+ /* XXX incorrect
+ offset = face * nblocksy * stride;
+ */
}
else if (texture->target == PIPE_TEXTURE_3D) {
- unsigned tex_height = u_minify(texture->height0, level);
- offset += zslice * util_format_get_nblocksy(texture->format, tex_height) * stride;
+ offset = zslice * nblocksy * stride;
}
else {
assert(face == 0);
assert(zslice == 0);
+ offset = 0;
}
+ map = llvmpipe_get_texture_image(lpt, face, level, tex_usage, layout);
+ assert(map);
map += offset;
+ return map;
+ }
+ else {
+ return lpt->data;
}
-
- return map;
}
@@ -249,11 +366,30 @@ llvmpipe_resource_unmap(struct pipe_resource *texture,
assert(level == 0);
assert(zslice == 0);
+ /* make sure linear image is up to date */
+ (void) llvmpipe_get_texture_image(lpt, 0, 0,
+ LP_TEX_USAGE_READ,
+ LP_TEX_LAYOUT_LINEAR);
+
winsys->displaytarget_unmap(winsys, lpt->dt);
}
}
+void *
+llvmpipe_resource_data(struct pipe_resource *resource)
+{
+ struct llvmpipe_resource *lpt = llvmpipe_resource(resource);
+
+ assert((lpt->base.bind & (PIPE_BIND_DISPLAY_TARGET |
+ PIPE_BIND_SCANOUT |
+ PIPE_BIND_SHARED |
+ PIPE_BIND_SAMPLER_VIEW)) == 0);
+
+ return lpt->data;
+}
+
+
static struct pipe_resource *
llvmpipe_resource_from_handle(struct pipe_screen *screen,
const struct pipe_resource *template,
@@ -303,7 +439,7 @@ static struct pipe_surface *
llvmpipe_get_tex_surface(struct pipe_screen *screen,
struct pipe_resource *pt,
unsigned face, unsigned level, unsigned zslice,
- unsigned usage)
+ enum lp_texture_usage usage)
{
struct pipe_surface *ps;
@@ -389,6 +525,34 @@ llvmpipe_transfer_map( struct pipe_context *pipe,
ubyte *map;
struct llvmpipe_resource *lpt;
enum pipe_format format;
+ enum lp_texture_usage tex_usage;
+ const char *mode;
+
+ assert(transfer->sr.face < 6);
+ assert(transfer->sr.level < LP_MAX_TEXTURE_LEVELS);
+
+ /*
+ printf("tex_transfer_map(%d, %d %d x %d of %d x %d, usage %d )\n",
+ transfer->x, transfer->y, transfer->width, transfer->height,
+ transfer->texture->width0,
+ transfer->texture->height0,
+ transfer->usage);
+ */
+
+ if (transfer->usage == PIPE_TRANSFER_READ) {
+ tex_usage = LP_TEX_USAGE_READ;
+ mode = "read";
+ }
+ else {
+ tex_usage = LP_TEX_USAGE_READ_WRITE;
+ mode = "read/write";
+ }
+
+ if (0) {
+ struct llvmpipe_resource *lpt = llvmpipe_resource(transfer->resource);
+ printf("transfer map tex %u mode %s\n", lpt->id, mode);
+ }
+
assert(transfer->resource);
lpt = llvmpipe_resource(transfer->resource);
@@ -408,12 +572,13 @@ llvmpipe_transfer_map( struct pipe_context *pipe,
FALSE); /* do_not_flush */
map = llvmpipe_resource_map(transfer->resource,
- transfer->usage,
transfer->sr.face,
transfer->sr.level,
- transfer->box.z);
+ transfer->box.z,
+ tex_usage, LP_TEX_LAYOUT_LINEAR);
+
- /* May want to different things here depending on read/write nature
+ /* May want to do different things here depending on read/write nature
* of the map:
*/
if (transfer->usage & PIPE_TRANSFER_WRITE) {
@@ -488,6 +653,395 @@ llvmpipe_user_buffer_create(struct pipe_screen *screen,
}
+/**
+ * Compute size (in bytes) need to store a texture image / mipmap level,
+ * for just one cube face.
+ */
+static unsigned
+tex_image_face_size(const struct llvmpipe_resource *lpt, unsigned level,
+ enum lp_texture_layout layout)
+{
+ /* for tiled layout, force a 32bpp format */
+ enum pipe_format format = layout == LP_TEX_LAYOUT_TILED
+ ? PIPE_FORMAT_B8G8R8A8_UNORM : lpt->base.format;
+ const unsigned height = u_minify(lpt->base.height0, level);
+ const unsigned depth = u_minify(lpt->base.depth0, level);
+ const unsigned nblocksy =
+ util_format_get_nblocksy(format, align(height, TILE_SIZE));
+ const unsigned buffer_size =
+ nblocksy * lpt->stride[level] *
+ (lpt->base.target == PIPE_TEXTURE_3D ? depth : 1);
+ return buffer_size;
+}
+
+
+/**
+ * Compute size (in bytes) need to store a texture image / mipmap level,
+ * including all cube faces.
+ */
+static unsigned
+tex_image_size(const struct llvmpipe_resource *lpt, unsigned level,
+ enum lp_texture_layout layout)
+{
+ const unsigned buf_size = tex_image_face_size(lpt, level, layout);
+ const unsigned num_faces = lpt->base.target == PIPE_TEXTURE_CUBE ? 6 : 1;
+ return buf_size * num_faces;
+}
+
+
+/**
+ * This function encapsulates some complicated logic for determining
+ * how to convert a tile of image data from linear layout to tiled
+ * layout, or vice versa.
+ * \param cur_layout the current tile layout
+ * \param target_layout the desired tile layout
+ * \param usage how the tile will be accessed (R/W vs. read-only, etc)
+ * \param new_layout_return returns the new layout mode
+ * \param convert_return returns TRUE if image conversion is needed
+ */
+static void
+layout_logic(enum lp_texture_layout cur_layout,
+ enum lp_texture_layout target_layout,
+ enum lp_texture_usage usage,
+ enum lp_texture_layout *new_layout_return,
+ boolean *convert)
+{
+ enum lp_texture_layout other_layout, new_layout;
+
+ *convert = FALSE;
+
+ new_layout = 99; /* debug check */
+
+ if (target_layout == LP_TEX_LAYOUT_LINEAR) {
+ other_layout = LP_TEX_LAYOUT_TILED;
+ }
+ else {
+ assert(target_layout == LP_TEX_LAYOUT_TILED);
+ other_layout = LP_TEX_LAYOUT_LINEAR;
+ }
+
+ new_layout = target_layout; /* may get changed below */
+
+ if (cur_layout == LP_TEX_LAYOUT_BOTH) {
+ if (usage == LP_TEX_USAGE_READ) {
+ new_layout = LP_TEX_LAYOUT_BOTH;
+ }
+ }
+ else if (cur_layout == other_layout) {
+ if (usage != LP_TEX_USAGE_WRITE_ALL) {
+ /* need to convert tiled data to linear or vice versa */
+ *convert = TRUE;
+
+ if (usage == LP_TEX_USAGE_READ)
+ new_layout = LP_TEX_LAYOUT_BOTH;
+ }
+ }
+ else {
+ assert(cur_layout == LP_TEX_LAYOUT_NONE ||
+ cur_layout == target_layout);
+ }
+
+ assert(new_layout == LP_TEX_LAYOUT_BOTH ||
+ new_layout == target_layout);
+
+ *new_layout_return = new_layout;
+}
+
+
+/**
+ * Return pointer to a texture image. No tiled/linear conversion is done.
+ */
+void *
+llvmpipe_get_texture_image_address(struct llvmpipe_resource *lpt,
+ unsigned face, unsigned level,
+ enum lp_texture_layout layout)
+{
+ struct llvmpipe_texture_image *img;
+ unsigned face_offset;
+
+ if (layout == LP_TEX_LAYOUT_LINEAR) {
+ img = &lpt->linear[level];
+ }
+ else {
+ assert (layout == LP_TEX_LAYOUT_TILED);
+ img = &lpt->tiled[level];
+ }
+
+ if (face > 0)
+ face_offset = face * tex_image_face_size(lpt, level, layout);
+ else
+ face_offset = 0;
+
+ return (ubyte *) img->data + face_offset;
+}
+
+
+
+/**
+ * Return pointer to texture image data (either linear or tiled layout).
+ * \param usage one of LP_TEX_USAGE_READ/WRITE_ALL/READ_WRITE
+ * \param layout either LP_TEX_LAYOUT_LINEAR or LP_TEX_LAYOUT_TILED
+ */
+void *
+llvmpipe_get_texture_image(struct llvmpipe_resource *lpt,
+ unsigned face, unsigned level,
+ enum lp_texture_usage usage,
+ enum lp_texture_layout layout)
+{
+ /*
+ * 'target' refers to the image which we're retrieving (either in
+ * tiled or linear layout).
+ * 'other' refers to the same image but in the other layout. (it may
+ * or may not exist.
+ */
+ struct llvmpipe_texture_image *target_img;
+ struct llvmpipe_texture_image *other_img;
+ void *target_data;
+ void *other_data;
+ const unsigned width = u_minify(lpt->base.width0, level);
+ const unsigned height = u_minify(lpt->base.height0, level);
+ const unsigned width_t = align(width, TILE_SIZE) / TILE_SIZE;
+ const unsigned height_t = align(height, TILE_SIZE) / TILE_SIZE;
+ enum lp_texture_layout other_layout;
+
+ assert(layout == LP_TEX_LAYOUT_NONE ||
+ layout == LP_TEX_LAYOUT_TILED ||
+ layout == LP_TEX_LAYOUT_LINEAR);
+
+ assert(usage == LP_TEX_USAGE_READ ||
+ usage == LP_TEX_USAGE_READ_WRITE ||
+ usage == LP_TEX_USAGE_WRITE_ALL);
+
+ if (lpt->dt) {
+ assert(lpt->linear[level].data);
+ }
+
+ /* which is target? which is other? */
+ if (layout == LP_TEX_LAYOUT_LINEAR) {
+ target_img = &lpt->linear[level];
+ other_img = &lpt->tiled[level];
+ other_layout = LP_TEX_LAYOUT_TILED;
+ }
+ else {
+ target_img = &lpt->tiled[level];
+ other_img = &lpt->linear[level];
+ other_layout = LP_TEX_LAYOUT_LINEAR;
+ }
+
+ target_data = target_img->data;
+ other_data = other_img->data;
+
+ if (!target_data) {
+ /* allocate memory for the target image now */
+ unsigned buffer_size = tex_image_size(lpt, level, layout);
+ target_img->data = align_malloc(buffer_size, 16);
+ target_data = target_img->data;
+ }
+
+ if (face > 0) {
+ unsigned offset = face * tex_image_face_size(lpt, level, layout);
+ if (target_data) {
+ target_data = (uint8_t *) target_data + offset;
+ }
+ if (other_data) {
+ other_data = (uint8_t *) other_data + offset;
+ }
+ }
+
+ if (layout == LP_TEX_LAYOUT_NONE) {
+ /* just allocating memory */
+ return target_data;
+ }
+
+ if (other_data) {
+ /* may need to convert other data to the requested layout */
+ enum lp_texture_layout new_layout;
+ unsigned x, y, i = 0;
+
+ /* loop over all image tiles, doing layout conversion where needed */
+ for (y = 0; y < height_t; y++) {
+ for (x = 0; x < width_t; x++) {
+ enum lp_texture_layout cur_layout = lpt->layout[face][level][i];
+ boolean convert;
+
+ layout_logic(cur_layout, layout, usage, &new_layout, &convert);
+
+ if (convert) {
+ if (layout == LP_TEX_LAYOUT_TILED) {
+ lp_linear_to_tiled(other_data, target_data,
+ x * TILE_SIZE, y * TILE_SIZE,
+ TILE_SIZE, TILE_SIZE,
+ lpt->base.format,
+ lpt->stride[level]);
+ }
+ else {
+ lp_tiled_to_linear(other_data, target_data,
+ x * TILE_SIZE, y * TILE_SIZE,
+ TILE_SIZE, TILE_SIZE,
+ lpt->base.format,
+ lpt->stride[level]);
+ }
+ }
+
+ lpt->layout[face][level][i] = new_layout;
+ i++;
+ }
+ }
+ }
+ else {
+ /* no other data */
+ unsigned i;
+ for (i = 0; i < width_t * height_t; i++) {
+ lpt->layout[face][level][i] = layout;
+ }
+ }
+
+ assert(target_data);
+
+ return target_data;
+}
+
+
+static INLINE enum lp_texture_layout
+llvmpipe_get_texture_tile_layout(const struct llvmpipe_resource *lpt,
+ unsigned face, unsigned level,
+ unsigned x, unsigned y)
+{
+ uint i;
+ assert(resource_is_texture(&lpt->base));
+ assert(x < lpt->tiles_per_row[level]);
+ i = y * lpt->tiles_per_row[level] + x;
+ return lpt->layout[face][level][i];
+}
+
+
+static INLINE void
+llvmpipe_set_texture_tile_layout(struct llvmpipe_resource *lpt,
+ unsigned face, unsigned level,
+ unsigned x, unsigned y,
+ enum lp_texture_layout layout)
+{
+ uint i;
+ assert(resource_is_texture(&lpt->base));
+ assert(x < lpt->tiles_per_row[level]);
+ i = y * lpt->tiles_per_row[level] + x;
+ lpt->layout[face][level][i] = layout;
+}
+
+
+/**
+ * Get pointer to a linear image where the tile at (x,y) is known to be
+ * in linear layout.
+ * Conversion from tiled to linear will be done if necessary.
+ * \return pointer to start of image/face (not the tile)
+ */
+ubyte *
+llvmpipe_get_texture_tile_linear(struct llvmpipe_resource *lpt,
+ unsigned face, unsigned level,
+ enum lp_texture_usage usage,
+ unsigned x, unsigned y)
+{
+ struct llvmpipe_texture_image *tiled_img = &lpt->tiled[level];
+ struct llvmpipe_texture_image *linear_img = &lpt->linear[level];
+ enum lp_texture_layout cur_layout, new_layout;
+ const unsigned tx = x / TILE_SIZE, ty = y / TILE_SIZE;
+ boolean convert;
+
+ assert(resource_is_texture(&lpt->base));
+ assert(x % TILE_SIZE == 0);
+ assert(y % TILE_SIZE == 0);
+
+ if (!linear_img->data) {
+ /* allocate memory for the tiled image now */
+ unsigned buffer_size = tex_image_size(lpt, level, LP_TEX_LAYOUT_LINEAR);
+ linear_img->data = align_malloc(buffer_size, 16);
+ }
+
+ cur_layout = llvmpipe_get_texture_tile_layout(lpt, face, level, tx, ty);
+
+ layout_logic(cur_layout, LP_TEX_LAYOUT_LINEAR, usage,
+ &new_layout, &convert);
+
+ if (convert) {
+ lp_tiled_to_linear(tiled_img->data, linear_img->data,
+ x, y, TILE_SIZE, TILE_SIZE, lpt->base.format,
+ lpt->stride[level]);
+ }
+
+ if (new_layout != cur_layout)
+ llvmpipe_set_texture_tile_layout(lpt, face, level, tx, ty, new_layout);
+
+ if (face > 0) {
+ unsigned offset
+ = face * tex_image_face_size(lpt, level, LP_TEX_LAYOUT_LINEAR);
+ return (ubyte *) linear_img->data + offset;
+ }
+ else {
+ return linear_img->data;
+ }
+}
+
+
+/**
+ * Get pointer to tiled data for rendering.
+ * \return pointer to the tiled data at the given tile position
+ */
+ubyte *
+llvmpipe_get_texture_tile(struct llvmpipe_resource *lpt,
+ unsigned face, unsigned level,
+ enum lp_texture_usage usage,
+ unsigned x, unsigned y)
+{
+ const unsigned width = u_minify(lpt->base.width0, level);
+ struct llvmpipe_texture_image *tiled_img = &lpt->tiled[level];
+ struct llvmpipe_texture_image *linear_img = &lpt->linear[level];
+ enum lp_texture_layout cur_layout, new_layout;
+ const unsigned tx = x / TILE_SIZE, ty = y / TILE_SIZE;
+ boolean convert;
+
+ assert(x % TILE_SIZE == 0);
+ assert(y % TILE_SIZE == 0);
+
+ if (!tiled_img->data) {
+ /* allocate memory for the tiled image now */
+ unsigned buffer_size = tex_image_size(lpt, level, LP_TEX_LAYOUT_TILED);
+ tiled_img->data = align_malloc(buffer_size, 16);
+ }
+
+ cur_layout = llvmpipe_get_texture_tile_layout(lpt, face, level, tx, ty);
+
+ layout_logic(cur_layout, LP_TEX_LAYOUT_TILED, usage, &new_layout, &convert);
+ if (convert) {
+ lp_linear_to_tiled(linear_img->data, tiled_img->data,
+ x, y, TILE_SIZE, TILE_SIZE, lpt->base.format,
+ lpt->stride[level]);
+ }
+
+ if (new_layout != cur_layout)
+ llvmpipe_set_texture_tile_layout(lpt, face, level, tx, ty, new_layout);
+
+ /* compute, return address of the 64x64 tile */
+ {
+ unsigned tiles_per_row, tile_offset, face_offset;
+
+ tiles_per_row = align(width, TILE_SIZE) / TILE_SIZE;
+
+ assert(tiles_per_row == lpt->tiles_per_row[level]);
+
+ tile_offset = ty * tiles_per_row + tx;
+ tile_offset *= TILE_SIZE * TILE_SIZE * 4;
+
+ assert(tiled_img->data);
+
+ face_offset = (face > 0)
+ ? (face * tex_image_face_size(lpt, level, LP_TEX_LAYOUT_TILED))
+ : 0;
+
+ return (ubyte *) tiled_img->data + face_offset + tile_offset;
+ }
+}
+
+
void
llvmpipe_init_screen_resource_funcs(struct pipe_screen *screen)
{