gfxrenderer.c 5.73 KB
#include <ultra64.h>
#include <PR/sched.h>
#include "gfxrenderer.h"
#include "uimain.h"

#define GLIST_LEN 512
typedef struct {
        Gfx     glist[GLIST_LEN];     /* buffer to hold top level display list */
} Dynamic;

typedef struct {
    OSScTask    task;
    Dynamic     dp;
    GFXMsg      msg;
    u16         *cfb;
} GFXInfo;

/* these are the static display lists */
extern Gfx      rspinit_dl[];
extern Gfx      rdpinit_dl[];
extern Gfx      clearcfb_dl[];

/* RSP address for the color frame buffer */
extern u16      cfb[][SCREEN_WD*SCREEN_HT];
extern u16      rsp_cfb[];

extern u64 dram_stack[]; /* used for matrix stack */

static OSMesgQueue gfxRendererMsgQ;
static OSMesg gfxRendererMsgBuf[MAX_MESGS];
static Gfx *glistp;
static GFXInfo gInfo[2];

static OSMesgQueue *schedCmdQ;
static u64 gfxRendererStack[STACKSIZEBYTES/8];
static OSScClient gfxClient;
static OSThread gfxRendererThread;

static void createGfxTask(GFXInfo *i, Sprite **sp);
static void gfxRendererProc(void *argv);

extern char _staticSegmentRomStart[], _staticSegmentRomEnd[];
extern char _codeSegmentEnd[];
static char *staticSegment;

#if __GNUC__ 
u64 dram_stack[SP_DRAM_STACK_SIZE64] __attribute__((aligned (16))); 
u64 gfxYieldBuf[OS_YIELD_DATA_SIZE/sizeof(u64)] __attribute__((aligned (16)));
#else 
u64 gfxYieldBuf[OS_YIELD_DATA_SIZE/sizeof(u64)];
u64 dram_stack[SP_DRAM_STACK_SIZE64];
#endif

OSMesgQueue *initGfxRenderer(OSSched *sc, OSPri pri)
{

    /*
     * Get the static display lists
     */
    u32 len = (u32)(_staticSegmentRomEnd - _staticSegmentRomStart);
    staticSegment = _codeSegmentEnd;
    romCopy(_staticSegmentRomStart, staticSegment, len);

    osCreateMesgQueue(&gfxRendererMsgQ, gfxRendererMsgBuf, MAX_MESGS);

    /**** Add ourselves to the scheduler to receive retrace messages ****/
    osScAddClient(sc, &gfxClient, &gfxRendererMsgQ);  

    schedCmdQ = osScGetCmdQ(sc);

    /*
     * Start the rendering thread
     */
    osCreateThread(&gfxRendererThread, 6, gfxRendererProc, NULL, gfxRendererStack + 
		   (STACKSIZEBYTES/sizeof(u64)), pri);

    osStartThread(&gfxRendererThread);

    return &gfxRendererMsgQ;

}

static void gfxRendererProc(void *argv)
{
    u32 drawBuffer = 0;
    u32 pendingGFX = 0;
    GFXMsg *msg = NULL;
    Sprite **newSp;

    /*
     * Scheduler reply messages
     */
    gInfo[0].msg.sched.type = OS_SC_DONE_MSG;
    gInfo[1].msg.sched.type = OS_SC_DONE_MSG;

    /*
     * Frame buffers
     */
    gInfo[0].cfb = cfb[0];
    gInfo[1].cfb = cfb[1];

    while (1) {
        (void) osRecvMesg(&gfxRendererMsgQ, (OSMesg *)&msg, OS_MESG_BLOCK);

        switch (msg->sched.type) {

        case (GFX_NEW_FRAME):
            /*
             * Got a new list of sprites to do
             */
            newSp = msg->gfx.spList;
            break;
        case (OS_SC_RETRACE_MSG):

            /**** Create a new gfx task unless we already have 2  ****/                                if (pendingGFX < 2) {
                createGfxTask(&gInfo[drawBuffer], newSp);
                pendingGFX++;
                drawBuffer ^= 1; /* switch the drawbuffer */
            }
        break;

        case (OS_SC_DONE_MSG):
            pendingGFX--;        /* decrement number of pending tasks */
            break;
                
        case (OS_SC_PRE_NMI_MSG): /* stop creation of graphics tasks */
            pendingGFX += 2;
            break;
	default:
#ifdef DEBUG
	    PRINTF("Unknown message %d\n", msg->sched.type);
#endif
	    break;
        }
    }
}

static void createGfxTask(GFXInfo *i, Sprite **psp) 
{
    Dynamic *dynamicp;
    OSScTask *t;
    Gfx *gp, *dl;
    Sprite *sp;

    /**** pointers to build the display list. ****/
    dynamicp = &i->dp;
    glistp   = i->dp.glist;

    /**** Tell RCP where each segment is  ****/
    gSPSegment(glistp++, 0, 0);	/* physical addressing segment */
    gSPSegment(glistp++, STATIC_SEGMENT,  osVirtualToPhysical(staticSegment));
    gSPSegment(glistp++, CFB_SEGMENT, OS_K0_TO_PHYSICAL(i->cfb));

    /*
     * Initialize RDP and RSP state, clear FB
     */
    gSPDisplayList(glistp++, rdpinit_dl);
    gSPDisplayList(glistp++, rspinit_dl);
    gSPDisplayList(glistp++, clearcfb_dl);

    /*
     * Render all the sprites - XXX just one for now
     */
    gp = glistp;
    spInit(&gp);

    while (*psp) {
        sp = *psp++;
        sp->rsp_dl_next = sp->rsp_dl;

        dl = spDraw(sp);
        gSPDisplayList(gp++, dl);
    }

    spFinish(&gp);
    /*
     * XXX What is this for?
     */
    gp--;

    gDPFullSync(gp++);
    gSPEndDisplayList(gp++);


    /* Flush the dynamic segment */
    osWritebackDCacheAll();

    /* build graphics task */

    t = &i->task;
    t->list.t.data_ptr = (u64 *) dynamicp->glist;
    t->list.t.data_size = (s32)(glistp - dynamicp->glist) * sizeof (Gfx);
    t->list.t.type = M_GFXTASK;
    t->list.t.flags = 0x0;
    t->list.t.ucode_boot = (u64 *)rspbootTextStart;
    t->list.t.ucode_boot_size = ((s32) rspbootTextEnd - 
				 (s32) rspbootTextStart);
    t->list.t.ucode = (u64 *) gspF3DEX2_xbusTextStart;
    t->list.t.ucode_data = (u64 *) gspF3DEX2_xbusDataStart;
    t->list.t.ucode_data_size = SP_UCODE_DATA_SIZE;
    t->list.t.dram_stack = (u64 *) dram_stack;
    t->list.t.dram_stack_size = SP_DRAM_STACK_SIZE8;
    t->list.t.output_buff = (u64 *) 0x0;
    t->list.t.output_buff_size = (u64 *) 0x0;
    t->list.t.yield_data_ptr = (u64 *) gfxYieldBuf;
    t->list.t.yield_data_size = OS_YIELD_DATA_SIZE;

    t->next     = 0;                   /* paranoia */
    t->flags	= (OS_SC_NEEDS_RSP | OS_SC_NEEDS_RDP | OS_SC_LAST_TASK |
		   OS_SC_SWAPBUFFER);
    t->msgQ     = &gfxRendererMsgQ;       /* reply to when finished */
    t->msg      = (OSMesg)&i->msg;     /* reply with this message */
    t->framebuffer = (void *)i->cfb;

    osSendMesg(schedCmdQ, (OSMesg) t, OS_MESG_BLOCK); 
    
}