2009-10-08 12:51:46 +01:00
|
|
|
/**************************************************************************
|
|
|
|
*
|
|
|
|
* Copyright 2009 VMware, Inc.
|
|
|
|
* All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
* copy of this software and associated documentation files (the
|
|
|
|
* "Software"), to deal in the Software without restriction, including
|
|
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
* distribute, sub license, and/or sell copies of the Software, and to
|
|
|
|
* permit persons to whom the Software is furnished to do so, subject to
|
|
|
|
* the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice (including the
|
|
|
|
* next paragraph) shall be included in all copies or substantial portions
|
|
|
|
* of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
|
|
|
|
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
|
|
|
|
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
|
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
|
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
*
|
|
|
|
**************************************************************************/
|
|
|
|
|
2009-12-16 23:02:59 +00:00
|
|
|
#include <limits.h>
|
2009-10-08 12:51:46 +01:00
|
|
|
#include "util/u_memory.h"
|
2009-12-08 01:01:12 +00:00
|
|
|
#include "util/u_math.h"
|
2009-12-08 08:02:49 +00:00
|
|
|
#include "util/u_cpu_detect.h"
|
2009-12-11 18:46:23 +00:00
|
|
|
#include "util/u_surface.h"
|
2009-10-08 12:51:46 +01:00
|
|
|
|
2009-12-13 18:17:25 +00:00
|
|
|
#include "lp_scene_queue.h"
|
2009-12-04 21:11:25 +00:00
|
|
|
#include "lp_debug.h"
|
2009-12-12 00:57:45 +00:00
|
|
|
#include "lp_fence.h"
|
2009-10-08 12:51:46 +01:00
|
|
|
#include "lp_rast.h"
|
2009-10-08 17:26:13 +01:00
|
|
|
#include "lp_rast_priv.h"
|
|
|
|
#include "lp_tile_soa.h"
|
|
|
|
#include "lp_bld_debug.h"
|
2009-12-13 18:17:25 +00:00
|
|
|
#include "lp_scene.h"
|
2009-10-08 12:51:46 +01:00
|
|
|
|
2009-10-07 22:36:43 +01:00
|
|
|
|
2009-11-30 21:02:01 +00:00
|
|
|
/**
|
|
|
|
* Begin the rasterization phase.
|
|
|
|
* Map the framebuffer surfaces. Initialize the 'rast' state.
|
|
|
|
*/
|
2009-12-04 22:31:09 +00:00
|
|
|
static boolean
|
|
|
|
lp_rast_begin( struct lp_rasterizer *rast,
|
2009-12-11 18:46:23 +00:00
|
|
|
const struct pipe_framebuffer_state *fb,
|
|
|
|
boolean write_color,
|
|
|
|
boolean write_zstencil )
|
2009-10-09 10:24:19 +01:00
|
|
|
{
|
2009-10-09 14:29:25 +01:00
|
|
|
struct pipe_screen *screen = rast->screen;
|
2009-12-11 18:46:23 +00:00
|
|
|
struct pipe_surface *cbuf, *zsbuf;
|
2010-01-10 17:22:09 +00:00
|
|
|
int i;
|
2009-10-09 14:29:25 +01:00
|
|
|
|
2009-12-11 18:46:23 +00:00
|
|
|
LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
|
2009-10-09 14:02:39 +01:00
|
|
|
|
2009-12-11 18:46:23 +00:00
|
|
|
util_copy_framebuffer_state(&rast->state.fb, fb);
|
2009-10-09 14:29:25 +01:00
|
|
|
|
|
|
|
rast->state.write_zstencil = write_zstencil;
|
|
|
|
rast->state.write_color = write_color;
|
|
|
|
|
2009-12-11 18:46:23 +00:00
|
|
|
rast->check_for_clipped_tiles = (fb->width % TILE_SIZE != 0 ||
|
|
|
|
fb->height % TILE_SIZE != 0);
|
2009-10-09 10:24:19 +01:00
|
|
|
|
2010-01-10 17:22:09 +00:00
|
|
|
|
|
|
|
for (i = 0; i < rast->state.fb.nr_cbufs; i++) {
|
|
|
|
cbuf = rast->state.fb.cbufs[i];
|
|
|
|
if (cbuf) {
|
|
|
|
rast->cbuf_transfer[i] = screen->get_tex_transfer(rast->screen,
|
|
|
|
cbuf->texture,
|
|
|
|
cbuf->face,
|
|
|
|
cbuf->level,
|
|
|
|
cbuf->zslice,
|
|
|
|
PIPE_TRANSFER_READ_WRITE,
|
|
|
|
0, 0,
|
|
|
|
cbuf->width,
|
|
|
|
cbuf->height);
|
|
|
|
if (!rast->cbuf_transfer[i])
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
rast->cbuf_map[i] = screen->transfer_map(rast->screen,
|
|
|
|
rast->cbuf_transfer[i]);
|
|
|
|
if (!rast->cbuf_map[i])
|
|
|
|
goto fail;
|
|
|
|
}
|
2009-10-09 14:29:25 +01:00
|
|
|
}
|
2009-10-09 14:02:39 +01:00
|
|
|
|
2009-12-11 18:46:23 +00:00
|
|
|
zsbuf = rast->state.fb.zsbuf;
|
2009-12-03 18:41:45 +00:00
|
|
|
if (zsbuf) {
|
|
|
|
rast->zsbuf_transfer = screen->get_tex_transfer(rast->screen,
|
2009-12-11 18:46:23 +00:00
|
|
|
zsbuf->texture,
|
|
|
|
zsbuf->face,
|
|
|
|
zsbuf->level,
|
|
|
|
zsbuf->zslice,
|
|
|
|
PIPE_TRANSFER_READ_WRITE,
|
|
|
|
0, 0,
|
2010-01-10 17:22:09 +00:00
|
|
|
zsbuf->width,
|
|
|
|
zsbuf->height);
|
2009-12-03 18:41:45 +00:00
|
|
|
if (!rast->zsbuf_transfer)
|
2010-01-10 17:22:09 +00:00
|
|
|
goto fail;
|
2009-12-03 18:41:45 +00:00
|
|
|
|
|
|
|
rast->zsbuf_map = screen->transfer_map(rast->screen,
|
|
|
|
rast->zsbuf_transfer);
|
|
|
|
if (!rast->zsbuf_map)
|
2010-01-10 17:22:09 +00:00
|
|
|
goto fail;
|
2009-12-03 18:41:45 +00:00
|
|
|
}
|
|
|
|
|
2009-10-09 14:29:25 +01:00
|
|
|
return TRUE;
|
2010-01-10 17:22:09 +00:00
|
|
|
|
|
|
|
fail:
|
|
|
|
/* Unmap and release transfers?
|
|
|
|
*/
|
|
|
|
return FALSE;
|
2009-10-08 19:58:28 +01:00
|
|
|
}
|
|
|
|
|
2009-10-09 14:29:25 +01:00
|
|
|
|
2009-11-30 21:02:01 +00:00
|
|
|
/**
|
|
|
|
* Finish the rasterization phase.
|
|
|
|
* Unmap framebuffer surfaces.
|
|
|
|
*/
|
2009-12-04 22:31:09 +00:00
|
|
|
static void
|
|
|
|
lp_rast_end( struct lp_rasterizer *rast )
|
2009-10-08 19:58:28 +01:00
|
|
|
{
|
2009-10-09 14:29:25 +01:00
|
|
|
struct pipe_screen *screen = rast->screen;
|
2010-01-10 17:22:09 +00:00
|
|
|
unsigned i;
|
2009-10-09 14:02:39 +01:00
|
|
|
|
2010-01-10 17:22:09 +00:00
|
|
|
for (i = 0; i < rast->state.fb.nr_cbufs; i++) {
|
|
|
|
if (rast->cbuf_map[i])
|
|
|
|
screen->transfer_unmap(screen, rast->cbuf_transfer[i]);
|
|
|
|
|
|
|
|
if (rast->cbuf_transfer[i])
|
|
|
|
screen->tex_transfer_destroy(rast->cbuf_transfer[i]);
|
|
|
|
|
|
|
|
rast->cbuf_transfer[i] = NULL;
|
|
|
|
rast->cbuf_map[i] = NULL;
|
|
|
|
}
|
2009-10-09 14:29:25 +01:00
|
|
|
|
|
|
|
if (rast->zsbuf_map)
|
|
|
|
screen->transfer_unmap(screen, rast->zsbuf_transfer);
|
|
|
|
|
|
|
|
if (rast->zsbuf_transfer)
|
2009-12-03 18:41:45 +00:00
|
|
|
screen->tex_transfer_destroy(rast->zsbuf_transfer);
|
2009-10-09 14:29:25 +01:00
|
|
|
|
|
|
|
rast->zsbuf_transfer = NULL;
|
|
|
|
rast->zsbuf_map = NULL;
|
2009-10-07 22:36:43 +01:00
|
|
|
}
|
|
|
|
|
2009-10-08 17:20:40 +01:00
|
|
|
|
2009-11-30 21:02:01 +00:00
|
|
|
/**
|
|
|
|
* 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
|
2009-10-07 22:36:43 +01:00
|
|
|
*/
|
2009-12-04 21:47:40 +00:00
|
|
|
static void
|
|
|
|
lp_rast_start_tile( struct lp_rasterizer *rast,
|
2009-12-08 00:02:17 +00:00
|
|
|
unsigned thread_index,
|
2009-12-04 21:47:40 +00:00
|
|
|
unsigned x, unsigned y )
|
2009-10-07 22:36:43 +01:00
|
|
|
{
|
2009-12-04 21:11:25 +00:00
|
|
|
LP_DBG(DEBUG_RAST, "%s %d,%d\n", __FUNCTION__, x, y);
|
2009-10-09 14:02:39 +01:00
|
|
|
|
2009-12-08 00:02:17 +00:00
|
|
|
rast->tasks[thread_index].x = x;
|
|
|
|
rast->tasks[thread_index].y = y;
|
2009-10-07 22:36:43 +01:00
|
|
|
}
|
|
|
|
|
2009-11-30 21:02:01 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Clear the rasterizer's current color tile.
|
2009-12-03 21:57:44 +00:00
|
|
|
* This is a bin command called during bin processing.
|
2009-11-30 21:02:01 +00:00
|
|
|
*/
|
2009-10-08 17:20:40 +01:00
|
|
|
void lp_rast_clear_color( struct lp_rasterizer *rast,
|
2009-12-08 00:02:17 +00:00
|
|
|
unsigned thread_index,
|
2009-10-09 11:29:01 +01:00
|
|
|
const union lp_rast_cmd_arg arg )
|
2009-10-07 22:36:43 +01:00
|
|
|
{
|
2009-10-09 11:29:01 +01:00
|
|
|
const uint8_t *clear_color = arg.clear_color;
|
2010-01-10 17:22:09 +00:00
|
|
|
uint8_t **color_tile = rast->tasks[thread_index].tile.color;
|
|
|
|
unsigned i;
|
|
|
|
|
2009-12-04 21:11:25 +00:00
|
|
|
LP_DBG(DEBUG_RAST, "%s 0x%x,0x%x,0x%x,0x%x\n", __FUNCTION__,
|
2009-10-09 14:07:25 +01:00
|
|
|
clear_color[0],
|
|
|
|
clear_color[1],
|
|
|
|
clear_color[2],
|
|
|
|
clear_color[3]);
|
2009-10-09 14:02:39 +01:00
|
|
|
|
2009-10-08 17:59:44 +01:00
|
|
|
if (clear_color[0] == clear_color[1] &&
|
|
|
|
clear_color[1] == clear_color[2] &&
|
|
|
|
clear_color[2] == clear_color[3]) {
|
2010-01-10 17:22:09 +00:00
|
|
|
for (i = 0; i < rast->state.fb.nr_cbufs; i++) {
|
|
|
|
memset(color_tile[i], clear_color[0], TILE_SIZE * TILE_SIZE * 4);
|
|
|
|
}
|
2009-10-08 17:59:44 +01:00
|
|
|
}
|
|
|
|
else {
|
2009-10-08 19:16:47 +01:00
|
|
|
unsigned x, y, chan;
|
2010-01-10 17:22:09 +00:00
|
|
|
for (i = 0; i < rast->state.fb.nr_cbufs; i++)
|
|
|
|
for (y = 0; y < TILE_SIZE; y++)
|
|
|
|
for (x = 0; x < TILE_SIZE; x++)
|
|
|
|
for (chan = 0; chan < 4; ++chan)
|
|
|
|
TILE_PIXEL(color_tile[i], x, y, chan) = clear_color[chan];
|
2009-10-08 17:59:44 +01:00
|
|
|
}
|
2009-10-07 22:36:43 +01:00
|
|
|
}
|
|
|
|
|
2009-11-30 21:02:01 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Clear the rasterizer's current z/stencil tile.
|
2009-12-03 21:57:44 +00:00
|
|
|
* This is a bin command called during bin processing.
|
2009-11-30 21:02:01 +00:00
|
|
|
*/
|
2009-10-08 17:20:40 +01:00
|
|
|
void lp_rast_clear_zstencil( struct lp_rasterizer *rast,
|
2009-12-08 00:02:17 +00:00
|
|
|
unsigned thread_index,
|
2009-10-09 11:29:01 +01:00
|
|
|
const union lp_rast_cmd_arg arg)
|
2009-10-07 22:36:43 +01:00
|
|
|
{
|
|
|
|
unsigned i, j;
|
2009-12-08 00:02:17 +00:00
|
|
|
uint32_t *depth_tile = rast->tasks[thread_index].tile.depth;
|
2009-10-07 22:36:43 +01:00
|
|
|
|
2009-12-04 21:11:25 +00:00
|
|
|
LP_DBG(DEBUG_RAST, "%s 0x%x\n", __FUNCTION__, arg.clear_zstencil);
|
2009-10-09 14:02:39 +01:00
|
|
|
|
2009-10-08 17:59:44 +01:00
|
|
|
for (i = 0; i < TILE_SIZE; i++)
|
|
|
|
for (j = 0; j < TILE_SIZE; j++)
|
2009-12-08 00:02:17 +00:00
|
|
|
depth_tile[i*TILE_SIZE + j] = arg.clear_zstencil;
|
2009-10-07 22:36:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-03 21:57:44 +00:00
|
|
|
/**
|
|
|
|
* Load tile color from the framebuffer surface.
|
|
|
|
* This is a bin command called during bin processing.
|
|
|
|
*/
|
2009-10-08 17:20:40 +01:00
|
|
|
void lp_rast_load_color( struct lp_rasterizer *rast,
|
2009-12-08 00:02:17 +00:00
|
|
|
unsigned thread_index,
|
2009-10-09 11:29:01 +01:00
|
|
|
const union lp_rast_cmd_arg arg)
|
2009-10-07 22:36:43 +01:00
|
|
|
{
|
2009-12-11 22:00:28 +00:00
|
|
|
struct lp_rasterizer_task *task = &rast->tasks[thread_index];
|
|
|
|
const unsigned x = task->x;
|
|
|
|
const unsigned y = task->y;
|
2010-01-10 17:22:09 +00:00
|
|
|
unsigned i;
|
2009-12-11 22:00:28 +00:00
|
|
|
|
|
|
|
LP_DBG(DEBUG_RAST, "%s at %u, %u\n", __FUNCTION__, x, y);
|
|
|
|
|
2010-01-10 17:22:09 +00:00
|
|
|
for (i = 0; i < rast->state.fb.nr_cbufs; i++) {
|
|
|
|
struct pipe_transfer *transfer = rast->cbuf_transfer[i];
|
|
|
|
int w = TILE_SIZE;
|
|
|
|
int h = TILE_SIZE;
|
2009-12-11 22:00:28 +00:00
|
|
|
|
2010-01-10 17:22:09 +00:00
|
|
|
if (x >= transfer->width)
|
|
|
|
continue;
|
2009-12-11 22:00:28 +00:00
|
|
|
|
2010-01-10 17:22:09 +00:00
|
|
|
if (y >= transfer->height)
|
|
|
|
continue;
|
|
|
|
/* XXX: require tile-size aligned render target dimensions:
|
|
|
|
*/
|
|
|
|
if (x + w > transfer->width)
|
|
|
|
w -= x + w - transfer->width;
|
|
|
|
|
|
|
|
if (y + h > transfer->height)
|
|
|
|
h -= y + h - transfer->height;
|
|
|
|
|
|
|
|
assert(w >= 0);
|
|
|
|
assert(h >= 0);
|
|
|
|
assert(w <= TILE_SIZE);
|
|
|
|
assert(h <= TILE_SIZE);
|
|
|
|
|
|
|
|
lp_tile_read_4ub(transfer->texture->format,
|
|
|
|
rast->tasks[thread_index].tile.color[i],
|
|
|
|
rast->cbuf_map[i],
|
|
|
|
transfer->stride,
|
|
|
|
x, y,
|
|
|
|
w, h);
|
|
|
|
}
|
2009-10-07 22:36:43 +01:00
|
|
|
}
|
|
|
|
|
2009-12-03 21:57:44 +00:00
|
|
|
|
2010-01-13 16:52:17 +00:00
|
|
|
static void
|
|
|
|
lp_tile_read_z32(uint32_t *tile,
|
|
|
|
const uint8_t *map,
|
|
|
|
unsigned map_stride,
|
|
|
|
unsigned x0, unsigned y0, unsigned w, unsigned h)
|
|
|
|
{
|
|
|
|
unsigned x, y;
|
|
|
|
const uint8_t *map_row = map + y0*map_stride;
|
|
|
|
for (y = 0; y < h; ++y) {
|
|
|
|
const uint32_t *map_pixel = (uint32_t *)(map_row + x0*4);
|
|
|
|
for (x = 0; x < w; ++x) {
|
|
|
|
*tile++ = *map_pixel++;
|
|
|
|
}
|
|
|
|
map_row += map_stride;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-03 21:57:44 +00:00
|
|
|
/**
|
|
|
|
* Load tile z/stencil from the framebuffer surface.
|
|
|
|
* This is a bin command called during bin processing.
|
|
|
|
*/
|
2009-10-08 17:20:40 +01:00
|
|
|
void lp_rast_load_zstencil( struct lp_rasterizer *rast,
|
2009-12-08 00:02:17 +00:00
|
|
|
unsigned thread_index,
|
2009-10-09 11:29:01 +01:00
|
|
|
const union lp_rast_cmd_arg arg )
|
2009-10-07 22:36:43 +01:00
|
|
|
{
|
2010-01-13 16:52:17 +00:00
|
|
|
const unsigned x = rast->tasks[thread_index].x;
|
|
|
|
const unsigned y = rast->tasks[thread_index].y;
|
|
|
|
unsigned w = TILE_SIZE;
|
|
|
|
unsigned h = TILE_SIZE;
|
|
|
|
|
|
|
|
if (x + w > rast->state.fb.width)
|
|
|
|
w -= x + w - rast->state.fb.width;
|
|
|
|
|
|
|
|
if (y + h > rast->state.fb.height)
|
|
|
|
h -= y + h - rast->state.fb.height;
|
|
|
|
|
|
|
|
LP_DBG(DEBUG_RAST, "%s %d,%d %dx%d\n", __FUNCTION__, x, y, w, h);
|
2009-10-09 14:02:39 +01:00
|
|
|
|
2010-01-13 16:52:17 +00:00
|
|
|
assert(rast->zsbuf_transfer->texture->format == PIPE_FORMAT_Z32_UNORM);
|
|
|
|
lp_tile_read_z32(rast->tasks[thread_index].tile.depth,
|
|
|
|
rast->zsbuf_map,
|
|
|
|
rast->zsbuf_transfer->stride,
|
|
|
|
x, y, w, h);
|
2009-10-07 22:36:43 +01:00
|
|
|
}
|
|
|
|
|
2009-12-03 21:57:44 +00:00
|
|
|
|
|
|
|
void lp_rast_set_state( struct lp_rasterizer *rast,
|
2009-12-08 00:02:17 +00:00
|
|
|
unsigned thread_index,
|
2009-12-03 21:57:44 +00:00
|
|
|
const union lp_rast_cmd_arg arg )
|
|
|
|
{
|
2009-12-03 23:05:12 +00:00
|
|
|
const struct lp_rast_state *state = arg.set_state;
|
|
|
|
|
2009-12-04 21:11:25 +00:00
|
|
|
LP_DBG(DEBUG_RAST, "%s %p\n", __FUNCTION__, (void *) state);
|
2009-12-03 21:57:44 +00:00
|
|
|
|
2009-12-04 18:50:40 +00:00
|
|
|
/* just set the current state pointer for this rasterizer */
|
2009-12-08 00:02:17 +00:00
|
|
|
rast->tasks[thread_index].current_state = state;
|
2009-12-03 21:57:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2009-10-07 22:36:43 +01:00
|
|
|
/* Within a tile:
|
|
|
|
*/
|
2009-10-08 11:47:33 +01:00
|
|
|
|
2009-12-03 21:57:44 +00:00
|
|
|
/**
|
|
|
|
* Run the shader on all blocks in a tile. This is used when a tile is
|
|
|
|
* completely contained inside a triangle.
|
|
|
|
* This is a bin command called during bin processing.
|
|
|
|
*/
|
2009-10-07 22:36:43 +01:00
|
|
|
void lp_rast_shade_tile( struct lp_rasterizer *rast,
|
2009-12-08 00:02:17 +00:00
|
|
|
unsigned thread_index,
|
2009-10-09 11:29:01 +01:00
|
|
|
const union lp_rast_cmd_arg arg )
|
2009-10-07 22:36:43 +01:00
|
|
|
{
|
2009-12-16 23:02:59 +00:00
|
|
|
/* Set c1,c2,c3 to large values so the in/out test always passes */
|
2009-12-17 16:00:58 +00:00
|
|
|
const int32_t c1 = INT_MIN, c2 = INT_MIN, c3 = INT_MIN;
|
2009-10-09 11:29:01 +01:00
|
|
|
const struct lp_rast_shader_inputs *inputs = arg.shade_tile;
|
2009-12-08 00:02:17 +00:00
|
|
|
const unsigned tile_x = rast->tasks[thread_index].x;
|
|
|
|
const unsigned tile_y = rast->tasks[thread_index].y;
|
2009-10-08 19:16:47 +01:00
|
|
|
unsigned x, y;
|
2009-10-07 22:36:43 +01:00
|
|
|
|
2009-12-04 21:11:25 +00:00
|
|
|
LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
|
2009-10-09 14:02:39 +01:00
|
|
|
|
2009-10-19 17:10:48 +01:00
|
|
|
/* Use the existing preference for 4x4 (four quads) shading:
|
2009-10-07 22:36:43 +01:00
|
|
|
*/
|
2009-10-19 17:10:48 +01:00
|
|
|
for (y = 0; y < TILE_SIZE; y += 4)
|
|
|
|
for (x = 0; x < TILE_SIZE; x += 4)
|
2009-12-08 00:02:17 +00:00
|
|
|
lp_rast_shade_quads( rast,
|
|
|
|
thread_index,
|
|
|
|
inputs,
|
|
|
|
tile_x + x,
|
|
|
|
tile_y + y,
|
2009-12-16 23:02:59 +00:00
|
|
|
c1, c2, c3);
|
2009-10-07 22:36:43 +01:00
|
|
|
}
|
|
|
|
|
2009-10-08 12:44:30 +01:00
|
|
|
|
2009-12-02 22:13:45 +00:00
|
|
|
/**
|
|
|
|
* Compute shading for a 4x4 block of pixels.
|
2009-12-03 21:57:44 +00:00
|
|
|
* This is a bin command called during bin processing.
|
2009-12-02 22:13:45 +00:00
|
|
|
*/
|
2009-10-08 19:03:14 +01:00
|
|
|
void lp_rast_shade_quads( struct lp_rasterizer *rast,
|
2009-12-08 00:02:17 +00:00
|
|
|
unsigned thread_index,
|
2009-10-08 19:03:14 +01:00
|
|
|
const struct lp_rast_shader_inputs *inputs,
|
|
|
|
unsigned x, unsigned y,
|
2009-12-16 23:02:59 +00:00
|
|
|
int32_t c1, int32_t c2, int32_t c3)
|
2009-10-08 12:44:30 +01:00
|
|
|
{
|
2009-12-08 00:02:17 +00:00
|
|
|
const struct lp_rast_state *state = rast->tasks[thread_index].current_state;
|
|
|
|
struct lp_rast_tile *tile = &rast->tasks[thread_index].tile;
|
2010-01-10 17:22:09 +00:00
|
|
|
uint8_t *color[PIPE_MAX_COLOR_BUFS];
|
2009-10-08 19:16:47 +01:00
|
|
|
void *depth;
|
2010-01-10 17:22:09 +00:00
|
|
|
unsigned i;
|
2009-10-20 03:17:17 +01:00
|
|
|
unsigned ix, iy;
|
2009-12-02 22:13:45 +00:00
|
|
|
int block_offset;
|
2009-10-08 12:44:30 +01:00
|
|
|
|
2009-12-16 23:02:59 +00:00
|
|
|
#ifdef DEBUG
|
2009-12-04 18:50:40 +00:00
|
|
|
assert(state);
|
|
|
|
|
2009-10-08 12:44:30 +01:00
|
|
|
/* Sanity checks */
|
|
|
|
assert(x % TILE_VECTOR_WIDTH == 0);
|
|
|
|
assert(y % TILE_VECTOR_HEIGHT == 0);
|
|
|
|
|
2009-12-15 22:39:48 +00:00
|
|
|
assert((x % 4) == 0);
|
|
|
|
assert((y % 4) == 0);
|
2009-12-16 23:02:59 +00:00
|
|
|
#endif
|
2009-12-02 22:13:45 +00:00
|
|
|
|
2009-10-09 19:16:36 +01:00
|
|
|
ix = x % TILE_SIZE;
|
|
|
|
iy = y % TILE_SIZE;
|
|
|
|
|
2009-12-02 22:13:45 +00:00
|
|
|
/* offset of the 16x16 pixel block within the tile */
|
|
|
|
block_offset = ((iy/4)*(16*16) + (ix/4)*16);
|
|
|
|
|
2009-10-08 12:44:30 +01:00
|
|
|
/* color buffer */
|
2010-01-10 17:22:09 +00:00
|
|
|
for (i = 0; i < rast->state.fb.nr_cbufs; i++)
|
|
|
|
color[i] = tile->color[i] + 4 * block_offset;
|
2009-10-08 12:44:30 +01:00
|
|
|
|
|
|
|
/* depth buffer */
|
2009-12-02 22:13:45 +00:00
|
|
|
depth = tile->depth + block_offset;
|
2009-10-08 12:44:30 +01:00
|
|
|
|
2010-01-10 17:22:09 +00:00
|
|
|
|
|
|
|
|
2009-12-16 23:02:59 +00:00
|
|
|
#ifdef DEBUG
|
2010-01-10 17:22:09 +00:00
|
|
|
assert(lp_check_alignment(tile->depth, 16));
|
|
|
|
assert(lp_check_alignment(tile->color[0], 16));
|
2009-10-09 15:52:18 +01:00
|
|
|
assert(lp_check_alignment(state->jit_context.blend_color, 16));
|
2009-10-08 12:44:30 +01:00
|
|
|
|
2009-12-16 23:02:59 +00:00
|
|
|
assert(lp_check_alignment(inputs->step[0], 16));
|
|
|
|
assert(lp_check_alignment(inputs->step[1], 16));
|
|
|
|
assert(lp_check_alignment(inputs->step[2], 16));
|
|
|
|
#endif
|
|
|
|
|
2009-10-08 12:44:30 +01:00
|
|
|
/* run shader */
|
2009-10-09 15:52:18 +01:00
|
|
|
state->jit_function( &state->jit_context,
|
2009-10-09 19:16:36 +01:00
|
|
|
x, y,
|
2009-10-09 15:52:18 +01:00
|
|
|
inputs->a0,
|
|
|
|
inputs->dadx,
|
|
|
|
inputs->dady,
|
|
|
|
color,
|
2009-12-16 23:02:59 +00:00
|
|
|
depth,
|
|
|
|
c1, c2, c3,
|
2010-01-10 17:22:09 +00:00
|
|
|
inputs->step[0], inputs->step[1], inputs->step[2]);
|
2009-10-08 12:44:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-10-07 22:36:43 +01:00
|
|
|
/* End of tile:
|
|
|
|
*/
|
2009-10-08 17:59:44 +01:00
|
|
|
|
|
|
|
|
2009-11-30 21:02:01 +00:00
|
|
|
/**
|
|
|
|
* Write the rasterizer's color tile to the framebuffer.
|
|
|
|
*/
|
2009-12-08 00:02:17 +00:00
|
|
|
static void lp_rast_store_color( struct lp_rasterizer *rast,
|
|
|
|
unsigned thread_index)
|
2009-10-07 22:36:43 +01:00
|
|
|
{
|
2009-12-08 00:02:17 +00:00
|
|
|
const unsigned x = rast->tasks[thread_index].x;
|
|
|
|
const unsigned y = rast->tasks[thread_index].y;
|
2010-01-10 17:22:09 +00:00
|
|
|
unsigned i;
|
2009-10-09 16:19:00 +01:00
|
|
|
|
2010-01-10 17:22:09 +00:00
|
|
|
for (i = 0; i < rast->state.fb.nr_cbufs; i++) {
|
|
|
|
struct pipe_transfer *transfer = rast->cbuf_transfer[i];
|
|
|
|
int w = TILE_SIZE;
|
|
|
|
int h = TILE_SIZE;
|
2009-12-08 01:18:37 +00:00
|
|
|
|
2010-01-10 17:22:09 +00:00
|
|
|
if (x >= transfer->width)
|
|
|
|
continue;
|
2009-10-09 16:19:00 +01:00
|
|
|
|
2010-01-10 17:22:09 +00:00
|
|
|
if (y >= transfer->height)
|
|
|
|
continue;
|
2009-10-07 22:36:43 +01:00
|
|
|
|
2010-01-10 17:22:09 +00:00
|
|
|
/* XXX: require tile-size aligned render target dimensions:
|
|
|
|
*/
|
|
|
|
if (x + w > transfer->width)
|
|
|
|
w -= x + w - transfer->width;
|
|
|
|
|
|
|
|
if (y + h > transfer->height)
|
|
|
|
h -= y + h - transfer->height;
|
|
|
|
|
|
|
|
assert(w >= 0);
|
|
|
|
assert(h >= 0);
|
|
|
|
assert(w <= TILE_SIZE);
|
|
|
|
assert(h <= TILE_SIZE);
|
|
|
|
|
|
|
|
LP_DBG(DEBUG_RAST, "%s [%u] %d,%d %dx%d\n", __FUNCTION__,
|
|
|
|
thread_index, x, y, w, h);
|
|
|
|
|
|
|
|
lp_tile_write_4ub(transfer->texture->format,
|
|
|
|
rast->tasks[thread_index].tile.color[i],
|
|
|
|
rast->cbuf_map[i],
|
|
|
|
transfer->stride,
|
|
|
|
x, y,
|
|
|
|
w, h);
|
|
|
|
}
|
2009-10-07 22:36:43 +01:00
|
|
|
}
|
|
|
|
|
2009-10-09 10:37:24 +01:00
|
|
|
|
2009-12-03 18:41:45 +00:00
|
|
|
static void
|
|
|
|
lp_tile_write_z32(const uint32_t *src, uint8_t *dst, unsigned dst_stride,
|
|
|
|
unsigned x0, unsigned y0, unsigned w, unsigned h)
|
|
|
|
{
|
|
|
|
unsigned x, y;
|
|
|
|
uint8_t *dst_row = dst + y0*dst_stride;
|
|
|
|
for (y = 0; y < h; ++y) {
|
|
|
|
uint32_t *dst_pixel = (uint32_t *)(dst_row + x0*4);
|
|
|
|
for (x = 0; x < w; ++x) {
|
|
|
|
*dst_pixel++ = *src++;
|
|
|
|
}
|
|
|
|
dst_row += dst_stride;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-30 21:02:01 +00:00
|
|
|
/**
|
|
|
|
* Write the rasterizer's z/stencil tile to the framebuffer.
|
|
|
|
*/
|
2009-12-08 00:02:17 +00:00
|
|
|
static void lp_rast_store_zstencil( struct lp_rasterizer *rast,
|
|
|
|
unsigned thread_index )
|
2009-10-09 10:37:24 +01:00
|
|
|
{
|
2009-12-08 00:02:17 +00:00
|
|
|
const unsigned x = rast->tasks[thread_index].x;
|
|
|
|
const unsigned y = rast->tasks[thread_index].y;
|
2009-12-03 18:41:45 +00:00
|
|
|
unsigned w = TILE_SIZE;
|
|
|
|
unsigned h = TILE_SIZE;
|
|
|
|
|
2009-12-11 18:46:23 +00:00
|
|
|
if (x + w > rast->state.fb.width)
|
|
|
|
w -= x + w - rast->state.fb.width;
|
2009-12-03 18:41:45 +00:00
|
|
|
|
2009-12-11 18:46:23 +00:00
|
|
|
if (y + h > rast->state.fb.height)
|
|
|
|
h -= y + h - rast->state.fb.height;
|
2009-12-03 18:41:45 +00:00
|
|
|
|
2009-12-04 21:11:25 +00:00
|
|
|
LP_DBG(DEBUG_RAST, "%s %d,%d %dx%d\n", __FUNCTION__, x, y, w, h);
|
2009-10-09 14:02:39 +01:00
|
|
|
|
2010-01-08 15:42:57 +00:00
|
|
|
assert(rast->zsbuf_transfer->texture->format == PIPE_FORMAT_Z32_UNORM);
|
2009-12-08 00:02:17 +00:00
|
|
|
lp_tile_write_z32(rast->tasks[thread_index].tile.depth,
|
2009-12-03 18:41:45 +00:00
|
|
|
rast->zsbuf_map,
|
|
|
|
rast->zsbuf_transfer->stride,
|
|
|
|
x, y, w, h);
|
2009-10-09 10:37:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-11-30 21:02:01 +00:00
|
|
|
/**
|
|
|
|
* Write the rasterizer's tiles to the framebuffer.
|
|
|
|
*/
|
2009-12-04 21:47:40 +00:00
|
|
|
static void
|
2009-12-08 00:02:17 +00:00
|
|
|
lp_rast_end_tile( struct lp_rasterizer *rast,
|
|
|
|
unsigned thread_index )
|
2009-10-09 10:37:24 +01:00
|
|
|
{
|
2009-12-04 21:11:25 +00:00
|
|
|
LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
|
2009-10-09 14:02:39 +01:00
|
|
|
|
2009-10-09 10:37:24 +01:00
|
|
|
if (rast->state.write_color)
|
2009-12-08 00:02:17 +00:00
|
|
|
lp_rast_store_color(rast, thread_index);
|
2009-10-09 10:37:24 +01:00
|
|
|
|
|
|
|
if (rast->state.write_zstencil)
|
2009-12-08 00:02:17 +00:00
|
|
|
lp_rast_store_zstencil(rast, thread_index);
|
2009-10-09 10:37:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-12 00:57:45 +00:00
|
|
|
/**
|
|
|
|
* Signal on a fence. This is called during bin execution/rasterization.
|
|
|
|
* Called per thread.
|
|
|
|
*/
|
|
|
|
void lp_rast_fence( struct lp_rasterizer *rast,
|
|
|
|
unsigned thread_index,
|
|
|
|
const union lp_rast_cmd_arg arg )
|
|
|
|
{
|
|
|
|
struct lp_fence *fence = arg.fence;
|
|
|
|
|
|
|
|
pipe_mutex_lock( fence->mutex );
|
|
|
|
|
|
|
|
fence->count++;
|
|
|
|
assert(fence->count <= fence->rank);
|
|
|
|
|
|
|
|
LP_DBG(DEBUG_RAST, "%s count=%u rank=%u\n", __FUNCTION__,
|
|
|
|
fence->count, fence->rank);
|
|
|
|
|
|
|
|
pipe_condvar_signal( fence->signalled );
|
|
|
|
|
|
|
|
pipe_mutex_unlock( fence->mutex );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-11 21:52:42 +00:00
|
|
|
/**
|
2009-12-13 18:17:25 +00:00
|
|
|
* When all the threads are done rasterizing a scene, one thread will
|
|
|
|
* call this function to reset the scene and put it onto the empty queue.
|
2009-12-11 21:52:42 +00:00
|
|
|
*/
|
|
|
|
static void
|
2009-12-13 18:17:25 +00:00
|
|
|
release_scene( struct lp_rasterizer *rast,
|
|
|
|
struct lp_scene *scene )
|
2009-12-11 21:52:42 +00:00
|
|
|
{
|
2009-12-13 18:17:25 +00:00
|
|
|
util_unreference_framebuffer_state( &scene->fb );
|
2009-12-11 21:52:42 +00:00
|
|
|
|
2009-12-13 18:17:25 +00:00
|
|
|
lp_scene_reset( scene );
|
|
|
|
lp_scene_enqueue( rast->empty_scenes, scene );
|
|
|
|
rast->curr_scene = NULL;
|
2009-12-11 21:52:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-04 21:47:40 +00:00
|
|
|
/**
|
|
|
|
* Rasterize commands for a single bin.
|
2009-12-04 22:31:09 +00:00
|
|
|
* \param x, y position of the bin's tile in the framebuffer
|
2009-12-04 21:47:40 +00:00
|
|
|
* Must be called between lp_rast_begin() and lp_rast_end().
|
2009-12-10 21:56:30 +00:00
|
|
|
* Called per thread.
|
2009-12-04 21:47:40 +00:00
|
|
|
*/
|
2009-12-04 22:31:09 +00:00
|
|
|
static void
|
|
|
|
rasterize_bin( struct lp_rasterizer *rast,
|
2009-12-08 00:02:17 +00:00
|
|
|
unsigned thread_index,
|
2009-12-04 22:31:09 +00:00
|
|
|
const struct cmd_bin *bin,
|
|
|
|
int x, int y)
|
2009-12-04 21:47:40 +00:00
|
|
|
{
|
|
|
|
const struct cmd_block_list *commands = &bin->commands;
|
|
|
|
struct cmd_block *block;
|
|
|
|
unsigned k;
|
|
|
|
|
2009-12-08 00:02:17 +00:00
|
|
|
lp_rast_start_tile( rast, thread_index, x, y );
|
2009-12-04 21:47:40 +00:00
|
|
|
|
|
|
|
/* simply execute each of the commands in the block list */
|
|
|
|
for (block = commands->head; block; block = block->next) {
|
|
|
|
for (k = 0; k < block->count; k++) {
|
2009-12-08 01:01:12 +00:00
|
|
|
block->cmd[k]( rast, thread_index, block->arg[k] );
|
2009-12-04 21:47:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-08 00:02:17 +00:00
|
|
|
lp_rast_end_tile( rast, thread_index );
|
2009-12-04 21:47:40 +00:00
|
|
|
}
|
|
|
|
|
2010-01-13 20:14:04 +00:00
|
|
|
|
|
|
|
#define RAST(x) { lp_rast_##x, #x }
|
|
|
|
|
|
|
|
static struct {
|
|
|
|
lp_rast_cmd cmd;
|
|
|
|
const char *name;
|
|
|
|
} cmd_names[] =
|
|
|
|
{
|
|
|
|
RAST(load_color),
|
|
|
|
RAST(load_zstencil),
|
|
|
|
RAST(clear_color),
|
|
|
|
RAST(clear_zstencil),
|
|
|
|
RAST(triangle),
|
|
|
|
RAST(shade_tile),
|
|
|
|
RAST(set_state),
|
|
|
|
RAST(fence),
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
debug_bin( const struct cmd_bin *bin )
|
|
|
|
{
|
|
|
|
const struct cmd_block *head = bin->commands.head;
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
for (i = 0; i < head->count; i++) {
|
|
|
|
debug_printf("%d: ", i);
|
|
|
|
for (j = 0; j < Elements(cmd_names); j++) {
|
|
|
|
if (head->cmd[i] == cmd_names[j].cmd) {
|
|
|
|
debug_printf("%s\n", cmd_names[j].name);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (j == Elements(cmd_names))
|
|
|
|
debug_printf("...other\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-01-13 16:29:39 +00:00
|
|
|
/* An empty bin is one that just loads the contents of the tile and
|
|
|
|
* stores them again unchanged. This typically happens when bins have
|
|
|
|
* been flushed for some reason in the middle of a frame, or when
|
|
|
|
* incremental updates are being made to a render target.
|
|
|
|
*
|
|
|
|
* Try to avoid doing pointless work in this case.
|
|
|
|
*/
|
2010-01-13 14:41:02 +00:00
|
|
|
static boolean
|
2010-01-13 16:29:39 +00:00
|
|
|
is_empty_bin( const struct cmd_bin *bin )
|
2010-01-13 14:41:02 +00:00
|
|
|
{
|
|
|
|
const struct cmd_block *head = bin->commands.head;
|
|
|
|
int i;
|
2010-01-13 20:14:04 +00:00
|
|
|
|
|
|
|
if (0)
|
|
|
|
debug_bin(bin);
|
|
|
|
|
2010-01-13 16:29:39 +00:00
|
|
|
/* We emit at most two load-tile commands at the start of the first
|
2010-01-13 20:14:04 +00:00
|
|
|
* command block. In addition we seem to emit a couple of
|
|
|
|
* set-state commands even in empty bins.
|
|
|
|
*
|
|
|
|
* As a heuristic, if a bin has more than 4 commands, consider it
|
|
|
|
* non-empty.
|
2010-01-13 16:29:39 +00:00
|
|
|
*/
|
2010-01-13 14:41:02 +00:00
|
|
|
if (head->next != NULL ||
|
2010-01-13 20:14:04 +00:00
|
|
|
head->count > 4) {
|
2010-01-13 14:41:02 +00:00
|
|
|
return FALSE;
|
2010-01-13 20:14:04 +00:00
|
|
|
}
|
2010-01-13 14:41:02 +00:00
|
|
|
|
|
|
|
for (i = 0; i < head->count; i++)
|
|
|
|
if (head->cmd[i] != lp_rast_load_color &&
|
2010-01-13 20:14:04 +00:00
|
|
|
head->cmd[i] != lp_rast_load_zstencil &&
|
|
|
|
head->cmd[i] != lp_rast_set_state) {
|
2010-01-13 14:41:02 +00:00
|
|
|
return FALSE;
|
2010-01-13 20:14:04 +00:00
|
|
|
}
|
2010-01-13 14:41:02 +00:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-04 21:47:40 +00:00
|
|
|
|
2009-12-04 22:31:09 +00:00
|
|
|
/**
|
2009-12-13 18:17:25 +00:00
|
|
|
* Rasterize/execute all bins within a scene.
|
2009-12-10 21:56:30 +00:00
|
|
|
* Called per thread.
|
2009-12-04 22:31:09 +00:00
|
|
|
*/
|
2009-12-08 01:01:12 +00:00
|
|
|
static void
|
2009-12-13 18:17:25 +00:00
|
|
|
rasterize_scene( struct lp_rasterizer *rast,
|
2009-12-08 01:01:12 +00:00
|
|
|
unsigned thread_index,
|
2009-12-13 18:17:25 +00:00
|
|
|
struct lp_scene *scene,
|
2009-12-08 01:01:12 +00:00
|
|
|
bool write_depth )
|
|
|
|
{
|
2009-12-13 18:17:25 +00:00
|
|
|
/* loop over scene bins, rasterize each */
|
2009-12-08 01:01:12 +00:00
|
|
|
#if 0
|
|
|
|
{
|
|
|
|
unsigned i, j;
|
2009-12-13 18:17:25 +00:00
|
|
|
for (i = 0; i < scene->tiles_x; i++) {
|
|
|
|
for (j = 0; j < scene->tiles_y; j++) {
|
|
|
|
struct cmd_bin *bin = lp_get_bin(scene, i, j);
|
2009-12-08 01:01:12 +00:00
|
|
|
rasterize_bin( rast, thread_index,
|
|
|
|
bin, i * TILE_SIZE, j * TILE_SIZE );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
{
|
|
|
|
struct cmd_bin *bin;
|
|
|
|
int x, y;
|
|
|
|
|
2009-12-13 18:17:25 +00:00
|
|
|
assert(scene);
|
|
|
|
while ((bin = lp_scene_bin_iter_next(scene, &x, &y))) {
|
2010-01-13 16:29:39 +00:00
|
|
|
if (!is_empty_bin( bin ))
|
2010-01-13 14:41:02 +00:00
|
|
|
rasterize_bin( rast, thread_index, bin, x * TILE_SIZE, y * TILE_SIZE);
|
2009-12-08 01:01:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2009-12-11 18:16:48 +00:00
|
|
|
* Called by setup module when it has something for us to render.
|
2009-12-08 01:01:12 +00:00
|
|
|
*/
|
2009-12-04 22:31:09 +00:00
|
|
|
void
|
2009-12-13 18:17:25 +00:00
|
|
|
lp_rasterize_scene( struct lp_rasterizer *rast,
|
|
|
|
struct lp_scene *scene,
|
2009-12-04 22:31:09 +00:00
|
|
|
const struct pipe_framebuffer_state *fb,
|
|
|
|
bool write_depth )
|
|
|
|
{
|
2009-12-09 23:32:32 +00:00
|
|
|
boolean debug = false;
|
|
|
|
|
2009-12-04 22:31:09 +00:00
|
|
|
LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
|
|
|
|
|
2009-12-09 23:32:32 +00:00
|
|
|
if (debug) {
|
|
|
|
unsigned x, y;
|
2009-12-13 18:17:25 +00:00
|
|
|
printf("rasterize scene:\n");
|
|
|
|
printf(" data size: %u\n", lp_scene_data_size(scene));
|
|
|
|
for (y = 0; y < scene->tiles_y; y++) {
|
|
|
|
for (x = 0; x < scene->tiles_x; x++) {
|
2009-12-09 23:32:32 +00:00
|
|
|
printf(" bin %u, %u size: %u\n", x, y,
|
2009-12-13 18:17:25 +00:00
|
|
|
lp_scene_bin_size(scene, x, y));
|
2009-12-09 23:32:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-11 21:52:42 +00:00
|
|
|
/* save framebuffer state in the bin */
|
2009-12-13 18:17:25 +00:00
|
|
|
util_copy_framebuffer_state(&scene->fb, fb);
|
|
|
|
scene->write_depth = write_depth;
|
2009-12-08 01:01:12 +00:00
|
|
|
|
|
|
|
if (rast->num_threads == 0) {
|
|
|
|
/* no threading */
|
2009-12-11 21:52:42 +00:00
|
|
|
|
|
|
|
lp_rast_begin( rast, fb,
|
2010-01-10 17:22:09 +00:00
|
|
|
fb->nr_cbufs != 0, /* always write color if cbufs present */
|
2009-12-11 21:52:42 +00:00
|
|
|
fb->zsbuf != NULL && write_depth );
|
|
|
|
|
2009-12-13 18:17:25 +00:00
|
|
|
lp_scene_bin_iter_begin( scene );
|
|
|
|
rasterize_scene( rast, 0, scene, write_depth );
|
2009-12-09 23:02:30 +00:00
|
|
|
|
2009-12-13 18:17:25 +00:00
|
|
|
release_scene( rast, scene );
|
2009-12-11 21:52:42 +00:00
|
|
|
|
|
|
|
lp_rast_end( rast );
|
2009-12-04 22:31:09 +00:00
|
|
|
}
|
2009-12-08 01:01:12 +00:00
|
|
|
else {
|
|
|
|
/* threaded rendering! */
|
|
|
|
unsigned i;
|
|
|
|
|
2009-12-13 18:17:25 +00:00
|
|
|
lp_scene_enqueue( rast->full_scenes, scene );
|
2009-12-10 21:56:30 +00:00
|
|
|
|
2009-12-08 01:01:12 +00:00
|
|
|
/* signal the threads that there's work to do */
|
|
|
|
for (i = 0; i < rast->num_threads; i++) {
|
|
|
|
pipe_semaphore_signal(&rast->tasks[i].work_ready);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* wait for work to complete */
|
|
|
|
for (i = 0; i < rast->num_threads; i++) {
|
|
|
|
pipe_semaphore_wait(&rast->tasks[i].work_done);
|
2009-12-07 22:31:50 +00:00
|
|
|
}
|
|
|
|
}
|
2009-12-04 22:31:09 +00:00
|
|
|
|
|
|
|
LP_DBG(DEBUG_SETUP, "%s done \n", __FUNCTION__);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-08 01:01:12 +00:00
|
|
|
/**
|
|
|
|
* This is the thread's main entrypoint.
|
|
|
|
* It's a simple loop:
|
|
|
|
* 1. wait for work
|
|
|
|
* 2. do work
|
|
|
|
* 3. signal that we're done
|
|
|
|
*/
|
|
|
|
static void *
|
|
|
|
thread_func( void *init_data )
|
|
|
|
{
|
|
|
|
struct lp_rasterizer_task *task = (struct lp_rasterizer_task *) init_data;
|
|
|
|
struct lp_rasterizer *rast = task->rast;
|
2009-12-10 21:56:30 +00:00
|
|
|
boolean debug = false;
|
2009-12-08 01:01:12 +00:00
|
|
|
|
|
|
|
while (1) {
|
|
|
|
/* wait for work */
|
|
|
|
if (debug)
|
|
|
|
debug_printf("thread %d waiting for work\n", task->thread_index);
|
|
|
|
pipe_semaphore_wait(&task->work_ready);
|
|
|
|
|
2009-12-11 21:52:42 +00:00
|
|
|
if (task->thread_index == 0) {
|
|
|
|
/* thread[0]:
|
2009-12-13 18:17:25 +00:00
|
|
|
* - get next scene to rasterize
|
2009-12-11 21:52:42 +00:00
|
|
|
* - map the framebuffer surfaces
|
|
|
|
*/
|
|
|
|
const struct pipe_framebuffer_state *fb;
|
|
|
|
boolean write_depth;
|
|
|
|
|
2009-12-13 18:17:25 +00:00
|
|
|
rast->curr_scene = lp_scene_dequeue( rast->full_scenes );
|
2009-12-11 21:52:42 +00:00
|
|
|
|
2009-12-13 18:17:25 +00:00
|
|
|
lp_scene_bin_iter_begin( rast->curr_scene );
|
2009-12-11 21:52:42 +00:00
|
|
|
|
2009-12-13 18:17:25 +00:00
|
|
|
fb = &rast->curr_scene->fb;
|
|
|
|
write_depth = rast->curr_scene->write_depth;
|
2009-12-11 21:52:42 +00:00
|
|
|
|
|
|
|
lp_rast_begin( rast, fb,
|
2010-01-10 17:22:09 +00:00
|
|
|
fb->nr_cbufs != 0,
|
2009-12-11 21:52:42 +00:00
|
|
|
fb->zsbuf != NULL && write_depth );
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Wait for all threads to get here so that threads[1+] don't
|
2009-12-13 18:17:25 +00:00
|
|
|
* get a null rast->curr_scene pointer.
|
2009-12-11 21:52:42 +00:00
|
|
|
*/
|
|
|
|
pipe_barrier_wait( &rast->barrier );
|
2009-12-10 21:56:30 +00:00
|
|
|
|
2009-12-08 01:01:12 +00:00
|
|
|
/* do work */
|
|
|
|
if (debug)
|
|
|
|
debug_printf("thread %d doing work\n", task->thread_index);
|
2009-12-13 18:17:25 +00:00
|
|
|
rasterize_scene(rast,
|
|
|
|
task->thread_index,
|
|
|
|
rast->curr_scene,
|
|
|
|
rast->curr_scene->write_depth);
|
2009-12-10 21:56:30 +00:00
|
|
|
|
2009-12-13 18:17:25 +00:00
|
|
|
/* wait for all threads to finish with this scene */
|
2009-12-11 21:52:42 +00:00
|
|
|
pipe_barrier_wait( &rast->barrier );
|
|
|
|
|
|
|
|
if (task->thread_index == 0) {
|
|
|
|
/* thread[0]:
|
2009-12-13 18:17:25 +00:00
|
|
|
* - release the scene object
|
2009-12-11 21:52:42 +00:00
|
|
|
* - unmap the framebuffer surfaces
|
|
|
|
*/
|
2009-12-13 18:17:25 +00:00
|
|
|
release_scene( rast, rast->curr_scene );
|
2009-12-11 21:52:42 +00:00
|
|
|
lp_rast_end( rast );
|
|
|
|
}
|
2009-12-08 01:01:12 +00:00
|
|
|
|
|
|
|
/* signal done with work */
|
|
|
|
if (debug)
|
|
|
|
debug_printf("thread %d done working\n", task->thread_index);
|
|
|
|
pipe_semaphore_signal(&task->work_done);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialize semaphores and spawn the threads.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
create_rast_threads(struct lp_rasterizer *rast)
|
|
|
|
{
|
|
|
|
unsigned i;
|
|
|
|
|
2009-12-08 08:02:49 +00:00
|
|
|
rast->num_threads = util_cpu_caps.nr_cpus;
|
|
|
|
rast->num_threads = debug_get_num_option("LP_NUM_THREADS", rast->num_threads);
|
2009-12-08 01:01:12 +00:00
|
|
|
rast->num_threads = MIN2(rast->num_threads, MAX_THREADS);
|
|
|
|
|
|
|
|
/* NOTE: if num_threads is zero, we won't use any threads */
|
|
|
|
for (i = 0; i < rast->num_threads; i++) {
|
|
|
|
pipe_semaphore_init(&rast->tasks[i].work_ready, 0);
|
|
|
|
pipe_semaphore_init(&rast->tasks[i].work_done, 0);
|
|
|
|
rast->threads[i] = pipe_thread_create(thread_func,
|
|
|
|
(void *) &rast->tasks[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2009-12-09 21:53:33 +00:00
|
|
|
/**
|
|
|
|
* Create new lp_rasterizer.
|
2009-12-13 18:17:25 +00:00
|
|
|
* \param empty the queue to put empty scenes on after we've finished
|
2009-12-09 21:53:33 +00:00
|
|
|
* processing them.
|
|
|
|
*/
|
|
|
|
struct lp_rasterizer *
|
2009-12-13 18:17:25 +00:00
|
|
|
lp_rast_create( struct pipe_screen *screen, struct lp_scene_queue *empty )
|
2009-12-08 01:01:12 +00:00
|
|
|
{
|
|
|
|
struct lp_rasterizer *rast;
|
2010-01-10 17:22:09 +00:00
|
|
|
unsigned i, cbuf;
|
2009-12-08 01:01:12 +00:00
|
|
|
|
|
|
|
rast = CALLOC_STRUCT(lp_rasterizer);
|
|
|
|
if(!rast)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
rast->screen = screen;
|
|
|
|
|
2009-12-13 18:17:25 +00:00
|
|
|
rast->empty_scenes = empty;
|
|
|
|
rast->full_scenes = lp_scene_queue_create();
|
2009-12-09 21:53:33 +00:00
|
|
|
|
2009-12-08 01:01:12 +00:00
|
|
|
for (i = 0; i < Elements(rast->tasks); i++) {
|
2010-01-10 17:22:09 +00:00
|
|
|
for (cbuf = 0; cbuf < PIPE_MAX_COLOR_BUFS; cbuf++ )
|
|
|
|
rast->tasks[i].tile.color[cbuf] = align_malloc( TILE_SIZE*TILE_SIZE*4, 16 );
|
|
|
|
|
2009-12-08 01:01:12 +00:00
|
|
|
rast->tasks[i].tile.depth = align_malloc( TILE_SIZE*TILE_SIZE*4, 16 );
|
|
|
|
rast->tasks[i].rast = rast;
|
|
|
|
rast->tasks[i].thread_index = i;
|
|
|
|
}
|
|
|
|
|
|
|
|
create_rast_threads(rast);
|
|
|
|
|
2009-12-11 21:52:42 +00:00
|
|
|
/* for synchronizing rasterization threads */
|
|
|
|
pipe_barrier_init( &rast->barrier, rast->num_threads );
|
|
|
|
|
2009-12-08 01:01:12 +00:00
|
|
|
return rast;
|
|
|
|
}
|
|
|
|
|
2009-12-04 21:47:40 +00:00
|
|
|
|
2009-10-07 22:36:43 +01:00
|
|
|
/* Shutdown:
|
|
|
|
*/
|
|
|
|
void lp_rast_destroy( struct lp_rasterizer *rast )
|
|
|
|
{
|
2010-01-10 17:22:09 +00:00
|
|
|
unsigned i, cbuf;
|
2009-12-08 00:02:17 +00:00
|
|
|
|
2009-12-11 18:46:23 +00:00
|
|
|
util_unreference_framebuffer_state(&rast->state.fb);
|
2009-12-08 00:02:17 +00:00
|
|
|
|
|
|
|
for (i = 0; i < Elements(rast->tasks); i++) {
|
|
|
|
align_free(rast->tasks[i].tile.depth);
|
2010-01-10 17:22:09 +00:00
|
|
|
for (cbuf = 0; cbuf < PIPE_MAX_COLOR_BUFS; cbuf++ )
|
|
|
|
align_free(rast->tasks[i].tile.color[cbuf]);
|
2009-12-08 00:02:17 +00:00
|
|
|
}
|
|
|
|
|
2009-12-11 21:52:42 +00:00
|
|
|
/* for synchronizing rasterization threads */
|
|
|
|
pipe_barrier_destroy( &rast->barrier );
|
|
|
|
|
2009-10-07 22:36:43 +01:00
|
|
|
FREE(rast);
|
|
|
|
}
|
|
|
|
|
2009-12-12 00:45:52 +00:00
|
|
|
|
|
|
|
/** Return number of rasterization threads */
|
|
|
|
unsigned
|
|
|
|
lp_rast_get_num_threads( struct lp_rasterizer *rast )
|
|
|
|
{
|
|
|
|
return rast->num_threads;
|
|
|
|
}
|