1 /**************************************************************************
3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 **************************************************************************/
30 * SPU command processing code
37 #include "pipe/p_defines.h"
39 #include "spu_command.h"
41 #include "spu_render.h"
42 #include "spu_per_fragment_op.h"
43 #include "spu_texture.h"
45 #include "spu_vertex_shader.h"
46 #include "spu_dcache.h"
47 #include "cell/common.h"
50 struct spu_vs_context draw
;
54 * Buffers containing dynamically generated SPU code:
56 PIPE_ALIGN_VAR(16) static unsigned char attribute_fetch_code_buffer
[136 * PIPE_MAX_ATTRIBS
];
61 align(int value
, int alignment
)
63 return (value
+ alignment
- 1) & ~(alignment
- 1);
69 * Tell the PPU that this SPU has finished copying a buffer to
70 * local store and that it may be reused by the PPU.
71 * This is done by writting a 16-byte batch-buffer-status block back into
72 * main memory (in cell_context->buffer_status[]).
75 release_buffer(uint buffer
)
77 /* Evidently, using less than a 16-byte status doesn't work reliably */
78 static const vector
unsigned int status
= {CELL_BUFFER_STATUS_FREE
,
79 CELL_BUFFER_STATUS_FREE
,
80 CELL_BUFFER_STATUS_FREE
,
81 CELL_BUFFER_STATUS_FREE
};
82 const uint index
= 4 * (spu
.init
.id
* CELL_NUM_BUFFERS
+ buffer
);
83 uint
*dst
= spu
.init
.buffer_status
+ index
;
85 ASSERT(buffer
< CELL_NUM_BUFFERS
);
87 mfc_put((void *) &status
, /* src in local memory */
88 (unsigned int) dst
, /* dst in main memory */
89 sizeof(status
), /* size */
90 TAG_MISC
, /* tag is unimportant */
97 * Write CELL_FENCE_SIGNALLED back to the fence status qword in main memory.
98 * There's a qword of status per SPU.
101 cmd_fence(struct cell_command_fence
*fence_cmd
)
103 static const vector
unsigned int status
= {CELL_FENCE_SIGNALLED
,
104 CELL_FENCE_SIGNALLED
,
105 CELL_FENCE_SIGNALLED
,
106 CELL_FENCE_SIGNALLED
};
107 uint
*dst
= (uint
*) fence_cmd
->fence
;
108 dst
+= 4 * spu
.init
.id
; /* main store/memory address, not local store */
110 mfc_put((void *) &status
, /* src in local memory */
111 (unsigned int) dst
, /* dst in main memory */
112 sizeof(status
), /* size */
120 cmd_clear_surface(const struct cell_command_clear_surface
*clear
)
122 D_PRINTF(CELL_DEBUG_CMD
, "CLEAR SURF %u to 0x%08x\n", clear
->surface
, clear
->value
);
124 if (clear
->surface
== 0) {
125 spu
.fb
.color_clear_value
= clear
->value
;
126 if (spu
.init
.debug_flags
& CELL_DEBUG_CHECKER
) {
127 uint x
= (spu
.init
.id
<< 4) | (spu
.init
.id
<< 12) |
128 (spu
.init
.id
<< 20) | (spu
.init
.id
<< 28);
129 spu
.fb
.color_clear_value
^= x
;
133 spu
.fb
.depth_clear_value
= clear
->value
;
139 /* Simply set all tiles' status to CLEAR.
140 * When we actually begin rendering into a tile, we'll initialize it to
141 * the clear value. If any tiles go untouched during the frame,
142 * really_clear_tiles() will set them to the clear value.
144 if (clear
->surface
== 0) {
145 memset(spu
.ctile_status
, TILE_STATUS_CLEAR
, sizeof(spu
.ctile_status
));
148 memset(spu
.ztile_status
, TILE_STATUS_CLEAR
, sizeof(spu
.ztile_status
));
154 * This path clears the whole framebuffer to the clear color right now.
158 printf("SPU: %s num=%d w=%d h=%d\n",
159 __FUNCTION__, num_tiles, spu.fb.width_tiles, spu.fb.height_tiles);
162 /* init a single tile to the clear value */
163 if (clear
->surface
== 0) {
164 clear_c_tile(&spu
.ctile
);
167 clear_z_tile(&spu
.ztile
);
170 /* walk over my tiles, writing the 'clear' tile's data */
172 const uint num_tiles
= spu
.fb
.width_tiles
* spu
.fb
.height_tiles
;
174 for (i
= spu
.init
.id
; i
< num_tiles
; i
+= spu
.init
.num_spus
) {
175 uint tx
= i
% spu
.fb
.width_tiles
;
176 uint ty
= i
/ spu
.fb
.width_tiles
;
177 if (clear
->surface
== 0)
178 put_tile(tx
, ty
, &spu
.ctile
, TAG_SURFACE_CLEAR
, 0);
180 put_tile(tx
, ty
, &spu
.ztile
, TAG_SURFACE_CLEAR
, 1);
184 if (spu
.init
.debug_flags
& CELL_DEBUG_SYNC
) {
185 wait_on_mask(1 << TAG_SURFACE_CLEAR
);
188 #endif /* CLEAR_OPT */
190 D_PRINTF(CELL_DEBUG_CMD
, "CLEAR SURF done\n");
195 cmd_release_verts(const struct cell_command_release_verts
*release
)
197 D_PRINTF(CELL_DEBUG_CMD
, "RELEASE VERTS %u\n", release
->vertex_buf
);
198 ASSERT(release
->vertex_buf
!= ~0U);
199 release_buffer(release
->vertex_buf
);
204 * Process a CELL_CMD_STATE_FRAGMENT_OPS command.
205 * This involves installing new fragment ops SPU code.
206 * If this function is never called, we'll use a regular C fallback function
207 * for fragment processing.
210 cmd_state_fragment_ops(const struct cell_command_fragment_ops
*fops
)
212 D_PRINTF(CELL_DEBUG_CMD
, "CMD_STATE_FRAGMENT_OPS\n");
214 /* Copy state info (for fallback case only - this will eventually
215 * go away when the fallback case goes away)
217 memcpy(&spu
.depth_stencil_alpha
, &fops
->dsa
, sizeof(fops
->dsa
));
218 memcpy(&spu
.blend
, &fops
->blend
, sizeof(fops
->blend
));
219 memcpy(&spu
.blend_color
, &fops
->blend_color
, sizeof(fops
->blend_color
));
221 /* Make sure the SPU knows which buffers it's expected to read when
222 * it's told to pull tiles.
224 spu
.read_depth_stencil
= (spu
.depth_stencil_alpha
.depth
.enabled
|| spu
.depth_stencil_alpha
.stencil
[0].enabled
);
226 /* If we're forcing the fallback code to be used (for debug purposes),
227 * install that. Otherwise install the incoming SPU code.
229 if ((spu
.init
.debug_flags
& CELL_DEBUG_FRAGMENT_OP_FALLBACK
) != 0) {
230 static unsigned int warned
= 0;
232 fprintf(stderr
, "Cell Warning: using fallback per-fragment code\n");
235 /* The following two lines aren't really necessary if you
236 * know the debug flags won't change during a run, and if you
237 * know that the function pointers are initialized correctly.
238 * We set them here to allow a person to change the debug
239 * flags during a run (from inside a debugger).
241 spu
.fragment_ops
[CELL_FACING_FRONT
] = spu_fallback_fragment_ops
;
242 spu
.fragment_ops
[CELL_FACING_BACK
] = spu_fallback_fragment_ops
;
246 /* Make sure the SPU code buffer is large enough to hold the incoming code.
247 * Note that we *don't* use align_malloc() and align_free(), because
248 * those utility functions are *not* available in SPU code.
250 if (spu
.fragment_ops_code_size
< fops
->total_code_size
) {
251 if (spu
.fragment_ops_code
!= NULL
) {
252 free(spu
.fragment_ops_code
);
254 spu
.fragment_ops_code_size
= fops
->total_code_size
;
255 spu
.fragment_ops_code
= malloc(fops
->total_code_size
);
256 if (spu
.fragment_ops_code
== NULL
) {
258 fprintf(stderr
, "CELL Warning: failed to allocate fragment ops code (%d bytes) - using fallback\n", fops
->total_code_size
);
259 spu
.fragment_ops_code
= NULL
;
260 spu
.fragment_ops_code_size
= 0;
261 spu
.fragment_ops
[CELL_FACING_FRONT
] = spu_fallback_fragment_ops
;
262 spu
.fragment_ops
[CELL_FACING_BACK
] = spu_fallback_fragment_ops
;
267 /* Copy the SPU code from the command buffer to the spu buffer */
268 memcpy(spu
.fragment_ops_code
, fops
->code
, fops
->total_code_size
);
270 /* Set the pointers for the front-facing and back-facing fragments
271 * to the specified offsets within the code. Note that if the
272 * front-facing and back-facing code are the same, they'll have
275 spu
.fragment_ops
[CELL_FACING_FRONT
] = (spu_fragment_ops_func
) &spu
.fragment_ops_code
[fops
->front_code_index
];
276 spu
.fragment_ops
[CELL_FACING_BACK
] = (spu_fragment_ops_func
) &spu
.fragment_ops_code
[fops
->back_code_index
];
280 cmd_state_fragment_program(const struct cell_command_fragment_program
*fp
)
282 D_PRINTF(CELL_DEBUG_CMD
, "CMD_STATE_FRAGMENT_PROGRAM\n");
283 /* Copy SPU code from batch buffer to spu buffer */
284 memcpy(spu
.fragment_program_code
, fp
->code
,
285 SPU_MAX_FRAGMENT_PROGRAM_INSTS
* 4);
287 /* Point function pointer at new code */
288 spu
.fragment_program
= (spu_fragment_program_func
)spu
.fragment_program_code
;
294 cmd_state_fs_constants(const qword
*buffer
, uint pos
)
296 const uint num_const
= spu_extract((vector
unsigned int)buffer
[pos
+1], 0);
297 const float *constants
= (const float *) &buffer
[pos
+2];
300 D_PRINTF(CELL_DEBUG_CMD
, "CMD_STATE_FS_CONSTANTS (%u)\n", num_const
);
302 /* Expand each float to float[4] for SOA execution */
303 for (i
= 0; i
< num_const
; i
++) {
304 D_PRINTF(CELL_DEBUG_CMD
, " const[%u] = %f\n", i
, constants
[i
]);
305 spu
.constants
[i
] = spu_splats(constants
[i
]);
308 /* return new buffer pos (in 16-byte words) */
309 return pos
+ 2 + (ROUNDUP16(num_const
* sizeof(float)) / 16);
314 cmd_state_framebuffer(const struct cell_command_framebuffer
*cmd
)
316 D_PRINTF(CELL_DEBUG_CMD
, "FRAMEBUFFER: %d x %d at %p, cformat 0x%x zformat 0x%x\n",
323 ASSERT_ALIGN16(cmd
->color_start
);
324 ASSERT_ALIGN16(cmd
->depth_start
);
326 spu
.fb
.color_start
= cmd
->color_start
;
327 spu
.fb
.depth_start
= cmd
->depth_start
;
328 spu
.fb
.color_format
= cmd
->color_format
;
329 spu
.fb
.depth_format
= cmd
->depth_format
;
330 spu
.fb
.width
= cmd
->width
;
331 spu
.fb
.height
= cmd
->height
;
332 spu
.fb
.width_tiles
= (spu
.fb
.width
+ TILE_SIZE
- 1) / TILE_SIZE
;
333 spu
.fb
.height_tiles
= (spu
.fb
.height
+ TILE_SIZE
- 1) / TILE_SIZE
;
335 switch (spu
.fb
.depth_format
) {
336 case PIPE_FORMAT_Z32_UNORM
:
338 spu
.fb
.zscale
= (float) 0xffffffffu
;
340 case PIPE_FORMAT_S8_USCALED_Z24_UNORM
:
341 case PIPE_FORMAT_Z24_UNORM_S8_USCALED
:
342 case PIPE_FORMAT_X8Z24_UNORM
:
343 case PIPE_FORMAT_Z24X8_UNORM
:
345 spu
.fb
.zscale
= (float) 0x00ffffffu
;
347 case PIPE_FORMAT_Z16_UNORM
:
349 spu
.fb
.zscale
= (float) 0xffffu
;
359 * Tex texture mask_s/t and scale_s/t fields depend on the texture size and
360 * sampler wrap modes.
363 update_tex_masks(struct spu_texture
*texture
,
364 const struct pipe_sampler_state
*sampler
)
368 for (i
= 0; i
< CELL_MAX_TEXTURE_LEVELS
; i
++) {
369 int width
= texture
->level
[i
].width
;
370 int height
= texture
->level
[i
].height
;
372 if (sampler
->wrap_s
== PIPE_TEX_WRAP_REPEAT
)
373 texture
->level
[i
].mask_s
= spu_splats(width
- 1);
375 texture
->level
[i
].mask_s
= spu_splats(~0);
377 if (sampler
->wrap_t
== PIPE_TEX_WRAP_REPEAT
)
378 texture
->level
[i
].mask_t
= spu_splats(height
- 1);
380 texture
->level
[i
].mask_t
= spu_splats(~0);
382 if (sampler
->normalized_coords
) {
383 texture
->level
[i
].scale_s
= spu_splats((float) width
);
384 texture
->level
[i
].scale_t
= spu_splats((float) height
);
387 texture
->level
[i
].scale_s
= spu_splats(1.0f
);
388 texture
->level
[i
].scale_t
= spu_splats(1.0f
);
395 cmd_state_sampler(const struct cell_command_sampler
*sampler
)
397 uint unit
= sampler
->unit
;
399 D_PRINTF(CELL_DEBUG_CMD
, "SAMPLER [%u]\n", unit
);
401 spu
.sampler
[unit
] = sampler
->state
;
403 switch (spu
.sampler
[unit
].min_img_filter
) {
404 case PIPE_TEX_FILTER_LINEAR
:
405 spu
.min_sample_texture_2d
[unit
] = sample_texture_2d_bilinear
;
407 case PIPE_TEX_FILTER_NEAREST
:
408 spu
.min_sample_texture_2d
[unit
] = sample_texture_2d_nearest
;
414 switch (spu
.sampler
[sampler
->unit
].mag_img_filter
) {
415 case PIPE_TEX_FILTER_LINEAR
:
416 spu
.mag_sample_texture_2d
[unit
] = sample_texture_2d_bilinear
;
418 case PIPE_TEX_FILTER_NEAREST
:
419 spu
.mag_sample_texture_2d
[unit
] = sample_texture_2d_nearest
;
425 switch (spu
.sampler
[sampler
->unit
].min_mip_filter
) {
426 case PIPE_TEX_MIPFILTER_NEAREST
:
427 case PIPE_TEX_MIPFILTER_LINEAR
:
428 spu
.sample_texture_2d
[unit
] = sample_texture_2d_lod
;
430 case PIPE_TEX_MIPFILTER_NONE
:
431 spu
.sample_texture_2d
[unit
] = spu
.mag_sample_texture_2d
[unit
];
437 update_tex_masks(&spu
.texture
[unit
], &spu
.sampler
[unit
]);
442 cmd_state_texture(const struct cell_command_texture
*texture
)
444 const uint unit
= texture
->unit
;
447 D_PRINTF(CELL_DEBUG_CMD
, "TEXTURE [%u]\n", texture
->unit
);
449 spu
.texture
[unit
].max_level
= 0;
450 spu
.texture
[unit
].target
= texture
->target
;
452 for (i
= 0; i
< CELL_MAX_TEXTURE_LEVELS
; i
++) {
453 uint width
= texture
->width
[i
];
454 uint height
= texture
->height
[i
];
455 uint depth
= texture
->depth
[i
];
457 D_PRINTF(CELL_DEBUG_CMD
, " LEVEL %u: at %p size[0] %u x %u\n", i
,
458 texture
->start
[i
], texture
->width
[i
], texture
->height
[i
]);
460 spu
.texture
[unit
].level
[i
].start
= texture
->start
[i
];
461 spu
.texture
[unit
].level
[i
].width
= width
;
462 spu
.texture
[unit
].level
[i
].height
= height
;
463 spu
.texture
[unit
].level
[i
].depth
= depth
;
465 spu
.texture
[unit
].level
[i
].tiles_per_row
=
466 (width
+ TILE_SIZE
- 1) / TILE_SIZE
;
468 spu
.texture
[unit
].level
[i
].bytes_per_image
=
469 4 * align(width
, TILE_SIZE
) * align(height
, TILE_SIZE
) * depth
;
471 spu
.texture
[unit
].level
[i
].max_s
= spu_splats((int) width
- 1);
472 spu
.texture
[unit
].level
[i
].max_t
= spu_splats((int) height
- 1);
474 if (texture
->start
[i
])
475 spu
.texture
[unit
].max_level
= i
;
478 update_tex_masks(&spu
.texture
[unit
], &spu
.sampler
[unit
]);
483 cmd_state_vertex_info(const struct vertex_info
*vinfo
)
485 D_PRINTF(CELL_DEBUG_CMD
, "VERTEX_INFO num_attribs=%u\n", vinfo
->num_attribs
);
486 ASSERT(vinfo
->num_attribs
>= 1);
487 ASSERT(vinfo
->num_attribs
<= 8);
488 memcpy(&spu
.vertex_info
, vinfo
, sizeof(*vinfo
));
493 cmd_state_vs_array_info(const struct cell_array_info
*vs_info
)
495 const unsigned attr
= vs_info
->attr
;
497 ASSERT(attr
< PIPE_MAX_ATTRIBS
);
498 draw
.vertex_fetch
.src_ptr
[attr
] = vs_info
->base
;
499 draw
.vertex_fetch
.pitch
[attr
] = vs_info
->pitch
;
500 draw
.vertex_fetch
.size
[attr
] = vs_info
->size
;
501 draw
.vertex_fetch
.code_offset
[attr
] = vs_info
->function_offset
;
502 draw
.vertex_fetch
.dirty
= 1;
507 cmd_state_attrib_fetch(const struct cell_attribute_fetch_code
*code
)
509 mfc_get(attribute_fetch_code_buffer
,
510 (unsigned int) code
->base
, /* src */
515 wait_on_mask(1 << TAG_BATCH_BUFFER
);
517 draw
.vertex_fetch
.code
= attribute_fetch_code_buffer
;
524 D_PRINTF(CELL_DEBUG_CMD
, "FINISH\n");
525 really_clear_tiles(0);
526 /* wait for all outstanding DMAs to finish */
527 mfc_write_tag_mask(~0);
528 mfc_read_tag_status_all();
529 /* send mbox message to PPU */
530 spu_write_out_mbox(CELL_CMD_FINISH
);
535 * Execute a batch of commands which was sent to us by the PPU.
536 * See the cell_emit_state.c code to see where the commands come from.
538 * The opcode param encodes the location of the buffer and its size.
541 cmd_batch(uint opcode
)
543 const uint buf
= (opcode
>> 8) & 0xff;
544 uint size
= (opcode
>> 16);
545 PIPE_ALIGN_VAR(16) qword buffer
[CELL_BUFFER_SIZE
/ 16];
546 const unsigned usize
= ROUNDUP16(size
) / sizeof(buffer
[0]);
549 D_PRINTF(CELL_DEBUG_CMD
, "BATCH buffer %u, len %u, from %p\n",
550 buf
, size
, spu
.init
.buffers
[buf
]);
552 ASSERT((opcode
& CELL_CMD_OPCODE_MASK
) == CELL_CMD_BATCH
);
554 ASSERT_ALIGN16(spu
.init
.buffers
[buf
]);
556 size
= ROUNDUP16(size
);
558 ASSERT_ALIGN16(spu
.init
.buffers
[buf
]);
560 mfc_get(buffer
, /* dest */
561 (unsigned int) spu
.init
.buffers
[buf
], /* src */
566 wait_on_mask(1 << TAG_BATCH_BUFFER
);
568 /* Tell PPU we're done copying the buffer to local store */
569 D_PRINTF(CELL_DEBUG_CMD
, "release batch buf %u\n", buf
);
573 * Loop over commands in the batch buffer
575 for (pos
= 0; pos
< usize
; /* no incr */) {
576 switch (si_to_uint(buffer
[pos
])) {
580 case CELL_CMD_CLEAR_SURFACE
:
582 struct cell_command_clear_surface
*clr
583 = (struct cell_command_clear_surface
*) &buffer
[pos
];
584 cmd_clear_surface(clr
);
585 pos
+= sizeof(*clr
) / 16;
588 case CELL_CMD_RENDER
:
590 struct cell_command_render
*render
591 = (struct cell_command_render
*) &buffer
[pos
];
593 cmd_render(render
, &pos_incr
);
594 pos
+= ((pos_incr
+1)&~1) / 2; // should 'fix' cmd_render return
598 * state-update commands
600 case CELL_CMD_STATE_FRAMEBUFFER
:
602 struct cell_command_framebuffer
*fb
603 = (struct cell_command_framebuffer
*) &buffer
[pos
];
604 cmd_state_framebuffer(fb
);
605 pos
+= sizeof(*fb
) / 16;
608 case CELL_CMD_STATE_FRAGMENT_OPS
:
610 struct cell_command_fragment_ops
*fops
611 = (struct cell_command_fragment_ops
*) &buffer
[pos
];
612 cmd_state_fragment_ops(fops
);
613 /* This is a variant-sized command */
614 pos
+= ROUNDUP16(sizeof(*fops
) + fops
->total_code_size
) / 16;
617 case CELL_CMD_STATE_FRAGMENT_PROGRAM
:
619 struct cell_command_fragment_program
*fp
620 = (struct cell_command_fragment_program
*) &buffer
[pos
];
621 cmd_state_fragment_program(fp
);
622 pos
+= sizeof(*fp
) / 16;
625 case CELL_CMD_STATE_FS_CONSTANTS
:
626 pos
= cmd_state_fs_constants(buffer
, pos
);
628 case CELL_CMD_STATE_RASTERIZER
:
630 struct cell_command_rasterizer
*rast
=
631 (struct cell_command_rasterizer
*) &buffer
[pos
];
632 spu
.rasterizer
= rast
->rasterizer
;
633 pos
+= sizeof(*rast
) / 16;
636 case CELL_CMD_STATE_SAMPLER
:
638 struct cell_command_sampler
*sampler
639 = (struct cell_command_sampler
*) &buffer
[pos
];
640 cmd_state_sampler(sampler
);
641 pos
+= sizeof(*sampler
) / 16;
644 case CELL_CMD_STATE_TEXTURE
:
646 struct cell_command_texture
*texture
647 = (struct cell_command_texture
*) &buffer
[pos
];
648 cmd_state_texture(texture
);
649 pos
+= sizeof(*texture
) / 16;
652 case CELL_CMD_STATE_VERTEX_INFO
:
653 cmd_state_vertex_info((struct vertex_info
*) &buffer
[pos
+1]);
654 pos
+= 1 + ROUNDUP16(sizeof(struct vertex_info
)) / 16;
656 case CELL_CMD_STATE_VIEWPORT
:
657 (void) memcpy(& draw
.viewport
, &buffer
[pos
+1],
658 sizeof(struct pipe_viewport_state
));
659 pos
+= 1 + ROUNDUP16(sizeof(struct pipe_viewport_state
)) / 16;
661 case CELL_CMD_STATE_UNIFORMS
:
662 draw
.constants
= (const float (*)[4]) (uintptr_t)spu_extract((vector
unsigned int)buffer
[pos
+1],0);
665 case CELL_CMD_STATE_VS_ARRAY_INFO
:
666 cmd_state_vs_array_info((struct cell_array_info
*) &buffer
[pos
+1]);
667 pos
+= 1 + ROUNDUP16(sizeof(struct cell_array_info
)) / 16;
669 case CELL_CMD_STATE_BIND_VS
:
671 spu_bind_vertex_shader(&draw
,
672 (struct cell_shader_info
*) &buffer
[pos
+1]);
674 pos
+= 1 + ROUNDUP16(sizeof(struct cell_shader_info
)) / 16;
676 case CELL_CMD_STATE_ATTRIB_FETCH
:
677 cmd_state_attrib_fetch((struct cell_attribute_fetch_code
*)
679 pos
+= 1 + ROUNDUP16(sizeof(struct cell_attribute_fetch_code
)) / 16;
684 case CELL_CMD_FINISH
:
690 struct cell_command_fence
*fence_cmd
=
691 (struct cell_command_fence
*) &buffer
[pos
];
692 cmd_fence(fence_cmd
);
693 pos
+= sizeof(*fence_cmd
) / 16;
696 case CELL_CMD_RELEASE_VERTS
:
698 struct cell_command_release_verts
*release
699 = (struct cell_command_release_verts
*) &buffer
[pos
];
700 cmd_release_verts(release
);
701 pos
+= sizeof(*release
) / 16;
704 case CELL_CMD_FLUSH_BUFFER_RANGE
: {
705 struct cell_buffer_range
*br
= (struct cell_buffer_range
*)
708 spu_dcache_mark_dirty((unsigned) br
->base
, br
->size
);
709 pos
+= 1 + ROUNDUP16(sizeof(struct cell_buffer_range
)) / 16;
713 printf("SPU %u: bad opcode: 0x%x\n", spu
.init
.id
, si_to_uint(buffer
[pos
]));
719 D_PRINTF(CELL_DEBUG_CMD
, "BATCH complete\n");
727 * Main loop for SPEs: Get a command, execute it, repeat.
735 D_PRINTF(CELL_DEBUG_CMD
, "Enter command loop\n");
740 D_PRINTF(CELL_DEBUG_CMD
, "Wait for cmd...\n");
743 spu_write_decrementer(~0);
745 /* read/wait from mailbox */
746 opcode
= (unsigned int) spu_read_in_mbox();
747 D_PRINTF(CELL_DEBUG_CMD
, "got cmd 0x%x\n", opcode
);
750 t0
= spu_read_decrementer();
752 switch (opcode
& CELL_CMD_OPCODE_MASK
) {
754 D_PRINTF(CELL_DEBUG_CMD
, "EXIT\n");
757 case CELL_CMD_VS_EXECUTE
:
759 spu_execute_vertex_shader(&draw
, &cmd
.vs
);
766 printf("Bad opcode 0x%x!\n", opcode
& CELL_CMD_OPCODE_MASK
);
770 t1
= spu_read_decrementer();
771 printf("wait mbox time: %gms batch time: %gms\n",
772 (~0u - t0
) * spu
.init
.inv_timebase
,
773 (t0
- t1
) * spu
.init
.inv_timebase
);
777 D_PRINTF(CELL_DEBUG_CMD
, "Exit command loop\n");
779 if (spu
.init
.debug_flags
& CELL_DEBUG_CACHE
)
783 /* Initialize this module; we manage the fragment ops buffer here. */
785 spu_command_init(void)
787 /* Install default/fallback fragment processing function.
788 * This will normally be overriden by a code-gen'd function
789 * unless CELL_FORCE_FRAGMENT_OPS_FALLBACK is set.
791 spu
.fragment_ops
[CELL_FACING_FRONT
] = spu_fallback_fragment_ops
;
792 spu
.fragment_ops
[CELL_FACING_BACK
] = spu_fallback_fragment_ops
;
794 /* Set up the basic empty buffer for code-gen'ed fragment ops */
795 spu
.fragment_ops_code
= NULL
;
796 spu
.fragment_ops_code_size
= 0;
800 spu_command_close(void)
802 /* Deallocate the code-gen buffer for fragment ops, and reset the
803 * fragment ops functions to their initial setting (just to leave
804 * things in a good state).
806 if (spu
.fragment_ops_code
!= NULL
) {
807 free(spu
.fragment_ops_code
);