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 static unsigned char attribute_fetch_code_buffer
[136 * PIPE_MAX_ATTRIBS
]
62 align(int value
, int alignment
)
64 return (value
+ alignment
- 1) & ~(alignment
- 1);
70 * Tell the PPU that this SPU has finished copying a buffer to
71 * local store and that it may be reused by the PPU.
72 * This is done by writting a 16-byte batch-buffer-status block back into
73 * main memory (in cell_context->buffer_status[]).
76 release_buffer(uint buffer
)
78 /* Evidently, using less than a 16-byte status doesn't work reliably */
79 static const vector
unsigned int status
= {CELL_BUFFER_STATUS_FREE
,
80 CELL_BUFFER_STATUS_FREE
,
81 CELL_BUFFER_STATUS_FREE
,
82 CELL_BUFFER_STATUS_FREE
};
83 const uint index
= 4 * (spu
.init
.id
* CELL_NUM_BUFFERS
+ buffer
);
84 uint
*dst
= spu
.init
.buffer_status
+ index
;
86 ASSERT(buffer
< CELL_NUM_BUFFERS
);
88 mfc_put((void *) &status
, /* src in local memory */
89 (unsigned int) dst
, /* dst in main memory */
90 sizeof(status
), /* size */
91 TAG_MISC
, /* tag is unimportant */
98 * Write CELL_FENCE_SIGNALLED back to the fence status qword in main memory.
99 * There's a qword of status per SPU.
102 cmd_fence(struct cell_command_fence
*fence_cmd
)
104 static const vector
unsigned int status
= {CELL_FENCE_SIGNALLED
,
105 CELL_FENCE_SIGNALLED
,
106 CELL_FENCE_SIGNALLED
,
107 CELL_FENCE_SIGNALLED
};
108 uint
*dst
= (uint
*) fence_cmd
->fence
;
109 dst
+= 4 * spu
.init
.id
; /* main store/memory address, not local store */
111 mfc_put((void *) &status
, /* src in local memory */
112 (unsigned int) dst
, /* dst in main memory */
113 sizeof(status
), /* size */
121 cmd_clear_surface(const struct cell_command_clear_surface
*clear
)
123 D_PRINTF(CELL_DEBUG_CMD
, "CLEAR SURF %u to 0x%08x\n", clear
->surface
, clear
->value
);
125 if (clear
->surface
== 0) {
126 spu
.fb
.color_clear_value
= clear
->value
;
127 if (spu
.init
.debug_flags
& CELL_DEBUG_CHECKER
) {
128 uint x
= (spu
.init
.id
<< 4) | (spu
.init
.id
<< 12) |
129 (spu
.init
.id
<< 20) | (spu
.init
.id
<< 28);
130 spu
.fb
.color_clear_value
^= x
;
134 spu
.fb
.depth_clear_value
= clear
->value
;
140 /* Simply set all tiles' status to CLEAR.
141 * When we actually begin rendering into a tile, we'll initialize it to
142 * the clear value. If any tiles go untouched during the frame,
143 * really_clear_tiles() will set them to the clear value.
145 if (clear
->surface
== 0) {
146 memset(spu
.ctile_status
, TILE_STATUS_CLEAR
, sizeof(spu
.ctile_status
));
149 memset(spu
.ztile_status
, TILE_STATUS_CLEAR
, sizeof(spu
.ztile_status
));
155 * This path clears the whole framebuffer to the clear color right now.
159 printf("SPU: %s num=%d w=%d h=%d\n",
160 __FUNCTION__, num_tiles, spu.fb.width_tiles, spu.fb.height_tiles);
163 /* init a single tile to the clear value */
164 if (clear
->surface
== 0) {
165 clear_c_tile(&spu
.ctile
);
168 clear_z_tile(&spu
.ztile
);
171 /* walk over my tiles, writing the 'clear' tile's data */
173 const uint num_tiles
= spu
.fb
.width_tiles
* spu
.fb
.height_tiles
;
175 for (i
= spu
.init
.id
; i
< num_tiles
; i
+= spu
.init
.num_spus
) {
176 uint tx
= i
% spu
.fb
.width_tiles
;
177 uint ty
= i
/ spu
.fb
.width_tiles
;
178 if (clear
->surface
== 0)
179 put_tile(tx
, ty
, &spu
.ctile
, TAG_SURFACE_CLEAR
, 0);
181 put_tile(tx
, ty
, &spu
.ztile
, TAG_SURFACE_CLEAR
, 1);
185 if (spu
.init
.debug_flags
& CELL_DEBUG_SYNC
) {
186 wait_on_mask(1 << TAG_SURFACE_CLEAR
);
189 #endif /* CLEAR_OPT */
191 D_PRINTF(CELL_DEBUG_CMD
, "CLEAR SURF done\n");
196 cmd_release_verts(const struct cell_command_release_verts
*release
)
198 D_PRINTF(CELL_DEBUG_CMD
, "RELEASE VERTS %u\n", release
->vertex_buf
);
199 ASSERT(release
->vertex_buf
!= ~0U);
200 release_buffer(release
->vertex_buf
);
205 * Process a CELL_CMD_STATE_FRAGMENT_OPS command.
206 * This involves installing new fragment ops SPU code.
207 * If this function is never called, we'll use a regular C fallback function
208 * for fragment processing.
211 cmd_state_fragment_ops(const struct cell_command_fragment_ops
*fops
)
213 D_PRINTF(CELL_DEBUG_CMD
, "CMD_STATE_FRAGMENT_OPS\n");
215 /* Copy state info (for fallback case only - this will eventually
216 * go away when the fallback case goes away)
218 memcpy(&spu
.depth_stencil_alpha
, &fops
->dsa
, sizeof(fops
->dsa
));
219 memcpy(&spu
.blend
, &fops
->blend
, sizeof(fops
->blend
));
220 memcpy(&spu
.blend_color
, &fops
->blend_color
, sizeof(fops
->blend_color
));
222 /* Make sure the SPU knows which buffers it's expected to read when
223 * it's told to pull tiles.
225 spu
.read_depth_stencil
= (spu
.depth_stencil_alpha
.depth
.enabled
|| spu
.depth_stencil_alpha
.stencil
[0].enabled
);
227 /* If we're forcing the fallback code to be used (for debug purposes),
228 * install that. Otherwise install the incoming SPU code.
230 if ((spu
.init
.debug_flags
& CELL_DEBUG_FRAGMENT_OP_FALLBACK
) != 0) {
231 static unsigned int warned
= 0;
233 fprintf(stderr
, "Cell Warning: using fallback per-fragment code\n");
236 /* The following two lines aren't really necessary if you
237 * know the debug flags won't change during a run, and if you
238 * know that the function pointers are initialized correctly.
239 * We set them here to allow a person to change the debug
240 * flags during a run (from inside a debugger).
242 spu
.fragment_ops
[CELL_FACING_FRONT
] = spu_fallback_fragment_ops
;
243 spu
.fragment_ops
[CELL_FACING_BACK
] = spu_fallback_fragment_ops
;
247 /* Make sure the SPU code buffer is large enough to hold the incoming code.
248 * Note that we *don't* use align_malloc() and align_free(), because
249 * those utility functions are *not* available in SPU code.
251 if (spu
.fragment_ops_code_size
< fops
->total_code_size
) {
252 if (spu
.fragment_ops_code
!= NULL
) {
253 free(spu
.fragment_ops_code
);
255 spu
.fragment_ops_code_size
= fops
->total_code_size
;
256 spu
.fragment_ops_code
= malloc(fops
->total_code_size
);
257 if (spu
.fragment_ops_code
== NULL
) {
259 fprintf(stderr
, "CELL Warning: failed to allocate fragment ops code (%d bytes) - using fallback\n", fops
->total_code_size
);
260 spu
.fragment_ops_code
= NULL
;
261 spu
.fragment_ops_code_size
= 0;
262 spu
.fragment_ops
[CELL_FACING_FRONT
] = spu_fallback_fragment_ops
;
263 spu
.fragment_ops
[CELL_FACING_BACK
] = spu_fallback_fragment_ops
;
268 /* Copy the SPU code from the command buffer to the spu buffer */
269 memcpy(spu
.fragment_ops_code
, fops
->code
, fops
->total_code_size
);
271 /* Set the pointers for the front-facing and back-facing fragments
272 * to the specified offsets within the code. Note that if the
273 * front-facing and back-facing code are the same, they'll have
276 spu
.fragment_ops
[CELL_FACING_FRONT
] = (spu_fragment_ops_func
) &spu
.fragment_ops_code
[fops
->front_code_index
];
277 spu
.fragment_ops
[CELL_FACING_BACK
] = (spu_fragment_ops_func
) &spu
.fragment_ops_code
[fops
->back_code_index
];
281 cmd_state_fragment_program(const struct cell_command_fragment_program
*fp
)
283 D_PRINTF(CELL_DEBUG_CMD
, "CMD_STATE_FRAGMENT_PROGRAM\n");
284 /* Copy SPU code from batch buffer to spu buffer */
285 memcpy(spu
.fragment_program_code
, fp
->code
,
286 SPU_MAX_FRAGMENT_PROGRAM_INSTS
* 4);
288 /* Point function pointer at new code */
289 spu
.fragment_program
= (spu_fragment_program_func
)spu
.fragment_program_code
;
295 cmd_state_fs_constants(const uint64_t *buffer
, uint pos
)
297 const uint num_const
= buffer
[pos
+ 1];
298 const float *constants
= (const float *) &buffer
[pos
+ 2];
301 D_PRINTF(CELL_DEBUG_CMD
, "CMD_STATE_FS_CONSTANTS (%u)\n", num_const
);
303 /* Expand each float to float[4] for SOA execution */
304 for (i
= 0; i
< num_const
; i
++) {
305 D_PRINTF(CELL_DEBUG_CMD
, " const[%u] = %f\n", i
, constants
[i
]);
306 spu
.constants
[i
] = spu_splats(constants
[i
]);
309 /* return new buffer pos (in 8-byte words) */
310 return pos
+ 2 + num_const
/ 2;
315 cmd_state_framebuffer(const struct cell_command_framebuffer
*cmd
)
317 D_PRINTF(CELL_DEBUG_CMD
, "FRAMEBUFFER: %d x %d at %p, cformat 0x%x zformat 0x%x\n",
324 ASSERT_ALIGN16(cmd
->color_start
);
325 ASSERT_ALIGN16(cmd
->depth_start
);
327 spu
.fb
.color_start
= cmd
->color_start
;
328 spu
.fb
.depth_start
= cmd
->depth_start
;
329 spu
.fb
.color_format
= cmd
->color_format
;
330 spu
.fb
.depth_format
= cmd
->depth_format
;
331 spu
.fb
.width
= cmd
->width
;
332 spu
.fb
.height
= cmd
->height
;
333 spu
.fb
.width_tiles
= (spu
.fb
.width
+ TILE_SIZE
- 1) / TILE_SIZE
;
334 spu
.fb
.height_tiles
= (spu
.fb
.height
+ TILE_SIZE
- 1) / TILE_SIZE
;
336 switch (spu
.fb
.depth_format
) {
337 case PIPE_FORMAT_Z32_UNORM
:
339 spu
.fb
.zscale
= (float) 0xffffffffu
;
341 case PIPE_FORMAT_Z24S8_UNORM
:
342 case PIPE_FORMAT_S8Z24_UNORM
:
343 case PIPE_FORMAT_Z24X8_UNORM
:
344 case PIPE_FORMAT_X8Z24_UNORM
:
346 spu
.fb
.zscale
= (float) 0x00ffffffu
;
348 case PIPE_FORMAT_Z16_UNORM
:
350 spu
.fb
.zscale
= (float) 0xffffu
;
360 * Tex texture mask_s/t and scale_s/t fields depend on the texture size and
361 * sampler wrap modes.
364 update_tex_masks(struct spu_texture
*texture
,
365 const struct pipe_sampler_state
*sampler
)
369 for (i
= 0; i
< CELL_MAX_TEXTURE_LEVELS
; i
++) {
370 int width
= texture
->level
[i
].width
;
371 int height
= texture
->level
[i
].height
;
373 if (sampler
->wrap_s
== PIPE_TEX_WRAP_REPEAT
)
374 texture
->level
[i
].mask_s
= spu_splats(width
- 1);
376 texture
->level
[i
].mask_s
= spu_splats(~0);
378 if (sampler
->wrap_t
== PIPE_TEX_WRAP_REPEAT
)
379 texture
->level
[i
].mask_t
= spu_splats(height
- 1);
381 texture
->level
[i
].mask_t
= spu_splats(~0);
383 if (sampler
->normalized_coords
) {
384 texture
->level
[i
].scale_s
= spu_splats((float) width
);
385 texture
->level
[i
].scale_t
= spu_splats((float) height
);
388 texture
->level
[i
].scale_s
= spu_splats(1.0f
);
389 texture
->level
[i
].scale_t
= spu_splats(1.0f
);
396 cmd_state_sampler(const struct cell_command_sampler
*sampler
)
398 uint unit
= sampler
->unit
;
400 D_PRINTF(CELL_DEBUG_CMD
, "SAMPLER [%u]\n", unit
);
402 spu
.sampler
[unit
] = sampler
->state
;
404 switch (spu
.sampler
[unit
].min_img_filter
) {
405 case PIPE_TEX_FILTER_LINEAR
:
406 spu
.min_sample_texture_2d
[unit
] = sample_texture_2d_bilinear
;
408 case PIPE_TEX_FILTER_ANISO
:
409 /* fall-through, for now */
410 case PIPE_TEX_FILTER_NEAREST
:
411 spu
.min_sample_texture_2d
[unit
] = sample_texture_2d_nearest
;
417 switch (spu
.sampler
[sampler
->unit
].mag_img_filter
) {
418 case PIPE_TEX_FILTER_LINEAR
:
419 spu
.mag_sample_texture_2d
[unit
] = sample_texture_2d_bilinear
;
421 case PIPE_TEX_FILTER_ANISO
:
422 /* fall-through, for now */
423 case PIPE_TEX_FILTER_NEAREST
:
424 spu
.mag_sample_texture_2d
[unit
] = sample_texture_2d_nearest
;
430 switch (spu
.sampler
[sampler
->unit
].min_mip_filter
) {
431 case PIPE_TEX_MIPFILTER_NEAREST
:
432 case PIPE_TEX_MIPFILTER_LINEAR
:
433 spu
.sample_texture_2d
[unit
] = sample_texture_2d_lod
;
435 case PIPE_TEX_MIPFILTER_NONE
:
436 spu
.sample_texture_2d
[unit
] = spu
.mag_sample_texture_2d
[unit
];
442 update_tex_masks(&spu
.texture
[unit
], &spu
.sampler
[unit
]);
447 cmd_state_texture(const struct cell_command_texture
*texture
)
449 const uint unit
= texture
->unit
;
452 D_PRINTF(CELL_DEBUG_CMD
, "TEXTURE [%u]\n", texture
->unit
);
454 spu
.texture
[unit
].max_level
= 0;
455 spu
.texture
[unit
].target
= texture
->target
;
457 for (i
= 0; i
< CELL_MAX_TEXTURE_LEVELS
; i
++) {
458 uint width
= texture
->width
[i
];
459 uint height
= texture
->height
[i
];
460 uint depth
= texture
->depth
[i
];
462 D_PRINTF(CELL_DEBUG_CMD
, " LEVEL %u: at %p size[0] %u x %u\n", i
,
463 texture
->start
[i
], texture
->width
[i
], texture
->height
[i
]);
465 spu
.texture
[unit
].level
[i
].start
= texture
->start
[i
];
466 spu
.texture
[unit
].level
[i
].width
= width
;
467 spu
.texture
[unit
].level
[i
].height
= height
;
468 spu
.texture
[unit
].level
[i
].depth
= depth
;
470 spu
.texture
[unit
].level
[i
].tiles_per_row
=
471 (width
+ TILE_SIZE
- 1) / TILE_SIZE
;
473 spu
.texture
[unit
].level
[i
].bytes_per_image
=
474 4 * align(width
, TILE_SIZE
) * align(height
, TILE_SIZE
) * depth
;
476 spu
.texture
[unit
].level
[i
].max_s
= spu_splats((int) width
- 1);
477 spu
.texture
[unit
].level
[i
].max_t
= spu_splats((int) height
- 1);
479 if (texture
->start
[i
])
480 spu
.texture
[unit
].max_level
= i
;
483 update_tex_masks(&spu
.texture
[unit
], &spu
.sampler
[unit
]);
488 cmd_state_vertex_info(const struct vertex_info
*vinfo
)
490 D_PRINTF(CELL_DEBUG_CMD
, "VERTEX_INFO num_attribs=%u\n", vinfo
->num_attribs
);
491 ASSERT(vinfo
->num_attribs
>= 1);
492 ASSERT(vinfo
->num_attribs
<= 8);
493 memcpy(&spu
.vertex_info
, vinfo
, sizeof(*vinfo
));
498 cmd_state_vs_array_info(const struct cell_array_info
*vs_info
)
500 const unsigned attr
= vs_info
->attr
;
502 ASSERT(attr
< PIPE_MAX_ATTRIBS
);
503 draw
.vertex_fetch
.src_ptr
[attr
] = vs_info
->base
;
504 draw
.vertex_fetch
.pitch
[attr
] = vs_info
->pitch
;
505 draw
.vertex_fetch
.size
[attr
] = vs_info
->size
;
506 draw
.vertex_fetch
.code_offset
[attr
] = vs_info
->function_offset
;
507 draw
.vertex_fetch
.dirty
= 1;
512 cmd_state_attrib_fetch(const struct cell_attribute_fetch_code
*code
)
514 mfc_get(attribute_fetch_code_buffer
,
515 (unsigned int) code
->base
, /* src */
520 wait_on_mask(1 << TAG_BATCH_BUFFER
);
522 draw
.vertex_fetch
.code
= attribute_fetch_code_buffer
;
529 D_PRINTF(CELL_DEBUG_CMD
, "FINISH\n");
530 really_clear_tiles(0);
531 /* wait for all outstanding DMAs to finish */
532 mfc_write_tag_mask(~0);
533 mfc_read_tag_status_all();
534 /* send mbox message to PPU */
535 spu_write_out_mbox(CELL_CMD_FINISH
);
540 * Execute a batch of commands which was sent to us by the PPU.
541 * See the cell_emit_state.c code to see where the commands come from.
543 * The opcode param encodes the location of the buffer and its size.
546 cmd_batch(uint opcode
)
548 const uint buf
= (opcode
>> 8) & 0xff;
549 uint size
= (opcode
>> 16);
550 uint64_t buffer
[CELL_BUFFER_SIZE
/ 8] ALIGN16_ATTRIB
;
551 const unsigned usize
= size
/ sizeof(buffer
[0]);
554 D_PRINTF(CELL_DEBUG_CMD
, "BATCH buffer %u, len %u, from %p\n",
555 buf
, size
, spu
.init
.buffers
[buf
]);
557 ASSERT((opcode
& CELL_CMD_OPCODE_MASK
) == CELL_CMD_BATCH
);
559 ASSERT_ALIGN16(spu
.init
.buffers
[buf
]);
561 size
= ROUNDUP16(size
);
563 ASSERT_ALIGN16(spu
.init
.buffers
[buf
]);
565 mfc_get(buffer
, /* dest */
566 (unsigned int) spu
.init
.buffers
[buf
], /* src */
571 wait_on_mask(1 << TAG_BATCH_BUFFER
);
573 /* Tell PPU we're done copying the buffer to local store */
574 D_PRINTF(CELL_DEBUG_CMD
, "release batch buf %u\n", buf
);
578 * Loop over commands in the batch buffer
580 for (pos
= 0; pos
< usize
; /* no incr */) {
581 switch (buffer
[pos
]) {
585 case CELL_CMD_CLEAR_SURFACE
:
587 struct cell_command_clear_surface
*clr
588 = (struct cell_command_clear_surface
*) &buffer
[pos
];
589 cmd_clear_surface(clr
);
590 pos
+= sizeof(*clr
) / 8;
593 case CELL_CMD_RENDER
:
595 struct cell_command_render
*render
596 = (struct cell_command_render
*) &buffer
[pos
];
598 cmd_render(render
, &pos_incr
);
603 * state-update commands
605 case CELL_CMD_STATE_FRAMEBUFFER
:
607 struct cell_command_framebuffer
*fb
608 = (struct cell_command_framebuffer
*) &buffer
[pos
];
609 cmd_state_framebuffer(fb
);
610 pos
+= sizeof(*fb
) / 8;
613 case CELL_CMD_STATE_FRAGMENT_OPS
:
615 struct cell_command_fragment_ops
*fops
616 = (struct cell_command_fragment_ops
*) &buffer
[pos
];
617 cmd_state_fragment_ops(fops
);
618 /* This is a variant-sized command */
619 pos
+= (sizeof(*fops
) + fops
->total_code_size
)/ 8;
622 case CELL_CMD_STATE_FRAGMENT_PROGRAM
:
624 struct cell_command_fragment_program
*fp
625 = (struct cell_command_fragment_program
*) &buffer
[pos
];
626 cmd_state_fragment_program(fp
);
627 pos
+= sizeof(*fp
) / 8;
630 case CELL_CMD_STATE_FS_CONSTANTS
:
631 pos
= cmd_state_fs_constants(buffer
, pos
);
633 case CELL_CMD_STATE_RASTERIZER
:
635 struct cell_command_rasterizer
*rast
=
636 (struct cell_command_rasterizer
*) &buffer
[pos
];
637 spu
.rasterizer
= rast
->rasterizer
;
638 pos
+= sizeof(*rast
) / 8;
641 case CELL_CMD_STATE_SAMPLER
:
643 struct cell_command_sampler
*sampler
644 = (struct cell_command_sampler
*) &buffer
[pos
];
645 cmd_state_sampler(sampler
);
646 pos
+= sizeof(*sampler
) / 8;
649 case CELL_CMD_STATE_TEXTURE
:
651 struct cell_command_texture
*texture
652 = (struct cell_command_texture
*) &buffer
[pos
];
653 cmd_state_texture(texture
);
654 pos
+= sizeof(*texture
) / 8;
657 case CELL_CMD_STATE_VERTEX_INFO
:
658 cmd_state_vertex_info((struct vertex_info
*) &buffer
[pos
+1]);
659 pos
+= (1 + ROUNDUP8(sizeof(struct vertex_info
)) / 8);
661 case CELL_CMD_STATE_VIEWPORT
:
662 (void) memcpy(& draw
.viewport
, &buffer
[pos
+1],
663 sizeof(struct pipe_viewport_state
));
664 pos
+= (1 + ROUNDUP8(sizeof(struct pipe_viewport_state
)) / 8);
666 case CELL_CMD_STATE_UNIFORMS
:
667 draw
.constants
= (const float (*)[4]) (uintptr_t) buffer
[pos
+ 1];
670 case CELL_CMD_STATE_VS_ARRAY_INFO
:
671 cmd_state_vs_array_info((struct cell_array_info
*) &buffer
[pos
+1]);
672 pos
+= (1 + ROUNDUP8(sizeof(struct cell_array_info
)) / 8);
674 case CELL_CMD_STATE_BIND_VS
:
676 spu_bind_vertex_shader(&draw
,
677 (struct cell_shader_info
*) &buffer
[pos
+1]);
679 pos
+= (1 + ROUNDUP8(sizeof(struct cell_shader_info
)) / 8);
681 case CELL_CMD_STATE_ATTRIB_FETCH
:
682 cmd_state_attrib_fetch((struct cell_attribute_fetch_code
*)
684 pos
+= (1 + ROUNDUP8(sizeof(struct cell_attribute_fetch_code
)) / 8);
689 case CELL_CMD_FINISH
:
695 struct cell_command_fence
*fence_cmd
=
696 (struct cell_command_fence
*) &buffer
[pos
];
697 cmd_fence(fence_cmd
);
698 pos
+= sizeof(*fence_cmd
) / 8;
701 case CELL_CMD_RELEASE_VERTS
:
703 struct cell_command_release_verts
*release
704 = (struct cell_command_release_verts
*) &buffer
[pos
];
705 cmd_release_verts(release
);
706 pos
+= sizeof(*release
) / 8;
709 case CELL_CMD_FLUSH_BUFFER_RANGE
: {
710 struct cell_buffer_range
*br
= (struct cell_buffer_range
*)
713 spu_dcache_mark_dirty((unsigned) br
->base
, br
->size
);
714 pos
+= (1 + ROUNDUP8(sizeof(struct cell_buffer_range
)) / 8);
718 printf("SPU %u: bad opcode: 0x%llx\n", spu
.init
.id
, buffer
[pos
]);
724 D_PRINTF(CELL_DEBUG_CMD
, "BATCH complete\n");
732 * Main loop for SPEs: Get a command, execute it, repeat.
740 D_PRINTF(CELL_DEBUG_CMD
, "Enter command loop\n");
745 D_PRINTF(CELL_DEBUG_CMD
, "Wait for cmd...\n");
748 spu_write_decrementer(~0);
750 /* read/wait from mailbox */
751 opcode
= (unsigned int) spu_read_in_mbox();
752 D_PRINTF(CELL_DEBUG_CMD
, "got cmd 0x%x\n", opcode
);
755 t0
= spu_read_decrementer();
757 switch (opcode
& CELL_CMD_OPCODE_MASK
) {
759 D_PRINTF(CELL_DEBUG_CMD
, "EXIT\n");
762 case CELL_CMD_VS_EXECUTE
:
764 spu_execute_vertex_shader(&draw
, &cmd
.vs
);
771 printf("Bad opcode 0x%x!\n", opcode
& CELL_CMD_OPCODE_MASK
);
775 t1
= spu_read_decrementer();
776 printf("wait mbox time: %gms batch time: %gms\n",
777 (~0u - t0
) * spu
.init
.inv_timebase
,
778 (t0
- t1
) * spu
.init
.inv_timebase
);
782 D_PRINTF(CELL_DEBUG_CMD
, "Exit command loop\n");
784 if (spu
.init
.debug_flags
& CELL_DEBUG_CACHE
)
788 /* Initialize this module; we manage the fragment ops buffer here. */
790 spu_command_init(void)
792 /* Install default/fallback fragment processing function.
793 * This will normally be overriden by a code-gen'd function
794 * unless CELL_FORCE_FRAGMENT_OPS_FALLBACK is set.
796 spu
.fragment_ops
[CELL_FACING_FRONT
] = spu_fallback_fragment_ops
;
797 spu
.fragment_ops
[CELL_FACING_BACK
] = spu_fallback_fragment_ops
;
799 /* Set up the basic empty buffer for code-gen'ed fragment ops */
800 spu
.fragment_ops_code
= NULL
;
801 spu
.fragment_ops_code_size
= 0;
805 spu_command_close(void)
807 /* Deallocate the code-gen buffer for fragment ops, and reset the
808 * fragment ops functions to their initial setting (just to leave
809 * things in a good state).
811 if (spu
.fragment_ops_code
!= NULL
) {
812 free(spu
.fragment_ops_code
);