00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include <stdio.h>
00033 #include <libmisc.h>
00034
00035 #include "spu_main.h"
00036 #include "spu_render.h"
00037 #include "spu_per_fragment_op.h"
00038 #include "spu_texture.h"
00039 #include "spu_tile.h"
00040
00041 #include "spu_vertex_shader.h"
00042 #include "spu_dcache.h"
00043 #include "cell/common.h"
00044 #include "pipe/p_defines.h"
00045
00046
00047
00048
00049
00050
00051
00052
00053 boolean Debug = FALSE;
00054
00055 struct spu_global spu;
00056
00057 struct spu_vs_context draw;
00058
00059
00063 static unsigned char attribute_fetch_code_buffer[136 * PIPE_MAX_ATTRIBS]
00064 ALIGN16_ATTRIB;
00065
00066
00067
00074 static void
00075 release_buffer(uint buffer)
00076 {
00077
00078 static const uint status[4] ALIGN16_ATTRIB
00079 = {CELL_BUFFER_STATUS_FREE, 0, 0, 0};
00080
00081 const uint index = 4 * (spu.init.id * CELL_NUM_BUFFERS + buffer);
00082 uint *dst = spu.init.buffer_status + index;
00083
00084 ASSERT(buffer < CELL_NUM_BUFFERS);
00085
00086 mfc_put((void *) &status,
00087 (unsigned int) dst,
00088 sizeof(status),
00089 TAG_MISC,
00090 0,
00091 0 );
00092 }
00093
00094
00099 static void
00100 really_clear_tiles(uint surfaceIndex)
00101 {
00102 const uint num_tiles = spu.fb.width_tiles * spu.fb.height_tiles;
00103 uint i;
00104
00105 if (surfaceIndex == 0) {
00106 clear_c_tile(&spu.ctile);
00107
00108 for (i = spu.init.id; i < num_tiles; i += spu.init.num_spus) {
00109 uint tx = i % spu.fb.width_tiles;
00110 uint ty = i / spu.fb.width_tiles;
00111 if (spu.ctile_status[ty][tx] == TILE_STATUS_CLEAR) {
00112 put_tile(tx, ty, &spu.ctile, TAG_SURFACE_CLEAR, 0);
00113 }
00114 }
00115 }
00116 else {
00117 clear_z_tile(&spu.ztile);
00118
00119 for (i = spu.init.id; i < num_tiles; i += spu.init.num_spus) {
00120 uint tx = i % spu.fb.width_tiles;
00121 uint ty = i / spu.fb.width_tiles;
00122 if (spu.ztile_status[ty][tx] == TILE_STATUS_CLEAR)
00123 put_tile(tx, ty, &spu.ctile, TAG_SURFACE_CLEAR, 1);
00124 }
00125 }
00126
00127 #if 0
00128 wait_on_mask(1 << TAG_SURFACE_CLEAR);
00129 #endif
00130 }
00131
00132
00133 static void
00134 cmd_clear_surface(const struct cell_command_clear_surface *clear)
00135 {
00136 if (Debug)
00137 printf("SPU %u: CLEAR SURF %u to 0x%08x\n", spu.init.id,
00138 clear->surface, clear->value);
00139
00140 if (clear->surface == 0) {
00141 spu.fb.color_clear_value = clear->value;
00142 if (spu.init.debug_flags & CELL_DEBUG_CHECKER) {
00143 uint x = (spu.init.id << 4) | (spu.init.id << 12) |
00144 (spu.init.id << 20) | (spu.init.id << 28);
00145 spu.fb.color_clear_value ^= x;
00146 }
00147 }
00148 else {
00149 spu.fb.depth_clear_value = clear->value;
00150 }
00151
00152 #define CLEAR_OPT 1
00153 #if CLEAR_OPT
00154
00155
00156
00157
00158
00159
00160 if (clear->surface == 0) {
00161 memset(spu.ctile_status, TILE_STATUS_CLEAR, sizeof(spu.ctile_status));
00162 }
00163 else {
00164 memset(spu.ztile_status, TILE_STATUS_CLEAR, sizeof(spu.ztile_status));
00165 }
00166
00167 #else
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179 if (clear->surface == 0) {
00180 clear_c_tile(&spu.ctile);
00181 }
00182 else {
00183 clear_z_tile(&spu.ztile);
00184 }
00185
00186
00187 {
00188 const uint num_tiles = spu.fb.width_tiles * spu.fb.height_tiles;
00189 uint i;
00190 for (i = spu.init.id; i < num_tiles; i += spu.init.num_spus) {
00191 uint tx = i % spu.fb.width_tiles;
00192 uint ty = i / spu.fb.width_tiles;
00193 if (clear->surface == 0)
00194 put_tile(tx, ty, &spu.ctile, TAG_SURFACE_CLEAR, 0);
00195 else
00196 put_tile(tx, ty, &spu.ztile, TAG_SURFACE_CLEAR, 1);
00197 }
00198 }
00199
00200 if (spu.init.debug_flags & CELL_DEBUG_SYNC) {
00201 wait_on_mask(1 << TAG_SURFACE_CLEAR);
00202 }
00203
00204 #endif
00205
00206 if (Debug)
00207 printf("SPU %u: CLEAR SURF done\n", spu.init.id);
00208 }
00209
00210
00211 static void
00212 cmd_release_verts(const struct cell_command_release_verts *release)
00213 {
00214 if (Debug)
00215 printf("SPU %u: RELEASE VERTS %u\n",
00216 spu.init.id, release->vertex_buf);
00217 ASSERT(release->vertex_buf != ~0U);
00218 release_buffer(release->vertex_buf);
00219 }
00220
00221
00228 static void
00229 cmd_state_fragment_ops(const struct cell_command_fragment_ops *fops)
00230 {
00231 if (Debug)
00232 printf("SPU %u: CMD_STATE_FRAGMENT_OPS\n", spu.init.id);
00233
00234 memcpy(spu.fragment_ops_code, fops->code, SPU_MAX_FRAGMENT_OPS_INSTS * 4);
00235
00236 memcpy(&spu.depth_stencil_alpha, &fops->dsa, sizeof(fops->dsa));
00237 memcpy(&spu.blend, &fops->blend, sizeof(fops->blend));
00238
00239
00240 spu.fragment_ops = (spu_fragment_ops_func) spu.fragment_ops_code;
00241
00242 spu.read_depth = spu.depth_stencil_alpha.depth.enabled;
00243 spu.read_stencil = spu.depth_stencil_alpha.stencil[0].enabled;
00244 }
00245
00246
00247 static void
00248 cmd_state_fragment_program(const struct cell_command_fragment_program *fp)
00249 {
00250 if (Debug)
00251 printf("SPU %u: CMD_STATE_FRAGMENT_PROGRAM\n", spu.init.id);
00252
00253 memcpy(spu.fragment_program_code, fp->code,
00254 SPU_MAX_FRAGMENT_PROGRAM_INSTS * 4);
00255 #if 01
00256
00257 spu.fragment_program = (spu_fragment_program_func)spu.fragment_program_code;
00258 #endif
00259 }
00260
00261
00262 static void
00263 cmd_state_framebuffer(const struct cell_command_framebuffer *cmd)
00264 {
00265 if (Debug)
00266 printf("SPU %u: FRAMEBUFFER: %d x %d at %p, cformat 0x%x zformat 0x%x\n",
00267 spu.init.id,
00268 cmd->width,
00269 cmd->height,
00270 cmd->color_start,
00271 cmd->color_format,
00272 cmd->depth_format);
00273
00274 ASSERT_ALIGN16(cmd->color_start);
00275 ASSERT_ALIGN16(cmd->depth_start);
00276
00277 spu.fb.color_start = cmd->color_start;
00278 spu.fb.depth_start = cmd->depth_start;
00279 spu.fb.color_format = cmd->color_format;
00280 spu.fb.depth_format = cmd->depth_format;
00281 spu.fb.width = cmd->width;
00282 spu.fb.height = cmd->height;
00283 spu.fb.width_tiles = (spu.fb.width + TILE_SIZE - 1) / TILE_SIZE;
00284 spu.fb.height_tiles = (spu.fb.height + TILE_SIZE - 1) / TILE_SIZE;
00285
00286 switch (spu.fb.depth_format) {
00287 case PIPE_FORMAT_Z32_UNORM:
00288 spu.fb.zsize = 4;
00289 spu.fb.zscale = (float) 0xffffffffu;
00290 break;
00291 case PIPE_FORMAT_Z24S8_UNORM:
00292 case PIPE_FORMAT_S8Z24_UNORM:
00293 case PIPE_FORMAT_Z24X8_UNORM:
00294 case PIPE_FORMAT_X8Z24_UNORM:
00295 spu.fb.zsize = 4;
00296 spu.fb.zscale = (float) 0x00ffffffu;
00297 break;
00298 case PIPE_FORMAT_Z16_UNORM:
00299 spu.fb.zsize = 2;
00300 spu.fb.zscale = (float) 0xffffu;
00301 break;
00302 default:
00303 spu.fb.zsize = 0;
00304 break;
00305 }
00306 }
00307
00308
00309 static void
00310 cmd_state_sampler(const struct cell_command_sampler *sampler)
00311 {
00312 if (Debug)
00313 printf("SPU %u: SAMPLER [%u]\n",
00314 spu.init.id, sampler->unit);
00315
00316 spu.sampler[sampler->unit] = sampler->state;
00317 if (spu.sampler[sampler->unit].min_img_filter == PIPE_TEX_FILTER_LINEAR)
00318 spu.sample_texture[sampler->unit] = sample_texture_bilinear;
00319 else
00320 spu.sample_texture[sampler->unit] = sample_texture_nearest;
00321 }
00322
00323
00324 static void
00325 cmd_state_texture(const struct cell_command_texture *texture)
00326 {
00327 const uint unit = texture->unit;
00328 const uint width = texture->width;
00329 const uint height = texture->height;
00330
00331 if (Debug) {
00332 printf("SPU %u: TEXTURE [%u] at %p size %u x %u\n", spu.init.id,
00333 texture->unit, texture->start,
00334 texture->width, texture->height);
00335 }
00336
00337 spu.texture[unit].start = texture->start;
00338 spu.texture[unit].width = width;
00339 spu.texture[unit].height = height;
00340
00341 spu.texture[unit].tiles_per_row = width / TILE_SIZE;
00342
00343 spu.texture[unit].tex_size = (vector float) { width, height, 0.0, 0.0};
00344 spu.texture[unit].tex_size_mask = (vector unsigned int)
00345 { width - 1, height - 1, 0, 0 };
00346 spu.texture[unit].tex_size_x_mask = spu_splats(width - 1);
00347 spu.texture[unit].tex_size_y_mask = spu_splats(height - 1);
00348 }
00349
00350
00351 static void
00352 cmd_state_vertex_info(const struct vertex_info *vinfo)
00353 {
00354 if (Debug) {
00355 printf("SPU %u: VERTEX_INFO num_attribs=%u\n", spu.init.id,
00356 vinfo->num_attribs);
00357 }
00358 ASSERT(vinfo->num_attribs >= 1);
00359 ASSERT(vinfo->num_attribs <= 8);
00360 memcpy(&spu.vertex_info, vinfo, sizeof(*vinfo));
00361 }
00362
00363
00364 static void
00365 cmd_state_vs_array_info(const struct cell_array_info *vs_info)
00366 {
00367 const unsigned attr = vs_info->attr;
00368
00369 ASSERT(attr < PIPE_MAX_ATTRIBS);
00370 draw.vertex_fetch.src_ptr[attr] = vs_info->base;
00371 draw.vertex_fetch.pitch[attr] = vs_info->pitch;
00372 draw.vertex_fetch.size[attr] = vs_info->size;
00373 draw.vertex_fetch.code_offset[attr] = vs_info->function_offset;
00374 draw.vertex_fetch.dirty = 1;
00375 }
00376
00377
00378 static void
00379 cmd_state_attrib_fetch(const struct cell_attribute_fetch_code *code)
00380 {
00381 mfc_get(attribute_fetch_code_buffer,
00382 (unsigned int) code->base,
00383 code->size,
00384 TAG_BATCH_BUFFER,
00385 0,
00386 0 );
00387 wait_on_mask(1 << TAG_BATCH_BUFFER);
00388
00389 draw.vertex_fetch.code = attribute_fetch_code_buffer;
00390 }
00391
00392
00393 static void
00394 cmd_finish(void)
00395 {
00396 if (Debug)
00397 printf("SPU %u: FINISH\n", spu.init.id);
00398 really_clear_tiles(0);
00399
00400 mfc_write_tag_mask(~0);
00401 mfc_read_tag_status_all();
00402
00403 spu_write_out_mbox(CELL_CMD_FINISH);
00404 }
00405
00406
00413 static void
00414 cmd_batch(uint opcode)
00415 {
00416 const uint buf = (opcode >> 8) & 0xff;
00417 uint size = (opcode >> 16);
00418 uint64_t buffer[CELL_BUFFER_SIZE / 8] ALIGN16_ATTRIB;
00419 const unsigned usize = size / sizeof(buffer[0]);
00420 uint pos;
00421
00422 if (Debug)
00423 printf("SPU %u: BATCH buffer %u, len %u, from %p\n",
00424 spu.init.id, buf, size, spu.init.buffers[buf]);
00425
00426 ASSERT((opcode & CELL_CMD_OPCODE_MASK) == CELL_CMD_BATCH);
00427
00428 ASSERT_ALIGN16(spu.init.buffers[buf]);
00429
00430 size = ROUNDUP16(size);
00431
00432 ASSERT_ALIGN16(spu.init.buffers[buf]);
00433
00434 mfc_get(buffer,
00435 (unsigned int) spu.init.buffers[buf],
00436 size,
00437 TAG_BATCH_BUFFER,
00438 0,
00439 0 );
00440 wait_on_mask(1 << TAG_BATCH_BUFFER);
00441
00442
00443 if (Debug)
00444 printf("SPU %u: release batch buf %u\n", spu.init.id, buf);
00445 release_buffer(buf);
00446
00447
00448
00449
00450 for (pos = 0; pos < usize; ) {
00451 switch (buffer[pos]) {
00452
00453
00454
00455 case CELL_CMD_CLEAR_SURFACE:
00456 {
00457 struct cell_command_clear_surface *clr
00458 = (struct cell_command_clear_surface *) &buffer[pos];
00459 cmd_clear_surface(clr);
00460 pos += sizeof(*clr) / 8;
00461 }
00462 break;
00463 case CELL_CMD_RENDER:
00464 {
00465 struct cell_command_render *render
00466 = (struct cell_command_render *) &buffer[pos];
00467 uint pos_incr;
00468 cmd_render(render, &pos_incr);
00469 pos += pos_incr;
00470 }
00471 break;
00472
00473
00474
00475 case CELL_CMD_STATE_FRAMEBUFFER:
00476 {
00477 struct cell_command_framebuffer *fb
00478 = (struct cell_command_framebuffer *) &buffer[pos];
00479 cmd_state_framebuffer(fb);
00480 pos += sizeof(*fb) / 8;
00481 }
00482 break;
00483 case CELL_CMD_STATE_FRAGMENT_OPS:
00484 {
00485 struct cell_command_fragment_ops *fops
00486 = (struct cell_command_fragment_ops *) &buffer[pos];
00487 cmd_state_fragment_ops(fops);
00488 pos += sizeof(*fops) / 8;
00489 }
00490 break;
00491 case CELL_CMD_STATE_FRAGMENT_PROGRAM:
00492 {
00493 struct cell_command_fragment_program *fp
00494 = (struct cell_command_fragment_program *) &buffer[pos];
00495 cmd_state_fragment_program(fp);
00496 pos += sizeof(*fp) / 8;
00497 }
00498 break;
00499 case CELL_CMD_STATE_SAMPLER:
00500 {
00501 struct cell_command_sampler *sampler
00502 = (struct cell_command_sampler *) &buffer[pos];
00503 cmd_state_sampler(sampler);
00504 pos += sizeof(*sampler) / 8;
00505 }
00506 break;
00507 case CELL_CMD_STATE_TEXTURE:
00508 {
00509 struct cell_command_texture *texture
00510 = (struct cell_command_texture *) &buffer[pos];
00511 cmd_state_texture(texture);
00512 pos += sizeof(*texture) / 8;
00513 }
00514 break;
00515 case CELL_CMD_STATE_VERTEX_INFO:
00516 cmd_state_vertex_info((struct vertex_info *) &buffer[pos+1]);
00517 pos += (1 + ROUNDUP8(sizeof(struct vertex_info)) / 8);
00518 break;
00519 case CELL_CMD_STATE_VIEWPORT:
00520 (void) memcpy(& draw.viewport, &buffer[pos+1],
00521 sizeof(struct pipe_viewport_state));
00522 pos += (1 + ROUNDUP8(sizeof(struct pipe_viewport_state)) / 8);
00523 break;
00524 case CELL_CMD_STATE_UNIFORMS:
00525 draw.constants = (const float (*)[4]) (uintptr_t) buffer[pos + 1];
00526 pos += 2;
00527 break;
00528 case CELL_CMD_STATE_VS_ARRAY_INFO:
00529 cmd_state_vs_array_info((struct cell_array_info *) &buffer[pos+1]);
00530 pos += (1 + ROUNDUP8(sizeof(struct cell_array_info)) / 8);
00531 break;
00532 case CELL_CMD_STATE_BIND_VS:
00533 #if 0
00534 spu_bind_vertex_shader(&draw,
00535 (struct cell_shader_info *) &buffer[pos+1]);
00536 #endif
00537 pos += (1 + ROUNDUP8(sizeof(struct cell_shader_info)) / 8);
00538 break;
00539 case CELL_CMD_STATE_ATTRIB_FETCH:
00540 cmd_state_attrib_fetch((struct cell_attribute_fetch_code *)
00541 &buffer[pos+1]);
00542 pos += (1 + ROUNDUP8(sizeof(struct cell_attribute_fetch_code)) / 8);
00543 break;
00544
00545
00546
00547 case CELL_CMD_FINISH:
00548 cmd_finish();
00549 pos += 1;
00550 break;
00551 case CELL_CMD_RELEASE_VERTS:
00552 {
00553 struct cell_command_release_verts *release
00554 = (struct cell_command_release_verts *) &buffer[pos];
00555 cmd_release_verts(release);
00556 pos += sizeof(*release) / 8;
00557 }
00558 break;
00559 case CELL_CMD_FLUSH_BUFFER_RANGE: {
00560 struct cell_buffer_range *br = (struct cell_buffer_range *)
00561 &buffer[pos+1];
00562
00563 spu_dcache_mark_dirty((unsigned) br->base, br->size);
00564 pos += (1 + ROUNDUP8(sizeof(struct cell_buffer_range)) / 8);
00565 break;
00566 }
00567 default:
00568 printf("SPU %u: bad opcode: 0x%llx\n", spu.init.id, buffer[pos]);
00569 ASSERT(0);
00570 break;
00571 }
00572 }
00573
00574 if (Debug)
00575 printf("SPU %u: BATCH complete\n", spu.init.id);
00576 }
00577
00578
00582 static void
00583 main_loop(void)
00584 {
00585 struct cell_command cmd;
00586 int exitFlag = 0;
00587
00588 if (Debug)
00589 printf("SPU %u: Enter main loop\n", spu.init.id);
00590
00591 ASSERT((sizeof(struct cell_command) & 0xf) == 0);
00592 ASSERT_ALIGN16(&cmd);
00593
00594 while (!exitFlag) {
00595 unsigned opcode;
00596 int tag = 0;
00597
00598 if (Debug)
00599 printf("SPU %u: Wait for cmd...\n", spu.init.id);
00600
00601
00602 opcode = (unsigned int) spu_read_in_mbox();
00603
00604 if (Debug)
00605 printf("SPU %u: got cmd 0x%x\n", spu.init.id, opcode);
00606
00607
00608 mfc_get(&cmd,
00609 (unsigned int) spu.init.cmd,
00610 sizeof(struct cell_command),
00611 tag,
00612 0,
00613 0 );
00614 wait_on_mask( 1 << tag );
00615
00616
00617
00618
00619
00620 switch (opcode & CELL_CMD_OPCODE_MASK) {
00621 case CELL_CMD_EXIT:
00622 if (Debug)
00623 printf("SPU %u: EXIT\n", spu.init.id);
00624 exitFlag = 1;
00625 break;
00626 case CELL_CMD_VS_EXECUTE:
00627 #if 0
00628 spu_execute_vertex_shader(&draw, &cmd.vs);
00629 #endif
00630 break;
00631 case CELL_CMD_BATCH:
00632 cmd_batch(opcode);
00633 break;
00634 default:
00635 printf("Bad opcode!\n");
00636 }
00637
00638 }
00639
00640 if (Debug)
00641 printf("SPU %u: Exit main loop\n", spu.init.id);
00642
00643 spu_dcache_report();
00644 }
00645
00646
00647
00648 static void
00649 one_time_init(void)
00650 {
00651 memset(spu.ctile_status, TILE_STATUS_DEFINED, sizeof(spu.ctile_status));
00652 memset(spu.ztile_status, TILE_STATUS_DEFINED, sizeof(spu.ztile_status));
00653 invalidate_tex_cache();
00654
00655
00656
00657
00658 spu.fragment_ops = spu_fallback_fragment_ops;
00659 }
00660
00661
00662
00663
00664
00665
00666
00667 #ifdef SPU_MAIN_PARAM_LONG_LONG
00668 typedef unsigned long long main_param_t;
00669 #else
00670 typedef unsigned long main_param_t;
00671 #endif
00672
00676 int
00677 main(main_param_t speid, main_param_t argp)
00678 {
00679 int tag = 0;
00680
00681 (void) speid;
00682
00683 ASSERT(sizeof(tile_t) == TILE_SIZE * TILE_SIZE * 4);
00684 ASSERT(sizeof(struct cell_command_render) % 8 == 0);
00685
00686 one_time_init();
00687
00688 if (Debug)
00689 printf("SPU: main() speid=%lu\n", (unsigned long) speid);
00690
00691 mfc_get(&spu.init,
00692 (unsigned int) argp,
00693 sizeof(struct cell_init_info),
00694 tag,
00695 0,
00696 0 );
00697 wait_on_mask( 1 << tag );
00698
00699 #if 0
00700 if (spu.init.id==0)
00701 spu_test_misc();
00702 #endif
00703
00704 main_loop();
00705
00706 return 0;
00707 }