const unsigned tile_x = task->x, tile_y = task->y;
unsigned x, y;
+ if (inputs->disable) {
+ /* This command was partially binned and has been disabled */
+ return;
+ }
+
LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
/* render the whole 64x64 tile in 4x4 chunks */
}
lp_rast_tile_end(task);
-
- /* Free data for this bin.
- */
- lp_scene_bin_reset( task->rast->curr_scene, x, y);
}
is_empty_bin( const struct cmd_bin *bin )
{
if (0) debug_bin(bin);
- return bin->commands.head->count == 0;
+ return bin->commands.head == NULL;
}
struct lp_rast_shader_inputs {
float facing; /** Positive for front-facing, negative for back-facing */
boolean opaque:1; /** Is opaque */
+ boolean disable:1; /** Partially binned, disable this command */
float (*a0)[4];
float (*dadx)[4];
outmask = 0; /* outside one or more trivial reject planes */
partmask = 0; /* outside one or more trivial accept planes */
+ if (tri->inputs.disable) {
+ /* This triangle was partially binned and has been disabled */
+ return;
+ }
+
while (plane_mask) {
int i = ffs(plane_mask) - 1;
plane[j] = tri->plane[i];
#include "util/u_inlines.h"
#include "util/u_simple_list.h"
#include "lp_scene.h"
+#include "lp_debug.h"
#include "lp_scene_queue.h"
#include "lp_fence.h"
-/** List of texture references */
-struct texture_ref {
- struct pipe_resource *texture;
- struct texture_ref *prev, *next; /**< linked list w/ u_simple_list.h */
-};
+#define RESOURCE_REF_SZ 32
+/** List of resource references */
+struct resource_ref {
+ struct pipe_resource *resource[RESOURCE_REF_SZ];
+ int count;
+ struct resource_ref *next;
+};
/**
lp_scene_create( struct pipe_context *pipe,
struct lp_scene_queue *queue )
{
- unsigned i, j;
struct lp_scene *scene = CALLOC_STRUCT(lp_scene);
if (!scene)
return NULL;
scene->pipe = pipe;
scene->empty_queue = queue;
- 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->resources);
-
pipe_mutex_init(scene->mutex);
return scene;
void
lp_scene_destroy(struct lp_scene *scene)
{
- unsigned i, j;
-
lp_scene_reset(scene);
- 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);
- 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);
-
FREE(scene);
}
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) {
+ if (list->head) {
return FALSE;
}
}
}
-/* Free data for one particular bin. May be called from the
- * rasterizer thread(s).
+/* Returns true if there has ever been a failed allocation attempt in
+ * this scene. Used in triangle/rectangle emit to avoid having to
+ * check success at each bin.
+ */
+boolean
+lp_scene_is_oom(struct lp_scene *scene)
+{
+ return scene->alloc_failed;
+}
+
+
+/* Remove all commands from a bin. Tries to reuse some of the memory
+ * allocated to the bin, however.
*/
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;
- assert(x < TILES_X);
- assert(y < TILES_Y);
-
- 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;
+ if (list->tail) {
+ list->tail->next = NULL;
+ list->tail->count = 0;
+ }
}
void
lp_scene_reset(struct lp_scene *scene )
{
- unsigned i, j;
+ int i, j;
- /* Free all but last binner command lists:
+ /* Reset all 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);
+ struct cmd_bin *bin = lp_scene_get_bin(scene, i, j);
+ memset(bin, 0, sizeof *bin);
}
}
*/
assert(lp_scene_is_empty(scene));
- /* Free all but last binned data block:
+ /* Decrement texture ref counts
+ */
+ {
+ struct resource_ref *ref;
+ int i, j = 0;
+
+ for (ref = scene->resources; ref; ref = ref->next) {
+ for (i = 0; i < ref->count; i++) {
+ if (LP_DEBUG & DEBUG_SETUP)
+ debug_printf("resource %d: %p %dx%d sz %d\n",
+ j,
+ ref->resource[i],
+ ref->resource[i]->width0,
+ ref->resource[i]->height0,
+ llvmpipe_resource_size(ref->resource[i]));
+ j++;
+ pipe_resource_reference(&ref->resource[i], NULL);
+ }
+ }
+
+ if (LP_DEBUG & DEBUG_SETUP)
+ debug_printf("scene %d resources, sz %d\n",
+ j, scene->resource_reference_size);
+ }
+
+ /* Free all scene data blocks:
*/
{
struct data_block_list *list = &scene->data;
struct data_block *block, *tmp;
- for (block = list->head; block != list->tail; block = tmp) {
+ for (block = list->head; block; block = tmp) {
tmp = block->next;
FREE(block);
}
-
- assert(list->tail->next == NULL);
- list->head = list->tail;
- list->head->used = 0;
- }
- /* Release texture refs
- */
- {
- struct resource_ref *ref, *next, *ref_list = &scene->resources;
- for (ref = ref_list->next; ref != ref_list; ref = next) {
- next = next_elem(ref);
- pipe_resource_reference(&ref->resource, NULL);
- FREE(ref);
- }
- make_empty_list(ref_list);
+ list->head = NULL;
}
lp_fence_reference(&scene->fence, NULL);
+ scene->resources = NULL;
scene->scene_size = 0;
+ scene->resource_reference_size = 0;
scene->has_depthstencil_clear = FALSE;
+ scene->alloc_failed = FALSE;
}
struct cmd_block *
-lp_bin_new_cmd_block( struct cmd_block_list *list )
+lp_scene_new_cmd_block( struct lp_scene *scene,
+ struct cmd_bin *bin )
{
- struct cmd_block *block = MALLOC_STRUCT(cmd_block);
+ struct cmd_block *block = lp_scene_alloc(scene, sizeof(struct cmd_block));
if (block) {
- list->tail->next = block;
- list->tail = block;
+ if (bin->commands.tail) {
+ bin->commands.tail->next = block;
+ bin->commands.tail = block;
+ }
+ else {
+ bin->commands.head = block;
+ bin->commands.tail = block;
+ }
+ //memset(block, 0, sizeof *block);
block->next = NULL;
block->count = 0;
}
struct data_block *
-lp_bin_new_data_block( struct data_block_list *list )
+lp_scene_new_data_block( struct lp_scene *scene )
{
- struct data_block *block = MALLOC_STRUCT(data_block);
- if (block) {
- list->tail->next = block;
- list->tail = block;
- block->next = NULL;
+ if (scene->scene_size + DATA_BLOCK_SIZE > LP_SCENE_MAX_SIZE) {
+ if (0) debug_printf("%s: failed\n", __FUNCTION__);
+ scene->alloc_failed = TRUE;
+ return NULL;
+ }
+ else {
+ struct data_block *block = MALLOC_STRUCT(data_block);
+ if (block == NULL)
+ return NULL;
+
+ scene->scene_size += sizeof *block;
+
block->used = 0;
+ block->next = scene->data.head;
+ scene->data.head = block;
+
+ return block;
}
- return block;
}
* Return number of bytes used for all bin data within a scene.
* This does not include resources (textures) referenced by the scene.
*/
-unsigned
+static unsigned
lp_scene_data_size( const struct lp_scene *scene )
{
unsigned size = 0;
/** Return number of bytes used for a single bin */
-unsigned
+static 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);
/**
* Add a reference to a resource by the scene.
*/
-void
+boolean
lp_scene_add_resource_reference(struct lp_scene *scene,
struct pipe_resource *resource)
{
- struct resource_ref *ref = CALLOC_STRUCT(resource_ref);
- if (ref) {
- struct resource_ref *ref_list = &scene->resources;
- pipe_resource_reference(&ref->resource, resource);
- insert_at_tail(ref_list, ref);
+ struct resource_ref *ref, **last = &scene->resources;
+ int i;
+
+ /* Look at existing resource blocks:
+ */
+ for (ref = scene->resources; ref; ref = ref->next) {
+
+ /* Search for this resource:
+ */
+ for (i = 0; i < ref->count; i++)
+ if (ref->resource[i] == resource)
+ return TRUE;
+
+ /* If the block is half-empty, this is the last block. Append
+ * the reference here.
+ */
+ if (ref->count < RESOURCE_REF_SZ)
+ goto add_new_ref;
+
+ last = &ref->next;
}
- scene->scene_size += llvmpipe_resource_size(resource);
+ /* Otherwise, need to create a new block:
+ */
+ *last = lp_scene_alloc(scene, sizeof(struct resource_ref));
+ if (*last) {
+ ref = *last;
+ memset(ref, 0, sizeof *ref);
+ goto add_new_ref;
+ }
+
+ return FALSE;
+
+add_new_ref:
+ pipe_resource_reference(&ref->resource[ref->count++], resource);
+ scene->resource_reference_size += llvmpipe_resource_size(resource);
+ return scene->resource_reference_size < LP_SCENE_MAX_RESOURCE_SIZE;
}
lp_scene_is_resource_referenced(const struct lp_scene *scene,
const struct pipe_resource *resource)
{
- const struct resource_ref *ref_list = &scene->resources;
const struct resource_ref *ref;
- foreach (ref, ref_list) {
- if (ref->resource == resource)
- return TRUE;
+ int i;
+
+ for (ref = scene->resources; ref; ref = ref->next) {
+ for (i = 0; i < ref->count; i++)
+ if (ref->resource[i] == resource)
+ return TRUE;
}
+
return FALSE;
}
#define TILES_Y (LP_MAX_HEIGHT / TILE_SIZE)
-#define CMD_BLOCK_MAX 128
-#define DATA_BLOCK_SIZE (16 * 1024 - sizeof(unsigned) - sizeof(void *))
-
+#define CMD_BLOCK_MAX 16
+#define DATA_BLOCK_SIZE (64 * 1024 - 2 * sizeof(void *))
+
+/* Scene temporary storage is clamped to this size:
+ */
+#define LP_SCENE_MAX_SIZE (1024*1024)
+
+/* The maximum amount of texture storage referenced by a scene is
+ * clamped ot this size:
+ */
+#define LP_SCENE_MAX_RESOURCE_SIZE (64*1024*1024)
/* switch to a non-pointer value for this:
struct cmd_block *next;
};
+struct cmd_block_list {
+ struct cmd_block *head;
+ struct cmd_block *tail;
+};
+
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.
/**
- * This stores bulk data which is shared by all bins within a scene.
+ * This stores bulk data which is used for all memory allocations
+ * 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 resource references */
-struct resource_ref {
- struct pipe_resource *resource;
- struct resource_ref *prev, *next; /**< linked list w/ u_simple_list.h */
};
+struct resource_ref;
/**
* All bins and bin data are contained here.
struct pipe_framebuffer_state fb;
/** list of resources referenced by the scene commands */
- struct resource_ref resources;
+ struct resource_ref *resources;
- /** Approx memory used by the scene (in bytes). This includes the
- * shared and per-tile bins plus any referenced resources/textures.
+ /** Total memory used by the scene (in bytes). This sums all the
+ * data blocks and counts all bins, state, resource references and
+ * other random allocations within the scene.
*/
unsigned scene_size;
+ /** Sum of sizes of all resources referenced by the scene. Sums
+ * all the textures read by the scene:
+ */
+ unsigned resource_reference_size;
+
+ boolean alloc_failed;
+
boolean has_depthstencil_clear;
/**
void lp_scene_destroy(struct lp_scene *scene);
-
-
boolean lp_scene_is_empty(struct lp_scene *scene );
+boolean lp_scene_is_oom(struct lp_scene *scene );
void lp_scene_reset(struct lp_scene *scene );
-struct data_block *lp_bin_new_data_block( struct data_block_list *list );
-
-struct cmd_block *lp_bin_new_cmd_block( struct cmd_block_list *list );
+struct data_block *lp_scene_new_data_block( struct lp_scene *scene );
-unsigned lp_scene_data_size( const struct lp_scene *scene );
+struct cmd_block *lp_scene_new_cmd_block( struct lp_scene *scene,
+ struct cmd_bin *bin );
-unsigned lp_scene_bin_size( const struct lp_scene *scene, unsigned x, unsigned y );
-
-void lp_scene_add_resource_reference(struct lp_scene *scene,
+boolean lp_scene_add_resource_reference(struct lp_scene *scene,
struct pipe_resource *resource);
boolean lp_scene_is_resource_referenced(const struct lp_scene *scene,
lp_scene_alloc( struct lp_scene *scene, unsigned size)
{
struct data_block_list *list = &scene->data;
- struct data_block *tail = list->tail;
+ struct data_block *block = list->head;
- if (tail->used + size > DATA_BLOCK_SIZE) {
- tail = lp_bin_new_data_block( list );
- if (!tail) {
+ assert(size <= DATA_BLOCK_SIZE);
+
+ if (block == NULL || block->used + size > DATA_BLOCK_SIZE) {
+ block = lp_scene_new_data_block( scene );
+ if (!block) {
/* out of memory */
return NULL;
}
}
- scene->scene_size += size;
-
{
- ubyte *data = tail->data + tail->used;
- tail->used += size;
+ ubyte *data = block->data + block->used;
+ block->used += size;
return data;
}
}
unsigned alignment )
{
struct data_block_list *list = &scene->data;
- struct data_block *tail = list->tail;
+ struct data_block *block = list->head;
- if (tail->used + size + alignment - 1 > DATA_BLOCK_SIZE) {
- tail = lp_bin_new_data_block( list );
- if (!tail)
+ if (block == NULL ||
+ block->used + size + alignment - 1 > DATA_BLOCK_SIZE) {
+ block = lp_scene_new_data_block( scene );
+ if (!block)
return NULL;
}
- scene->scene_size += size;
-
{
- ubyte *data = tail->data + tail->used;
+ ubyte *data = block->data + block->used;
unsigned offset = (((uintptr_t)data + alignment - 1) & ~(alignment - 1)) - (uintptr_t)data;
- tail->used += offset + size;
+ block->used += offset + size;
return data + offset;
}
}
lp_scene_putback_data( struct lp_scene *scene, unsigned size)
{
struct data_block_list *list = &scene->data;
- scene->scene_size -= size;
- assert(list->tail->used >= size);
- list->tail->used -= size;
+ assert(list->head && list->head->used >= size);
+ list->head->used -= size;
}
/* Add a command to bin[x][y].
*/
-static INLINE void
+static INLINE boolean
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;
- struct cmd_block *tail = list->tail;
+ struct cmd_block *tail = bin->commands.tail;
assert(x < scene->tiles_x);
assert(y < scene->tiles_y);
- if (tail->count == CMD_BLOCK_MAX) {
- tail = lp_bin_new_cmd_block( list );
+ if (tail == NULL || tail->count == CMD_BLOCK_MAX) {
+ tail = lp_scene_new_cmd_block( scene, bin );
if (!tail) {
- /* out of memory - simply ignore this command (for now) */
- return;
+ return FALSE;
}
assert(tail->count == 0);
}
tail->arg[i] = arg;
tail->count++;
}
+
+ return TRUE;
}
/* Add a command to all active bins.
*/
-static INLINE void
+static INLINE boolean
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 );
-}
-
+ for (i = 0; i < scene->tiles_x; i++) {
+ for (j = 0; j < scene->tiles_y; j++) {
+ if (!lp_scene_bin_command( scene, i, j, cmd, arg ))
+ return FALSE;
+ }
+ }
-void
-lp_scene_bin_state_command( struct lp_scene *scene,
- lp_rast_cmd cmd,
- const union lp_rast_cmd_arg arg );
+ return TRUE;
+}
static INLINE unsigned
struct pipe_framebuffer_state *fb );
-static INLINE unsigned
-lp_scene_get_size(const struct lp_scene *scene)
-{
- return scene->scene_size;
-}
-
#endif /* LP_BIN_H */
}
-/**
- * Check if the size of the current scene has exceeded the limit.
- * If so, flush/render it.
- */
-static void
-setup_check_scene_size_and_flush(struct lp_setup_context *setup)
-{
- if (setup->scene) {
- struct lp_scene *scene = lp_setup_get_current_scene(setup);
- unsigned size = lp_scene_get_size(scene);
-
- if (size > LP_MAX_SCENE_SIZE) {
- /*printf("LLVMPIPE: scene size = %u, flushing.\n", size);*/
- set_scene_state( setup, SETUP_FLUSHED );
- /*assert(lp_scene_get_size(scene) == 0);*/
- }
- }
-}
-
-
static void
first_triangle( struct lp_setup_context *setup,
const float (*v0)[4],
if (setup->fb.nr_cbufs) {
if (setup->clear.flags & PIPE_CLEAR_COLOR) {
- lp_scene_bin_everywhere( scene,
- lp_rast_clear_color,
- setup->clear.color );
+ ok = lp_scene_bin_everywhere( scene,
+ lp_rast_clear_color,
+ setup->clear.color );
+ assert(ok);
}
}
if (setup->clear.flags & PIPE_CLEAR_DEPTHSTENCIL) {
if (!need_zsload)
scene->has_depthstencil_clear = TRUE;
- lp_scene_bin_everywhere( scene,
- lp_rast_clear_zstencil,
- lp_rast_arg_clearzs(
- setup->clear.zsmask,
- setup->clear.zsvalue));
+ ok = lp_scene_bin_everywhere( scene,
+ lp_rast_clear_zstencil,
+ lp_rast_arg_clearzs(
+ setup->clear.zsmask,
+ setup->clear.zsvalue));
+ assert(ok);
}
}
if (setup->active_query) {
- lp_scene_bin_everywhere( scene,
- lp_rast_restart_query,
- lp_rast_arg_query(setup->active_query) );
+ ok = lp_scene_bin_everywhere( scene,
+ lp_rast_restart_query,
+ lp_rast_arg_query(setup->active_query) );
+ assert(ok);
}
/* wait for a free/empty scene
*/
setup->scene = lp_scene_dequeue(setup->empty_scenes, TRUE);
- assert(lp_scene_is_empty(setup->scene));
lp_scene_begin_binning(setup->scene,
&setup->fb );
break;
}
-void
-lp_setup_clear( struct lp_setup_context *setup,
- const float *color,
- double depth,
- unsigned stencil,
- unsigned flags )
+static boolean
+lp_setup_try_clear( struct lp_setup_context *setup,
+ const float *color,
+ double depth,
+ unsigned stencil,
+ unsigned flags )
{
struct lp_scene *scene = lp_setup_get_current_scene(setup);
uint32_t zsmask = 0;
* a common usage.
*/
if (flags & PIPE_CLEAR_COLOR) {
- lp_scene_bin_everywhere( scene,
- lp_rast_clear_color,
- setup->clear.color );
+ if (!lp_scene_bin_everywhere( scene,
+ lp_rast_clear_color,
+ setup->clear.color ))
+ return FALSE;
}
if (flags & PIPE_CLEAR_DEPTHSTENCIL) {
- lp_scene_bin_everywhere( scene,
- lp_rast_clear_zstencil,
- lp_rast_arg_clearzs(zsmask, zsvalue) );
+ if (!lp_scene_bin_everywhere( scene,
+ lp_rast_clear_zstencil,
+ lp_rast_arg_clearzs(zsmask, zsvalue) ))
+ return FALSE;
}
}
else {
sizeof clear_color);
}
}
-}
+ return TRUE;
+}
-/**
- * Emit a fence.
- */
-struct pipe_fence_handle *
-lp_setup_fence( struct lp_setup_context *setup )
+void
+lp_setup_clear( struct lp_setup_context *setup,
+ const float *color,
+ double depth,
+ unsigned stencil,
+ unsigned flags )
{
- if (setup->scene == NULL)
- return NULL;
- else if (setup->num_threads == 0)
- return NULL;
- else
- {
- struct lp_scene *scene = lp_setup_get_current_scene(setup);
- const unsigned rank = setup->num_threads;
+ if (!lp_setup_try_clear( setup, color, depth, stencil, flags )) {
+ lp_setup_flush(setup, 0, NULL, __FUNCTION__);
- set_scene_state( setup, SETUP_ACTIVE );
-
- assert(scene->fence == NULL);
+ if (!lp_setup_try_clear( setup, color, depth, stencil, flags ))
+ assert(0);
+ }
+}
- /* The caller gets a reference, we keep a copy too, so need to
- * bump the refcount:
- */
- lp_fence_reference(&scene->fence, lp_fence_create(rank));
- LP_DBG(DEBUG_SETUP, "%s rank %u\n", __FUNCTION__, rank);
- return (struct pipe_fence_handle *) scene->fence;
- }
-}
void
/**
* Called by vbuf code when we're about to draw something.
*/
-void
-lp_setup_update_state( struct lp_setup_context *setup )
+static boolean
+try_update_scene_state( struct lp_setup_context *setup )
{
struct lp_scene *scene;
LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
- setup_check_scene_size_and_flush(setup);
-
scene = lp_setup_get_current_scene(setup);
assert(setup->fs.current.variant);
- /* Some of the 'draw' pipeline stages may have changed some driver state.
- * Make sure we've processed those state changes before anything else.
- *
- * XXX this is the only place where llvmpipe_context is used in the
- * setup code. This may get refactored/changed...
- */
- {
- struct llvmpipe_context *lp = llvmpipe_context(scene->pipe);
-
- /* Will probably need to move this somewhere else, just need
- * to know about vertex shader point size attribute.
- */
- setup->psize = lp->psize_slot;
-
- if (lp->dirty) {
- llvmpipe_update_derived(lp);
- }
- assert(lp->dirty == 0);
- }
-
if(setup->dirty & LP_SETUP_NEW_BLEND_COLOR) {
uint8_t *stored;
unsigned i, j;
stored = lp_scene_alloc_aligned(scene, 4 * 16, 16);
-
- if (stored) {
- /* smear each blend color component across 16 ubyte elements */
- for (i = 0; i < 4; ++i) {
- uint8_t c = float_to_ubyte(setup->blend_color.current.color[i]);
- for (j = 0; j < 16; ++j)
- stored[i*16 + j] = c;
- }
-
- setup->blend_color.stored = stored;
-
- setup->fs.current.jit_context.blend_color = setup->blend_color.stored;
+ if (!stored)
+ return FALSE;
+
+ /* smear each blend color component across 16 ubyte elements */
+ for (i = 0; i < 4; ++i) {
+ uint8_t c = float_to_ubyte(setup->blend_color.current.color[i]);
+ for (j = 0; j < 16; ++j)
+ stored[i*16 + j] = c;
}
+ setup->blend_color.stored = stored;
+ setup->fs.current.jit_context.blend_color = setup->blend_color.stored;
setup->dirty |= LP_SETUP_NEW_FS;
}
void *stored;
stored = lp_scene_alloc(scene, current_size);
- if(stored) {
- memcpy(stored,
- current_data,
- current_size);
- setup->constants.stored_size = current_size;
- setup->constants.stored_data = stored;
- }
+ if (!stored)
+ return FALSE;
+
+ memcpy(stored,
+ current_data,
+ current_size);
+ setup->constants.stored_size = current_size;
+ setup->constants.stored_data = stored;
}
}
else {
}
- if(setup->dirty & LP_SETUP_NEW_FS) {
- if(!setup->fs.stored ||
- memcmp(setup->fs.stored,
- &setup->fs.current,
- sizeof setup->fs.current) != 0) {
+ if (setup->dirty & LP_SETUP_NEW_FS) {
+ if (!setup->fs.stored ||
+ memcmp(setup->fs.stored,
+ &setup->fs.current,
+ sizeof setup->fs.current) != 0)
+ {
+ struct lp_rast_state *stored;
+ uint i;
+
/* The fs state that's been stored in the scene is different from
* the new, current state. So allocate a new lp_rast_state object
* and append it to the bin's setup data buffer.
*/
- uint i;
- struct lp_rast_state *stored =
- (struct lp_rast_state *) lp_scene_alloc(scene, sizeof *stored);
- if(stored) {
- memcpy(stored,
- &setup->fs.current,
- sizeof setup->fs.current);
- setup->fs.stored = stored;
- }
+ stored = (struct lp_rast_state *) lp_scene_alloc(scene, sizeof *stored);
+ if (!stored)
+ return FALSE;
+ memcpy(stored,
+ &setup->fs.current,
+ sizeof setup->fs.current);
+ setup->fs.stored = stored;
+
/* The scene now references the textures in the rasterization
* state record. Note that now.
*/
for (i = 0; i < Elements(setup->fs.current_tex); i++) {
- if (setup->fs.current_tex[i])
- lp_scene_add_resource_reference(scene, setup->fs.current_tex[i]);
+ if (setup->fs.current_tex[i]) {
+ if (!lp_scene_add_resource_reference(scene,
+ setup->fs.current_tex[i]))
+ return FALSE;
+ }
}
}
}
setup->dirty = 0;
assert(setup->fs.stored);
+ return TRUE;
+}
+
+void
+lp_setup_update_state( struct lp_setup_context *setup )
+{
+ /* Some of the 'draw' pipeline stages may have changed some driver state.
+ * Make sure we've processed those state changes before anything else.
+ *
+ * XXX this is the only place where llvmpipe_context is used in the
+ * setup code. This may get refactored/changed...
+ */
+ {
+ struct llvmpipe_context *lp = llvmpipe_context(setup->pipe);
+ if (lp->dirty) {
+ llvmpipe_update_derived(lp);
+ }
+
+ /* Will probably need to move this somewhere else, just need
+ * to know about vertex shader point size attribute.
+ */
+ setup->psize = lp->psize_slot;
+
+ assert(lp->dirty == 0);
+ }
+
+ /* XXX: only call into update_scene_state() if we already have a
+ * scene:
+ */
+ if (!try_update_scene_state(setup)) {
+ set_scene_state( setup, SETUP_FLUSHED );
+ if (!try_update_scene_state(setup))
+ assert(0);
+ }
}
return NULL;
lp_setup_init_vbuf(setup);
+
+ /* Used only in update_state():
+ */
+ setup->pipe = pipe;
setup->empty_scenes = lp_scene_queue_create();
if (!setup->empty_scenes)
assert(setup->active_query == NULL);
if (setup->scene) {
- lp_scene_bin_everywhere(setup->scene,
- lp_rast_begin_query,
- lp_rast_arg_query(pq));
+ if (!lp_scene_bin_everywhere(setup->scene,
+ lp_rast_begin_query,
+ lp_rast_arg_query(pq))) {
+ lp_setup_flush_and_restart(setup);
+
+ if (!lp_scene_bin_everywhere(setup->scene,
+ lp_rast_begin_query,
+ lp_rast_arg_query(pq))) {
+ assert(0);
+ return;
+ }
+ }
}
setup->active_query = pq;
*/
lp_fence_reference(&pq->fence, setup->scene->fence);
- lp_scene_bin_everywhere(setup->scene, lp_rast_end_query, dummy);
+ if (!lp_scene_bin_everywhere(setup->scene, lp_rast_end_query, dummy)) {
+ lp_setup_flush(setup, 0, NULL, __FUNCTION__);
+ }
}
else {
lp_fence_reference(&pq->fence, setup->last_fence);
}
+void
+lp_setup_flush_and_restart(struct lp_setup_context *setup)
+{
+ if (0) debug_printf("%s\n", __FUNCTION__);
+
+ assert(setup->state == SETUP_ACTIVE);
+ set_scene_state(setup, SETUP_FLUSHED);
+ set_scene_state(setup, SETUP_EMPTY);
+ set_scene_state(setup, SETUP_ACTIVE);
+ lp_setup_update_state(setup);
+}
unsigned clear_stencil,
unsigned flags);
-struct pipe_fence_handle *
-lp_setup_fence( struct lp_setup_context *setup );
void
{
struct vbuf_render base;
+ struct pipe_context *pipe;
struct vertex_info *vertex_info;
uint prim;
uint vertex_size;
unsigned nr_planes,
unsigned *tri_size);
-void
+boolean
lp_setup_bin_triangle( struct lp_setup_context *setup,
struct lp_rast_triangle *tri,
const struct u_rect *bbox,
int nr_planes );
+void lp_setup_flush_and_restart(struct lp_setup_context *setup);
+
#endif
-static void
-lp_setup_line( struct lp_setup_context *setup,
+static boolean
+try_setup_line( struct lp_setup_context *setup,
const float (*v1)[4],
const float (*v2)[4])
{
bbox.y1 < bbox.y0) {
if (0) debug_printf("empty bounding box\n");
LP_COUNT(nr_culled_tris);
- return;
+ return TRUE;
}
if (!u_rect_test_intersection(&setup->draw_region, &bbox)) {
if (0) debug_printf("offscreen\n");
LP_COUNT(nr_culled_tris);
- return;
+ return TRUE;
}
u_rect_find_intersection(&setup->draw_region, &bbox);
nr_planes,
&tri_bytes);
if (!line)
- return;
+ return FALSE;
#ifdef DEBUG
line->v[0][0] = v1[0][0];
line->plane[7].eo = 0;
}
- lp_setup_bin_triangle(setup, line, &bbox, nr_planes);
+ return lp_setup_bin_triangle(setup, line, &bbox, nr_planes);
}
-
+
+
+static void lp_setup_line( struct lp_setup_context *setup,
+ const float (*v0)[4],
+ const float (*v1)[4] )
+{
+ if (!try_setup_line( setup, v0, v1 ))
+ {
+ lp_setup_flush_and_restart(setup);
+
+ if (!try_setup_line( setup, v0, v1 ))
+ assert(0);
+ }
+}
+
void lp_setup_choose_line( struct lp_setup_context *setup )
{
}
-static void lp_setup_point( struct lp_setup_context *setup,
- const float (*v0)[4] )
+static boolean
+try_setup_point( struct lp_setup_context *setup,
+ const float (*v0)[4] )
{
/* x/y positions in fixed point */
const int sizeAttr = setup->psize;
if (!u_rect_test_intersection(&setup->draw_region, &bbox)) {
if (0) debug_printf("offscreen\n");
LP_COUNT(nr_culled_tris);
- return;
+ return TRUE;
}
u_rect_find_intersection(&setup->draw_region, &bbox);
nr_planes,
&bytes);
if (!point)
- return;
+ return FALSE;
#ifdef DEBUG
point->v[0][0] = v0[0][0];
point->plane[3].eo = 0;
}
- lp_setup_bin_triangle(setup, point, &bbox, nr_planes);
+ return lp_setup_bin_triangle(setup, point, &bbox, nr_planes);
+}
+
+
+static void lp_setup_point( struct lp_setup_context *setup,
+ const float (*v0)[4] )
+{
+ if (!try_setup_point( setup, v0 ))
+ {
+ lp_setup_flush_and_restart(setup);
+
+ if (!try_setup_point( setup, v0 ))
+ assert(0);
+ }
}
*
* \param tx, ty the tile position in tiles, not pixels
*/
-static void
+static boolean
lp_setup_whole_tile(struct lp_setup_context *setup,
const struct lp_rast_shader_inputs *inputs,
int tx, int ty)
}
LP_COUNT(nr_shade_opaque_64);
- lp_scene_bin_command( scene, tx, ty,
- lp_rast_shade_tile_opaque,
- lp_rast_arg_inputs(inputs) );
+ return lp_scene_bin_command( scene, tx, ty,
+ lp_rast_shade_tile_opaque,
+ lp_rast_arg_inputs(inputs) );
} else {
LP_COUNT(nr_shade_64);
- lp_scene_bin_command( scene, tx, ty,
- lp_rast_shade_tile,
- lp_rast_arg_inputs(inputs) );
+ return lp_scene_bin_command( scene, tx, ty,
+ lp_rast_shade_tile,
+ lp_rast_arg_inputs(inputs) );
}
}
* framebuffer tiles are touched. Put the triangle in the scene's
* bins for the tiles which we overlap.
*/
-static void
+static boolean
do_triangle_ccw(struct lp_setup_context *setup,
const float (*v0)[4],
const float (*v1)[4],
bbox.y1 < bbox.y0) {
if (0) debug_printf("empty bounding box\n");
LP_COUNT(nr_culled_tris);
- return;
+ return FALSE;
}
if (!u_rect_test_intersection(&setup->draw_region, &bbox)) {
if (0) debug_printf("offscreen\n");
LP_COUNT(nr_culled_tris);
- return;
+ return FALSE;
}
u_rect_find_intersection(&setup->draw_region, &bbox);
nr_planes,
&tri_bytes);
if (!tri)
- return;
+ return FALSE;
#ifdef DEBUG
tri->v[0][0] = v0[0][0];
if (area <= 0) {
lp_scene_putback_data( scene, tri_bytes );
LP_COUNT(nr_culled_tris);
- return;
+ return TRUE;
}
tri->inputs.facing = frontfacing ? 1.0F : -1.0F;
tri->inputs.opaque = variant->opaque;
+ tri->inputs.disable = FALSE;
tri->inputs.state = setup->fs.stored;
tri->plane[6].eo = 0;
}
- lp_setup_bin_triangle( setup, tri, &bbox, nr_planes );
+ return lp_setup_bin_triangle( setup, tri, &bbox, nr_planes );
}
-void
+boolean
lp_setup_bin_triangle( struct lp_setup_context *setup,
struct lp_rast_triangle *tri,
const struct u_rect *bbox,
*/
int mask = (ix0 & 3) | ((iy0 & 3) << 4);
- lp_scene_bin_command( scene, ix0/4, iy0/4,
- lp_rast_triangle_3_16,
- lp_rast_arg_triangle(tri, mask) );
- return;
+ return lp_scene_bin_command( scene, ix0/4, iy0/4,
+ lp_rast_triangle_3_16,
+ lp_rast_arg_triangle(tri, mask) );
}
}
{
/* Triangle is contained in a single tile:
*/
- lp_scene_bin_command( scene, ix0, iy0,
- lp_rast_tri_tab[nr_planes],
- lp_rast_arg_triangle(tri, (1<<nr_planes)-1) );
+ return lp_scene_bin_command( scene, ix0, iy0,
+ lp_rast_tri_tab[nr_planes],
+ lp_rast_arg_triangle(tri, (1<<nr_planes)-1) );
}
else
{
*/
int count = util_bitcount(partial);
in = TRUE;
- lp_scene_bin_command( scene, x, y,
- lp_rast_tri_tab[count],
- lp_rast_arg_triangle(tri, partial) );
+ if (!lp_scene_bin_command( scene, x, y,
+ lp_rast_tri_tab[count],
+ lp_rast_arg_triangle(tri, partial) ))
+ goto fail;
LP_COUNT(nr_partially_covered_64);
}
/* triangle covers the whole tile- shade whole tile */
LP_COUNT(nr_fully_covered_64);
in = TRUE;
- lp_setup_whole_tile(setup, &tri->inputs, x, y);
+ if (!lp_setup_whole_tile(setup, &tri->inputs, x, y))
+ goto fail;
}
/* Iterate cx values across the region:
c[i] += ystep[i];
}
}
+
+ return TRUE;
+
+fail:
+ /* Need to disable any partially binned triangle. This is easier
+ * than trying to locate all the triangle, shade-tile, etc,
+ * commands which may have been binned.
+ */
+ tri->inputs.disable = TRUE;
+ return FALSE;
}
const float (*v1)[4],
const float (*v2)[4] )
{
- do_triangle_ccw( setup, v1, v0, v2, !setup->ccw_is_frontface );
+ if (!do_triangle_ccw( setup, v1, v0, v2, !setup->ccw_is_frontface ))
+ {
+ lp_setup_flush_and_restart(setup);
+
+ if (!do_triangle_ccw( setup, v1, v0, v2, !setup->ccw_is_frontface ))
+ assert(0);
+ }
}
const float (*v1)[4],
const float (*v2)[4] )
{
- do_triangle_ccw( setup, v0, v1, v2, setup->ccw_is_frontface );
+ if (!do_triangle_ccw( setup, v0, v1, v2, setup->ccw_is_frontface ))
+ {
+ lp_setup_flush_and_restart(setup);
+ if (!do_triangle_ccw( setup, v0, v1, v2, setup->ccw_is_frontface ))
+ assert(0);
+ }
}