texTemp.width0 = 1 << MAX_TEXTURE_LEVEL;
texTemp.height0 = 1 << MAX_TEXTURE_LEVEL;
texTemp.depth0 = 1;
+ texTemp.bind = PIPE_BIND_SAMPLER_VIEW;
aaline->texture = screen->resource_create(screen, &texTemp);
if (!aaline->texture)
texTemp.width0 = 32;
texTemp.height0 = 32;
texTemp.depth0 = 1;
+ texTemp.bind = PIPE_BIND_SAMPLER_VIEW;
pstip->texture = screen->resource_create(screen, &texTemp);
if (pstip->texture == NULL)
draw_install_aaline_stage(llvmpipe->draw, &llvmpipe->pipe);
draw_install_aapoint_stage(llvmpipe->draw, &llvmpipe->pipe);
+ /* convert points and lines into triangles: */
+ draw_wide_point_threshold(llvmpipe->draw, 0.0);
+ draw_wide_line_threshold(llvmpipe->draw, 0.0);
+
#if USE_DRAW_STAGE_PSTIPPLE
/* Do polygon stipple w/ texture map + frag prog? */
draw_install_pstipple_stage(llvmpipe->draw, &llvmpipe->pipe);
* Map vertex buffers
*/
for (i = 0; i < lp->num_vertex_buffers; i++) {
- void *buf = llvmpipe_resource(lp->vertex_buffer[i].buffer)->data;
+ void *buf = llvmpipe_resource_data(lp->vertex_buffer[i].buffer);
draw_set_mapped_vertex_buffer(draw, i, buf);
}
/* Map index buffer, if present */
if (indexBuffer) {
- void *mapped_indexes = llvmpipe_resource(indexBuffer)->data;
+ void *mapped_indexes = llvmpipe_resource_data(indexBuffer);
draw_set_mapped_element_buffer_range(draw, indexSize,
min_index,
max_index,
#include "lp_setup.h"
+/**
+ * \param flags bitmask of PIPE_FLUSH_x flags
+ * \param fence if non-null, returns pointer to a fench which can be waited on
+ */
void
llvmpipe_flush( struct pipe_context *pipe,
unsigned flags,
}
}
- /* XXX the lp_setup_flush(flags) param is not a bool, and it's ignored
- * at this time!
- */
- if (flags & PIPE_FLUSH_SWAPBUFFERS) {
- lp_setup_flush( llvmpipe->setup, FALSE );
- }
- else if (flags & PIPE_FLUSH_RENDER_CACHE) {
- lp_setup_flush( llvmpipe->setup, TRUE );
+ /* ask the setup module to flush */
+ if (flags & (PIPE_FLUSH_SWAPBUFFERS | PIPE_FLUSH_RENDER_CACHE)) {
+ lp_setup_flush(llvmpipe->setup, flags);
}
/* Enable to dump BMPs of the color/depth buffers each frame */
elem_types[LP_JIT_TEXTURE_DEPTH] = LLVMInt32Type();
elem_types[LP_JIT_TEXTURE_LAST_LEVEL] = LLVMInt32Type();
elem_types[LP_JIT_TEXTURE_ROW_STRIDE] =
- LLVMArrayType(LLVMInt32Type(), LP_MAX_TEXTURE_2D_LEVELS);
+ LLVMArrayType(LLVMInt32Type(), LP_MAX_TEXTURE_LEVELS);
elem_types[LP_JIT_TEXTURE_DATA] =
LLVMArrayType(LLVMPointerType(LLVMInt8Type(), 0),
- LP_MAX_TEXTURE_2D_LEVELS);
+ LP_MAX_TEXTURE_LEVELS);
texture_type = LLVMStructType(elem_types, Elements(elem_types), 0);
uint32_t height;
uint32_t depth;
uint32_t last_level;
- uint32_t row_stride[LP_MAX_TEXTURE_2D_LEVELS];
- const void *data[LP_MAX_TEXTURE_2D_LEVELS];
+ uint32_t row_stride[LP_MAX_TEXTURE_LEVELS];
+ const void *data[LP_MAX_TEXTURE_LEVELS];
};
#include "lp_scene.h"
-/* Begin rasterizing a scene:
+/**
+ * Begin rasterizing a scene.
+ * Called once per scene by one thread.
*/
-static boolean
+static void
lp_rast_begin( struct lp_rasterizer *rast,
struct lp_scene *scene )
{
const struct pipe_framebuffer_state *fb = &scene->fb;
- boolean write_color = fb->nr_cbufs != 0;
- boolean write_zstencil = fb->zsbuf != NULL;
int i;
rast->curr_scene = scene;
LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
rast->state.nr_cbufs = scene->fb.nr_cbufs;
- rast->state.write_zstencil = write_zstencil;
- rast->state.write_color = write_color;
for (i = 0; i < rast->state.nr_cbufs; i++) {
struct pipe_surface *cbuf = scene->fb.cbufs[i];
- rast->cbuf[i].map = scene->cbuf_map[i];
rast->cbuf[i].format = cbuf->texture->format;
- rast->cbuf[i].width = cbuf->width;
- rast->cbuf[i].height = cbuf->height;
- rast->cbuf[i].stride = llvmpipe_resource_stride(cbuf->texture, cbuf->level);
+ rast->cbuf[i].tiles_per_row = align(cbuf->width, TILE_SIZE) / TILE_SIZE;
+ rast->cbuf[i].blocksize =
+ util_format_get_blocksize(cbuf->texture->format);
+ rast->cbuf[i].map = llvmpipe_resource_map(cbuf->texture,
+ cbuf->face,
+ cbuf->level,
+ cbuf->zslice,
+ LP_TEX_USAGE_READ_WRITE,
+ LP_TEX_LAYOUT_NONE);
}
- if (write_zstencil) {
+ if (fb->zsbuf) {
struct pipe_surface *zsbuf = scene->fb.zsbuf;
- rast->zsbuf.map = scene->zsbuf_map;
rast->zsbuf.stride = llvmpipe_resource_stride(zsbuf->texture, zsbuf->level);
rast->zsbuf.blocksize =
util_format_get_blocksize(zsbuf->texture->format);
+
+ rast->zsbuf.map = llvmpipe_resource_map(zsbuf->texture,
+ zsbuf->face,
+ zsbuf->level,
+ zsbuf->zslice,
+ LP_TEX_USAGE_READ_WRITE,
+ LP_TEX_LAYOUT_NONE);
+ assert(rast->zsbuf.map);
}
lp_scene_bin_iter_begin( scene );
-
- return TRUE;
}
static void
lp_rast_end( struct lp_rasterizer *rast )
{
- int i;
-
- lp_scene_reset( rast->curr_scene );
+ struct lp_scene *scene = rast->curr_scene;
+ unsigned i;
- for (i = 0; i < rast->state.nr_cbufs; i++)
+ /* Unmap color buffers */
+ for (i = 0; i < rast->state.nr_cbufs; i++) {
+ struct pipe_surface *cbuf = scene->fb.cbufs[i];
+ llvmpipe_resource_unmap(cbuf->texture,
+ cbuf->face,
+ cbuf->level,
+ cbuf->zslice);
rast->cbuf[i].map = NULL;
+ }
+
+ /* Unmap z/stencil buffer */
+ if (rast->zsbuf.map) {
+ struct pipe_surface *zsbuf = scene->fb.zsbuf;
+ llvmpipe_resource_unmap(zsbuf->texture,
+ zsbuf->face,
+ zsbuf->level,
+ zsbuf->zslice);
+ rast->zsbuf.map = NULL;
+ }
+
+ lp_scene_reset( rast->curr_scene );
- rast->zsbuf.map = NULL;
rast->curr_scene = NULL;
+
+ if (0)
+ printf("Post render scene: tile read: %d tile write: %d\n",
+ tile_read_count, tile_write_count);
}
+
/**
* Begining rasterization of a tile.
* \param x window X position of the tile, in pixels
* \param y window Y position of the tile, in pixels
*/
static void
-lp_rast_start_tile(struct lp_rasterizer_task *task,
+lp_rast_tile_begin(struct lp_rasterizer_task *task,
unsigned x, unsigned y)
{
+ struct lp_rasterizer *rast = task->rast;
+ struct lp_scene *scene = rast->curr_scene;
+ enum lp_texture_usage usage;
+ unsigned buf;
+
LP_DBG(DEBUG_RAST, "%s %d,%d\n", __FUNCTION__, x, y);
+ assert(x % TILE_SIZE == 0);
+ assert(y % TILE_SIZE == 0);
+
task->x = x;
task->y = y;
+
+ if (scene->has_color_clear)
+ usage = LP_TEX_USAGE_WRITE_ALL;
+ else
+ usage = LP_TEX_USAGE_READ_WRITE;
+
+ /* get pointers to color tile(s) */
+ for (buf = 0; buf < rast->state.nr_cbufs; buf++) {
+ struct pipe_surface *cbuf = rast->curr_scene->fb.cbufs[buf];
+ struct llvmpipe_resource *lpt;
+ assert(cbuf);
+ lpt = llvmpipe_resource(cbuf->texture);
+ task->color_tiles[buf] = llvmpipe_get_texture_tile(lpt,
+ cbuf->face,
+ cbuf->level,
+ usage,
+ x, y);
+ assert(task->color_tiles[buf]);
+ }
+
+ /* get pointer to depth/stencil tile */
+ {
+ struct pipe_surface *zsbuf = rast->curr_scene->fb.zsbuf;
+ if (zsbuf) {
+ struct llvmpipe_resource *lpt = llvmpipe_resource(zsbuf->texture);
+
+ if (scene->has_depth_clear)
+ usage = LP_TEX_USAGE_WRITE_ALL;
+ else
+ usage = LP_TEX_USAGE_READ_WRITE;
+
+ /* "prime" the tile: convert data from linear to tiled if necessary
+ * and update the tile's layout info.
+ */
+ (void) llvmpipe_get_texture_tile(lpt,
+ zsbuf->face,
+ zsbuf->level,
+ usage,
+ x, y);
+ /* Get actual pointer to the tile data. Note that depth/stencil
+ * data is tiled differently than color data.
+ */
+ task->depth_tile = lp_rast_get_depth_block_pointer(rast, x, y);
+
+ assert(task->depth_tile);
+ }
+ else {
+ task->depth_tile = NULL;
+ }
+ }
}
{
struct lp_rasterizer *rast = task->rast;
const uint8_t *clear_color = arg.clear_color;
- uint8_t **color_tile = task->tile.color;
+
unsigned i;
LP_DBG(DEBUG_RAST, "%s 0x%x,0x%x,0x%x,0x%x\n", __FUNCTION__,
clear_color[2] == clear_color[3]) {
/* clear to grayscale value {x, x, x, x} */
for (i = 0; i < rast->state.nr_cbufs; i++) {
- memset(color_tile[i], clear_color[0], TILE_SIZE * TILE_SIZE * 4);
+ uint8_t *ptr = task->color_tiles[i];
+ memset(ptr, clear_color[0], TILE_SIZE * TILE_SIZE * 4);
}
}
else {
*/
const unsigned chunk = TILE_SIZE / 4;
for (i = 0; i < rast->state.nr_cbufs; i++) {
- uint8_t *c = color_tile[i];
+ uint8_t *c = task->color_tiles[i];
unsigned j;
+
for (j = 0; j < 4 * TILE_SIZE; j++) {
memset(c, clear_color[0], chunk);
c += chunk;
memset(c, clear_color[3], chunk);
c += chunk;
}
- assert(c - color_tile[i] == TILE_SIZE * TILE_SIZE * 4);
}
}
const union lp_rast_cmd_arg arg)
{
struct lp_rasterizer *rast = task->rast;
- const unsigned tile_x = task->x;
- const unsigned tile_y = task->y;
const unsigned height = TILE_SIZE / TILE_VECTOR_HEIGHT;
const unsigned width = TILE_SIZE * TILE_VECTOR_HEIGHT;
- unsigned block_size = rast->zsbuf.blocksize;
+ const unsigned block_size = rast->zsbuf.blocksize;
+ const unsigned dst_stride = rast->zsbuf.stride * TILE_VECTOR_HEIGHT;
uint8_t *dst;
- unsigned dst_stride = rast->zsbuf.stride * TILE_VECTOR_HEIGHT;
unsigned i, j;
LP_DBG(DEBUG_RAST, "%s 0x%x\n", __FUNCTION__, arg.clear_zstencil);
- /*assert(rast->zsbuf.map);*/
- if (!rast->zsbuf.map)
- return;
-
- LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
-
/*
* Clear the aera of the swizzled depth/depth buffer matching this tile, in
* stripes of TILE_VECTOR_HEIGHT x TILE_SIZE at a time.
* TILE_VECTOR_HEIGHT x TILE_VECTOR_WIDTH pixels have consecutive offsets.
*/
- dst = lp_rast_depth_pointer(rast, tile_x, tile_y);
+ dst = task->depth_tile;
+
+ assert(dst == lp_rast_get_depth_block_pointer(rast, task->x, task->y));
switch (block_size) {
case 1:
* Load tile color from the framebuffer surface.
* This is a bin command called during bin processing.
*/
+#if 0
void
lp_rast_load_color(struct lp_rasterizer_task *task,
const union lp_rast_cmd_arg arg)
{
struct lp_rasterizer *rast = task->rast;
- const unsigned x = task->x, y = task->y;
- unsigned i;
+ unsigned buf;
+ enum lp_texture_usage usage;
LP_DBG(DEBUG_RAST, "%s at %u, %u\n", __FUNCTION__, x, y);
- for (i = 0; i < rast->state.nr_cbufs; i++) {
- if (x >= rast->cbuf[i].width || y >= rast->cbuf[i].height)
- continue;
+ if (scene->has_color_clear)
+ usage = LP_TEX_USAGE_WRITE_ALL;
+ else
+ usage = LP_TEX_USAGE_READ_WRITE;
+
+ /* Get pointers to color tile(s).
+ * This will convert linear data to tiled if needed.
+ */
+ for (buf = 0; buf < rast->state.nr_cbufs; buf++) {
+ struct pipe_surface *cbuf = rast->curr_scene->fb.cbufs[buf];
+ struct llvmpipe_texture *lpt;
+ assert(cbuf);
+ lpt = llvmpipe_texture(cbuf->texture);
+ task->color_tiles[buf] = llvmpipe_get_texture_tile(lpt,
+ cbuf->face,
+ cbuf->level,
+ usage,
+ task->x, task->y);
+ assert(task->color_tiles[buf]);
+ }
+}
+#endif
- lp_tile_read_4ub(rast->cbuf[i].format,
- task->tile.color[i],
- rast->cbuf[i].map,
- rast->cbuf[i].stride,
- x, y,
- TILE_SIZE, TILE_SIZE);
- LP_COUNT(nr_color_tile_load);
+/**
+ * Convert the color tile from tiled to linear layout.
+ * This is generally only done when we're flushing the scene just prior to
+ * SwapBuffers. If we didn't do this here, we'd have to convert the entire
+ * tiled color buffer to linear layout in the llvmpipe_texture_unmap()
+ * function. It's better to do it here to take advantage of
+ * threading/parallelism.
+ * This is a bin command which is stored in all bins.
+ */
+void
+lp_rast_store_color( struct lp_rasterizer_task *task,
+ const union lp_rast_cmd_arg arg)
+{
+ struct lp_rasterizer *rast = task->rast;
+ struct lp_scene *scene = rast->curr_scene;
+ unsigned buf;
+
+ for (buf = 0; buf < rast->state.nr_cbufs; buf++) {
+ struct pipe_surface *cbuf = scene->fb.cbufs[buf];
+ const unsigned face = cbuf->face, level = cbuf->level;
+ struct llvmpipe_resource *lpt = llvmpipe_resource(cbuf->texture);
+ /* this will convert the tiled data to linear if needed */
+ (void) llvmpipe_get_texture_tile_linear(lpt, face,level,
+ LP_TEX_USAGE_READ,
+ task->x, task->y);
}
}
+/**
+ * This is a bin command called during bin processing.
+ */
void
lp_rast_set_state(struct lp_rasterizer_task *task,
const union lp_rast_cmd_arg arg)
}
-
/**
* Run the shader on all blocks in a tile. This is used when a tile is
* completely contained inside a triangle.
{
struct lp_rasterizer *rast = task->rast;
const struct lp_rast_state *state = task->current_state;
- struct lp_rast_tile *tile = &task->tile;
const struct lp_rast_shader_inputs *inputs = arg.shade_tile;
const unsigned tile_x = task->x, tile_y = task->y;
unsigned x, y;
for (x = 0; x < TILE_SIZE; x += 4) {
uint8_t *color[PIPE_MAX_COLOR_BUFS];
uint32_t *depth;
- unsigned block_offset, i;
-
- /* offset of the 16x16 pixel block within the tile */
- block_offset = ((y / 4) * (16 * 16) + (x / 4) * 16);
+ unsigned i;
/* color buffer */
for (i = 0; i < rast->state.nr_cbufs; i++)
- color[i] = tile->color[i] + 4 * block_offset;
+ color[i] = lp_rast_get_color_block_pointer(task, i,
+ tile_x + x, tile_y + y);
/* depth buffer */
- depth = lp_rast_depth_pointer(rast, tile_x + x, tile_y + y);
+ depth = lp_rast_get_depth_block_pointer(rast, tile_x + x, tile_y + y);
- /* run shader */
+ /* run shader on 4x4 block */
state->jit_function[RAST_WHOLE]( &state->jit_context,
tile_x + x, tile_y + y,
inputs->facing,
/**
* Compute shading for a 4x4 block of pixels.
* This is a bin command called during bin processing.
+ * \param x X position of quad in window coords
+ * \param y Y position of quad in window coords
*/
void lp_rast_shade_quads( struct lp_rasterizer_task *task,
const struct lp_rast_shader_inputs *inputs,
{
const struct lp_rast_state *state = task->current_state;
struct lp_rasterizer *rast = task->rast;
- struct lp_rast_tile *tile = &task->tile;
uint8_t *color[PIPE_MAX_COLOR_BUFS];
void *depth;
unsigned i;
- unsigned ix, iy;
- int block_offset;
assert(state);
assert((x % 4) == 0);
assert((y % 4) == 0);
- ix = x % TILE_SIZE;
- iy = y % TILE_SIZE;
-
- /* offset of the 16x16 pixel block within the tile */
- block_offset = ((iy / 4) * (16 * 16) + (ix / 4) * 16);
-
/* color buffer */
- for (i = 0; i < rast->state.nr_cbufs; i++)
- color[i] = tile->color[i] + 4 * block_offset;
+ for (i = 0; i < rast->state.nr_cbufs; i++) {
+ color[i] = lp_rast_get_color_block_pointer(task, i, x, y);
+ assert(lp_check_alignment(color[i], 16));
+ }
/* depth buffer */
- depth = lp_rast_depth_pointer(rast, x, y);
+ depth = lp_rast_get_depth_block_pointer(rast, x, y);
- assert(lp_check_alignment(tile->color[0], 16));
assert(lp_check_alignment(state->jit_context.blend_color, 16));
assert(lp_check_alignment(inputs->step[0], 16));
assert(lp_check_alignment(inputs->step[1], 16));
assert(lp_check_alignment(inputs->step[2], 16));
- /* run shader */
+ /* run shader on 4x4 block */
state->jit_function[RAST_EDGE_TEST]( &state->jit_context,
x, y,
inputs->facing,
/**
- * Write the rasterizer's color tile to the framebuffer.
+ * Called when we're done writing to a color tile.
*/
static void
-lp_rast_store_color(struct lp_rasterizer_task *task)
+lp_rast_tile_end(struct lp_rasterizer_task *task)
{
+#if DEBUG
struct lp_rasterizer *rast = task->rast;
- const unsigned x = task->x, y = task->y;
- unsigned i;
-
- for (i = 0; i < rast->state.nr_cbufs; i++) {
- if (x >= rast->cbuf[i].width)
- continue;
-
- if (y >= rast->cbuf[i].height)
- continue;
+ unsigned buf;
- LP_DBG(DEBUG_RAST, "%s [%u] %d,%d\n", __FUNCTION__,
- task->thread_index, x, y);
+ for (buf = 0; buf < rast->state.nr_cbufs; buf++) {
+ uint8_t *color = lp_rast_get_color_block_pointer(task, buf,
+ task->x, task->y);
if (LP_DEBUG & DEBUG_SHOW_SUBTILES)
- outline_subtiles(task->tile.color[i]);
+ outline_subtiles(color);
else if (LP_DEBUG & DEBUG_SHOW_TILES)
- outline_tile(task->tile.color[i]);
-
- lp_tile_write_4ub(rast->cbuf[i].format,
- task->tile.color[i],
- rast->cbuf[i].map,
- rast->cbuf[i].stride,
- x, y,
- TILE_SIZE, TILE_SIZE);
-
- LP_COUNT(nr_color_tile_store);
+ outline_tile(color);
}
+#else
+ (void) outline_subtiles;
+#endif
+
+ /* debug */
+ memset(task->color_tiles, 0, sizeof(task->color_tiles));
+ task->depth_tile = NULL;
}
struct cmd_block *block;
unsigned k;
- lp_rast_start_tile( task, x * TILE_SIZE, y * TILE_SIZE );
+ lp_rast_tile_begin( task, x * TILE_SIZE, y * TILE_SIZE );
/* simply execute each of the commands in the block list */
for (block = commands->head; block; block = block->next) {
}
}
- /* Write the rasterizer's tiles to the framebuffer.
- */
- if (task->rast->state.write_color)
- lp_rast_store_color(task);
+ lp_rast_tile_end(task);
/* Free data for this bin.
*/
const char *name;
} cmd_names[] =
{
- RAST(load_color),
RAST(clear_color),
RAST(clear_zstencil),
RAST(triangle),
RAST(shade_tile),
RAST(set_state),
+ RAST(store_color),
RAST(fence),
};
}
for (i = 0; i < head->count; i++)
- if (head->cmd[i] != lp_rast_load_color &&
- head->cmd[i] != lp_rast_set_state) {
+ if (head->cmd[i] != lp_rast_set_state) {
return FALSE;
}
rasterize_scene( &rast->tasks[0], scene );
lp_scene_reset( scene );
+
+ lp_rast_end( rast );
+
rast->curr_scene = NULL;
}
else {
lp_rast_create( void )
{
struct lp_rasterizer *rast;
- unsigned i, cbuf;
+ unsigned i;
rast = CALLOC_STRUCT(lp_rasterizer);
if(!rast)
for (i = 0; i < Elements(rast->tasks); i++) {
struct lp_rasterizer_task *task = &rast->tasks[i];
-
- for (cbuf = 0; cbuf < PIPE_MAX_COLOR_BUFS; cbuf++ )
- task->tile.color[cbuf] = align_malloc(TILE_SIZE * TILE_SIZE * 4, 16);
-
task->rast = rast;
task->thread_index = i;
}
*/
void lp_rast_destroy( struct lp_rasterizer *rast )
{
- unsigned i, cbuf;
-
- for (i = 0; i < Elements(rast->tasks); i++) {
- for (cbuf = 0; cbuf < PIPE_MAX_COLOR_BUFS; cbuf++ )
- align_free(rast->tasks[i].tile.color[cbuf]);
- }
+ unsigned i;
/* Set exit_flag and signal each thread's work_ready semaphore.
* Each thread will be woken up, notice that the exit_flag is set and
void lp_rast_clear_zstencil( struct lp_rasterizer_task *,
const union lp_rast_cmd_arg );
-void lp_rast_load_color( struct lp_rasterizer_task *,
- const union lp_rast_cmd_arg );
-
void lp_rast_set_state( struct lp_rasterizer_task *,
const union lp_rast_cmd_arg );
void lp_rast_fence( struct lp_rasterizer_task *,
const union lp_rast_cmd_arg );
+void lp_rast_store_color( struct lp_rasterizer_task *,
+ const union lp_rast_cmd_arg );
+
+
#endif
#include "util/u_format.h"
#include "gallivm/lp_bld_debug.h"
#include "lp_rast.h"
+#include "lp_scene.h"
+#include "lp_texture.h"
#include "lp_tile_soa.h"
struct lp_rasterizer;
-/**
- * A tile's color and depth memory.
- * We can choose whatever layout for the internal tile storage we prefer.
- */
-struct lp_rast_tile
-{
- uint8_t *color[PIPE_MAX_COLOR_BUFS];
-};
-
-
/**
* Per-thread rasterization state
*/
struct lp_rasterizer_task
{
- struct lp_rast_tile tile; /** Tile color/z/stencil memory */
-
unsigned x, y; /**< Pos of this tile in framebuffer, in pixels */
+ uint8_t *color_tiles[PIPE_MAX_COLOR_BUFS];
+ uint8_t *depth_tile;
+
const struct lp_rast_state *current_state;
/** "back" pointer */
*/
struct {
void *map;
- unsigned stride;
- unsigned width;
- unsigned height;
+ unsigned tiles_per_row;
+ unsigned blocksize;
enum pipe_format format;
} cbuf[PIPE_MAX_COLOR_BUFS];
struct {
unsigned nr_cbufs;
- boolean write_color;
- boolean write_zstencil;
unsigned clear_color;
unsigned clear_depth;
char clear_stencil;
/**
- * Get the pointer to the depth buffer for a block.
+ * Get the pointer to a 4x4 depth/stencil block.
+ * We'll map the z/stencil buffer on demand here.
+ * Note that this may be called even when there's no z/stencil buffer - return
+ * NULL in that case.
* \param x, y location of 4x4 block in window coords
*/
static INLINE void *
-lp_rast_depth_pointer( struct lp_rasterizer *rast,
- unsigned x, unsigned y )
+lp_rast_get_depth_block_pointer(const struct lp_rasterizer *rast,
+ unsigned x, unsigned y)
{
- void * depth;
+ void *depth;
assert((x % TILE_VECTOR_WIDTH) == 0);
assert((y % TILE_VECTOR_HEIGHT) == 0);
+ assert(rast->zsbuf.map || !rast->curr_scene->fb.zsbuf);
+
if (!rast->zsbuf.map)
return NULL;
}
+/**
+ * Get the pointer to a 4x4 color block (within a 64x64 tile).
+ * We'll map the color buffer on demand here.
+ * Note that this may be called even when there's no color buffers - return
+ * NULL in that case.
+ * \param x, y location of 4x4 block in window coords
+ */
+static INLINE uint8_t *
+lp_rast_get_color_block_pointer(struct lp_rasterizer_task *task,
+ unsigned buf, unsigned x, unsigned y)
+{
+ unsigned px, py, pixel_offset;
+ uint8_t *color;
+
+ assert((x % TILE_VECTOR_WIDTH) == 0);
+ assert((y % TILE_VECTOR_HEIGHT) == 0);
+
+ color = task->color_tiles[buf];
+ assert(color);
+
+ px = x % TILE_SIZE;
+ py = y % TILE_SIZE;
+ pixel_offset = tile_pixel_offset(px, py, 0);
+
+ color = color + pixel_offset;
+
+ assert(lp_check_alignment(color, 16));
+ return color;
+}
+
+
/**
* Shade all pixels in a 4x4 block. The fragment code omits the
{
struct lp_rasterizer *rast = task->rast;
const struct lp_rast_state *state = task->current_state;
- struct lp_rast_tile *tile = &task->tile;
- const unsigned ix = x % TILE_SIZE, iy = y % TILE_SIZE;
uint8_t *color[PIPE_MAX_COLOR_BUFS];
void *depth;
- unsigned block_offset, i;
-
- /* offset of the containing 16x16 pixel block within the tile */
- block_offset = (iy / 4) * (16 * 16) + (ix / 4) * 16;
+ unsigned i;
/* color buffer */
for (i = 0; i < rast->state.nr_cbufs; i++)
- color[i] = tile->color[i] + 4 * block_offset;
-
- depth = lp_rast_depth_pointer(rast, x, y);
-
- /* run shader */
- state->jit_function[0]( &state->jit_context,
- x, y,
- inputs->facing,
- inputs->a0,
- inputs->dadx,
- inputs->dady,
- color,
- depth,
- INT_MIN, INT_MIN, INT_MIN,
- NULL, NULL, NULL );
+ color[i] = lp_rast_get_color_block_pointer(task, i, x, y);
+
+ depth = lp_rast_get_depth_block_pointer(rast, x, y);
+
+ /* run shader on 4x4 block */
+ state->jit_function[RAST_WHOLE]( &state->jit_context,
+ x, y,
+ inputs->facing,
+ inputs->a0,
+ inputs->dadx,
+ inputs->dady,
+ color,
+ depth,
+ INT_MIN, INT_MIN, INT_MIN,
+ NULL, NULL, NULL );
}
}
make_empty_list(ref_list);
}
+
+ scene->has_color_clear = FALSE;
+ scene->has_depth_clear = FALSE;
}
}
+
/**
* Prepare this scene for the rasterizer.
* Map the framebuffer surfaces. Initialize the 'rast' state.
static boolean
lp_scene_map_buffers( struct lp_scene *scene )
{
- struct pipe_surface *cbuf, *zsbuf;
- unsigned usage;
- int i;
-
LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
- /* XXX: try to improve on this:
- */
- usage = PIPE_TRANSFER_READ_WRITE;
-
- /* Map all color buffers
- */
- for (i = 0; i < scene->fb.nr_cbufs; i++) {
- cbuf = scene->fb.cbufs[i];
- if (cbuf) {
- scene->cbuf_map[i] = llvmpipe_resource_map(cbuf->texture,
- usage,
- cbuf->face,
- cbuf->level,
- cbuf->zslice);
- if (!scene->cbuf_map[i])
- goto fail;
- }
- }
-
- /* Map the zsbuffer
- */
- zsbuf = scene->fb.zsbuf;
- if (zsbuf) {
- scene->zsbuf_map = llvmpipe_resource_map(zsbuf->texture,
- usage,
- zsbuf->face,
- zsbuf->level,
- zsbuf->zslice);
- if (!scene->zsbuf_map)
- goto fail;
- }
+ /* XXX framebuffer surfaces are no longer mapped here */
+ /* XXX move all map/unmap stuff into rast module... */
return TRUE;
-
-fail:
- /* Unmap and release transfers?
- */
- return FALSE;
}
static void
lp_scene_unmap_buffers( struct lp_scene *scene )
{
+#if 0
unsigned i;
for (i = 0; i < scene->fb.nr_cbufs; i++) {
zsbuf->zslice);
scene->zsbuf_map = NULL;
}
+#endif
util_unreference_framebuffer_state( &scene->fb );
}
}
}
-
scene->write_depth = (scene->fb.zsbuf != NULL &&
write_depth);
struct lp_scene {
struct pipe_context *pipe;
- /* Scene's buffers are mapped at the time the scene is enqueued:
- */
- void *cbuf_map[PIPE_MAX_COLOR_BUFS];
- uint8_t *zsbuf_map;
-
/** the framebuffer to render the scene into */
struct pipe_framebuffer_state fb;
struct texture_ref textures;
boolean write_depth;
+ boolean has_color_clear;
+ boolean has_depth_clear;
/**
* Number of active tiles in each dimension.
struct cmd_bin *
lp_scene_bin_iter_next( struct lp_scene *scene, int *bin_x, int *bin_y );
+
void
lp_scene_rasterize( struct lp_scene *scene,
struct lp_rasterizer *rast,
#include "draw/draw_vbuf.h"
-static void set_scene_state( struct lp_setup_context *, unsigned );
+static void set_scene_state( struct lp_setup_context *, enum setup_state );
struct lp_scene *
(setup->clear.flags & PIPE_CLEAR_DEPTHSTENCIL) ? "clear": "load");
if (setup->fb.nr_cbufs) {
- if (setup->clear.flags & PIPE_CLEAR_COLOR)
+ if (setup->clear.flags & PIPE_CLEAR_COLOR) {
lp_scene_bin_everywhere( scene,
lp_rast_clear_color,
setup->clear.color );
- else
- lp_scene_bin_everywhere( scene,
- lp_rast_load_color,
- lp_rast_arg_null() );
+ scene->has_color_clear = TRUE;
+ }
}
if (setup->fb.zsbuf) {
- if (setup->clear.flags & PIPE_CLEAR_DEPTHSTENCIL)
+ if (setup->clear.flags & PIPE_CLEAR_DEPTHSTENCIL) {
lp_scene_bin_everywhere( scene,
lp_rast_clear_zstencil,
setup->clear.zstencil );
+ scene->has_depth_clear = TRUE;
+ }
}
LP_DBG(DEBUG_SETUP, "%s done\n", __FUNCTION__);
static void
set_scene_state( struct lp_setup_context *setup,
- unsigned new_state )
+ enum setup_state new_state )
{
unsigned old_state = setup->state;
else
lp_setup_rasterize_scene( setup, TRUE );
break;
+
+ default:
+ assert(0 && "invalid setup state mode");
}
setup->state = new_state;
}
+/**
+ * \param flags bitmask of PIPE_FLUSH_x flags
+ */
void
lp_setup_flush( struct lp_setup_context *setup,
unsigned flags )
{
LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
+ if (setup->scene) {
+ struct lp_scene *scene = lp_setup_get_current_scene(setup);
+ union lp_rast_cmd_arg dummy;
+
+ if (flags & (PIPE_FLUSH_SWAPBUFFERS |
+ PIPE_FLUSH_FRAME)) {
+ /* Store colors in the linear color buffer(s).
+ * If we don't do this here, we'll end up converting the tiled
+ * data to linear in the texture_unmap() function, which will
+ * not be a parallel/threaded operation as here.
+ */
+ lp_scene_bin_everywhere(scene, lp_rast_store_color, dummy);
+ }
+ }
+
set_scene_state( setup, SETUP_FLUSHED );
}
* binned scene and start again, but I don't see that as being
* a common usage.
*/
- if (flags & PIPE_CLEAR_COLOR)
+ if (flags & PIPE_CLEAR_COLOR) {
lp_scene_bin_everywhere( scene,
lp_rast_clear_color,
setup->clear.color );
+ scene->has_color_clear = TRUE;
+ }
- if (setup->clear.flags & PIPE_CLEAR_DEPTHSTENCIL)
+ if (setup->clear.flags & PIPE_CLEAR_DEPTHSTENCIL) {
lp_scene_bin_everywhere( scene,
lp_rast_clear_zstencil,
setup->clear.zstencil );
+ scene->has_depth_clear = TRUE;
+ }
+
}
else {
/* Put ourselves into the 'pre-clear' state, specifically to try
/* regular texture - setup array of mipmap level pointers */
int j;
for (j = 0; j <= tex->last_level; j++) {
+#if 0
jit_tex->data[j] =
(ubyte *) lp_tex->data + lp_tex->level_offset[j];
+#else
+ jit_tex->data[j] =
+ llvmpipe_get_texture_image(lp_tex, 0, j, LP_TEX_USAGE_READ,
+ LP_TEX_LAYOUT_LINEAR);
+#endif
jit_tex->row_stride[j] = lp_tex->stride[j];
}
}
if(buffer) {
unsigned current_size = buffer->width0;
- const void *current_data = llvmpipe_resource(buffer)->data;
+ const void *current_data = llvmpipe_resource_data(buffer);
/* TODO: copy only the actually used constants? */
union lp_rast_cmd_arg zstencil; /**< lp_rast_clear_zstencil() cmd */
} clear;
- enum {
+ enum setup_state {
SETUP_FLUSHED,
SETUP_CLEARED,
SETUP_ACTIVE
{
struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
unsigned size = constants ? constants->width0 : 0;
- const void *data = constants ? llvmpipe_resource(constants)->data : NULL;
+ const void *data = constants ? llvmpipe_resource_data(constants) : NULL;
assert(shader < PIPE_SHADER_TYPES);
assert(index == 0);
#include "lp_context.h"
#include "lp_flush.h"
#include "lp_surface.h"
+#include "lp_texture.h"
+#include "lp_tile_image.h"
+#include "lp_tile_size.h"
+
+
+/**
+ * Adjust x, y, width, height to lie on tile bounds.
+ */
+static void
+adjust_to_tile_bounds(unsigned x, unsigned y, unsigned width, unsigned height,
+ unsigned *x_tile, unsigned *y_tile,
+ unsigned *w_tile, unsigned *h_tile)
+{
+ *x_tile = x & ~(TILE_SIZE - 1);
+ *y_tile = y & ~(TILE_SIZE - 1);
+ *w_tile = ((x + width + TILE_SIZE - 1) & ~(TILE_SIZE - 1)) - *x_tile;
+ *h_tile = ((y + height + TILE_SIZE - 1) & ~(TILE_SIZE - 1)) - *y_tile;
+}
+
static void
lp_surface_copy(struct pipe_context *pipe,
- struct pipe_surface *dest, unsigned destx, unsigned desty,
+ struct pipe_surface *dst, unsigned dstx, unsigned dsty,
struct pipe_surface *src, unsigned srcx, unsigned srcy,
unsigned width, unsigned height)
{
llvmpipe_flush_texture(pipe,
- dest->texture, dest->face, dest->level,
+ dst->texture, dst->face, dst->level,
0, /* flush_flags */
FALSE, /* read_only */
FALSE, /* cpu_access */
FALSE, /* cpu_access */
FALSE); /* do_not_flush */
+ /* Look for special case in which we're copying from a tiled image
+ * to a linear image.
+ */
+ {
+ struct llvmpipe_resource *src_tex = llvmpipe_resource(src->texture);
+ struct llvmpipe_resource *dst_tex = llvmpipe_resource(dst->texture);
+ enum pipe_format format = src_tex->base.format;
+
+ /*
+ printf("surface copy from %u to %u: %u,%u to %u,%u %u x %u\n",
+ src_tex->id, dst_tex->id,
+ srcx, srcy, dstx, dsty, width, height);
+ */
+
+ /* set src tiles to linear layout */
+ {
+ unsigned tx, ty, tw, th;
+ unsigned x, y;
+
+ adjust_to_tile_bounds(srcx, srcy, width, height, &tx, &ty, &tw, &th);
+
+ for (y = 0; y < th; y += TILE_SIZE) {
+ for (x = 0; x < tw; x += TILE_SIZE) {
+ (void) llvmpipe_get_texture_tile_linear(src_tex,
+ src->face, src->level,
+ LP_TEX_USAGE_READ,
+ tx + x, ty + y);
+ }
+ }
+ }
+
+ /* set dst tiles to linear layout */
+ {
+ unsigned tx, ty, tw, th;
+ unsigned x, y;
+ enum lp_texture_usage usage;
+
+ /* XXX for the tiles which are completely contained by the
+ * dest rectangle, we could set the usage mode to WRITE_ALL.
+ * Just test for the case of replacing the whole dest region for now.
+ */
+ if (width == dst_tex->base.width0 && height == dst_tex->base.height0)
+ usage = LP_TEX_USAGE_WRITE_ALL;
+ else
+ usage = LP_TEX_USAGE_READ_WRITE;
+
+ adjust_to_tile_bounds(dstx, dsty, width, height, &tx, &ty, &tw, &th);
+
+ for (y = 0; y < th; y += TILE_SIZE) {
+ for (x = 0; x < tw; x += TILE_SIZE) {
+ (void) llvmpipe_get_texture_tile_linear(dst_tex,
+ dst->face, dst->level,
+ usage,
+ tx + x, ty + y);
+ }
+ }
+ }
+
+ /* copy */
+ {
+ const ubyte *src_linear_ptr
+ = llvmpipe_get_texture_image_address(src_tex, src->face,
+ src->level,
+ LP_TEX_LAYOUT_LINEAR);
+ ubyte *dst_linear_ptr
+ = llvmpipe_get_texture_image_address(dst_tex, dst->face,
+ dst->level,
+ LP_TEX_LAYOUT_LINEAR);
+
+ util_copy_rect(dst_linear_ptr, format,
+ dst_tex->stride[dst->level],
+ dstx, dsty,
+ width, height,
+ src_linear_ptr, src_tex->stride[src->level],
+ srcx, srcy);
+ }
+ return;
+ }
+
util_surface_copy(pipe, FALSE,
- dest, destx, desty,
+ dst, dstx, dsty,
src, srcx, srcy,
width, height);
}
* 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;
}
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,
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)
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:
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);
}
/**
- * 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;
}
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,
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;
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);
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) {
}
+/**
+ * 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)
{
#define LP_MAX_TEXTURE_2D_LEVELS 12 /* 2K x 2K for now */
#define LP_MAX_TEXTURE_3D_LEVELS 10 /* 512 x 512 x 512 for now */
+#define LP_MAX_TEXTURE_LEVELS LP_MAX_TEXTURE_2D_LEVELS
+
+
+enum lp_texture_usage
+{
+ LP_TEX_USAGE_READ = 100,
+ LP_TEX_USAGE_READ_WRITE,
+ LP_TEX_USAGE_WRITE_ALL
+};
+
+
+/** Per-tile layout mode */
+enum lp_texture_layout
+{
+ LP_TEX_LAYOUT_NONE = 0, /**< no layout for the tile data yet */
+ LP_TEX_LAYOUT_TILED, /**< the tile data is in tiled layout */
+ LP_TEX_LAYOUT_LINEAR, /**< the tile data is in linear layout */
+ LP_TEX_LAYOUT_BOTH /**< the tile data is in both modes */
+};
+
struct pipe_context;
struct pipe_screen;
struct sw_displaytarget;
+/**
+ * We keep one or two copies of the texture image data: one in a simple
+ * linear layout (for texture sampling) and another in a tiled layout (for
+ * render targets). We keep track of whether each image tile is linear
+ * or tiled on a per-tile basis.
+ */
+
+
+/** A 1D/2D/3D image, one mipmap level */
+struct llvmpipe_texture_image
+{
+ void *data;
+};
+
+
+/**
+ * llvmpipe subclass of pipe_resource. A texture, drawing surface,
+ * vertex buffer, const buffer, etc.
+ * Textures are stored differently than othere types of objects such as
+ * vertex buffers and const buffers.
+ * The former are tiled and have per-tile layout flags.
+ * The later are simple malloc'd blocks of memory.
+ */
struct llvmpipe_resource
{
struct pipe_resource base;
- unsigned long level_offset[LP_MAX_TEXTURE_2D_LEVELS];
- unsigned stride[LP_MAX_TEXTURE_2D_LEVELS];
+ /** Row stride in bytes */
+ unsigned stride[LP_MAX_TEXTURE_LEVELS];
+ unsigned tiles_per_row[LP_MAX_TEXTURE_LEVELS];
/**
* Display target, for textures with the PIPE_BIND_DISPLAY_TARGET
/**
* Malloc'ed data for regular textures, or a mapping to dt above.
*/
+ struct llvmpipe_texture_image tiled[LP_MAX_TEXTURE_LEVELS];
+ struct llvmpipe_texture_image linear[LP_MAX_TEXTURE_LEVELS];
+
+ /**
+ * Data for non-texture resources.
+ */
void *data;
+ /** per-tile layout info */
+ enum lp_texture_layout *layout[PIPE_TEX_FACE_MAX][LP_MAX_TEXTURE_LEVELS];
+
boolean userBuffer; /** Is this a user-space buffer? */
unsigned timestamp;
+
+ unsigned id; /**< temporary, for debugging */
};
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);
void
llvmpipe_resource_unmap(struct pipe_resource *texture,
unsigned zslice);
+void *
+llvmpipe_resource_data(struct pipe_resource *resource);
+
+
+void *
+llvmpipe_get_texture_image_address(struct llvmpipe_resource *lpt,
+ unsigned face, unsigned level,
+ enum lp_texture_layout layout);
+
+void *
+llvmpipe_get_texture_image(struct llvmpipe_resource *resource,
+ unsigned face, unsigned level,
+ enum lp_texture_usage usage,
+ enum lp_texture_layout layout);
+
+
+ubyte *
+llvmpipe_get_texture_tile_linear(struct llvmpipe_resource *lpt,
+ unsigned face, unsigned level,
+ enum lp_texture_usage usage,
+ unsigned x, unsigned y);
+
+ubyte *
+llvmpipe_get_texture_tile(struct llvmpipe_resource *lpt,
+ unsigned face, unsigned level,
+ enum lp_texture_usage usage,
+ unsigned x, unsigned y);
+
+
+
+extern void
+llvmpipe_init_screen_texture_funcs(struct pipe_screen *screen);
+
+extern void
+llvmpipe_init_context_texture_funcs(struct pipe_context *pipe);
+
#endif /* LP_TEXTURE_H */
**************************************************************************/
+/**
+ * Code to convert images from tiled to linear and back.
+ * XXX there are quite a few assumptions about color and z/stencil being
+ * 32bpp.
+ */
+
+
+#include "util/u_format.h"
#include "lp_tile_soa.h"
#include "lp_tile_image.h"
#define BYTES_PER_TILE (TILE_SIZE * TILE_SIZE * 4)
+/**
+ * Untile a 4x4 block of 32-bit words (all contiguous) to linear layout
+ * at dst, with dst_stride words between rows.
+ */
+static void
+untile_4_4_uint32(const uint32_t *src, uint32_t *dst, unsigned dst_stride)
+{
+ uint32_t *d0 = dst;
+ uint32_t *d1 = d0 + dst_stride;
+ uint32_t *d2 = d1 + dst_stride;
+ uint32_t *d3 = d2 + dst_stride;
+
+ d0[0] = src[0]; d0[1] = src[1]; d0[2] = src[4]; d0[3] = src[5];
+ d1[0] = src[2]; d1[1] = src[3]; d1[2] = src[6]; d1[3] = src[7];
+ d2[0] = src[8]; d2[1] = src[9]; d2[2] = src[12]; d2[3] = src[13];
+ d3[0] = src[10]; d3[1] = src[11]; d3[2] = src[14]; d3[3] = src[15];
+}
+
+
+
+/**
+ * Untile a 4x4 block of 16-bit words (all contiguous) to linear layout
+ * at dst, with dst_stride words between rows.
+ */
+static void
+untile_4_4_uint16(const uint16_t *src, uint16_t *dst, unsigned dst_stride)
+{
+ uint16_t *d0 = dst;
+ uint16_t *d1 = d0 + dst_stride;
+ uint16_t *d2 = d1 + dst_stride;
+ uint16_t *d3 = d2 + dst_stride;
+
+ d0[0] = src[0]; d0[1] = src[1]; d0[2] = src[4]; d0[3] = src[5];
+ d1[0] = src[2]; d1[1] = src[3]; d1[2] = src[6]; d1[3] = src[7];
+ d2[0] = src[8]; d2[1] = src[9]; d2[2] = src[12]; d2[3] = src[13];
+ d3[0] = src[10]; d3[1] = src[11]; d3[2] = src[14]; d3[3] = src[15];
+}
+
+
+
+/**
+ * Convert a 4x4 rect of 32-bit words from a linear layout into tiled
+ * layout (in which all 16 words are contiguous).
+ */
+static void
+tile_4_4_uint32(const uint32_t *src, uint32_t *dst, unsigned src_stride)
+{
+ const uint32_t *s0 = src;
+ const uint32_t *s1 = s0 + src_stride;
+ const uint32_t *s2 = s1 + src_stride;
+ const uint32_t *s3 = s2 + src_stride;
+
+ dst[0] = s0[0]; dst[1] = s0[1]; dst[4] = s0[2]; dst[5] = s0[3];
+ dst[2] = s1[0]; dst[3] = s1[1]; dst[6] = s1[2]; dst[7] = s1[3];
+ dst[8] = s2[0]; dst[9] = s2[1]; dst[12] = s2[2]; dst[13] = s2[3];
+ dst[10] = s3[0]; dst[11] = s3[1]; dst[14] = s3[2]; dst[15] = s3[3];
+}
+
+
+
+/**
+ * Convert a 4x4 rect of 16-bit words from a linear layout into tiled
+ * layout (in which all 16 words are contiguous).
+ */
+static void
+tile_4_4_uint16(const uint16_t *src, uint16_t *dst, unsigned src_stride)
+{
+ const uint16_t *s0 = src;
+ const uint16_t *s1 = s0 + src_stride;
+ const uint16_t *s2 = s1 + src_stride;
+ const uint16_t *s3 = s2 + src_stride;
+
+ dst[0] = s0[0]; dst[1] = s0[1]; dst[4] = s0[2]; dst[5] = s0[3];
+ dst[2] = s1[0]; dst[3] = s1[1]; dst[6] = s1[2]; dst[7] = s1[3];
+ dst[8] = s2[0]; dst[9] = s2[1]; dst[12] = s2[2]; dst[13] = s2[3];
+ dst[10] = s3[0]; dst[11] = s3[1]; dst[14] = s3[2]; dst[15] = s3[3];
+}
+
+
+
/**
* Convert a tiled image into a linear image.
* \param src_stride source row stride in bytes (bytes per row of tiles)
* \param dst_stride dest row stride in bytes
*/
void
-lp_tiled_to_linear(const uint8_t *src,
- uint8_t *dst,
+lp_tiled_to_linear(const void *src, void *dst,
+ unsigned x, unsigned y,
unsigned width, unsigned height,
- enum pipe_format format,
- unsigned src_stride,
- unsigned dst_stride)
+ enum pipe_format format, unsigned dst_stride)
{
- const unsigned tiles_per_row = src_stride / BYTES_PER_TILE;
- unsigned i, j;
-
- for (j = 0; j < height; j += TILE_SIZE) {
- for (i = 0; i < width; i += TILE_SIZE) {
- unsigned tile_offset =
- ((j / TILE_SIZE) * tiles_per_row + i / TILE_SIZE);
- unsigned byte_offset = tile_offset * BYTES_PER_TILE;
- const uint8_t *src_tile = src + byte_offset;
-
- lp_tile_write_4ub(format,
- src_tile,
- dst,
- dst_stride,
- i, j, TILE_SIZE, TILE_SIZE);
+ assert(x % TILE_SIZE == 0);
+ assert(y % TILE_SIZE == 0);
+ /*assert(width % TILE_SIZE == 0);
+ assert(height % TILE_SIZE == 0);*/
+
+ /* Note that Z/stencil surfaces use a different tiling size than
+ * color surfaces.
+ */
+ if (util_format_is_depth_or_stencil(format)) {
+ const uint bpp = util_format_get_blocksize(format);
+ const uint src_stride = dst_stride * TILE_VECTOR_WIDTH;
+ const uint tile_w = TILE_VECTOR_WIDTH, tile_h = TILE_VECTOR_HEIGHT;
+ const uint tiles_per_row = src_stride / (tile_w * tile_h * bpp);
+
+ dst_stride /= bpp; /* convert from bytes to words */
+
+ if (bpp == 4) {
+ const uint32_t *src32 = (const uint32_t *) src;
+ uint32_t *dst32 = (uint32_t *) dst;
+ uint i, j;
+
+ for (j = 0; j < height; j += tile_h) {
+ for (i = 0; i < width; i += tile_w) {
+ /* compute offsets in 32-bit words */
+ uint ii = i + x, jj = j + y;
+ uint src_offset = (jj / tile_h * tiles_per_row + ii / tile_w)
+ * (tile_w * tile_h);
+ uint dst_offset = jj * dst_stride + ii;
+ untile_4_4_uint32(src32 + src_offset,
+ dst32 + dst_offset,
+ dst_stride);
+ }
+ }
+ }
+ else {
+ const uint16_t *src16 = (const uint16_t *) src;
+ uint16_t *dst16 = (uint16_t *) dst;
+ uint i, j;
+
+ assert(bpp == 2);
+
+ for (j = 0; j < height; j += tile_h) {
+ for (i = 0; i < width; i += tile_w) {
+ /* compute offsets in 16-bit words */
+ uint ii = i + x, jj = j + y;
+ uint src_offset = (jj / tile_h * tiles_per_row + ii / tile_w)
+ * (tile_w * tile_h);
+ uint dst_offset = jj * dst_stride + ii;
+ untile_4_4_uint16(src16 + src_offset,
+ dst16 + dst_offset,
+ dst_stride);
+ }
+ }
+ }
+ }
+ else {
+ /* color image */
+ const uint bpp = 4;
+ const uint tile_w = TILE_SIZE, tile_h = TILE_SIZE;
+ const uint bytes_per_tile = tile_w * tile_h * bpp;
+ const uint src_stride = dst_stride * tile_w;
+ const uint tiles_per_row = src_stride / bytes_per_tile;
+ uint i, j;
+
+ for (j = 0; j < height; j += tile_h) {
+ for (i = 0; i < width; i += tile_w) {
+ uint ii = i + x, jj = j + y;
+ uint tile_offset = ((jj / tile_h) * tiles_per_row + ii / tile_w);
+ uint byte_offset = tile_offset * bytes_per_tile;
+ const uint8_t *src_tile = (uint8_t *) src + byte_offset;
+
+ lp_tile_write_4ub(format,
+ src_tile,
+ dst, dst_stride,
+ ii, jj, tile_w, tile_h);
+ }
}
}
}
* \param dst_stride dest row stride in bytes (bytes per row of tiles)
*/
void
-lp_linear_to_tiled(const uint8_t *src,
- uint8_t *dst,
+lp_linear_to_tiled(const void *src, void *dst,
+ unsigned x, unsigned y,
unsigned width, unsigned height,
- enum pipe_format format,
- unsigned src_stride,
- unsigned dst_stride)
+ enum pipe_format format, unsigned src_stride)
{
- const unsigned tiles_per_row = dst_stride / BYTES_PER_TILE;
- unsigned i, j;
-
- for (j = 0; j < height; j += TILE_SIZE) {
- for (i = 0; i < width; i += TILE_SIZE) {
- unsigned tile_offset =
- ((j / TILE_SIZE) * tiles_per_row + i / TILE_SIZE);
- unsigned byte_offset = tile_offset * BYTES_PER_TILE;
- uint8_t *dst_tile = dst + byte_offset;
-
- lp_tile_read_4ub(format,
- dst_tile,
- src,
- src_stride,
- i, j, TILE_SIZE, TILE_SIZE);
+ assert(x % TILE_SIZE == 0);
+ assert(y % TILE_SIZE == 0);
+ /*
+ assert(width % TILE_SIZE == 0);
+ assert(height % TILE_SIZE == 0);
+ */
+
+ if (util_format_is_depth_or_stencil(format)) {
+ const uint bpp = util_format_get_blocksize(format);
+ const uint dst_stride = src_stride * TILE_VECTOR_WIDTH;
+ const uint tile_w = TILE_VECTOR_WIDTH, tile_h = TILE_VECTOR_HEIGHT;
+ const uint tiles_per_row = dst_stride / (tile_w * tile_h * bpp);
+
+ src_stride /= bpp; /* convert from bytes to words */
+
+ if (bpp == 4) {
+ const uint32_t *src32 = (const uint32_t *) src;
+ uint32_t *dst32 = (uint32_t *) dst;
+ uint i, j;
+
+ for (j = 0; j < height; j += tile_h) {
+ for (i = 0; i < width; i += tile_w) {
+ /* compute offsets in 32-bit words */
+ uint ii = i + x, jj = j + y;
+ uint src_offset = jj * src_stride + ii;
+ uint dst_offset = (jj / tile_h * tiles_per_row + ii / tile_w)
+ * (tile_w * tile_h);
+ tile_4_4_uint32(src32 + src_offset,
+ dst32 + dst_offset,
+ src_stride);
+ }
+ }
+ }
+ else {
+ const uint16_t *src16 = (const uint16_t *) src;
+ uint16_t *dst16 = (uint16_t *) dst;
+ uint i, j;
+
+ assert(bpp == 2);
+
+ for (j = 0; j < height; j += tile_h) {
+ for (i = 0; i < width; i += tile_w) {
+ /* compute offsets in 16-bit words */
+ uint ii = i + x, jj = j + y;
+ uint src_offset = jj * src_stride + ii;
+ uint dst_offset = (jj / tile_h * tiles_per_row + ii / tile_w)
+ * (tile_w * tile_h);
+ tile_4_4_uint16(src16 + src_offset,
+ dst16 + dst_offset,
+ src_stride);
+ }
+ }
+ }
+ }
+ else {
+ const uint bpp = 4;
+ const uint tile_w = TILE_SIZE, tile_h = TILE_SIZE;
+ const uint bytes_per_tile = tile_w * tile_h * bpp;
+ const uint dst_stride = src_stride * tile_w;
+ const uint tiles_per_row = dst_stride / bytes_per_tile;
+ uint i, j;
+
+ for (j = 0; j < height; j += TILE_SIZE) {
+ for (i = 0; i < width; i += TILE_SIZE) {
+ uint ii = i + x, jj = j + y;
+ uint tile_offset = ((jj / tile_h) * tiles_per_row + ii / tile_w);
+ uint byte_offset = tile_offset * bytes_per_tile;
+ uint8_t *dst_tile = (uint8_t *) dst + byte_offset;
+
+ lp_tile_read_4ub(format,
+ dst_tile,
+ src, src_stride,
+ ii, jj, tile_w, tile_h);
+ }
}
}
}
* For testing only.
*/
void
-test_tiled_linear_conversion(uint8_t *data,
+test_tiled_linear_conversion(void *data,
enum pipe_format format,
unsigned width, unsigned height,
unsigned stride)
uint8_t *tiled = malloc(wt * ht * TILE_SIZE * TILE_SIZE * 4);
- unsigned tiled_stride = wt * TILE_SIZE * TILE_SIZE * 4;
+ /*unsigned tiled_stride = wt * TILE_SIZE * TILE_SIZE * 4;*/
- lp_linear_to_tiled(data, tiled, width, height, format,
- stride, tiled_stride);
+ lp_linear_to_tiled(data, tiled, 0, 0, width, height, format,
+ stride);
- lp_tiled_to_linear(tiled, data, width, height, format,
- tiled_stride, stride);
+ lp_tiled_to_linear(tiled, data, 0, 0, width, height, format,
+ stride);
free(tiled);
}
void
-lp_tiled_to_linear(const uint8_t *src,
- uint8_t *dst,
+lp_tiled_to_linear(const void *src, void *dst,
+ unsigned x, unsigned y,
unsigned width, unsigned height,
- enum pipe_format format,
- unsigned src_stride,
- unsigned dst_stride);
+ enum pipe_format format, unsigned dst_stride);
void
-lp_linear_to_tiled(const uint8_t *src,
- uint8_t *dst,
+lp_linear_to_tiled(const void *src, void *dst,
+ unsigned x, unsigned y,
unsigned width, unsigned height,
- enum pipe_format format,
- unsigned src_stride,
- unsigned dst_stride);
+ enum pipe_format format, unsigned src_stride);
void
-test_tiled_linear_conversion(uint8_t *data,
+test_tiled_linear_conversion(void *data,
enum pipe_format format,
unsigned width, unsigned height,
unsigned stride);
#define TILE_X_STRIDE (NUM_CHANNELS * TILE_C_STRIDE) //64
#define TILE_Y_STRIDE (TILE_VECTOR_HEIGHT * TILE_SIZE * NUM_CHANNELS) //1024
-#define TILE_PIXEL(_p, _x, _y, _c) \
- ((_p)[((_y) / TILE_VECTOR_HEIGHT) * TILE_Y_STRIDE + \
- ((_x) / TILE_VECTOR_WIDTH) * TILE_X_STRIDE + \
- (_c) * TILE_C_STRIDE + \
- tile_offset[(_y) % TILE_VECTOR_HEIGHT][(_x) % TILE_VECTOR_WIDTH]])
+
+extern int tile_write_count, tile_read_count;
+
+
+/**
+ * Return offset of the given pixel (and color channel) from the start
+ * of a tile, in bytes.
+ */
+static INLINE unsigned
+tile_pixel_offset(unsigned x, unsigned y, unsigned c)
+{
+ unsigned ix = (x / TILE_VECTOR_WIDTH) * TILE_X_STRIDE;
+ unsigned iy = (y / TILE_VECTOR_HEIGHT) * TILE_Y_STRIDE;
+ unsigned offset = iy + ix + c * TILE_C_STRIDE +
+ tile_offset[y % TILE_VECTOR_HEIGHT][x % TILE_VECTOR_WIDTH];
+ return offset;
+}
+
+
+#define TILE_PIXEL(_p, _x, _y, _c) ((_p)[tile_pixel_offset(_x, _y, _c)])
void
print 'lp_tile_read_%s(enum pipe_format format, %s *dst, const void *src, unsigned src_stride, unsigned x, unsigned y, unsigned w, unsigned h)' % (dst_suffix, dst_native_type)
print '{'
print ' void (*func)(%s *dst, const uint8_t *src, unsigned src_stride, unsigned x0, unsigned y0, unsigned w, unsigned h);' % dst_native_type
+ print ' tile_read_count += 1;'
print ' switch(format) {'
for format in formats:
if is_format_supported(format):
print '{'
print ' void (*func)(const %s *src, uint8_t *dst, unsigned dst_stride, unsigned x0, unsigned y0, unsigned w, unsigned h);' % src_native_type
+ print ' tile_write_count += 1;'
print ' switch(format) {'
for format in formats:
if is_format_supported(format):
print '#include "util/u_half.h"'
print '#include "lp_tile_soa.h"'
print
+ print 'int tile_write_count=0, tile_read_count=0;'
+ print
print 'const unsigned char'
print 'tile_offset[TILE_VECTOR_HEIGHT][TILE_VECTOR_WIDTH] = {'
print ' { 0, 1, 4, 5},'