/** Dummy definitions */
typedef unsigned pipe_thread;
+
+#define PIPE_THREAD_ROUTINE( name, param ) \
+ void * name( void *param )
+
+static INLINE pipe_thread pipe_thread_create( void *(* routine)( void *), void *param )
+{
+ return 0;
+}
+
+static INLINE int pipe_thread_wait( pipe_thread thread )
+{
+ return -1;
+}
+
+static INLINE int pipe_thread_destroy( pipe_thread thread )
+{
+ return -1;
+}
+
typedef unsigned pipe_mutex;
typedef unsigned pipe_condvar;
+ typedef unsigned pipe_barrier;
#define pipe_static_mutex(mutex) \
static pipe_mutex mutex = 0
#include "pipe/p_screen.h"
#include "pipe/p_state.h"
#include "pipe/p_defines.h"
+#include "util/u_inlines.h"
+ #include "util/u_memory.h"
#include "util/u_surface.h"
};
-void
-util_time_get(struct util_time *t);
+PIPE_DEPRECATED
+static INLINE void
+util_time_get(struct util_time *t)
+{
+ t->counter = os_time_get();
+}
+
-void
+ /**
+ * Return t2 = t1 + usecs
+ */
+PIPE_DEPRECATED
+static INLINE void
util_time_add(const struct util_time *t1,
int64_t usecs,
- struct util_time *t2);
+ struct util_time *t2)
+{
+ t2->counter = t1->counter + usecs;
+}
-/**
- * Return current time in microseconds
- */
-uint64_t
-util_time_micros( void );
-int64_t
+ /**
+ * Return difference between times, in microseconds
+ */
+PIPE_DEPRECATED
+static INLINE int64_t
util_time_diff(const struct util_time *t1,
- const struct util_time *t2);
+ const struct util_time *t2)
+{
+ return t2->counter - t1->counter;
+}
+
+
+/**
+ * Compare two time values.
+ *
+ * Not publicly available because it does not take in account wrap-arounds.
+ * Use util_time_timeout instead.
+ */
+static INLINE int
+_util_time_compare(const struct util_time *t1,
+ const struct util_time *t2)
+{
+ if (t1->counter < t2->counter)
+ return -1;
+ else if(t1->counter > t2->counter)
+ return 1;
+ else
+ return 0;
+}
+
-boolean
+ /**
+ * Returns non-zero when the timeout expires.
+ */
+PIPE_DEPRECATED
+static INLINE boolean
util_time_timeout(const struct util_time *start,
const struct util_time *end,
- const struct util_time *curr);
+ const struct util_time *curr)
+{
+ return os_time_timeout(start->counter, end->counter, curr->counter);
+}
-#if defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS) || defined(PIPE_OS_APPLE) || defined(PIPE_OS_HAIKU)
-#define util_time_sleep usleep
-#else
-void
-util_time_sleep(unsigned usecs);
-#endif
+
++/**
++ * Return current time in microseconds
++ */
+PIPE_DEPRECATED
+static INLINE int64_t
+util_time_micros(void)
+{
+ return os_time_get();
+}
+
+
+PIPE_DEPRECATED
+static INLINE void
+util_time_sleep(int64_t usecs)
+{
+ os_time_sleep(usecs);
+}
#ifdef __cplusplus
--- /dev/null
+ /**************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+
+ #include "pipe/p_screen.h"
+ #include "util/u_memory.h"
++#include "util/u_inlines.h"
+ #include "lp_fence.h"
+
+
+ struct lp_fence *
+ lp_fence_create(unsigned rank)
+ {
+ struct lp_fence *fence = CALLOC_STRUCT(lp_fence);
+
+ pipe_reference_init(&fence->reference, 1);
+
+ pipe_mutex_init(fence->mutex);
+ pipe_condvar_init(fence->signalled);
+
+ fence->rank = rank;
+
+ return fence;
+ }
+
+
+ static void
+ lp_fence_destroy(struct lp_fence *fence)
+ {
+ pipe_mutex_destroy(fence->mutex);
+ pipe_condvar_destroy(fence->signalled);
+ FREE(fence);
+ }
+
+
+ static void
+ llvmpipe_fence_reference(struct pipe_screen *screen,
+ struct pipe_fence_handle **ptr,
+ struct pipe_fence_handle *fence)
+ {
+ struct lp_fence *old = (struct lp_fence *) *ptr;
+ struct lp_fence *f = (struct lp_fence *) fence;
+
+ if (pipe_reference(&old->reference, &f->reference)) {
+ lp_fence_destroy(old);
+ }
+ }
+
+
+ static int
+ llvmpipe_fence_signalled(struct pipe_screen *screen,
+ struct pipe_fence_handle *fence,
+ unsigned flag)
+ {
+ struct lp_fence *f = (struct lp_fence *) fence;
+
+ return f->count == f->rank;
+ }
+
+
+ static int
+ llvmpipe_fence_finish(struct pipe_screen *screen,
+ struct pipe_fence_handle *fence_handle,
+ unsigned flag)
+ {
+ struct lp_fence *fence = (struct lp_fence *) fence_handle;
+
+ pipe_mutex_lock(fence->mutex);
+ while (fence->count < fence->rank) {
+ pipe_condvar_wait(fence->signalled, fence->mutex);
+ }
+ pipe_mutex_unlock(fence->mutex);
+
+ return 0;
+ }
+
+
+
+
+ void
+ llvmpipe_init_screen_fence_funcs(struct pipe_screen *screen)
+ {
+ screen->fence_reference = llvmpipe_fence_reference;
+ screen->fence_signalled = llvmpipe_fence_signalled;
+ screen->fence_finish = llvmpipe_fence_finish;
+ }
--- /dev/null
-#include "pipe/p_refcnt.h"
-#include "pipe/p_thread.h"
+ /**************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+
+ #ifndef LP_FENCE_H
+ #define LP_FENCE_H
+
+
++#include "os/os_thread.h"
++#include "pipe/p_state.h"
+
+
+ struct pipe_screen;
+
+
+ struct lp_fence
+ {
+ struct pipe_reference reference;
+
+ pipe_mutex mutex;
+ pipe_condvar signalled;
+
+ unsigned rank;
+ unsigned count;
+ };
+
+
+ struct lp_fence *
+ lp_fence_create(unsigned rank);
+
+
+ void
+ llvmpipe_init_screen_fence_funcs(struct pipe_screen *screen);
+
+
+ #endif /* LP_FENCE_H */
--- /dev/null
- printf("rasterize scene:\n");
- printf(" data size: %u\n", lp_scene_data_size(scene));
+ /**************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+ #include <limits.h>
+ #include "util/u_memory.h"
+ #include "util/u_math.h"
+ #include "util/u_cpu_detect.h"
+ #include "util/u_surface.h"
+
+ #include "lp_scene_queue.h"
+ #include "lp_debug.h"
+ #include "lp_fence.h"
+ #include "lp_rast.h"
+ #include "lp_rast_priv.h"
+ #include "lp_tile_soa.h"
+ #include "lp_bld_debug.h"
+ #include "lp_scene.h"
+
+
+ /**
+ * Begin the rasterization phase.
+ * Map the framebuffer surfaces. Initialize the 'rast' state.
+ */
+ static boolean
+ lp_rast_begin( struct lp_rasterizer *rast,
+ const struct pipe_framebuffer_state *fb,
+ boolean write_color,
+ boolean write_zstencil )
+ {
+ struct pipe_screen *screen = rast->screen;
+ struct pipe_surface *cbuf, *zsbuf;
+ int i;
+
+ LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
+
+ util_copy_framebuffer_state(&rast->state.fb, fb);
+
+ rast->state.write_zstencil = write_zstencil;
+ rast->state.write_color = write_color;
+
+ rast->check_for_clipped_tiles = (fb->width % TILE_SIZE != 0 ||
+ fb->height % TILE_SIZE != 0);
+
+
+ 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;
+ }
+ }
+
+ zsbuf = rast->state.fb.zsbuf;
+ if (zsbuf) {
+ rast->zsbuf_transfer = screen->get_tex_transfer(rast->screen,
+ zsbuf->texture,
+ zsbuf->face,
+ zsbuf->level,
+ zsbuf->zslice,
+ PIPE_TRANSFER_READ_WRITE,
+ 0, 0,
+ zsbuf->width,
+ zsbuf->height);
+ if (!rast->zsbuf_transfer)
+ goto fail;
+
+ rast->zsbuf_map = screen->transfer_map(rast->screen,
+ rast->zsbuf_transfer);
+ if (!rast->zsbuf_map)
+ goto fail;
+ }
+
+ return TRUE;
+
+ fail:
+ /* Unmap and release transfers?
+ */
+ return FALSE;
+ }
+
+
+ /**
+ * Finish the rasterization phase.
+ * Unmap framebuffer surfaces.
+ */
+ static void
+ lp_rast_end( struct lp_rasterizer *rast )
+ {
+ struct pipe_screen *screen = rast->screen;
+ unsigned i;
+
+ 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;
+ }
+
+ if (rast->zsbuf_map)
+ screen->transfer_unmap(screen, rast->zsbuf_transfer);
+
+ if (rast->zsbuf_transfer)
+ screen->tex_transfer_destroy(rast->zsbuf_transfer);
+
+ rast->zsbuf_transfer = NULL;
+ rast->zsbuf_map = NULL;
+ }
+
+
+ /**
+ * 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 *rast,
+ unsigned thread_index,
+ unsigned x, unsigned y )
+ {
+ LP_DBG(DEBUG_RAST, "%s %d,%d\n", __FUNCTION__, x, y);
+
+ rast->tasks[thread_index].x = x;
+ rast->tasks[thread_index].y = y;
+ }
+
+
+ /**
+ * Clear the rasterizer's current color tile.
+ * This is a bin command called during bin processing.
+ */
+ void lp_rast_clear_color( struct lp_rasterizer *rast,
+ unsigned thread_index,
+ const union lp_rast_cmd_arg arg )
+ {
+ const uint8_t *clear_color = arg.clear_color;
+ uint8_t **color_tile = rast->tasks[thread_index].tile.color;
+ unsigned i;
+
+ LP_DBG(DEBUG_RAST, "%s 0x%x,0x%x,0x%x,0x%x\n", __FUNCTION__,
+ clear_color[0],
+ clear_color[1],
+ clear_color[2],
+ clear_color[3]);
+
+ if (clear_color[0] == clear_color[1] &&
+ clear_color[1] == clear_color[2] &&
+ clear_color[2] == clear_color[3]) {
+ /* clear to grayscale value {x, x, x, x} */
+ for (i = 0; i < rast->state.fb.nr_cbufs; i++) {
+ memset(color_tile[i], clear_color[0], TILE_SIZE * TILE_SIZE * 4);
+ }
+ }
+ else {
+ /* Non-gray color.
+ * Note: if the swizzled tile layout changes (see TILE_PIXEL) this code
+ * will need to change. It'll be pretty obvious when clearing no longer
+ * works.
+ */
+ const unsigned chunk = TILE_SIZE / 4;
+ for (i = 0; i < rast->state.fb.nr_cbufs; i++) {
+ uint8_t *c = color_tile[i];
+ unsigned j;
+ for (j = 0; j < 4 * TILE_SIZE; j++) {
+ memset(c, clear_color[0], chunk);
+ c += chunk;
+ memset(c, clear_color[1], chunk);
+ c += chunk;
+ memset(c, clear_color[2], chunk);
+ c += chunk;
+ memset(c, clear_color[3], chunk);
+ c += chunk;
+ }
+ assert(c - color_tile[i] == TILE_SIZE * TILE_SIZE * 4);
+ }
+ }
+ }
+
+
+ /**
+ * Clear the rasterizer's current z/stencil tile.
+ * This is a bin command called during bin processing.
+ */
+ void lp_rast_clear_zstencil( struct lp_rasterizer *rast,
+ unsigned thread_index,
+ const union lp_rast_cmd_arg arg)
+ {
+ unsigned i;
+ uint32_t *depth_tile = rast->tasks[thread_index].tile.depth;
+
+ LP_DBG(DEBUG_RAST, "%s 0x%x\n", __FUNCTION__, arg.clear_zstencil);
+
+ for (i = 0; i < TILE_SIZE * TILE_SIZE; i++)
+ depth_tile[i] = arg.clear_zstencil;
+ }
+
+
+ /**
+ * Load tile color from the framebuffer surface.
+ * This is a bin command called during bin processing.
+ */
+ void lp_rast_load_color( struct lp_rasterizer *rast,
+ unsigned thread_index,
+ const union lp_rast_cmd_arg arg)
+ {
+ struct lp_rasterizer_task *task = &rast->tasks[thread_index];
+ const unsigned x = task->x;
+ const unsigned y = task->y;
+ unsigned i;
+
+ LP_DBG(DEBUG_RAST, "%s at %u, %u\n", __FUNCTION__, x, y);
+
+ 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;
+
+ if (x >= transfer->width)
+ continue;
+
+ if (y >= transfer->height)
+ continue;
+
+ assert(w >= 0);
+ assert(h >= 0);
+ assert(w <= TILE_SIZE);
+ assert(h <= TILE_SIZE);
+
+ lp_tile_read_4ub(transfer->texture->format,
+ task->tile.color[i],
+ rast->cbuf_map[i],
+ transfer->stride,
+ x, y,
+ w, h);
+ }
+ }
+
+
+ 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;
+ }
+ }
+
+ /**
+ * Load tile z/stencil from the framebuffer surface.
+ * This is a bin command called during bin processing.
+ */
+ void lp_rast_load_zstencil( struct lp_rasterizer *rast,
+ unsigned thread_index,
+ const union lp_rast_cmd_arg arg )
+ {
+ struct lp_rasterizer_task *task = &rast->tasks[thread_index];
+ const unsigned x = task->x;
+ const unsigned y = task->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);
+
+ assert(rast->zsbuf_transfer->texture->format == PIPE_FORMAT_Z32_UNORM);
+ lp_tile_read_z32(task->tile.depth,
+ rast->zsbuf_map,
+ rast->zsbuf_transfer->stride,
+ x, y, w, h);
+ }
+
+
+ void lp_rast_set_state( struct lp_rasterizer *rast,
+ unsigned thread_index,
+ const union lp_rast_cmd_arg arg )
+ {
+ const struct lp_rast_state *state = arg.set_state;
+
+ LP_DBG(DEBUG_RAST, "%s %p\n", __FUNCTION__, (void *) state);
+
+ /* just set the current state pointer for this rasterizer */
+ rast->tasks[thread_index].current_state = state;
+ }
+
+
+
+ /**
+ * 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.
+ */
+ void lp_rast_shade_tile( struct lp_rasterizer *rast,
+ unsigned thread_index,
+ const union lp_rast_cmd_arg arg )
+ {
+ struct lp_rasterizer_task *task = &rast->tasks[thread_index];
+ 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;
+ const unsigned tile_y = task->y;
+ unsigned x, y;
+
+ LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
+
+ /* render the whole 64x64 tile in 4x4 chunks */
+ for (y = 0; y < TILE_SIZE; y += 4){
+ 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);
+
+ /* color buffer */
+ for (i = 0; i < rast->state.fb.nr_cbufs; i++)
+ color[i] = tile->color[i] + 4 * block_offset;
+
+ /* depth buffer */
+ depth = tile->depth + block_offset;
+
+ /* run shader */
+ state->jit_function[0]( &state->jit_context,
+ tile_x + x, tile_y + y,
+ inputs->a0,
+ inputs->dadx,
+ inputs->dady,
+ color,
+ depth,
+ INT_MIN, INT_MIN, INT_MIN,
+ NULL, NULL, NULL );
+ }
+ }
+ }
+
+
+ /**
+ * Compute shading for a 4x4 block of pixels.
+ * This is a bin command called during bin processing.
+ */
+ void lp_rast_shade_quads( struct lp_rasterizer *rast,
+ unsigned thread_index,
+ const struct lp_rast_shader_inputs *inputs,
+ unsigned x, unsigned y,
+ int32_t c1, int32_t c2, int32_t c3)
+ {
+ struct lp_rasterizer_task *task = &rast->tasks[thread_index];
+ const struct lp_rast_state *state = task->current_state;
+ struct lp_rast_tile *tile = &task->tile;
+ uint8_t *color[PIPE_MAX_COLOR_BUFS];
+ void *depth;
+ unsigned i;
+ unsigned ix, iy;
+ int block_offset;
+
+ #ifdef DEBUG
+ assert(state);
+
+ /* Sanity checks */
+ assert(x % TILE_VECTOR_WIDTH == 0);
+ assert(y % TILE_VECTOR_HEIGHT == 0);
+
+ assert((x % 4) == 0);
+ assert((y % 4) == 0);
+ #endif
+
+ 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.fb.nr_cbufs; i++)
+ color[i] = tile->color[i] + 4 * block_offset;
+
+ /* depth buffer */
+ depth = tile->depth + block_offset;
+
+
+
+ #ifdef DEBUG
+ assert(lp_check_alignment(tile->depth, 16));
+ 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));
+ #endif
+
+ /* run shader */
+ state->jit_function[1]( &state->jit_context,
+ x, y,
+ inputs->a0,
+ inputs->dadx,
+ inputs->dady,
+ color,
+ depth,
+ c1, c2, c3,
+ inputs->step[0], inputs->step[1], inputs->step[2]);
+ }
+
+
+ /**
+ * Set top row and left column of the tile's pixels to white. For debugging.
+ */
+ static void
+ outline_tile(uint8_t *tile)
+ {
+ const uint8_t val = 0xff;
+ unsigned i;
+
+ for (i = 0; i < TILE_SIZE; i++) {
+ TILE_PIXEL(tile, i, 0, 0) = val;
+ TILE_PIXEL(tile, i, 0, 1) = val;
+ TILE_PIXEL(tile, i, 0, 2) = val;
+ TILE_PIXEL(tile, i, 0, 3) = val;
+
+ TILE_PIXEL(tile, 0, i, 0) = val;
+ TILE_PIXEL(tile, 0, i, 1) = val;
+ TILE_PIXEL(tile, 0, i, 2) = val;
+ TILE_PIXEL(tile, 0, i, 3) = val;
+ }
+ }
+
+
+ /**
+ * Draw grid of gray lines at 16-pixel intervals across the tile to
+ * show the sub-tile boundaries. For debugging.
+ */
+ static void
+ outline_subtiles(uint8_t *tile)
+ {
+ const uint8_t val = 0x80;
+ const unsigned step = 16;
+ unsigned i, j;
+
+ for (i = 0; i < TILE_SIZE; i += step) {
+ for (j = 0; j < TILE_SIZE; j++) {
+ TILE_PIXEL(tile, i, j, 0) = val;
+ TILE_PIXEL(tile, i, j, 1) = val;
+ TILE_PIXEL(tile, i, j, 2) = val;
+ TILE_PIXEL(tile, i, j, 3) = val;
+
+ TILE_PIXEL(tile, j, i, 0) = val;
+ TILE_PIXEL(tile, j, i, 1) = val;
+ TILE_PIXEL(tile, j, i, 2) = val;
+ TILE_PIXEL(tile, j, i, 3) = val;
+ }
+ }
+
+ outline_tile(tile);
+ }
+
+
+
+ /**
+ * Write the rasterizer's color tile to the framebuffer.
+ */
+ static void lp_rast_store_color( struct lp_rasterizer *rast,
+ unsigned thread_index)
+ {
+ struct lp_rasterizer_task *task = &rast->tasks[thread_index];
+ const unsigned x = task->x;
+ const unsigned y = task->y;
+ unsigned i;
+
+ 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;
+
+ if (x >= transfer->width)
+ continue;
+
+ if (y >= transfer->height)
+ continue;
+
+ LP_DBG(DEBUG_RAST, "%s [%u] %d,%d %dx%d\n", __FUNCTION__,
+ thread_index, x, y, w, h);
+
+ if (LP_DEBUG & DEBUG_SHOW_SUBTILES)
+ outline_subtiles(task->tile.color[i]);
+ else if (LP_DEBUG & DEBUG_SHOW_TILES)
+ outline_tile(task->tile.color[i]);
+
+ lp_tile_write_4ub(transfer->texture->format,
+ task->tile.color[i],
+ rast->cbuf_map[i],
+ transfer->stride,
+ x, y,
+ w, h);
+ }
+ }
+
+
+ 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;
+ }
+ }
+
+ /**
+ * Write the rasterizer's z/stencil tile to the framebuffer.
+ */
+ static void lp_rast_store_zstencil( struct lp_rasterizer *rast,
+ unsigned thread_index )
+ {
+ struct lp_rasterizer_task *task = &rast->tasks[thread_index];
+ const unsigned x = task->x;
+ const unsigned y = task->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);
+
+ assert(rast->zsbuf_transfer->texture->format == PIPE_FORMAT_Z32_UNORM);
+ lp_tile_write_z32(task->tile.depth,
+ rast->zsbuf_map,
+ rast->zsbuf_transfer->stride,
+ x, y, w, h);
+ }
+
+
+ /**
+ * Write the rasterizer's tiles to the framebuffer.
+ */
+ static void
+ lp_rast_end_tile( struct lp_rasterizer *rast,
+ unsigned thread_index )
+ {
+ LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
+
+ if (rast->state.write_color)
+ lp_rast_store_color(rast, thread_index);
+
+ if (rast->state.write_zstencil)
+ lp_rast_store_zstencil(rast, thread_index);
+ }
+
+
+ /**
+ * 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 );
+ }
+
+
+ /**
+ * 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.
+ */
+ static void
+ release_scene( struct lp_rasterizer *rast,
+ struct lp_scene *scene )
+ {
+ util_unreference_framebuffer_state( &scene->fb );
+
+ lp_scene_reset( scene );
+ lp_scene_enqueue( rast->empty_scenes, scene );
+ rast->curr_scene = NULL;
+ }
+
+
+ /**
+ * Rasterize commands for a single bin.
+ * \param x, y position of the bin's tile in the framebuffer
+ * Must be called between lp_rast_begin() and lp_rast_end().
+ * Called per thread.
+ */
+ static void
+ rasterize_bin( struct lp_rasterizer *rast,
+ unsigned thread_index,
+ const struct cmd_bin *bin,
+ int x, int y)
+ {
+ const struct cmd_block_list *commands = &bin->commands;
+ struct cmd_block *block;
+ unsigned k;
+
+ lp_rast_start_tile( rast, thread_index, x, y );
+
+ /* 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++) {
+ block->cmd[k]( rast, thread_index, block->arg[k] );
+ }
+ }
+
+ lp_rast_end_tile( rast, thread_index );
+ }
+
+
+ #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");
+ }
+
+ }
+
+ /* 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.
+ */
+ static boolean
+ is_empty_bin( const struct cmd_bin *bin )
+ {
+ const struct cmd_block *head = bin->commands.head;
+ int i;
+
+ if (0)
+ debug_bin(bin);
+
+ /* We emit at most two load-tile commands at the start of the first
+ * 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.
+ */
+ if (head->next != NULL ||
+ head->count > 4) {
+ return FALSE;
+ }
+
+ for (i = 0; i < head->count; i++)
+ if (head->cmd[i] != lp_rast_load_color &&
+ head->cmd[i] != lp_rast_load_zstencil &&
+ head->cmd[i] != lp_rast_set_state) {
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+
+
+ /**
+ * Rasterize/execute all bins within a scene.
+ * Called per thread.
+ */
+ static void
+ rasterize_scene( struct lp_rasterizer *rast,
+ unsigned thread_index,
+ struct lp_scene *scene,
+ bool write_depth )
+ {
+ /* loop over scene bins, rasterize each */
+ #if 0
+ {
+ unsigned i, j;
+ 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);
+ rasterize_bin( rast, thread_index,
+ bin, i * TILE_SIZE, j * TILE_SIZE );
+ }
+ }
+ }
+ #else
+ {
+ struct cmd_bin *bin;
+ int x, y;
+
+ assert(scene);
+ while ((bin = lp_scene_bin_iter_next(scene, &x, &y))) {
+ if (!is_empty_bin( bin ))
+ rasterize_bin( rast, thread_index, bin, x * TILE_SIZE, y * TILE_SIZE);
+ }
+ }
+ #endif
+ }
+
+
+ /**
+ * Called by setup module when it has something for us to render.
+ */
+ void
+ lp_rasterize_scene( struct lp_rasterizer *rast,
+ struct lp_scene *scene,
+ const struct pipe_framebuffer_state *fb,
+ bool write_depth )
+ {
+ boolean debug = false;
+
+ LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
+
+ if (debug) {
+ unsigned x, y;
- printf(" bin %u, %u size: %u\n", x, y,
- lp_scene_bin_size(scene, x, y));
++ debug_printf("rasterize scene:\n");
++ debug_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++) {
-static void *
-thread_func( void *init_data )
++ debug_printf(" bin %u, %u size: %u\n", x, y,
++ lp_scene_bin_size(scene, x, y));
+ }
+ }
+ }
+
+ /* save framebuffer state in the bin */
+ util_copy_framebuffer_state(&scene->fb, fb);
+ scene->write_depth = write_depth;
+
+ if (rast->num_threads == 0) {
+ /* no threading */
+
+ lp_rast_begin( rast, fb,
+ fb->nr_cbufs != 0, /* always write color if cbufs present */
+ fb->zsbuf != NULL && write_depth );
+
+ lp_scene_bin_iter_begin( scene );
+ rasterize_scene( rast, 0, scene, write_depth );
+
+ release_scene( rast, scene );
+
+ lp_rast_end( rast );
+ }
+ else {
+ /* threaded rendering! */
+ unsigned i;
+
+ lp_scene_enqueue( rast->full_scenes, scene );
+
+ /* 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);
+ }
+ }
+
+ LP_DBG(DEBUG_SETUP, "%s done \n", __FUNCTION__);
+ }
+
+
+ /**
+ * 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 PIPE_THREAD_ROUTINE( thread_func, init_data )
+ {
+ struct lp_rasterizer_task *task = (struct lp_rasterizer_task *) init_data;
+ struct lp_rasterizer *rast = task->rast;
+ boolean debug = false;
+
+ while (1) {
+ /* wait for work */
+ if (debug)
+ debug_printf("thread %d waiting for work\n", task->thread_index);
+ pipe_semaphore_wait(&task->work_ready);
+
+ if (task->thread_index == 0) {
+ /* thread[0]:
+ * - get next scene to rasterize
+ * - map the framebuffer surfaces
+ */
+ const struct pipe_framebuffer_state *fb;
+ boolean write_depth;
+
+ rast->curr_scene = lp_scene_dequeue( rast->full_scenes, TRUE );
+
+ lp_scene_bin_iter_begin( rast->curr_scene );
+
+ fb = &rast->curr_scene->fb;
+ write_depth = rast->curr_scene->write_depth;
+
+ lp_rast_begin( rast, fb,
+ fb->nr_cbufs != 0,
+ fb->zsbuf != NULL && write_depth );
+ }
+
+ /* Wait for all threads to get here so that threads[1+] don't
+ * get a null rast->curr_scene pointer.
+ */
+ pipe_barrier_wait( &rast->barrier );
+
+ /* do work */
+ if (debug)
+ debug_printf("thread %d doing work\n", task->thread_index);
+ rasterize_scene(rast,
+ task->thread_index,
+ rast->curr_scene,
+ rast->curr_scene->write_depth);
+
+ /* wait for all threads to finish with this scene */
+ pipe_barrier_wait( &rast->barrier );
+
+ if (task->thread_index == 0) {
+ /* thread[0]:
+ * - release the scene object
+ * - unmap the framebuffer surfaces
+ */
+ release_scene( rast, rast->curr_scene );
+ lp_rast_end( rast );
+ }
+
+ /* 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;
+
+ rast->num_threads = util_cpu_caps.nr_cpus;
+ rast->num_threads = debug_get_num_option("LP_NUM_THREADS", rast->num_threads);
+ 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]);
+ }
+ }
+
+
+
+ /**
+ * Create new lp_rasterizer.
+ * \param empty the queue to put empty scenes on after we've finished
+ * processing them.
+ */
+ struct lp_rasterizer *
+ lp_rast_create( struct pipe_screen *screen, struct lp_scene_queue *empty )
+ {
+ struct lp_rasterizer *rast;
+ unsigned i, cbuf;
+
+ rast = CALLOC_STRUCT(lp_rasterizer);
+ if(!rast)
+ return NULL;
+
+ rast->screen = screen;
+
+ rast->empty_scenes = empty;
+ rast->full_scenes = lp_scene_queue_create();
+
+ 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->tile.depth = align_malloc(TILE_SIZE * TILE_SIZE * 4, 16);
+ task->rast = rast;
+ task->thread_index = i;
+ }
+
+ create_rast_threads(rast);
+
+ /* for synchronizing rasterization threads */
+ pipe_barrier_init( &rast->barrier, rast->num_threads );
+
+ return rast;
+ }
+
+
+ /* Shutdown:
+ */
+ void lp_rast_destroy( struct lp_rasterizer *rast )
+ {
+ unsigned i, cbuf;
+
+ util_unreference_framebuffer_state(&rast->state.fb);
+
+ for (i = 0; i < Elements(rast->tasks); i++) {
+ align_free(rast->tasks[i].tile.depth);
+ for (cbuf = 0; cbuf < PIPE_MAX_COLOR_BUFS; cbuf++ )
+ align_free(rast->tasks[i].tile.color[cbuf]);
+ }
+
+ /* for synchronizing rasterization threads */
+ pipe_barrier_destroy( &rast->barrier );
+
+ FREE(rast);
+ }
+
+
+ /** Return number of rasterization threads */
+ unsigned
+ lp_rast_get_num_threads( struct lp_rasterizer *rast )
+ {
+ return rast->num_threads;
+ }
--- /dev/null
-#include "pipe/p_thread.h"
+ /**************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+ #ifndef LP_RAST_PRIV_H
+ #define LP_RAST_PRIV_H
+
++#include "os/os_thread.h"
+ #include "lp_rast.h"
+ #include "lp_tile_soa.h"
+
+
+ #define MAX_THREADS 8 /* XXX probably temporary here */
+
+
+ struct pipe_transfer;
+ struct pipe_screen;
+ 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];
+
+ uint32_t *depth;
+ };
+
+
+ /**
+ * 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 */
+
+ const struct lp_rast_state *current_state;
+
+ /** "back" pointer */
+ struct lp_rasterizer *rast;
+
+ /** "my" index */
+ unsigned thread_index;
+
+ pipe_semaphore work_ready;
+ pipe_semaphore work_done;
+ };
+
+
+ /**
+ * This is the state required while rasterizing tiles.
+ * Note that this contains per-thread information too.
+ * The tile size is TILE_SIZE x TILE_SIZE pixels.
+ */
+ struct lp_rasterizer
+ {
+ boolean clipped_tile;
+ boolean check_for_clipped_tiles;
+
+ /* Framebuffer stuff
+ */
+ struct pipe_screen *screen;
+ struct pipe_transfer *cbuf_transfer[PIPE_MAX_COLOR_BUFS];
+ struct pipe_transfer *zsbuf_transfer;
+ void *cbuf_map[PIPE_MAX_COLOR_BUFS];
+ void *zsbuf_map;
+
+ struct {
+ struct pipe_framebuffer_state fb;
+ boolean write_color;
+ boolean write_zstencil;
+ unsigned clear_color;
+ unsigned clear_depth;
+ char clear_stencil;
+ } state;
+
+ /** The incoming queue of scenes ready to rasterize */
+ struct lp_scene_queue *full_scenes;
+ /** The outgoing queue of processed scenes to return to setup modulee */
+ struct lp_scene_queue *empty_scenes;
+
+ /** The scene currently being rasterized by the threads */
+ struct lp_scene *curr_scene;
+
+ /** A task object for each rasterization thread */
+ struct lp_rasterizer_task tasks[MAX_THREADS];
+
+ unsigned num_threads;
+ pipe_thread threads[MAX_THREADS];
+
+ /** For synchronizing the rasterization threads */
+ pipe_barrier barrier;
+ };
+
+
+ void lp_rast_shade_quads( struct lp_rasterizer *rast,
+ unsigned thread_index,
+ const struct lp_rast_shader_inputs *inputs,
+ unsigned x, unsigned y,
+ int32_t c1, int32_t c2, int32_t c3);
+
+
+ /**
+ * Shade all pixels in a 4x4 block. The fragment code omits the
+ * triangle in/out tests.
+ * \param x, y location of 4x4 block in window coords
+ */
+ static INLINE void
+ lp_rast_shade_quads_all( struct lp_rasterizer *rast,
+ unsigned thread_index,
+ const struct lp_rast_shader_inputs *inputs,
+ unsigned x, unsigned y )
+ {
+ const struct lp_rast_state *state = rast->tasks[thread_index].current_state;
+ struct lp_rast_tile *tile = &rast->tasks[thread_index].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;
+
+ /* color buffer */
+ for (i = 0; i < rast->state.fb.nr_cbufs; i++)
+ color[i] = tile->color[i] + 4 * block_offset;
+
+ /* depth buffer */
+ depth = tile->depth + block_offset;
+
+ /* run shader */
+ state->jit_function[0]( &state->jit_context,
+ x, y,
+ inputs->a0,
+ inputs->dadx,
+ inputs->dady,
+ color,
+ depth,
+ INT_MIN, INT_MIN, INT_MIN,
+ NULL, NULL, NULL );
+ }
+
+
+ #endif
--- /dev/null
+ /**************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+ #include "util/u_math.h"
+ #include "util/u_memory.h"
++#include "util/u_inlines.h"
+ #include "util/u_simple_list.h"
+ #include "lp_scene.h"
+
+
+ struct lp_scene *
+ lp_scene_create(void)
+ {
+ struct lp_scene *scene = CALLOC_STRUCT(lp_scene);
+ if (scene)
+ lp_scene_init(scene);
+ return scene;
+ }
+
+
+ void
+ lp_scene_destroy(struct lp_scene *scene)
+ {
+ lp_scene_reset(scene);
+ lp_scene_free_bin_data(scene);
+ FREE(scene);
+ }
+
+
+ void
+ lp_scene_init(struct lp_scene *scene)
+ {
+ unsigned i, j;
+ for (i = 0; i < TILES_X; i++)
+ for (j = 0; j < TILES_Y; j++) {
+ struct cmd_bin *bin = lp_scene_get_bin(scene, i, j);
+ bin->commands.head = bin->commands.tail = CALLOC_STRUCT(cmd_block);
+ }
+
+ scene->data.head =
+ scene->data.tail = CALLOC_STRUCT(data_block);
+
+ make_empty_list(&scene->textures);
+
+ pipe_mutex_init(scene->mutex);
+ }
+
+
+ /**
+ * Check if the scene's bins are all empty.
+ * For debugging purposes.
+ */
+ boolean
+ lp_scene_is_empty(struct lp_scene *scene )
+ {
+ unsigned x, y;
+
+ for (y = 0; y < TILES_Y; y++) {
+ for (x = 0; x < TILES_X; x++) {
+ const struct cmd_bin *bin = lp_scene_get_bin(scene, x, y);
+ const struct cmd_block_list *list = &bin->commands;
+ if (list->head != list->tail || list->head->count > 0) {
+ return FALSE;
+ }
+ }
+ }
+ return TRUE;
+ }
+
+
+ void
+ lp_scene_bin_reset(struct lp_scene *scene, unsigned x, unsigned y)
+ {
+ struct cmd_bin *bin = lp_scene_get_bin(scene, x, y);
+ struct cmd_block_list *list = &bin->commands;
+ struct cmd_block *block;
+ struct cmd_block *tmp;
+
+ for (block = list->head; block != list->tail; block = tmp) {
+ tmp = block->next;
+ FREE(block);
+ }
+
+ assert(list->tail->next == NULL);
+ list->head = list->tail;
+ list->head->count = 0;
+ }
+
+
+ /**
+ * Set scene to empty state.
+ */
+ void
+ lp_scene_reset(struct lp_scene *scene )
+ {
+ unsigned i, j;
+
+ /* Free all but last binner command lists:
+ */
+ for (i = 0; i < scene->tiles_x; i++) {
+ for (j = 0; j < scene->tiles_y; j++) {
+ lp_scene_bin_reset(scene, i, j);
+ }
+ }
+
+ assert(lp_scene_is_empty(scene));
+
+ /* Free all but last binned data block:
+ */
+ {
+ struct data_block_list *list = &scene->data;
+ struct data_block *block, *tmp;
+
+ for (block = list->head; block != list->tail; block = tmp) {
+ tmp = block->next;
+ FREE(block);
+ }
+
+ assert(list->tail->next == NULL);
+ list->head = list->tail;
+ list->head->used = 0;
+ }
+
+ /* Release texture refs
+ */
+ {
+ struct texture_ref *ref, *next, *ref_list = &scene->textures;
+ for (ref = ref_list->next; ref != ref_list; ref = next) {
+ next = next_elem(ref);
+ pipe_texture_reference(&ref->texture, NULL);
+ FREE(ref);
+ }
+ make_empty_list(ref_list);
+ }
+ }
+
+
+ /**
+ * Free all data associated with the given bin, but don't free(scene).
+ */
+ void
+ lp_scene_free_bin_data(struct lp_scene *scene)
+ {
+ unsigned i, j;
+
+ for (i = 0; i < TILES_X; i++)
+ for (j = 0; j < TILES_Y; j++) {
+ struct cmd_bin *bin = lp_scene_get_bin(scene, i, j);
+ /* lp_reset_scene() should have been already called */
+ assert(bin->commands.head == bin->commands.tail);
+ FREE(bin->commands.head);
+ bin->commands.head = NULL;
+ bin->commands.tail = NULL;
+ }
+
+ FREE(scene->data.head);
+ scene->data.head = NULL;
+
+ pipe_mutex_destroy(scene->mutex);
+ }
+
+
+ void
+ lp_scene_set_framebuffer_size( struct lp_scene *scene,
+ unsigned width, unsigned height )
+ {
+ assert(lp_scene_is_empty(scene));
+
+ scene->tiles_x = align(width, TILE_SIZE) / TILE_SIZE;
+ scene->tiles_y = align(height, TILE_SIZE) / TILE_SIZE;
+ }
+
+
+ void
+ lp_bin_new_cmd_block( struct cmd_block_list *list )
+ {
+ struct cmd_block *block = MALLOC_STRUCT(cmd_block);
+ list->tail->next = block;
+ list->tail = block;
+ block->next = NULL;
+ block->count = 0;
+ }
+
+
+ void
+ lp_bin_new_data_block( struct data_block_list *list )
+ {
+ struct data_block *block = MALLOC_STRUCT(data_block);
+ list->tail->next = block;
+ list->tail = block;
+ block->next = NULL;
+ block->used = 0;
+ }
+
+
+ /** Return number of bytes used for all bin data within a scene */
+ unsigned
+ lp_scene_data_size( const struct lp_scene *scene )
+ {
+ unsigned size = 0;
+ const struct data_block *block;
+ for (block = scene->data.head; block; block = block->next) {
+ size += block->used;
+ }
+ return size;
+ }
+
+
+ /** Return number of bytes used for a single bin */
+ unsigned
+ lp_scene_bin_size( const struct lp_scene *scene, unsigned x, unsigned y )
+ {
+ struct cmd_bin *bin = lp_scene_get_bin((struct lp_scene *) scene, x, y);
+ const struct cmd_block *cmd;
+ unsigned size = 0;
+ for (cmd = bin->commands.head; cmd; cmd = cmd->next) {
+ size += (cmd->count *
+ (sizeof(lp_rast_cmd) + sizeof(union lp_rast_cmd_arg)));
+ }
+ return size;
+ }
+
+
+ /**
+ * Add a reference to a texture by the scene.
+ */
+ void
+ lp_scene_texture_reference( struct lp_scene *scene,
+ struct pipe_texture *texture )
+ {
+ struct texture_ref *ref = CALLOC_STRUCT(texture_ref);
+ if (ref) {
+ struct texture_ref *ref_list = &scene->textures;
+ pipe_texture_reference(&ref->texture, texture);
+ insert_at_tail(ref_list, ref);
+ }
+ }
+
+
+ /**
+ * Does this scene have a reference to the given texture?
+ */
+ boolean
+ lp_scene_is_textured_referenced( const struct lp_scene *scene,
+ const struct pipe_texture *texture )
+ {
+ const struct texture_ref *ref_list = &scene->textures;
+ const struct texture_ref *ref;
+ foreach (ref, ref_list) {
+ if (ref->texture == texture)
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+
+ /**
+ * Return last command in the bin
+ */
+ static lp_rast_cmd
+ lp_get_last_command( const struct cmd_bin *bin )
+ {
+ const struct cmd_block *tail = bin->commands.tail;
+ const unsigned i = tail->count;
+ if (i > 0)
+ return tail->cmd[i - 1];
+ else
+ return NULL;
+ }
+
+
+ /**
+ * Replace the arg of the last command in the bin.
+ */
+ static void
+ lp_replace_last_command_arg( struct cmd_bin *bin,
+ const union lp_rast_cmd_arg arg )
+ {
+ struct cmd_block *tail = bin->commands.tail;
+ const unsigned i = tail->count;
+ assert(i > 0);
+ tail->arg[i - 1] = arg;
+ }
+
+
+
+ /**
+ * Put a state-change command into all bins.
+ * If we find that the last command in a bin was also a state-change
+ * command, we can simply replace that one with the new one.
+ */
+ void
+ lp_scene_bin_state_command( struct lp_scene *scene,
+ lp_rast_cmd cmd,
+ const union lp_rast_cmd_arg arg )
+ {
+ unsigned i, j;
+ for (i = 0; i < scene->tiles_x; i++) {
+ for (j = 0; j < scene->tiles_y; j++) {
+ struct cmd_bin *bin = lp_scene_get_bin(scene, i, j);
+ lp_rast_cmd last_cmd = lp_get_last_command(bin);
+ if (last_cmd == cmd) {
+ lp_replace_last_command_arg(bin, arg);
+ }
+ else {
+ lp_scene_bin_command( scene, i, j, cmd, arg );
+ }
+ }
+ }
+ }
+
+
+ /** advance curr_x,y to the next bin */
+ static boolean
+ next_bin(struct lp_scene *scene)
+ {
+ scene->curr_x++;
+ if (scene->curr_x >= scene->tiles_x) {
+ scene->curr_x = 0;
+ scene->curr_y++;
+ }
+ if (scene->curr_y >= scene->tiles_y) {
+ /* no more bins */
+ return FALSE;
+ }
+ return TRUE;
+ }
+
+
+ void
+ lp_scene_bin_iter_begin( struct lp_scene *scene )
+ {
+ scene->curr_x = scene->curr_y = -1;
+ }
+
+
+ /**
+ * Return pointer to next bin to be rendered.
+ * The lp_scene::curr_x and ::curr_y fields will be advanced.
+ * Multiple rendering threads will call this function to get a chunk
+ * of work (a bin) to work on.
+ */
+ struct cmd_bin *
+ lp_scene_bin_iter_next( struct lp_scene *scene, int *bin_x, int *bin_y )
+ {
+ struct cmd_bin *bin = NULL;
+
+ pipe_mutex_lock(scene->mutex);
+
+ if (scene->curr_x < 0) {
+ /* first bin */
+ scene->curr_x = 0;
+ scene->curr_y = 0;
+ }
+ else if (!next_bin(scene)) {
+ /* no more bins left */
+ goto end;
+ }
+
+ bin = lp_scene_get_bin(scene, scene->curr_x, scene->curr_y);
+ *bin_x = scene->curr_x;
+ *bin_y = scene->curr_y;
+
+ end:
+ /*printf("return bin %p at %d, %d\n", (void *) bin, *bin_x, *bin_y);*/
+ pipe_mutex_unlock(scene->mutex);
+ return bin;
+ }
--- /dev/null
-#include "pipe/p_thread.h"
+ /**************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+
+ /**
+ * Binner data structures and bin-related functions.
+ * Note: the "setup" code is concerned with building scenes while
+ * The "rast" code is concerned with consuming/executing scenes.
+ */
+
+ #ifndef LP_SCENE_H
+ #define LP_SCENE_H
+
++#include "os/os_thread.h"
+ #include "lp_tile_soa.h"
+ #include "lp_rast.h"
+
+
+ /* We're limited to 2K by 2K for 32bit fixed point rasterization.
+ * Will need a 64-bit version for larger framebuffers.
+ */
+ #define MAXHEIGHT 2048
+ #define MAXWIDTH 2048
+ #define TILES_X (MAXWIDTH / TILE_SIZE)
+ #define TILES_Y (MAXHEIGHT / TILE_SIZE)
+
+
+ #define CMD_BLOCK_MAX 128
+ #define DATA_BLOCK_SIZE (16 * 1024 - sizeof(unsigned) - sizeof(void *))
+
+
+
+ /* switch to a non-pointer value for this:
+ */
+ typedef void (*lp_rast_cmd)( struct lp_rasterizer *,
+ unsigned thread_index,
+ const union lp_rast_cmd_arg );
+
+ struct cmd_block {
+ lp_rast_cmd cmd[CMD_BLOCK_MAX];
+ union lp_rast_cmd_arg arg[CMD_BLOCK_MAX];
+ unsigned count;
+ struct cmd_block *next;
+ };
+
+ struct data_block {
+ ubyte data[DATA_BLOCK_SIZE];
+ unsigned used;
+ struct data_block *next;
+ };
+
+ struct cmd_block_list {
+ struct cmd_block *head;
+ struct cmd_block *tail;
+ };
+
+ /**
+ * For each screen tile we have one of these bins.
+ */
+ struct cmd_bin {
+ struct cmd_block_list commands;
+ };
+
+
+ /**
+ * This stores bulk data which is shared by all bins within a scene.
+ * Examples include triangle data and state data. The commands in
+ * the per-tile bins will point to chunks of data in this structure.
+ */
+ struct data_block_list {
+ struct data_block *head;
+ struct data_block *tail;
+ };
+
+
+ /** List of texture references */
+ struct texture_ref {
+ struct pipe_texture *texture;
+ struct texture_ref *prev, *next; /**< linked list w/ u_simple_list.h */
+ };
+
+
+ /**
+ * All bins and bin data are contained here.
+ * Per-bin data goes into the 'tile' bins.
+ * Shared data goes into the 'data' buffer.
+ *
+ * When there are multiple threads, will want to double-buffer between
+ * scenes:
+ */
+ struct lp_scene {
+ struct cmd_bin tile[TILES_X][TILES_Y];
+ struct data_block_list data;
+
+ /** the framebuffer to render the scene into */
+ struct pipe_framebuffer_state fb;
+
+ /** list of textures referenced by the scene commands */
+ struct texture_ref textures;
+
+ boolean write_depth;
+
+ /**
+ * Number of active tiles in each dimension.
+ * This basically the framebuffer size divided by tile size
+ */
+ unsigned tiles_x, tiles_y;
+
+ int curr_x, curr_y; /**< for iterating over bins */
+ pipe_mutex mutex;
+ };
+
+
+
+ struct lp_scene *lp_scene_create(void);
+
+ void lp_scene_destroy(struct lp_scene *scene);
+
+
+ void lp_scene_init(struct lp_scene *scene);
+
+ boolean lp_scene_is_empty(struct lp_scene *scene );
+
+ void lp_scene_reset(struct lp_scene *scene );
+
+ void lp_scene_free_bin_data(struct lp_scene *scene);
+
+ void lp_scene_set_framebuffer_size( struct lp_scene *scene,
+ unsigned width, unsigned height );
+
+ void lp_bin_new_data_block( struct data_block_list *list );
+
+ void lp_bin_new_cmd_block( struct cmd_block_list *list );
+
+ unsigned lp_scene_data_size( const struct lp_scene *scene );
+
+ unsigned lp_scene_bin_size( const struct lp_scene *scene, unsigned x, unsigned y );
+
+ void lp_scene_texture_reference( struct lp_scene *scene,
+ struct pipe_texture *texture );
+
+ boolean lp_scene_is_textured_referenced( const struct lp_scene *scene,
+ const struct pipe_texture *texture );
+
+
+ /**
+ * Allocate space for a command/data in the bin's data buffer.
+ * Grow the block list if needed.
+ */
+ static INLINE void *
+ lp_scene_alloc( struct lp_scene *scene, unsigned size)
+ {
+ struct data_block_list *list = &scene->data;
+
+ if (list->tail->used + size > DATA_BLOCK_SIZE) {
+ lp_bin_new_data_block( list );
+ }
+
+ {
+ struct data_block *tail = list->tail;
+ ubyte *data = tail->data + tail->used;
+ tail->used += size;
+ return data;
+ }
+ }
+
+
+ /**
+ * As above, but with specific alignment.
+ */
+ static INLINE void *
+ lp_scene_alloc_aligned( struct lp_scene *scene, unsigned size,
+ unsigned alignment )
+ {
+ struct data_block_list *list = &scene->data;
+
+ if (list->tail->used + size + alignment - 1 > DATA_BLOCK_SIZE) {
+ lp_bin_new_data_block( list );
+ }
+
+ {
+ struct data_block *tail = list->tail;
+ ubyte *data = tail->data + tail->used;
+ unsigned offset = (((uintptr_t)data + alignment - 1) & ~(alignment - 1)) - (uintptr_t)data;
+ tail->used += offset + size;
+ return data + offset;
+ }
+ }
+
+
+ /* Put back data if we decide not to use it, eg. culled triangles.
+ */
+ static INLINE void
+ lp_scene_putback_data( struct lp_scene *scene, unsigned size)
+ {
+ struct data_block_list *list = &scene->data;
+ assert(list->tail->used >= size);
+ list->tail->used -= size;
+ }
+
+
+ /** Return pointer to a particular tile's bin. */
+ static INLINE struct cmd_bin *
+ lp_scene_get_bin(struct lp_scene *scene, unsigned x, unsigned y)
+ {
+ return &scene->tile[x][y];
+ }
+
+
+ /** Remove all commands from a bin */
+ void
+ lp_scene_bin_reset(struct lp_scene *scene, unsigned x, unsigned y);
+
+
+ /* Add a command to bin[x][y].
+ */
+ static INLINE void
+ lp_scene_bin_command( struct lp_scene *scene,
+ unsigned x, unsigned y,
+ lp_rast_cmd cmd,
+ union lp_rast_cmd_arg arg )
+ {
+ struct cmd_bin *bin = lp_scene_get_bin(scene, x, y);
+ struct cmd_block_list *list = &bin->commands;
+
+ assert(x < scene->tiles_x);
+ assert(y < scene->tiles_y);
+
+ if (list->tail->count == CMD_BLOCK_MAX) {
+ lp_bin_new_cmd_block( list );
+ }
+
+ {
+ struct cmd_block *tail = list->tail;
+ unsigned i = tail->count;
+ tail->cmd[i] = cmd;
+ tail->arg[i] = arg;
+ tail->count++;
+ }
+ }
+
+
+ /* Add a command to all active bins.
+ */
+ static INLINE void
+ lp_scene_bin_everywhere( struct lp_scene *scene,
+ lp_rast_cmd cmd,
+ const union lp_rast_cmd_arg arg )
+ {
+ unsigned i, j;
+ for (i = 0; i < scene->tiles_x; i++)
+ for (j = 0; j < scene->tiles_y; j++)
+ lp_scene_bin_command( scene, i, j, cmd, arg );
+ }
+
+
+ void
+ lp_scene_bin_state_command( struct lp_scene *scene,
+ lp_rast_cmd cmd,
+ const union lp_rast_cmd_arg arg );
+
+
+ static INLINE unsigned
+ lp_scene_get_num_bins( const struct lp_scene *scene )
+ {
+ return scene->tiles_x * scene->tiles_y;
+ }
+
+
+ void
+ lp_scene_bin_iter_begin( struct lp_scene *scene );
+
+ struct cmd_bin *
+ lp_scene_bin_iter_next( struct lp_scene *scene, int *bin_x, int *bin_y );
+
+
+ #endif /* LP_BIN_H */
**************************************************************************/
/**
- * \brief Primitive rasterization/rendering (points, lines, triangles)
+ * Tiling engine.
*
- * \author Keith Whitwell <keith@tungstengraphics.com>
- * \author Brian Paul
+ * Builds per-tile display lists and executes them on calls to
+ * lp_setup_flush().
*/
- #include "lp_context.h"
- #include "lp_quad.h"
- #include "lp_setup.h"
- #include "lp_state.h"
- #include "draw/draw_context.h"
- #include "draw/draw_vertex.h"
- #include "pipe/p_shader_tokens.h"
- #include "util/u_format.h"
- #include "util/u_math.h"
+ #include "pipe/p_defines.h"
-#include "pipe/p_inlines.h"
++#include "util/u_inlines.h"
#include "util/u_memory.h"
- #include "lp_bld_debug.h"
- #include "lp_tile_cache.h"
- #include "lp_tile_soa.h"
-
-
- #define DEBUG_VERTS 0
- #define DEBUG_FRAGS 0
-
- /**
- * Triangle edge info
- */
- struct edge {
- float dx; /**< X(v1) - X(v0), used only during setup */
- float dy; /**< Y(v1) - Y(v0), used only during setup */
- float dxdy; /**< dx/dy */
- float sx, sy; /**< first sample point coord */
- int lines; /**< number of lines on this edge */
- };
-
-
- #define MAX_QUADS 16
-
+ #include "util/u_pack_color.h"
+ #include "util/u_surface.h"
+ #include "lp_scene.h"
+ #include "lp_scene_queue.h"
+ #include "lp_buffer.h"
+ #include "lp_texture.h"
+ #include "lp_debug.h"
+ #include "lp_fence.h"
+ #include "lp_rast.h"
+ #include "lp_setup_context.h"
- /**
- * Triangle setup info (derived from draw_stage).
- * Also used for line drawing (taking some liberties).
- */
- struct setup_context {
- struct llvmpipe_context *llvmpipe;
-
- /* Vertices are just an array of floats making up each attribute in
- * turn. Currently fixed at 4 floats, but should change in time.
- * Codegen will help cope with this.
- */
- const float (*vmax)[4];
- const float (*vmid)[4];
- const float (*vmin)[4];
- const float (*vprovoke)[4];
-
- struct edge ebot;
- struct edge etop;
- struct edge emaj;
-
- float oneoverarea;
- int facing;
+ #include "draw/draw_context.h"
+ #include "draw/draw_vbuf.h"
- float pixel_offset;
- struct quad_header quad[MAX_QUADS];
- struct quad_header *quad_ptrs[MAX_QUADS];
- unsigned count;
+ static void set_scene_state( struct setup_context *, unsigned );
- struct quad_interp_coef coef;
- struct {
- int left[2]; /**< [0] = row0, [1] = row1 */
- int right[2];
- int y;
- } span;
+ struct lp_scene *
+ lp_setup_get_current_scene(struct setup_context *setup)
+ {
+ if (!setup->scene) {
- #if DEBUG_FRAGS
- uint numFragsEmitted; /**< per primitive */
- uint numFragsWritten; /**< per primitive */
- #endif
+ /* wait for a free/empty scene
+ */
+ setup->scene = lp_scene_dequeue(setup->empty_scenes, TRUE);
- unsigned winding; /* which winding to cull */
- };
+ if(0)lp_scene_reset( setup->scene ); /* XXX temporary? */
+ lp_scene_set_framebuffer_size(setup->scene,
+ setup->fb.width,
+ setup->fb.height);
+ }
+ return setup->scene;
+ }
- /**
- * Execute fragment shader for the four fragments in the quad.
- */
- PIPE_ALIGN_STACK
static void
- shade_quads(struct llvmpipe_context *llvmpipe,
- struct quad_header *quads[],
- unsigned nr)
+ first_triangle( struct setup_context *setup,
+ const float (*v0)[4],
+ const float (*v1)[4],
+ const float (*v2)[4])
{
- struct lp_fragment_shader *fs = llvmpipe->fs;
- struct quad_header *quad = quads[0];
- const unsigned x = quad->input.x0;
- const unsigned y = quad->input.y0;
- uint8_t *tile;
- uint8_t *color;
- void *depth;
- PIPE_ALIGN_VAR(16) uint32_t mask[4][NUM_CHANNELS];
- unsigned chan_index;
- unsigned q;
-
- assert(fs->current);
- if(!fs->current)
- return;
-
- /* Sanity checks */
- assert(nr * QUAD_SIZE == TILE_VECTOR_HEIGHT * TILE_VECTOR_WIDTH);
- assert(x % TILE_VECTOR_WIDTH == 0);
- assert(y % TILE_VECTOR_HEIGHT == 0);
- for (q = 0; q < nr; ++q) {
- assert(quads[q]->input.x0 == x + q*2);
- assert(quads[q]->input.y0 == y);
- }
-
- /* mask */
- for (q = 0; q < 4; ++q)
- for (chan_index = 0; chan_index < NUM_CHANNELS; ++chan_index)
- mask[q][chan_index] = quads[q]->inout.mask & (1 << chan_index) ? ~0 : 0;
+ set_scene_state( setup, SETUP_ACTIVE );
+ lp_setup_choose_triangle( setup );
+ setup->triangle( setup, v0, v1, v2 );
+ }
- /* color buffer */
- if(llvmpipe->framebuffer.nr_cbufs >= 1 &&
- llvmpipe->framebuffer.cbufs[0]) {
- tile = lp_get_cached_tile(llvmpipe->cbuf_cache[0], x, y);
- color = &TILE_PIXEL(tile, x & (TILE_SIZE-1), y & (TILE_SIZE-1), 0);
- }
- else
- color = NULL;
-
- /* depth buffer */
- if(llvmpipe->zsbuf_map) {
- assert((x % 2) == 0);
- assert((y % 2) == 0);
- depth = llvmpipe->zsbuf_map +
- y*llvmpipe->zsbuf_transfer->stride +
- 2*x*util_format_get_blocksize(llvmpipe->zsbuf_transfer->texture->format);
- }
- else
- depth = NULL;
-
- /* XXX: This will most likely fail on 32bit x86 without -mstackrealign */
- assert(lp_check_alignment(mask, 16));
-
- assert(lp_check_alignment(depth, 16));
- assert(lp_check_alignment(color, 16));
- assert(lp_check_alignment(llvmpipe->jit_context.blend_color, 16));
-
- /* run shader */
- fs->current->jit_function( &llvmpipe->jit_context,
- x, y,
- quad->coef->a0,
- quad->coef->dadx,
- quad->coef->dady,
- &mask[0][0],
- color,
- depth);
+ static void
+ first_line( struct setup_context *setup,
+ const float (*v0)[4],
+ const float (*v1)[4])
+ {
+ set_scene_state( setup, SETUP_ACTIVE );
+ lp_setup_choose_line( setup );
+ setup->line( setup, v0, v1 );
}
+ static void
+ first_point( struct setup_context *setup,
+ const float (*v0)[4])
+ {
+ set_scene_state( setup, SETUP_ACTIVE );
+ lp_setup_choose_point( setup );
+ setup->point( setup, v0 );
+ }
+ static void reset_context( struct setup_context *setup )
+ {
+ LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
+ /* Reset derived state */
+ setup->constants.stored_size = 0;
+ setup->constants.stored_data = NULL;
+ setup->fs.stored = NULL;
+ setup->dirty = ~0;
- /**
- * Do triangle cull test using tri determinant (sign indicates orientation)
- * \return true if triangle is to be culled.
- */
- static INLINE boolean
- cull_tri(const struct setup_context *setup, float det)
- {
- if (det != 0) {
- /* if (det < 0 then Z points toward camera and triangle is
- * counter-clockwise winding.
- */
- unsigned winding = (det < 0) ? PIPE_WINDING_CCW : PIPE_WINDING_CW;
+ /* no current bin */
+ setup->scene = NULL;
- if ((winding & setup->winding) == 0)
- return FALSE;
- }
+ /* Reset some state:
+ */
+ setup->clear.flags = 0;
- /* Culled:
+ /* Have an explicit "start-binning" call and get rid of this
+ * pointer twiddling?
*/
- return TRUE;
+ setup->line = first_line;
+ setup->point = first_point;
+ setup->triangle = first_triangle;
}
* @author Jose Fonseca <jfonseca@vmware.com>
*/
+ #include <limits.h>
#include "pipe/p_defines.h"
+#include "util/u_inlines.h"
#include "util/u_memory.h"
#include "util/u_format.h"
#include "util/u_debug_dump.h"
/* Authors: Keith Whitwell <keith@tungstengraphics.com>
*/
-
+ #include "pipe/p_state.h"
+#include "util/u_inlines.h"
+ #include "util/u_surface.h"
#include "lp_context.h"
#include "lp_state.h"
- #include "lp_tile_cache.h"
+ #include "lp_setup.h"
#include "draw/draw_context.h"