graphic.c 7.85 KB
/*============================================================================

		NINTENDO64 TECHNICAL SUPPORT CENTER 
		
		    NINTENDO64 SAMPLE PROGRAM 1

		Copyright (C) 1997, NINTENDO Co,Ltd.

============================================================================*/
#include <ultra64.h>
#include <PR/ramrom.h>
#include <assert.h>

#include "def.h"
#include "vram.h"
#include "segment.h"
#include "message.h"
#include "nnsched.h"
#include "graphic.h"

/* グラフィックマイクロコード */
u32 gfx_ucode[][2] = {
  {(u32)gspF3DEX2_fifoTextStart, (u32)gspF3DEX2_fifoDataStart},
  {(u32)gspL3DEX2_fifoTextStart, (u32)gspL3DEX2_fifoDataStart},
};

OSMesgQueue  gfx_msgQ;
OSMesg       gfx_msgbuf[GFX_MESGS_MAX];
NNScClient   gfx_client;
u32          gfx_cfbdrawbuffer = 0;
u32          graphic_no = GFX_NULL;
OSThread     gfxThread;

OSMesgQueue  *sched_gfxMQ;

GFXMsg       gfx_msg;
GFXMsg       gfx_msg_no;
u64          gfxThreadStack[STACKSIZE/sizeof(u64)];
NNScTask     gfx_task[GFX_GTASK_NUM];
Gfx          gfx_glist[GFX_GTASK_NUM][GFX_GLIST_LEN];
Dynamic      gfx_dynamic[GFX_GTASK_NUM];
Gfx*         glist_ptr;
u32          gfx_gtask_no;
CLookAt      lookat;
u32          pendingGFX = 0;
extern void  graphic_00(void);
extern void  graphic_01(void);


/*-----------------------------------------------------------------------------
  グラフィックパラメータの初期化
-----------------------------------------------------------------------------*/
void gfxInit(u8* gfxdlistStart_ptr)
{

  /* グラフィックタスク終了メッセージの設定 */
  gfx_msg.gen.type = NN_SC_DONE_MSG;  /* タスク終了とフレームバッファ切り替え
					   メッセージ */
  gfx_msg_no.gen.type = NN_SC_GTASKEND_MSG;  /* タスク終了のみのメッセージ */

  graphic_no = GFX_NULL; /* グラフィックスレッド分岐フラグの初期化 */
  gfx_gtask_no = 0;
}

/*-----------------------------------------------------------------------------
  グラフィックスレッド
-----------------------------------------------------------------------------*/
void gfxproc(void* arg)
{
  short* msg_type = NULL;

  pendingGFX = 0;
  /*  create message queue for VI reatrace */
  osCreateMesgQueue(&gfx_msgQ, gfx_msgbuf, GFX_MESGS_MAX);

  nnScAddClient((NNSched*)arg, &gfx_client, &gfx_msgQ);

  /* グラフィックメッセージキューの取得 */
  sched_gfxMQ = nnScGetGfxMQ((NNSched*)arg);

  /*
     グラフィック処理ループ
     SHVCでのNMI(V-SYNC)処理にあたる部分
  */
  while(1){
    (void)osRecvMesg(&gfx_msgQ,(OSMesg *)&msg_type, OS_MESG_BLOCK);

    switch(*msg_type){
    case NN_SC_RETRACE_MSG:    /* リトレースメッセージ処理 */

      switch(graphic_no){
      case GFX_00:   /* コントローラーモデル画面 */
	if(pendingGFX <2){
	  graphic_00();
	  pendingGFX++;
	}
	break;
      case GFX_01:  /* 戦闘機の画面 */
	if(pendingGFX <1){
	  graphic_01();
	  pendingGFX++;
	}
	break;
      case GFX_10:
      case GFX_20:
      case GFX_30:
      case GFX_NULL:
	break;
      }
      break;
    case NN_SC_DONE_MSG:   /* グラフィックタスク終了メッセージ */
      pendingGFX--;
      break;
    case NN_SC_PRE_NMI_MSG: /* PRE NMIメッセージ */
      /* PRE NMIメッセージの処理をここに書いてください */

      /* !!重要!! Yスケールを1.0に戻すこと */
      osViSetYScale(1.0);

      /* タスクを作成しないようにする */
      pendingGFX+=2;
      break;
    }
  }
}

/*-----------------------------------------------------------------------------
  グラフィックスレッドの作成と起動
-----------------------------------------------------------------------------*/
void gfxCreateGraphicThread(NNSched* sched)
{
  osCreateThread(&gfxThread, GRAPHIC_THREAD_ID, gfxproc,(void *) sched,
		 gfxThreadStack+STACKSIZE/sizeof(u64),
		 GRAPHIC_THREAD_PRI);
  osStartThread(&gfxThread);
}

/*----------------------------------------------------------------------------
  gfxWaitMessage

  スケジューラからのメッセージ待ち
  return :スケジューラからのメッセージの種類
          OS_SC_RETRACE_MSG    : リトレースメッセージ
	  OS_SC_PRE_NMI_MSG    :  PRE NMIメッセージ
----------------------------------------------------------------------------*/
short gfxWaitMessage(void)
{
  short* msg_type = NULL;
  (void)osRecvMesg(&gfx_msgQ,(OSMesg *)&msg_type, OS_MESG_BLOCK);
  return *msg_type;
}
/*----------------------------------------------------------------------------
  gfxSendMessage

  スケジューラにグラフィックタスク起動メッセージを送る
  NNScTask *gtask     :タスク構造体
  Gfx*        glist_ptr :ディスプレイリストのポインタ
  s32         glsit_size:ディスプレイリストサイズ
  u32         ucode_type:マイクロコードの種類(graphic.h参照)
  u32         flag      :フレームバッファ変更フラグ
----------------------------------------------------------------------------*/
void gfxTaskStart(NNScTask *gtask,Gfx* glist_ptr, s32 glist_size,
		    u32 ucode_type, u32 flag)
{

  gtask->list.t.data_ptr = (u64 *)glist_ptr;
  gtask->list.t.data_size = glist_size;

  gtask->list.t.type = M_GFXTASK;
  gtask->list.t.flags = 0x0;
  gtask->list.t.ucode_boot = (u64 *)rspbootTextStart;
  gtask->list.t.ucode_boot_size = ((s32) rspbootTextEnd 
				  - (s32) rspbootTextStart);
  gtask->list.t.ucode =(u64*) gfx_ucode[ucode_type][0];
  gtask->list.t.ucode_data =  (u64 *)gfx_ucode[ucode_type][1];
  gtask->list.t.ucode_data_size = SP_UCODE_DATA_SIZE;
  gtask->list.t.dram_stack = (u64 *) dram_stack;
  gtask->list.t.dram_stack_size = SP_DRAM_STACK_SIZE8;
  gtask->list.t.output_buff =  (u64 *)&rdp_output[0];
  gtask->list.t.output_buff_size =  (u64 *)&rdp_output[GFX_RDP_OUTPUT_SIZE];

  gtask->list.t.yield_data_ptr = (u64 *) gfxYieldBuf;
  gtask->list.t.yield_data_size = OS_YIELD_DATA_SIZE;

  gtask->next        = 0;
  gtask->flags       = flag;
  gtask->msgQ        = &gfx_msgQ;

  /* タスク終了メッセージの設定*/
  if(flag & NN_SC_SWAPBUFFER){
    /* 1画面分のタスクが終了した場合 */
    gtask->msg         = (OSMesg)&gfx_msg;
  } else {
    /* 1画面分のタスクが終了していない場合 */
    gtask->msg         = (OSMesg)&gfx_msg_no;
  }

  gtask->framebuffer = cfb[gfx_cfbdrawbuffer];

  /* グラフィックタスクの起動 */
  osSendMesg(sched_gfxMQ, (OSMesg *) gtask, OS_MESG_BLOCK);

  /* フレームバッファの切り替え */
  if(flag & NN_SC_SWAPBUFFER){
    gfx_cfbdrawbuffer ^= 1;
  }

  /* ディスプレイリスト・タスクバッファ切り替え */
  gfx_gtask_no++;
  gfx_gtask_no %= GFX_GTASK_NUM;
}

/*----------------------------------------------------------------------------
  gfxRCPIinit

  RSP RDPの初期化
----------------------------------------------------------------------------*/
void gfxRCPInit(void)
{
  static int rdpinit_flag = 1;    /* RDP初期化フラグ */

  /* RSPセグメントレジスタの設定 */
  gSPSegment(glist_ptr++, 0, 0x0);  /* CPU仮想アドレス用 */

    /* RSPの設定 */
  gSPDisplayList(glist_ptr++, OS_K0_TO_PHYSICAL(setup_rspstate));

  /* RDPの初期化(1回のみ) */
  if(rdpinit_flag){
    gSPDisplayList(glist_ptr++, OS_K0_TO_PHYSICAL(rdpstateinit_dl));
    rdpinit_flag = 0;
  }
  /* RDPの設定 */
  gSPDisplayList(glist_ptr++, OS_K0_TO_PHYSICAL(setup_rdpstate));
}

/*----------------------------------------------------------------------------
  gfxClearCfb

  フレームバッファ/Zバッファのクリア
----------------------------------------------------------------------------*/
void gfxClearCfb(void)
{
  /* Zバッファのクリア */
  gDPSetDepthImage(glist_ptr++, OS_K0_TO_PHYSICAL(zbuffer));
  gDPPipeSync(glist_ptr++);
  gDPSetCycleType(glist_ptr++, G_CYC_FILL);
  gDPSetColorImage(glist_ptr++, G_IM_FMT_RGBA, G_IM_SIZ_16b,SCREEN_WD,
		   OS_K0_TO_PHYSICAL(zbuffer));
  gDPSetFillColor(glist_ptr++,(GPACK_ZDZ(G_MAXFBZ,0) << 16 |
			       GPACK_ZDZ(G_MAXFBZ,0)));
  gDPFillRectangle(glist_ptr++, 0, 0, SCREEN_WD-1, SCREEN_HT-1);
  gDPPipeSync(glist_ptr++);
  
    /* フレームバッファのクリア */
  gDPSetColorImage(glist_ptr++, G_IM_FMT_RGBA, G_IM_SIZ_16b, SCREEN_WD,
		   osVirtualToPhysical(cfb[gfx_cfbdrawbuffer]));
  gDPSetFillColor(glist_ptr++, (GPACK_RGBA5551(0, 0, 0, 1) << 16 | 
				GPACK_RGBA5551(0, 0, 0, 1)));
  gDPFillRectangle(glist_ptr++, 0, 0, SCREEN_WD-1, SCREEN_HT-1);
  gDPPipeSync(glist_ptr++);

}