static void
cmd_state_fragment_ops(const struct cell_command_fragment_ops *fops)
{
- static int warned = 0;
-
D_PRINTF(CELL_DEBUG_CMD, "CMD_STATE_FRAGMENT_OPS\n");
- /* Copy SPU code from batch buffer to spu buffer */
- memcpy(spu.fragment_ops_code_front, fops->code_front, SPU_MAX_FRAGMENT_OPS_INSTS * 4);
- memcpy(spu.fragment_ops_code_back, fops->code_back, SPU_MAX_FRAGMENT_OPS_INSTS * 4);
- /* Copy state info (for fallback case only) */
+
+ /* Copy state info (for fallback case only - this will eventually
+ * go away when the fallback case goes away)
+ */
memcpy(&spu.depth_stencil_alpha, &fops->dsa, sizeof(fops->dsa));
memcpy(&spu.blend, &fops->blend, sizeof(fops->blend));
memcpy(&spu.blend_color, &fops->blend_color, sizeof(fops->blend_color));
- /* Parity twist! For now, always use the fallback code by default,
- * only switching to codegen when specifically requested. This
- * allows us to develop freely without risking taking down the
- * branch.
- *
- * Later, the parity of this check will be reversed, so that
- * codegen is *always* used, unless we specifically indicate that
- * we don't want it.
- *
- * Eventually, the option will be removed completely, because in
- * final code we'll always use codegen and won't even provide the
- * raw state records that the fallback code requires.
+ /* Make sure the SPU knows which buffers it's expected to read when
+ * it's told to pull tiles.
*/
- if ((spu.init.debug_flags & CELL_DEBUG_FRAGMENT_OP_FALLBACK) == 0) {
- spu.fragment_ops[CELL_FACING_FRONT] = (spu_fragment_ops_func) spu.fragment_ops_code_front;
- spu.fragment_ops[CELL_FACING_BACK] = (spu_fragment_ops_func) spu.fragment_ops_code_back;
- }
- else {
- /* otherwise, the default fallback code remains in place */
+ spu.read_depth_stencil = (spu.depth_stencil_alpha.depth.enabled || spu.depth_stencil_alpha.stencil[0].enabled);
+
+ /* If we're forcing the fallback code to be used (for debug purposes),
+ * install that. Otherwise install the incoming SPU code.
+ */
+ if ((spu.init.debug_flags & CELL_DEBUG_FRAGMENT_OP_FALLBACK) != 0) {
+ static unsigned int warned = 0;
if (!warned) {
fprintf(stderr, "Cell Warning: using fallback per-fragment code\n");
warned = 1;
}
+ /* The following two lines aren't really necessary if you
+ * know the debug flags won't change during a run, and if you
+ * know that the function pointers are initialized correctly.
+ * We set them here to allow a person to change the debug
+ * flags during a run (from inside a debugger).
+ */
+ spu.fragment_ops[CELL_FACING_FRONT] = spu_fallback_fragment_ops;
+ spu.fragment_ops[CELL_FACING_BACK] = spu_fallback_fragment_ops;
+ return;
}
- spu.read_depth_stencil = (spu.depth_stencil_alpha.depth.enabled || spu.depth_stencil_alpha.stencil[0].enabled);
-}
+ /* Make sure the SPU code buffer is large enough to hold the incoming code.
+ * Note that we *don't* use align_malloc() and align_free(), because
+ * those utility functions are *not* available in SPU code.
+ * */
+ if (spu.fragment_ops_code_size < fops->total_code_size) {
+ if (spu.fragment_ops_code != NULL) {
+ free(spu.fragment_ops_code);
+ }
+ spu.fragment_ops_code_size = fops->total_code_size;
+ spu.fragment_ops_code = malloc(fops->total_code_size);
+ if (spu.fragment_ops_code == NULL) {
+ /* Whoops. */
+ fprintf(stderr, "CELL Warning: failed to allocate fragment ops code (%d bytes) - using fallback\n", fops->total_code_size);
+ spu.fragment_ops_code = NULL;
+ spu.fragment_ops_code_size = 0;
+ spu.fragment_ops[CELL_FACING_FRONT] = spu_fallback_fragment_ops;
+ spu.fragment_ops[CELL_FACING_BACK] = spu_fallback_fragment_ops;
+ return;
+ }
+ }
+ /* Copy the SPU code from the command buffer to the spu buffer */
+ memcpy(spu.fragment_ops_code, fops->code, fops->total_code_size);
+
+ /* Set the pointers for the front-facing and back-facing fragments
+ * to the specified offsets within the code. Note that if the
+ * front-facing and back-facing code are the same, they'll have
+ * the same offset.
+ */
+ spu.fragment_ops[CELL_FACING_FRONT] = (spu_fragment_ops_func) &spu.fragment_ops_code[fops->front_code_index];
+ spu.fragment_ops[CELL_FACING_BACK] = (spu_fragment_ops_func) &spu.fragment_ops_code[fops->back_code_index];
+}
static void
cmd_state_fragment_program(const struct cell_command_fragment_program *fp)
static uint
-cmd_state_fs_constants(const uint64_t *buffer, uint pos)
+cmd_state_fs_constants(const qword *buffer, uint pos)
{
- const uint num_const = buffer[pos + 1];
- const float *constants = (const float *) &buffer[pos + 2];
+ const uint num_const = spu_extract((vector unsigned int)buffer[pos+1], 0);
+ const float *constants = (const float *) &buffer[pos+2];
uint i;
D_PRINTF(CELL_DEBUG_CMD, "CMD_STATE_FS_CONSTANTS (%u)\n", num_const);
spu.constants[i] = spu_splats(constants[i]);
}
- /* return new buffer pos (in 8-byte words) */
- return pos + 2 + num_const / 2;
+ /* return new buffer pos (in 16-byte words) */
+ return pos + 2 + (ROUNDUP16(num_const * sizeof(float)) / 16);
}
{
const uint buf = (opcode >> 8) & 0xff;
uint size = (opcode >> 16);
- uint64_t buffer[CELL_BUFFER_SIZE / 8] ALIGN16_ATTRIB;
- const unsigned usize = size / sizeof(buffer[0]);
+ qword buffer[CELL_BUFFER_SIZE / 16] ALIGN16_ATTRIB;
+ const unsigned usize = ROUNDUP16(size) / sizeof(buffer[0]);
uint pos;
D_PRINTF(CELL_DEBUG_CMD, "BATCH buffer %u, len %u, from %p\n",
* Loop over commands in the batch buffer
*/
for (pos = 0; pos < usize; /* no incr */) {
- switch (buffer[pos]) {
+ switch (si_to_uint(buffer[pos])) {
/*
* rendering commands
*/
struct cell_command_clear_surface *clr
= (struct cell_command_clear_surface *) &buffer[pos];
cmd_clear_surface(clr);
- pos += sizeof(*clr) / 8;
+ pos += sizeof(*clr) / 16;
}
break;
case CELL_CMD_RENDER:
= (struct cell_command_render *) &buffer[pos];
uint pos_incr;
cmd_render(render, &pos_incr);
- pos += pos_incr;
+ pos += ((pos_incr+1)&~1) / 2; // should 'fix' cmd_render return
}
break;
/*
struct cell_command_framebuffer *fb
= (struct cell_command_framebuffer *) &buffer[pos];
cmd_state_framebuffer(fb);
- pos += sizeof(*fb) / 8;
+ pos += sizeof(*fb) / 16;
}
break;
case CELL_CMD_STATE_FRAGMENT_OPS:
struct cell_command_fragment_ops *fops
= (struct cell_command_fragment_ops *) &buffer[pos];
cmd_state_fragment_ops(fops);
- pos += sizeof(*fops) / 8;
+ /* This is a variant-sized command */
+ pos += ROUNDUP16(sizeof(*fops) + fops->total_code_size) / 16;
}
break;
case CELL_CMD_STATE_FRAGMENT_PROGRAM:
struct cell_command_fragment_program *fp
= (struct cell_command_fragment_program *) &buffer[pos];
cmd_state_fragment_program(fp);
- pos += sizeof(*fp) / 8;
+ pos += sizeof(*fp) / 16;
}
break;
case CELL_CMD_STATE_FS_CONSTANTS:
struct cell_command_rasterizer *rast =
(struct cell_command_rasterizer *) &buffer[pos];
spu.rasterizer = rast->rasterizer;
- pos += sizeof(*rast) / 8;
+ pos += sizeof(*rast) / 16;
}
break;
case CELL_CMD_STATE_SAMPLER:
struct cell_command_sampler *sampler
= (struct cell_command_sampler *) &buffer[pos];
cmd_state_sampler(sampler);
- pos += sizeof(*sampler) / 8;
+ pos += sizeof(*sampler) / 16;
}
break;
case CELL_CMD_STATE_TEXTURE:
struct cell_command_texture *texture
= (struct cell_command_texture *) &buffer[pos];
cmd_state_texture(texture);
- pos += sizeof(*texture) / 8;
+ pos += sizeof(*texture) / 16;
}
break;
case CELL_CMD_STATE_VERTEX_INFO:
cmd_state_vertex_info((struct vertex_info *) &buffer[pos+1]);
- pos += (1 + ROUNDUP8(sizeof(struct vertex_info)) / 8);
+ pos += 1 + ROUNDUP16(sizeof(struct vertex_info)) / 16;
break;
case CELL_CMD_STATE_VIEWPORT:
(void) memcpy(& draw.viewport, &buffer[pos+1],
sizeof(struct pipe_viewport_state));
- pos += (1 + ROUNDUP8(sizeof(struct pipe_viewport_state)) / 8);
+ pos += 1 + ROUNDUP16(sizeof(struct pipe_viewport_state)) / 16;
break;
case CELL_CMD_STATE_UNIFORMS:
- draw.constants = (const float (*)[4]) (uintptr_t) buffer[pos + 1];
+ draw.constants = (const float (*)[4]) (uintptr_t)spu_extract((vector unsigned int)buffer[pos+1],0);
pos += 2;
break;
case CELL_CMD_STATE_VS_ARRAY_INFO:
cmd_state_vs_array_info((struct cell_array_info *) &buffer[pos+1]);
- pos += (1 + ROUNDUP8(sizeof(struct cell_array_info)) / 8);
+ pos += 1 + ROUNDUP16(sizeof(struct cell_array_info)) / 16;
break;
case CELL_CMD_STATE_BIND_VS:
#if 0
spu_bind_vertex_shader(&draw,
(struct cell_shader_info *) &buffer[pos+1]);
#endif
- pos += (1 + ROUNDUP8(sizeof(struct cell_shader_info)) / 8);
+ pos += 1 + ROUNDUP16(sizeof(struct cell_shader_info)) / 16;
break;
case CELL_CMD_STATE_ATTRIB_FETCH:
cmd_state_attrib_fetch((struct cell_attribute_fetch_code *)
&buffer[pos+1]);
- pos += (1 + ROUNDUP8(sizeof(struct cell_attribute_fetch_code)) / 8);
+ pos += 1 + ROUNDUP16(sizeof(struct cell_attribute_fetch_code)) / 16;
break;
/*
* misc commands
struct cell_command_fence *fence_cmd =
(struct cell_command_fence *) &buffer[pos];
cmd_fence(fence_cmd);
- pos += sizeof(*fence_cmd) / 8;
+ pos += sizeof(*fence_cmd) / 16;
}
break;
case CELL_CMD_RELEASE_VERTS:
struct cell_command_release_verts *release
= (struct cell_command_release_verts *) &buffer[pos];
cmd_release_verts(release);
- pos += sizeof(*release) / 8;
+ pos += sizeof(*release) / 16;
}
break;
case CELL_CMD_FLUSH_BUFFER_RANGE: {
&buffer[pos+1];
spu_dcache_mark_dirty((unsigned) br->base, br->size);
- pos += (1 + ROUNDUP8(sizeof(struct cell_buffer_range)) / 8);
+ pos += 1 + ROUNDUP16(sizeof(struct cell_buffer_range)) / 16;
break;
}
default:
- printf("SPU %u: bad opcode: 0x%llx\n", spu.init.id, buffer[pos]);
+ printf("SPU %u: bad opcode: 0x%x\n", spu.init.id, si_to_uint(buffer[pos]));
ASSERT(0);
break;
}
if (spu.init.debug_flags & CELL_DEBUG_CACHE)
spu_dcache_report();
}
+
+/* Initialize this module; we manage the fragment ops buffer here. */
+void
+spu_command_init(void)
+{
+ /* Install default/fallback fragment processing function.
+ * This will normally be overriden by a code-gen'd function
+ * unless CELL_FORCE_FRAGMENT_OPS_FALLBACK is set.
+ */
+ spu.fragment_ops[CELL_FACING_FRONT] = spu_fallback_fragment_ops;
+ spu.fragment_ops[CELL_FACING_BACK] = spu_fallback_fragment_ops;
+
+ /* Set up the basic empty buffer for code-gen'ed fragment ops */
+ spu.fragment_ops_code = NULL;
+ spu.fragment_ops_code_size = 0;
+}
+
+void
+spu_command_close(void)
+{
+ /* Deallocate the code-gen buffer for fragment ops, and reset the
+ * fragment ops functions to their initial setting (just to leave
+ * things in a good state).
+ */
+ if (spu.fragment_ops_code != NULL) {
+ free(spu.fragment_ops_code);
+ }
+ spu_command_init();
+}