gfx.c 5.16 KB
#include <assert.h>

#include "sysapp.h"
#include "gfx.h"

/* Size of message to display */
#define TEX_MSG_W 160
#define TEX_MSG_H 96

u16 cfb[SCREEN_WD*SCREEN_HT] __attribute__((aligned(64)));

/* Memory to hold the texture - we only have one message to display at a time */
static unsigned char gTexture[TEX_MSG_W*TEX_MSG_H*2] __attribute__ ((aligned(16)));

static Gfx                *gpGfxList;
static GFXInfo             gpGfxInfo[1];

static OSMesgQueue	rdpMessageQ;
static OSMesg		rdpMessageBuf, dummyMessage;

/* Derived from viewer's initGFX in gfx.c */
void initGFX(void) 
{   
    osCreateMesgQueue(&rdpMessageQ, &rdpMessageBuf, 1);
    osSetEventMesg(OS_EVENT_DP, &rdpMessageQ, dummyMessage);

    gpGfxInfo[0].cfb = cfb;
}

/* Derived from viewer's drawTexRect in texrect.c */
void drawTexRect(void* texMem, 
                 u32 txlfmt, u32 txlsz,
                 u32 texwd, u32 texht, 
                 u32 tilewd, u32 tileht, 
                 f32 posx, f32 posy )
{
    int x, y, x0, y0, x1, y1;
    int sld0, tld0, sld1, tld1;
    float s, t;

    /* Only support G_IM_SIZ_16b */
    assert(txlsz == G_IM_SIZ_16b);

    gSPDisplayList(gpGfxList++, rdpinit_dl);

    for( x = 0; x < texwd; x += tilewd ) {
        for( y = 0; y < texht; y += tileht ) {
          /* texture coordinates */
          s = x ? (float)x - 0.5 : 0.5;
          t = y ? (float)y - 0.5 : 0.5;

          /* load coordinates */
          sld0 = (x > 0) ? x - 1 : 0;
          sld1 = (x + tilewd >= texwd) ? texwd - 1: x + tilewd;
          tld0 = (y > 0) ? y - 1 : 0;
          tld1 = (y + tileht >= texht) ? texht - 1: y + tileht;

          /* do texture rectangle */
          x0 = posx + x;
          x1 = x0 + tilewd + 1;
          if( x1 > posx + texwd ) x1 = posx + texwd;
          y0 = posy + y;
          y1 = y0 + tileht + 1;
          if( y1 > posy + texht ) y1 = posy + texht; 

          // load texture
          gDPLoadTextureTile(gpGfxList++, texMem,
                             txlfmt, G_IM_SIZ_16b,  
                             texwd, texht, sld0, tld0, sld1, tld1,
                             0, G_TX_CLAMP, G_TX_CLAMP,
                             0, 0, G_TX_NOLOD, G_TX_NOLOD);

          // texture rectangle
          gSPTextureRectangle(gpGfxList++, x0<<2, y0<<2, x1<<2, y1<<2,
                              G_TX_RENDERTILE,
                              (int)(s*32) & 0xffff, (int)(t*32) & 0xffff,
                              1<<10, 1<<10 );
        }
    }
}

/* Derived from viewer's createGfxTask in gfx.c */
void createGfxTask(GFXInfo *i) 
{
    Dynamic *pDynamic;
    OSTask tlist;

    pDynamic = &i->dp;
    gpGfxList   = i->dp.glist;

    PRINTF("Setup display\n");
    gSPDisplayList(gpGfxList++, rdpinit_dl);
    gSPDisplayList(gpGfxList++, rspinit_dl);

    gDPPipeSync(gpGfxList++);
    gDPSetCycleType(gpGfxList++, G_CYC_FILL);
    gDPSetColorImage(gpGfxList++, G_IM_FMT_RGBA, G_IM_SIZ_16b, SCREEN_WD,
                     osVirtualToPhysical(i->cfb)); 
    gDPSetFillColor(gpGfxList++, (GPACK_RGBA5551(0, 0, 0, 1) << 16 | 
                   GPACK_RGBA5551(0, 0, 0, 1)));
    gDPFillRectangle(gpGfxList++, 0, 0, SCREEN_WD-1, SCREEN_HT-1);
    gDPPipeSync(gpGfxList++);

    drawTexRect( gTexture, 
                 G_IM_FMT_RGBA, G_IM_SIZ_16b,
                 TEX_MSG_W, TEX_MSG_H,  
                 32, 32,
                 (SCREEN_WD-TEX_MSG_W)/2, (SCREEN_HT-TEX_MSG_H)/2 );

    /**** Put an end on the top-level display list  ****/
    gDPFullSync(gpGfxList++);
    gSPEndDisplayList(gpGfxList++);

    /* build graphics task */
    PRINTF("Build graphics task\n");    
    tlist.t.data_ptr = (u64 *) pDynamic->glist;
    tlist.t.data_size = (s32)(gpGfxList - pDynamic->glist) * sizeof (Gfx);
    tlist.t.type = M_GFXTASK;
    tlist.t.flags = 0x0;
    tlist.t.ucode_boot = (u64 *)rspbootTextStart;
    tlist.t.ucode_boot_size = ((s32) rspbootTextEnd - (s32) rspbootTextStart);
    tlist.t.ucode = (u64 *) gspFast3DTextStart;
    tlist.t.ucode_data = (u64 *) gspFast3DDataStart;
    tlist.t.ucode_data_size = SP_UCODE_DATA_SIZE;
    tlist.t.dram_stack = (u64 *) dram_stack;
    tlist.t.dram_stack_size = SP_DRAM_STACK_SIZE8;
    tlist.t.output_buff = (u64 *) 0x0;
    tlist.t.output_buff_size = (u64 *) 0x0;
    tlist.t.yield_data_ptr = (u64 *) gfxYieldBuf;
    tlist.t.yield_data_size = OS_YIELD_DATA_SIZE;
    
    /* Flush all */
	osWritebackDCacheAll();

    /* Start task */
    PRINTF("Start task\n");    
    osSpTaskStart(&tlist);

    PRINTF("Wait for task completion\n");    
    /* wait for task completion (can ignore SP compeletion 
       and wait only for DP completion) */
    (void)osRecvMesg(&rdpMessageQ, &dummyMessage, OS_MESG_BLOCK);

    /* Setup to swap buffers */
    PRINTF("Swap buffers\n");    
    osViSwapBuffer((void *)i->cfb);
}

/* Unzips a textures and creates a GFX task for it */
int displayGzippedTexture(unsigned char gzTex[], int gzTexSize)
{
    int outsize;
    bzero(gTexture, sizeof(gTexture));
    PRINTF("Unzipping texture\n");
    outsize = expand_gzip( gzTex, gTexture, gzTexSize, sizeof(gTexture));
    if (outsize > 0) {
        PRINTF("Creating Gfx Task\n");
        createGfxTask(&gpGfxInfo[0]);
    }
    else {
        PRINTF("Error unzipping texture\n");
    }
    return outsize;
}