cell: use new keymap to save/re-use fragment ops code

This commit is contained in:
Brian Paul 2008-10-07 14:34:08 -06:00
parent f192ad5ebc
commit 44799c3b7e
3 changed files with 103 additions and 0 deletions

View file

@ -62,6 +62,8 @@ cell_destroy_context( struct pipe_context *pipe )
{
struct cell_context *cell = cell_context(pipe);
util_delete_keymap(cell->fragment_ops_cache, NULL);
cell_spu_exit(cell);
align_free(cell);
@ -131,6 +133,10 @@ cell_create_context(struct pipe_screen *screen,
cell->draw = cell_draw_create(cell);
/* Create cache of fragment ops generated code */
cell->fragment_ops_cache =
util_new_keymap(sizeof(struct cell_fragment_ops_key), ~0, NULL);
cell_init_vbuf(cell);
draw_set_rasterize_stage(cell->draw, cell->vbuf);

View file

@ -38,6 +38,7 @@
#include "cell/common.h"
#include "rtasm/rtasm_ppc_spe.h"
#include "tgsi/tgsi_scan.h"
#include "util/u_keymap.h"
struct cell_vbuf_render;
@ -66,6 +67,19 @@ struct cell_fragment_shader_state
};
/**
* Key for mapping per-fragment state to cached SPU machine code.
* keymap(cell_fragment_ops_key) => cell_command_fragment_ops
*/
struct cell_fragment_ops_key
{
struct pipe_blend_state blend;
struct pipe_depth_stencil_alpha_state dsa;
enum pipe_format color_format;
enum pipe_format zs_format;
};
/**
* Per-context state, subclass of pipe_context.
*/
@ -107,6 +121,9 @@ struct cell_context
uint dirty;
/** Cache of code generated for per-fragment ops */
struct keymap *fragment_ops_cache;
/** The primitive drawing context */
struct draw_context *draw;
struct draw_stage *render_stage;

View file

@ -36,6 +36,78 @@
#include "draw/draw_private.h"
/**
* Find/create a cell_command_fragment_ops object corresponding to the
* current blend/stencil/z/colormask/etc. state.
*/
static struct cell_command_fragment_ops *
lookup_fragment_ops(struct cell_context *cell)
{
struct cell_fragment_ops_key key;
struct cell_command_fragment_ops *ops;
/*
* Build key
*/
key.blend = *cell->blend;
key.dsa = *cell->depth_stencil;
if (cell->framebuffer.cbufs[0])
key.color_format = cell->framebuffer.cbufs[0]->format;
else
key.color_format = PIPE_FORMAT_NONE;
if (cell->framebuffer.zsbuf)
key.zs_format = cell->framebuffer.zsbuf->format;
else
key.zs_format = PIPE_FORMAT_NONE;
/*
* Look up key in cache.
*/
ops = (struct cell_command_fragment_ops *)
util_keymap_lookup(cell->fragment_ops_cache, &key);
/*
* If not found, create/save new fragment ops command.
*/
if (!ops) {
struct spe_function spe_code;
if (0)
debug_printf("**** Create New Fragment Ops\n");
/* Prepare the buffer that will hold the generated code. */
spe_init_func(&spe_code, SPU_MAX_FRAGMENT_OPS_INSTS * SPE_INST_SIZE);
/* generate new code */
cell_gen_fragment_function(cell, &spe_code);
/* alloc new fragment ops command */
ops = CALLOC_STRUCT(cell_command_fragment_ops);
/* populate the new cell_command_fragment_ops object */
ops->opcode = CELL_CMD_STATE_FRAGMENT_OPS;
memcpy(ops->code, spe_code.store, spe_code_size(&spe_code));
ops->dsa = *cell->depth_stencil;
ops->blend = *cell->blend;
/* insert cell_command_fragment_ops object into keymap/cache */
util_keymap_insert(cell->fragment_ops_cache, &key, ops, NULL);
/* release rtasm buffer */
spe_release_func(&spe_code);
}
else {
if (0)
debug_printf("**** Re-use Fragment Ops\n");
}
return ops;
}
static void
emit_state_cmd(struct cell_context *cell, uint cmd,
const void *state, uint state_size)
@ -92,6 +164,7 @@ cell_emit_state(struct cell_context *cell)
if (cell->dirty & (CELL_NEW_FRAMEBUFFER |
CELL_NEW_DEPTH_STENCIL |
CELL_NEW_BLEND)) {
#if 0
/* XXX we don't want to always do codegen here. We should have
* a hash/lookup table to cache previous results...
*/
@ -114,6 +187,13 @@ cell_emit_state(struct cell_context *cell)
/* free codegen buffer */
spe_release_func(&spe_code);
#else
struct cell_command_fragment_ops *fops, *fops_cmd;
fops_cmd = cell_batch_alloc(cell, sizeof(*fops_cmd));
fops = lookup_fragment_ops(cell);
memcpy(fops_cmd, fops, sizeof(*fops));
#endif
}
if (cell->dirty & CELL_NEW_SAMPLER) {