From a1f4a5e802ad62c88fca6834b9de1c83672230a6 Mon Sep 17 00:00:00 2001 From: Brian Date: Sat, 19 Jan 2008 12:04:06 -0700 Subject: [PATCH] Cell: improve "finished copying batch buffer" signalling. When the SPU is done copying a batch buffer to local store, use an mfc_put() to write a "done" message back to the buffer status array in main memory. We were previously using a mailbox message for synchronization. --- src/mesa/pipe/cell/common.h | 7 ++-- src/mesa/pipe/cell/ppu/cell_batch.c | 47 +++++++++++++++++++-------- src/mesa/pipe/cell/ppu/cell_context.c | 23 +++++++++++-- src/mesa/pipe/cell/ppu/cell_context.h | 7 ++++ src/mesa/pipe/cell/ppu/cell_spu.c | 1 + src/mesa/pipe/cell/spu/spu_main.c | 38 ++++++++++++++++++++-- src/mesa/pipe/cell/spu/spu_main.h | 2 ++ 7 files changed, 103 insertions(+), 22 deletions(-) diff --git a/src/mesa/pipe/cell/common.h b/src/mesa/pipe/cell/common.h index 29d1cbeddad..f05070d25a1 100644 --- a/src/mesa/pipe/cell/common.h +++ b/src/mesa/pipe/cell/common.h @@ -62,10 +62,12 @@ #define CELL_CMD_STATE_DEPTH_STENCIL 7 -#define CELL_NUM_BATCH_BUFFERS 2 +#define CELL_NUM_BATCH_BUFFERS 3 #define CELL_BATCH_BUFFER_SIZE 1024 /**< 16KB would be the max */ -#define CELL_BATCH_FINISHED 0x1234 /**< mbox message */ +#define CELL_BUFFER_STATUS_FREE 10 +#define CELL_BUFFER_STATUS_USED 20 + /** @@ -122,6 +124,7 @@ struct cell_init_info unsigned num_spus; struct cell_command *cmd; ubyte *batch_buffers[CELL_NUM_BATCH_BUFFERS]; + uint *buffer_status; /**< points at cell_context->buffer_status */ } ALIGN16_ATTRIB; diff --git a/src/mesa/pipe/cell/ppu/cell_batch.c b/src/mesa/pipe/cell/ppu/cell_batch.c index 45f62ac3add..ab4553f16ca 100644 --- a/src/mesa/pipe/cell/ppu/cell_batch.c +++ b/src/mesa/pipe/cell/ppu/cell_batch.c @@ -34,9 +34,9 @@ void cell_batch_flush(struct cell_context *cell) { - const uint batch = cell->cur_batch; + uint batch = cell->cur_batch; const uint size = cell->batch_buffer_size[batch]; - uint i, cmd_word; + uint spu, cmd_word; if (size == 0) return; @@ -48,25 +48,44 @@ cell_batch_flush(struct cell_context *cell) batch, &cell->batch_buffer[batch][0], size); */ + /* + * Build "BATCH" command and sent to all SPUs. + */ cmd_word = CELL_CMD_BATCH | (batch << 8) | (size << 16); - for (i = 0; i < cell->num_spus; i++) { - send_mbox_message(cell_global.spe_contexts[i], cmd_word); + for (spu = 0; spu < cell->num_spus; spu++) { + assert(cell->buffer_status[spu][batch][0] == CELL_BUFFER_STATUS_USED); + send_mbox_message(cell_global.spe_contexts[spu], cmd_word); } - /* XXX wait for the DMX xfer to finish. - * Using mailboxes here is temporary. - * Ideally, we want to use a PPE-side DMA status check function... + /* When the SPUs are done copying the buffer into their locals stores + * they'll write a BUFFER_STATUS_FREE message into the buffer_status[] + * array indicating that the PPU can re-use the buffer. */ - for (i = 0; i < cell->num_spus; i++) { - uint k = wait_mbox_message(cell_global.spe_contexts[i]); - assert(k == CELL_BATCH_FINISHED); - } - /* next buffer */ - cell->cur_batch = (batch + 1) % CELL_NUM_BATCH_BUFFERS; - cell->batch_buffer_size[cell->cur_batch] = 0; /* empty */ + /* Find a buffer that's marked as free by all SPUs */ + while (1) { + uint num_free = 0; + + batch = (batch + 1) % CELL_NUM_BATCH_BUFFERS; + + for (spu = 0; spu < cell->num_spus; spu++) { + if (cell->buffer_status[spu][batch][0] == CELL_BUFFER_STATUS_FREE) + num_free++; + } + + if (num_free == cell->num_spus) { + /* found a free buffer, now mark status as used */ + for (spu = 0; spu < cell->num_spus; spu++) { + cell->buffer_status[spu][batch][0] = CELL_BUFFER_STATUS_USED; + } + break; + } + } + + cell->batch_buffer_size[batch] = 0; /* empty */ + cell->cur_batch = batch; } diff --git a/src/mesa/pipe/cell/ppu/cell_context.c b/src/mesa/pipe/cell/ppu/cell_context.c index 6ba3b0d4138..897c187d654 100644 --- a/src/mesa/pipe/cell/ppu/cell_context.c +++ b/src/mesa/pipe/cell/ppu/cell_context.c @@ -160,7 +160,7 @@ struct pipe_context * cell_create_context(struct pipe_winsys *winsys, struct cell_winsys *cws) { struct cell_context *cell; - uint i; + uint spu, buf; /* some fields need to be 16-byte aligned, so align the whole object */ cell = (struct cell_context*) align_malloc(sizeof(struct cell_context), 16); @@ -248,13 +248,30 @@ cell_create_context(struct pipe_winsys *winsys, struct cell_winsys *cws) cell_start_spus(cell); - for (i = 0; i < CELL_NUM_BATCH_BUFFERS; i++) { - cell->batch_buffer_size[i] = 0; + for (buf = 0; buf < CELL_NUM_BATCH_BUFFERS; buf++) { + cell->batch_buffer_size[buf] = 0; + + /* init batch buffer status values, + * mark 0th buffer as used, rest as free. + */ + for (spu = 0; spu < cell->num_spus; spu++) { + if (buf == 0) + cell->buffer_status[spu][buf][0] = CELL_BUFFER_STATUS_USED; + else + cell->buffer_status[spu][buf][0] = CELL_BUFFER_STATUS_FREE; + } } + #if 0 test_spus(cell); #endif return &cell->pipe; } + + +#if 0 +/** [4] to ensure 16-byte alignment for each status word */ +uint buffer_status[CELL_MAX_SPUS][CELL_NUM_BATCH_BUFFERS][4] ALIGN16_ATTRIB; +#endif diff --git a/src/mesa/pipe/cell/ppu/cell_context.h b/src/mesa/pipe/cell/ppu/cell_context.h index 43e32a8abb6..08e448f14f6 100644 --- a/src/mesa/pipe/cell/ppu/cell_context.h +++ b/src/mesa/pipe/cell/ppu/cell_context.h @@ -38,6 +38,9 @@ #include "pipe/cell/common.h" +#define CELL_MAX_SPUS 6 + + struct cell_vbuf_render; struct cell_vertex_shader_state @@ -103,10 +106,14 @@ struct cell_context ubyte batch_buffer[CELL_NUM_BATCH_BUFFERS][CELL_BATCH_BUFFER_SIZE] ALIGN16_ATTRIB; int cur_batch; /**< which batch buffer is being filled */ + /** [4] to ensure 16-byte alignment for each status word */ + uint buffer_status[CELL_MAX_SPUS][CELL_NUM_BATCH_BUFFERS][4] ALIGN16_ATTRIB; + }; + static INLINE struct cell_context * cell_context(struct pipe_context *pipe) { diff --git a/src/mesa/pipe/cell/ppu/cell_spu.c b/src/mesa/pipe/cell/ppu/cell_spu.c index 77ddd9ccbf4..a21ab9ff3ab 100644 --- a/src/mesa/pipe/cell/ppu/cell_spu.c +++ b/src/mesa/pipe/cell/ppu/cell_spu.c @@ -114,6 +114,7 @@ cell_start_spus(struct cell_context *cell) for (j = 0; j < CELL_NUM_BATCH_BUFFERS; j++) { cell_global.inits[i].batch_buffers[j] = cell->batch_buffer[j]; } + cell_global.inits[i].buffer_status = &cell->buffer_status[0][0][0]; cell_global.spe_contexts[i] = spe_context_create(0, NULL); if (!cell_global.spe_contexts[i]) { diff --git a/src/mesa/pipe/cell/spu/spu_main.c b/src/mesa/pipe/cell/spu/spu_main.c index 2727b037566..bff098f06e9 100644 --- a/src/mesa/pipe/cell/spu/spu_main.c +++ b/src/mesa/pipe/cell/spu/spu_main.c @@ -395,6 +395,38 @@ cmd_finish(void) } +/** + * Tell the PPU that this SPU has finished copying a batch buffer to + * local store and that it may be reused by the PPU. + * This is done by writting a 16-byte batch-buffer-status block back into + * main memory (in cell_contex->buffer_status[]). + */ +static void +release_batch_buffer(uint buffer) +{ + /* Evidently, using less than a 16-byte status doesn't work reliably */ + static const uint status[4] ALIGN16_ATTRIB + = {CELL_BUFFER_STATUS_FREE, 0, 0, 0}; + + const uint index = 4 * (spu.init.id * CELL_NUM_BATCH_BUFFERS + buffer); + uint *dst = spu.init.buffer_status + index; + + ASSERT(buffer < CELL_NUM_BATCH_BUFFERS); + + /* + printf("SPU %u: Set batch status buf=%u, index %u, at %p to FREE\n", + spu.init.id, buffer, index, dst); + */ + + mfc_put((void *) &status, /* src in local memory */ + (unsigned int) dst, /* dst in main memory */ + sizeof(status), /* size */ + TAG_MISC, /* tag is unimportant */ + 0, /* tid */ + 0 /* rid */); +} + + /** * Execute a batch of commands * The opcode param encodes the location of the buffer and its size. @@ -429,9 +461,9 @@ cmd_batch(uint opcode) 0 /* rid */); wait_on_mask(1 << TAG_BATCH_BUFFER); - /* send mbox message to indicate DMA completed */ - /* XXX temporary */ - spu_write_out_mbox(CELL_BATCH_FINISHED); + /* Tell PPU we're done copying the buffer to local store */ + release_batch_buffer(buf); + for (pos = 0; pos < usize; /* no incr */) { switch (buffer[pos]) { diff --git a/src/mesa/pipe/cell/spu/spu_main.h b/src/mesa/pipe/cell/spu/spu_main.h index 75fb5b388b0..f39f375d244 100644 --- a/src/mesa/pipe/cell/spu/spu_main.h +++ b/src/mesa/pipe/cell/spu/spu_main.h @@ -76,6 +76,8 @@ extern struct spu_global spu; #define TAG_WRITE_TILE_Z 15 #define TAG_INDEX_BUFFER 16 #define TAG_BATCH_BUFFER 17 +#define TAG_MISC 18 + /** The standard assert macro doesn't seem to work on SPUs */ #define ASSERT(x) \ -- 2.30.2