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 }