Cell: compute min index referenced in draw command, use it to reduce size of vertex...
[mesa.git] / src / mesa / pipe / cell / spu / spu_main.c
1 /**************************************************************************
2 *
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
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:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
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.
25 *
26 **************************************************************************/
27
28
29 /* main() for Cell SPU code */
30
31
32 #include <stdio.h>
33 #include <libmisc.h>
34 #include <spu_mfcio.h>
35
36 #include "spu_main.h"
37 #include "spu_texture.h"
38 #include "spu_tri.h"
39 #include "spu_tile.h"
40 #include "pipe/cell/common.h"
41 #include "pipe/p_defines.h"
42
43
44 /*
45 helpful headers:
46 /usr/lib/gcc/spu/4.1.1/include/spu_mfcio.h
47 /opt/ibm/cell-sdk/prototype/sysroot/usr/include/libmisc.h
48 */
49
50 static boolean Debug = FALSE;
51
52 struct spu_global spu;
53
54
55 void
56 wait_on_mask(unsigned tagMask)
57 {
58 mfc_write_tag_mask( tagMask );
59 /* wait for completion of _any_ DMAs specified by tagMask */
60 mfc_read_tag_status_any();
61 }
62
63
64 static void
65 wait_on_mask_all(unsigned tagMask)
66 {
67 mfc_write_tag_mask( tagMask );
68 /* wait for completion of _any_ DMAs specified by tagMask */
69 mfc_read_tag_status_all();
70 }
71
72
73 /**
74 * Tell the PPU that this SPU has finished copying a buffer to
75 * local store and that it may be reused by the PPU.
76 * This is done by writting a 16-byte batch-buffer-status block back into
77 * main memory (in cell_context->buffer_status[]).
78 */
79 static void
80 release_buffer(uint buffer)
81 {
82 /* Evidently, using less than a 16-byte status doesn't work reliably */
83 static const uint status[4] ALIGN16_ATTRIB
84 = {CELL_BUFFER_STATUS_FREE, 0, 0, 0};
85
86 const uint index = 4 * (spu.init.id * CELL_NUM_BUFFERS + buffer);
87 uint *dst = spu.init.buffer_status + index;
88
89 ASSERT(buffer < CELL_NUM_BUFFERS);
90
91 mfc_put((void *) &status, /* src in local memory */
92 (unsigned int) dst, /* dst in main memory */
93 sizeof(status), /* size */
94 TAG_MISC, /* tag is unimportant */
95 0, /* tid */
96 0 /* rid */);
97 }
98
99
100 /**
101 * For tiles whose status is TILE_STATUS_CLEAR, write solid-filled
102 * tiles back to the main framebuffer.
103 */
104 static void
105 really_clear_tiles(uint surfaceIndex)
106 {
107 const uint num_tiles = spu.fb.width_tiles * spu.fb.height_tiles;
108 uint i;
109
110 if (surfaceIndex == 0) {
111 clear_c_tile(&ctile);
112
113 for (i = spu.init.id; i < num_tiles; i += spu.init.num_spus) {
114 uint tx = i % spu.fb.width_tiles;
115 uint ty = i / spu.fb.width_tiles;
116 if (tile_status[ty][tx] == TILE_STATUS_CLEAR) {
117 put_tile(tx, ty, &ctile, TAG_SURFACE_CLEAR, 0);
118 }
119 }
120 }
121 else {
122 clear_z_tile(&ztile);
123
124 for (i = spu.init.id; i < num_tiles; i += spu.init.num_spus) {
125 uint tx = i % spu.fb.width_tiles;
126 uint ty = i / spu.fb.width_tiles;
127 if (tile_status_z[ty][tx] == TILE_STATUS_CLEAR)
128 put_tile(tx, ty, &ctile, TAG_SURFACE_CLEAR, 1);
129 }
130 }
131
132 #if 0
133 wait_on_mask(1 << TAG_SURFACE_CLEAR);
134 #endif
135 }
136
137
138 static void
139 cmd_clear_surface(const struct cell_command_clear_surface *clear)
140 {
141 const uint num_tiles = spu.fb.width_tiles * spu.fb.height_tiles;
142 uint i;
143
144 if (Debug)
145 printf("SPU %u: CLEAR SURF %u to 0x%08x\n", spu.init.id,
146 clear->surface, clear->value);
147
148 #define CLEAR_OPT 1
149 #if CLEAR_OPT
150 /* set all tile's status to CLEAR */
151 if (clear->surface == 0) {
152 memset(tile_status, TILE_STATUS_CLEAR, sizeof(tile_status));
153 spu.fb.color_clear_value = clear->value;
154 }
155 else {
156 memset(tile_status_z, TILE_STATUS_CLEAR, sizeof(tile_status_z));
157 spu.fb.depth_clear_value = clear->value;
158 }
159 return;
160 #endif
161
162 if (clear->surface == 0) {
163 spu.fb.color_clear_value = clear->value;
164 clear_c_tile(&ctile);
165 }
166 else {
167 spu.fb.depth_clear_value = clear->value;
168 clear_z_tile(&ztile);
169 }
170
171 /*
172 printf("SPU: %s num=%d w=%d h=%d\n",
173 __FUNCTION__, num_tiles, spu.fb.width_tiles, spu.fb.height_tiles);
174 */
175
176 for (i = spu.init.id; i < num_tiles; i += spu.init.num_spus) {
177 uint tx = i % spu.fb.width_tiles;
178 uint ty = i / spu.fb.width_tiles;
179 if (clear->surface == 0)
180 put_tile(tx, ty, &ctile, TAG_SURFACE_CLEAR, 0);
181 else
182 put_tile(tx, ty, &ztile, TAG_SURFACE_CLEAR, 1);
183 /* XXX we don't want this here, but it fixes bad tile results */
184 }
185
186 #if 0
187 wait_on_mask(1 << TAG_SURFACE_CLEAR);
188 #endif
189
190 if (Debug)
191 printf("SPU %u: CLEAR SURF done\n", spu.init.id);
192 }
193
194
195 /**
196 * Given a rendering command's bounding box (in pixels) compute the
197 * location of the corresponding screen tile bounding box.
198 */
199 static INLINE void
200 tile_bounding_box(const struct cell_command_render *render,
201 uint *txmin, uint *tymin,
202 uint *box_num_tiles, uint *box_width_tiles)
203 {
204 #if 0
205 /* Debug: full-window bounding box */
206 uint txmax = spu.fb.width_tiles - 1;
207 uint tymax = spu.fb.height_tiles - 1;
208 *txmin = 0;
209 *tymin = 0;
210 *box_num_tiles = spu.fb.width_tiles * spu.fb.height_tiles;
211 *box_width_tiles = spu.fb.width_tiles;
212 (void) render;
213 (void) txmax;
214 (void) tymax;
215 #else
216 uint txmax, tymax, box_height_tiles;
217
218 *txmin = (uint) render->xmin / TILE_SIZE;
219 *tymin = (uint) render->ymin / TILE_SIZE;
220 txmax = (uint) render->xmax / TILE_SIZE;
221 tymax = (uint) render->ymax / TILE_SIZE;
222 *box_width_tiles = txmax - *txmin + 1;
223 box_height_tiles = tymax - *tymin + 1;
224 *box_num_tiles = *box_width_tiles * box_height_tiles;
225 #endif
226 #if 0
227 printf("SPU %u: bounds: %g, %g ... %g, %g\n", spu.init.id,
228 render->xmin, render->ymin, render->xmax, render->ymax);
229 printf("SPU %u: tiles: %u, %u .. %u, %u\n",
230 spu.init.id, *txmin, *tymin, txmax, tymax);
231 ASSERT(render->xmin <= render->xmax);
232 ASSERT(render->ymin <= render->ymax);
233 #endif
234 }
235
236
237 /** Check if the tile at (tx,ty) belongs to this SPU */
238 static INLINE boolean
239 my_tile(uint tx, uint ty)
240 {
241 return (spu.fb.width_tiles * ty + tx) % spu.init.num_spus == spu.init.id;
242 }
243
244
245 /**
246 * Render primitives
247 * \param pos_incr returns value indicating how may words to skip after
248 * this command in the batch buffer
249 */
250 static void
251 cmd_render(const struct cell_command_render *render, uint *pos_incr)
252 {
253 /* we'll DMA into these buffers */
254 ubyte vertex_data[CELL_BUFFER_SIZE] ALIGN16_ATTRIB;
255 const uint vertex_size = render->vertex_size; /* in bytes */
256 /*const*/ uint total_vertex_bytes = render->num_verts * vertex_size;
257 const ubyte *vertices;
258 const ushort *indexes;
259 uint i, j;
260
261
262 if (Debug) {
263 printf("SPU %u: RENDER prim %u, num_vert=%u num_ind=%u "
264 "inline_vert=%u\n",
265 spu.init.id,
266 render->prim_type,
267 render->num_verts,
268 render->num_indexes,
269 render->inline_verts);
270
271 /*
272 printf(" bound: %g, %g .. %g, %g\n",
273 render->xmin, render->ymin, render->xmax, render->ymax);
274 */
275 }
276
277 ASSERT(sizeof(*render) % 4 == 0);
278 ASSERT(total_vertex_bytes % 16 == 0);
279
280 /* indexes are right after the render command in the batch buffer */
281 indexes = (const ushort *) (render + 1);
282 *pos_incr = (render->num_indexes * 2 + 3) / 4;
283
284
285 if (render->inline_verts) {
286 /* Vertices are right after indexes in batch buffer */
287 vertices = (const ubyte *) (render + 1) + *pos_incr * 4;
288 *pos_incr = *pos_incr + total_vertex_bytes / 4;
289 }
290 else {
291 /* Begin DMA fetch of vertex buffer */
292 ubyte *src = spu.init.buffers[render->vertex_buf];
293 ubyte *dest = vertex_data;
294
295 /* skip vertex data we won't use */
296 #if 01
297 src += render->min_index * vertex_size;
298 dest += render->min_index * vertex_size;
299 total_vertex_bytes -= render->min_index * vertex_size;
300 #endif
301 ASSERT(total_vertex_bytes % 16 == 0);
302 ASSERT_ALIGN16(dest);
303 ASSERT_ALIGN16(src);
304
305 mfc_get(dest, /* in vertex_data[] array */
306 (unsigned int) src, /* src in main memory */
307 total_vertex_bytes, /* size */
308 TAG_VERTEX_BUFFER,
309 0, /* tid */
310 0 /* rid */);
311
312 vertices = vertex_data;
313
314 wait_on_mask(1 << TAG_VERTEX_BUFFER);
315 }
316
317
318 /**
319 ** find tiles which intersect the prim bounding box
320 **/
321 uint txmin, tymin, box_width_tiles, box_num_tiles;
322 tile_bounding_box(render, &txmin, &tymin,
323 &box_num_tiles, &box_width_tiles);
324
325
326 /* make sure any pending clears have completed */
327 wait_on_mask(1 << TAG_SURFACE_CLEAR); /* XXX temporary */
328
329
330 /**
331 ** loop over tiles, rendering tris
332 **/
333 for (i = 0; i < box_num_tiles; i++) {
334 const uint tx = txmin + i % box_width_tiles;
335 const uint ty = tymin + i / box_width_tiles;
336
337 ASSERT(tx < spu.fb.width_tiles);
338 ASSERT(ty < spu.fb.height_tiles);
339
340 if (!my_tile(tx, ty))
341 continue;
342
343 /* Start fetching color/z tiles. We'll wait for completion when
344 * we need read/write to them later in triangle rasterization.
345 */
346 if (spu.depth_stencil.depth.enabled) {
347 if (tile_status_z[ty][tx] != TILE_STATUS_CLEAR) {
348 get_tile(tx, ty, &ztile, TAG_READ_TILE_Z, 1);
349 }
350 }
351
352 if (tile_status[ty][tx] != TILE_STATUS_CLEAR) {
353 get_tile(tx, ty, &ctile, TAG_READ_TILE_COLOR, 0);
354 }
355
356 ASSERT(render->prim_type == PIPE_PRIM_TRIANGLES);
357 ASSERT(render->num_indexes % 3 == 0);
358
359 /* loop over tris */
360 for (j = 0; j < render->num_indexes; j += 3) {
361 const float *v0, *v1, *v2;
362
363 v0 = (const float *) (vertices + indexes[j+0] * vertex_size);
364 v1 = (const float *) (vertices + indexes[j+1] * vertex_size);
365 v2 = (const float *) (vertices + indexes[j+2] * vertex_size);
366
367 tri_draw(v0, v1, v2, tx, ty);
368 }
369
370 /* write color/z tiles back to main framebuffer, if dirtied */
371 if (tile_status[ty][tx] == TILE_STATUS_DIRTY) {
372 put_tile(tx, ty, &ctile, TAG_WRITE_TILE_COLOR, 0);
373 tile_status[ty][tx] = TILE_STATUS_DEFINED;
374 }
375 if (spu.depth_stencil.depth.enabled) {
376 if (tile_status_z[ty][tx] == TILE_STATUS_DIRTY) {
377 put_tile(tx, ty, &ztile, TAG_WRITE_TILE_Z, 1);
378 tile_status_z[ty][tx] = TILE_STATUS_DEFINED;
379 }
380 }
381
382 /* XXX move these... */
383 wait_on_mask(1 << TAG_WRITE_TILE_COLOR);
384 if (spu.depth_stencil.depth.enabled) {
385 wait_on_mask(1 << TAG_WRITE_TILE_Z);
386 }
387 }
388
389 if (Debug)
390 printf("SPU %u: RENDER done\n",
391 spu.init.id);
392 }
393
394
395 static void
396 cmd_release_verts(const struct cell_command_release_verts *release)
397 {
398 if (Debug)
399 printf("SPU %u: RELEASE VERTS %u\n",
400 spu.init.id, release->vertex_buf);
401 ASSERT(release->vertex_buf != ~0U);
402 release_buffer(release->vertex_buf);
403 }
404
405
406 static void
407 cmd_state_framebuffer(const struct cell_command_framebuffer *cmd)
408 {
409 if (Debug)
410 printf("SPU %u: FRAMEBUFFER: %d x %d at %p, cformat 0x%x zformat 0x%x\n",
411 spu.init.id,
412 cmd->width,
413 cmd->height,
414 cmd->color_start,
415 cmd->color_format,
416 cmd->depth_format);
417
418 ASSERT_ALIGN16(cmd->color_start);
419 ASSERT_ALIGN16(cmd->depth_start);
420
421 spu.fb.color_start = cmd->color_start;
422 spu.fb.depth_start = cmd->depth_start;
423 spu.fb.color_format = cmd->color_format;
424 spu.fb.depth_format = cmd->depth_format;
425 spu.fb.width = cmd->width;
426 spu.fb.height = cmd->height;
427 spu.fb.width_tiles = (spu.fb.width + TILE_SIZE - 1) / TILE_SIZE;
428 spu.fb.height_tiles = (spu.fb.height + TILE_SIZE - 1) / TILE_SIZE;
429
430 if (spu.fb.depth_format == PIPE_FORMAT_Z32_UNORM)
431 spu.fb.zsize = 4;
432 else if (spu.fb.depth_format == PIPE_FORMAT_Z16_UNORM)
433 spu.fb.zsize = 2;
434 else
435 spu.fb.zsize = 0;
436 }
437
438
439 static void
440 cmd_state_depth_stencil(const struct pipe_depth_stencil_alpha_state *state)
441 {
442 if (Debug)
443 printf("SPU %u: DEPTH_STENCIL: ztest %d\n",
444 spu.init.id,
445 state->depth.enabled);
446
447 memcpy(&spu.depth_stencil, state, sizeof(*state));
448 }
449
450
451 static void
452 cmd_state_sampler(const struct pipe_sampler_state *state)
453 {
454 if (Debug)
455 printf("SPU %u: SAMPLER\n",
456 spu.init.id);
457
458 memcpy(&spu.sampler[0], state, sizeof(*state));
459 }
460
461
462 static void
463 cmd_state_texture(const struct cell_command_texture *texture)
464 {
465 if (Debug)
466 printf("SPU %u: TEXTURE at %p size %u x %u\n",
467 spu.init.id, texture->start, texture->width, texture->height);
468
469 memcpy(&spu.texture, texture, sizeof(*texture));
470 }
471
472
473 static void
474 cmd_state_vertex_info(const struct vertex_info *vinfo)
475 {
476 if (Debug) {
477 printf("SPU %u: VERTEX_INFO num_attribs=%u\n", spu.init.id,
478 vinfo->num_attribs);
479 }
480 ASSERT(vinfo->num_attribs >= 1);
481 ASSERT(vinfo->num_attribs <= 8);
482 memcpy(&spu.vertex_info, vinfo, sizeof(*vinfo));
483 }
484
485
486
487 static void
488 cmd_finish(void)
489 {
490 if (Debug)
491 printf("SPU %u: FINISH\n", spu.init.id);
492 really_clear_tiles(0);
493 /* wait for all outstanding DMAs to finish */
494 mfc_write_tag_mask(~0);
495 mfc_read_tag_status_all();
496 /* send mbox message to PPU */
497 spu_write_out_mbox(CELL_CMD_FINISH);
498 }
499
500
501 /**
502 * Execute a batch of commands
503 * The opcode param encodes the location of the buffer and its size.
504 */
505 static void
506 cmd_batch(uint opcode)
507 {
508 const uint buf = (opcode >> 8) & 0xff;
509 uint size = (opcode >> 16);
510 uint buffer[CELL_BUFFER_SIZE / 4] ALIGN16_ATTRIB;
511 const uint usize = size / sizeof(uint);
512 uint pos;
513
514 if (Debug)
515 printf("SPU %u: BATCH buffer %u, len %u, from %p\n",
516 spu.init.id, buf, size, spu.init.buffers[buf]);
517
518 ASSERT((opcode & CELL_CMD_OPCODE_MASK) == CELL_CMD_BATCH);
519
520 ASSERT_ALIGN16(spu.init.buffers[buf]);
521
522 size = ROUNDUP16(size);
523
524 ASSERT_ALIGN16(spu.init.buffers[buf]);
525
526 mfc_get(buffer, /* dest */
527 (unsigned int) spu.init.buffers[buf], /* src */
528 size,
529 TAG_BATCH_BUFFER,
530 0, /* tid */
531 0 /* rid */);
532 wait_on_mask(1 << TAG_BATCH_BUFFER);
533
534 /* Tell PPU we're done copying the buffer to local store */
535 if (Debug)
536 printf("SPU %u: release batch buf %u\n", spu.init.id, buf);
537 release_buffer(buf);
538
539 for (pos = 0; pos < usize; /* no incr */) {
540 switch (buffer[pos]) {
541 case CELL_CMD_STATE_FRAMEBUFFER:
542 {
543 struct cell_command_framebuffer *fb
544 = (struct cell_command_framebuffer *) &buffer[pos];
545 cmd_state_framebuffer(fb);
546 pos += sizeof(*fb) / 4;
547 }
548 break;
549 case CELL_CMD_CLEAR_SURFACE:
550 {
551 struct cell_command_clear_surface *clr
552 = (struct cell_command_clear_surface *) &buffer[pos];
553 cmd_clear_surface(clr);
554 pos += sizeof(*clr) / 4;
555 }
556 break;
557 case CELL_CMD_RENDER:
558 {
559 struct cell_command_render *render
560 = (struct cell_command_render *) &buffer[pos];
561 uint pos_incr;
562 cmd_render(render, &pos_incr);
563 pos += sizeof(*render) / 4 + pos_incr;
564 }
565 break;
566 case CELL_CMD_RELEASE_VERTS:
567 {
568 struct cell_command_release_verts *release
569 = (struct cell_command_release_verts *) &buffer[pos];
570 cmd_release_verts(release);
571 ASSERT(sizeof(*release) == 8);
572 pos += sizeof(*release) / 4;
573 }
574 break;
575 case CELL_CMD_FINISH:
576 cmd_finish();
577 pos += 1;
578 break;
579 case CELL_CMD_STATE_DEPTH_STENCIL:
580 cmd_state_depth_stencil((struct pipe_depth_stencil_alpha_state *)
581 &buffer[pos+1]);
582 pos += (1 + sizeof(struct pipe_depth_stencil_alpha_state) / 4);
583 break;
584 case CELL_CMD_STATE_SAMPLER:
585 cmd_state_sampler((struct pipe_sampler_state *) &buffer[pos+1]);
586 pos += (1 + sizeof(struct pipe_sampler_state) / 4);
587 break;
588 case CELL_CMD_STATE_TEXTURE:
589 cmd_state_texture((struct cell_command_texture *) &buffer[pos+1]);
590 pos += (1 + sizeof(struct cell_command_texture) / 4);
591 break;
592 case CELL_CMD_STATE_VERTEX_INFO:
593 cmd_state_vertex_info((struct vertex_info *) &buffer[pos+1]);
594 pos += (1 + sizeof(struct vertex_info) / 4);
595 break;
596 default:
597 printf("SPU %u: bad opcode: 0x%x\n", spu.init.id, buffer[pos]);
598 ASSERT(0);
599 break;
600 }
601 }
602
603 if (Debug)
604 printf("SPU %u: BATCH complete\n", spu.init.id);
605 }
606
607
608 /**
609 * Temporary/simple main loop for SPEs: Get a command, execute it, repeat.
610 */
611 static void
612 main_loop(void)
613 {
614 struct cell_command cmd;
615 int exitFlag = 0;
616
617 if (Debug)
618 printf("SPU %u: Enter main loop\n", spu.init.id);
619
620 ASSERT((sizeof(struct cell_command) & 0xf) == 0);
621 ASSERT_ALIGN16(&cmd);
622
623 while (!exitFlag) {
624 unsigned opcode;
625 int tag = 0;
626
627 if (Debug)
628 printf("SPU %u: Wait for cmd...\n", spu.init.id);
629
630 /* read/wait from mailbox */
631 opcode = (unsigned int) spu_read_in_mbox();
632
633 if (Debug)
634 printf("SPU %u: got cmd 0x%x\n", spu.init.id, opcode);
635
636 /* command payload */
637 mfc_get(&cmd, /* dest */
638 (unsigned int) spu.init.cmd, /* src */
639 sizeof(struct cell_command), /* bytes */
640 tag,
641 0, /* tid */
642 0 /* rid */);
643 wait_on_mask( 1 << tag );
644
645 switch (opcode & CELL_CMD_OPCODE_MASK) {
646 case CELL_CMD_EXIT:
647 if (Debug)
648 printf("SPU %u: EXIT\n", spu.init.id);
649 exitFlag = 1;
650 break;
651 case CELL_CMD_STATE_FRAMEBUFFER:
652 cmd_state_framebuffer(&cmd.fb);
653 break;
654 case CELL_CMD_CLEAR_SURFACE:
655 cmd_clear_surface(&cmd.clear);
656 break;
657 case CELL_CMD_RENDER:
658 {
659 uint pos_incr;
660 cmd_render(&cmd.render, &pos_incr);
661 assert(pos_incr == 0);
662 }
663 break;
664 case CELL_CMD_BATCH:
665 cmd_batch(opcode);
666 break;
667 case CELL_CMD_FINISH:
668 cmd_finish();
669 break;
670 default:
671 printf("Bad opcode!\n");
672 }
673
674 }
675
676 if (Debug)
677 printf("SPU %u: Exit main loop\n", spu.init.id);
678 }
679
680
681
682 static void
683 one_time_init(void)
684 {
685 memset(tile_status, TILE_STATUS_DEFINED, sizeof(tile_status));
686 memset(tile_status_z, TILE_STATUS_DEFINED, sizeof(tile_status_z));
687 invalidate_tex_cache();
688 }
689
690
691 /* In some versions of the SDK the SPE main takes 'unsigned long' as a
692 * parameter. In others it takes 'unsigned long long'. Use a define to
693 * select between the two.
694 */
695 #ifdef SPU_MAIN_PARAM_LONG_LONG
696 typedef unsigned long long main_param_t;
697 #else
698 typedef unsigned long main_param_t;
699 #endif
700
701 /**
702 * SPE entrypoint.
703 */
704 int
705 main(main_param_t speid, main_param_t argp)
706 {
707 int tag = 0;
708
709 (void) speid;
710
711 one_time_init();
712
713 if (Debug)
714 printf("SPU: main() speid=%lu\n", speid);
715
716 mfc_get(&spu.init, /* dest */
717 (unsigned int) argp, /* src */
718 sizeof(struct cell_init_info), /* bytes */
719 tag,
720 0, /* tid */
721 0 /* rid */);
722 wait_on_mask( 1 << tag );
723
724
725 main_loop();
726
727 return 0;
728 }