"INSIDE NuSystem"

4.1 What the Graphics Manager Does
4.2 How to Customize the Graphics Manager

4.1 What the Graphics Manager Does

NuSystem graphics management consists of the graphics thread, the Graphics Manager thread, and the graphics setting functions.
The graphics thread is created and executed by the nuGfxThreadStart function. It executes a retrace callback function or PRE-NMI callback function registered by the application. (The nuGfxThreadStart function is called in the nuGfxInit function.) The graphics thread is first registered as a client in the Scheduler so that it can receive retrace and PRE-NMI event messages. If it receives a retrace message, it executes the callback function registered by the nuGfxFuncSet function. However, if it receives a PRE-NMI event message, it executes the callback function registered by the nuGfxPreNMIFuncSet function as shown here:

Figure 4.1 -- Graphics Thread Process Flow

The Graphics Stack Manager consists of the nuGfxTaskStart function and the Graphics Task Manager thread.

The nuGfxTaskStart function receives the display list buffer pointer, size, and microcode type from your application, as well as the frame buffer swap flag. It sets these values in the task structure. It then sends this task structure as a message to the graphics task thread.

The graphics task thread sends an end message to the Graphics Task Manager when the task is complete. The Graphics Task Manager checks messages, and in the case of an end message or buffer swap message, it uses the ViSwapBuffer function to swap the frame buffer. This is shown in Figure 4.2.

Figure 4.2 -- Activation of a Graphics Task

Task structures are in ring buffers and are automatically swapped by the nuGfxTaskStart function. The size of the graphics task thread message queue is 8, and if more than eight messages are sent in block mode, the transmitted threads will wait until the queue opens up. Because this can be used to accommodate more than 8 task structures, the size of the task structure is 10 ring buffers.

The internal processing of the nuGfxTaskStart function differs depending on whether NU_SC_SWAPBUFFER or NU_SC_NOSWAPBUFFER is specified in the argument. In the case of NU_SC_SWAPBUFFER, a flag specifies that the frame buffer can be swapped by a task-end message, and the value of the variable nuGfxCfb_ptr is changed. The value of nuGfxCfb_ptr is set in the order of the frame buffer address table which is entered by the nuGfxSetCfb function. The frame buffer address table is defined as a frame buffer pointer array by the nuGfxInit function in this way:

    	static u16* FrameBuf[3] = {
    		(u16*)NU_GFX_FRAMEBUFFER0_ADDR,
    		(u16*)NU_GFX_FRAMEBUFFER1_ADDR,
    		(u16*)NU_GFX_FRAMEBUFFER2_ADDR
    	};
    	....
    	void nuGfxInit(void)
    	{
    		....
    		nuGfxSetCfb(FrameBuf, 3):
    		....
    	}

The value of nuGfxCfb_ptr is entered into the task structure by the nuGfxTaskStart function and passed to the Graphics Task Manager after a task is completed. The value is then passed as an argument of the frame buffer swap callback function (the nuGfxSwapCfb function is registered as the callback in the nuGfxInit function). The callback function, by passing the argument value to the osViSwapBuffer function, can specify which frame buffer to display next. If you change the value of nuGfxCfb_ptr before calling the nuGfxTaskStart function, the frame buffer with that value can be displayed.

4.2 How to Customize the Graphics Manager

By calling appropriate functions, the nuGfxInit function does the following to set the defaults for the graphics settings:

- Activates the graphics thread by calling the nuGfxThreadStart function.
- Enters the frame buffer address table by calling the nuGfxSetCfb function.
- Sets the frame buffer size by calling the nuGfxSetCfb function.
- Sets the Z-Buffer address by calling the nuGfxSetZBuffer function.
- Enters the frame buffer swap callback function by calling the nuGfxSwapCfbFuncSet function.
- Enters the graphics microcode array by calling the nuGfxSetUCode function.
- Activates the Graphics Task Manager by calling the nuGfxTaskMgrInit function.
- Initializes the RDP (reality display processor).

As this list shows, there are many functions, so if you do not use the nuGfxInit function, you can use these other functions to set the graphics for your application. Note that to change the Z-Buffer address setting and the graphics microcode array, you need to change the spec file.

When the nuGfxSetUCode function is called, all of the Fast3D graphics microcode presently in use is entered. Therefore, by deleting all microcode that is ultimately unnecessary for the application, you can open up a little more ROM space. Because this action is related to the microcode array defined in the nuGfxInit function, to do it, you will need to initialize all eight items in the list within your application. But this is not a big job; all you need to do is copy the nuGfxInit function source code into your application source code, and then change the necessary parts. It is a good idea to try out several different pieces of the microcode so that you can check the performance of each and see how they display differently.

The following additional information shows you how to change the graphics microcode to fit the needs of your game application. Any change to the default microcode setting involves the deletion of microcode. In the following example all microcode is deleted except F3DEX and L3DED, leaving only N_Audio microcode. Start by changing the spec file. The following segment of the spec file defines microcode:

    beginseg
    	name "code"
    	flags BOOT OBJECT
    	entry nuBoot
    	address NU_SPEC_BOOT_ADDR
    	stack NU_SPEC_BOOT_STACK
    	include "codesegment.o"
    	include "$(ROOT)/usr/lib/PR/rspboot.o"
    	include "$(ROOT)/usr/lib/PR/aspMain.o"
    	include "$(ROOT)/usr/lib/PR/n_aspMain.o"
    	include "$(ROOT)/usr/lib/PR/gspF3DEX.fifo.o"
    	include "$(ROOT)/usr/lib/PR/gspF3DEX.NoN.fifo.o"
    	include "$(ROOT)/usr/lib/PR/gspF3DLX.fifo.o"
    	include "$(ROOT)/usr/lib/PR/gspF3DLX.NoN.fifo.o"
    	include "$(ROOT)/usr/lib/PR/gspF3DLX.Rej.fifo.o"
    	include "$(ROOT)/usr/lib/PR/gspF3DLP.Rej.fifo.o"
    	include "$(ROOT)/usr/lib/PR/gspL3DEX.fifo.o"
    	include "$(ROOT)/usr/lib/PR/gspS2DEX.fifo.o"
    	include "$(ROOT)/usr/lib/PR/gspS2DEX.fifo_d.o"
    endseg

    You can delete the lines in boldface type thus changing the code segment to this:

    beginseg
    	name "code"
    	flags BOOT OBJECT
    	entry nuBoot
    	address NU_SPEC_BOOT_ADDR
    	stack NU_SPEC_BOOT_STACK
    	include "codesegment.o"
    	include "$(ROOT)/usr/lib/PR/rspboot.o"
    	include "$(ROOT)/usr/lib/PR/n_aspMain.o"
    	include "$(ROOT)/usr/lib/PR/gspF3DEX.fifo.o"
    	include "$(ROOT)/usr/lib/PR/gspL3DEX.fifo.o"
    endseg

That's all you need to do to modify the spec file. The next step is to copy nugfxinit.c from the NuSystem source code directory to the application directory, and then change the name of the copied file. For this example, rename it to appgfxinit.c. Now you can change the contents of this file to customize the graphics settings. For example, you might change the following portion of the appgfxinit.c file:

    //line 17
    static NUUcode nugfx_ucode[] = {
    	{(u64*)gspF3DEX_fifoTextStart,(u64*)gspF3DEX_fifoDataStart},
    	{(u64*)gspF3DEX_NoN_fifoTextStart,(u64*)gspF3DEX_NoN_fifoDataStart},
    	{(u64*)gspF3DLX_fifoTextStart, (u64*)gspF3DLX_fifoDataStart},
    	{(u64*)gspF3DLX_NoN_fifoTextStart,(u64*)gspF3DLX_NoN_fifoDataStart},
    	{(u64*)gspF3DLX_Rej_fifoTextStart,(u64*)gspF3DLX_Rej_fifoDataStart},
    	{(u64*)gspF3DLP_Rej_fifoTextStart,(u64*)gspF3DLP_Rej_fifoDataStart},
    	{(u64*)gspL3DEX_fifoTextStart, (u64*)gspL3DEX_fifoDataStart},
    	{(u64*)gspS2DEX_fifoTextStart, (u64*)gspS2DEX_fifoDataStart},
    	{(u64*)gspS2DEX_fifo_dTextStart, (u64*)gspS2DEX_fifo_dDataStart},
    };

Delete the red lines to make the code section look like this:

    static NUUcode nugfx_ucode[] = {
    	{(u64*)gspF3DEX_fifoTextStart, (u64*)gspF3DEX_fifoDataStart},
    	{(u64*)gspL3DEX_fifoTextStart, (u64*)gspL3DEX_fifoDataStart},
    };

Now, change the function name from nuGfxInit(void) to appGfxInit(void), and you have prepared the graphics set for use by your application.