
---------------------------------------------------
Overview
---------------------------------------------------

This document is a work in progress.

The API consists of 2 primary modules.  PS2Renderer.h and MasterList.h.  MasterList manages the primary 
DMA chains for the engine, while PS2Renderer handles loadtime fixup of models and adding them to MasterList.
Both modules are implimented as namespaces.

To initialize the renderer, you must initialize both these modules.  They are not order dependant, just dont
initialize them more than once (or you may leak memory). TODO: assert on multiple init.

The sections below I tried to list in an order that would make more sense when read linearly.  

There is an additional module VIFInline.h that can be used to help generate DMA Chains.  It is designed to
replace the similar SCE macros.

---------------------------------------------------
MasterList Initialization
---------------------------------------------------

Simply call MasterList::Init(masterBufferSize, path3BufferSize); where masterBufferSize is the amount of
memory (in bytes) that you want MasterList to reserve for the main dma chain (frequently quite high), and
path3BufferSize is 0 or the amount of memory in bytes that you want MasterList to reserve for the path3
dma chain (used to stream textures durring a frame).  If you get either of these sizes too low, you should
assert.


---------------------------------------------------
PS2Renderer Initialization
---------------------------------------------------

There are 2 functions that must be called to fully initialize the PS2Renderer.  

First is PS2Renderer::Init(vumemBase, vumemSize);  Where vumemBase defines the first address (measured
in word pairs) that the ps2renderer is allowed to upload microcodes into VU1 micro-memory, and
vumemSize is the length of that space.  Usually, you will just init these to 0 and 2048 respectively
(thus giving the PS2Renderer all of micro-memory to stomp on).

The second call is only nessisary if your models have texture settings embedded in them that need fixup.
The call is PS2Renderer::SetTextureAddrCallback(callback).  where callback is the address of a function 
matching this prototype: 
void TextureAddrCallback(u_int textureID, u_long &tex0_1, u_long &tex1_1, u_long &clamp_1, u_long &miptbp1_1, u_long &miptbp2_1);
It is up to the calling code to determine the meaning of the textureID value.  It is pulled out of the
model and passed to this function to get the correct register settings to use this texture.  It is up
to the calling code to assure that the texture is already in texture memory before drawing the object.


---------------------------------------------------
MasterList Usage Overview
---------------------------------------------------

MasterList's public API consists of several ways to get dma data into the primary dma chain and (currently)
one way to get dma data into the path3 dma chain, as well as functions to define the beginning and end of
the dma chain.  A sample of the flow of chain management would be like:


// load game here

loop {

	MasterList::Start(); // Begin a new dma chain

	// call PS2Renderer/MasterList calls to draw stuff here.

	MasterList::End(); // wait for prior dma chain to complete

	// add stuff here that must happen between renders (swap frame buffers, etc)

	MasterList::Render(); // fire off new dma chain.

};


---------------------------------------------------
PS2Renderer Usage Overview
---------------------------------------------------

The PS2Renderer is designed to be used with data blocks created by external tools that match certain
internal specifications (Namely, those generated by the packetizer).  Details on the data format are
not in this document.  This document assumes that you can get data in the correct format loaded into
the game.

The basic steps are

	1) define the PS2Renderer*() memory management functions
	2) create/load your data - this is up to the calling code to do..
	3) create a dma object from that data using PS2Renderer::CreateDMAObject()
	
	main game loop {

		4) Set matrices & lighting using PS2Renderer::Set*()
		5) Draw dma objects using PS2Renderer::DrawDMAObject()

	}

---------------------------------------------------
PS2Renderer Memory Management
---------------------------------------------------

	void* PS2RendererMalloc(u_int size);
	void* PS2RendererMemAlign(u_int alignment, u_int size);
	void PS2RendererFree(void* block);

	These functions are referred to by the PS2Renderer, but are not defined by the renderer.
	You must write your own versions of these functions in order to avoid a link error.


---------------------------------------------------
PS2Renderer Object Management
---------------------------------------------------

	void DrawDMAObject(DDMAObject& object, const PS2Matrix4x4& ModelMatrix, u_int flags);
	DDMAObject* CreateDMAObject(void* dataBuffer, u_int dataSize, u_int patchSet, void* patchData);
	u_int GetPatchSetCount(void* dataBuffer, u_int dataSize);

	typedef void TextureAddrCallback(u_int textureID, u_long &tex0_1, u_long &tex1_1, u_long &clamp_1, u_long &miptbp1_1, u_long &miptbp2_1);
	void SetTextureAddrCallback(TextureAddrCallback* callback);


---------------------------------------------------
PS2Renderer Matrix Settings
---------------------------------------------------

Overview

	The renderer needs quite a few matrices to get its job done.  There are 3 categories of matrices
	that the renderer deals with, those that are passed by the calling code, those that are generated
	when needed, and the texture matrix.  The functions are listed by category below.

	There are some unneeded matrices listed here.  If you never pass a LOCAL_TO_WORLD matrix, the
	renderer will never use the WorldToCamera matrix.  If you also never pass a LOCAL_TO_CAMERA 
	matrix, the renderer will happily restrict itself to the ViewTo* matrices.

Category 1 -  passed matrices

	void SetWorldToCamera(const PS2Matrix4x4& mtx);
	void SetCameraToView(const PS2Matrix4x4& mtx);
	void SetViewToScreen(const PS2Matrix4x4& mtx);
	void SetViewToClip(const PS2Matrix4x4& mtx);
	void SetViewToCull(const PS2Matrix4x4& mtx);
	const PS2Matrix4x4& GetWorldToCamera(void);
	const PS2Matrix4x4& GetCameraToView(void);
	const PS2Matrix4x4& GetViewToScreen(void);
	const PS2Matrix4x4& GetViewToClip(void);
	const PS2Matrix4x4& GetViewToCull(void);

Category 2 - generated matrices

	const PS2Matrix4x4& GetWorldToClip(void);
	const PS2Matrix4x4& GetCameraToClip(void);
	const PS2Matrix4x4& GetScreenToClip(void);
	const PS2Matrix4x4& GetWorldToScreen(void);
	const PS2Matrix4x4& GetCameraToScreen(void);
	const PS2Matrix4x4& GetClipToScreen(void);
	const PS2Matrix4x4& GetClipToView(void);

Category 3 - texture matrix (full access any time)

	void SetTexture(const PS2Matrix4x4& mtx);
	const PS2Matrix4x4& GetTexture(void);

Helpers - these functions are helpers to ease Category 1 & 3 matrix setting.

	void SetViewToClip(u_int frameBufferWidth, u_int frameBufferHeight); // full screen support guardband
	void SetViewToCull(u_int frameBufferWidth, u_int frameBufferHeight); // full screen support guardband

	Currently, the only 2 helpers are to help in setting up clipping & culling.  They set their respective
	matrices to the full screen including a gaurdband region.  To do their job, they only need to know
	the resolution of your screen.  Passing smaller values will not seem to work as they allow use of the
	(rather large) gaurdband on the PS2.


---------------------------------------------------
PS2Renderer Light Settings (currently doesnt work)
Subject to frequent changing right now...
---------------------------------------------------

	void SetLight(int lightNumber, const lightStruct& lightData);
	void SetLightActive(int lightNumber, bool Active);


---------------------------------------------------
PS2Renderer Clipping & Culling
---------------------------------------------------


---------------------------------------------------
MasterList Usage Details
---------------------------------------------------

As I said, there are several ways to add data to the primary chain.  Any of these can be
called between MasterList::Start() and MasterList::End().  There are some managerial issued associated
with using any of these that you need to be aware of.  MasterList works in conjunction with the
PS2Renderer to help keep data flowing without stalls through VIF1.  Those management methods are discussed
after the DMA Methods below.

DMA Method 1 (highest level):

	Use PS2Renderer.  Thats what its for.

DMA Method 2 (high level):

	void CallDisplayList(pDisplayList, pData, u32QWC, vifCode1, vifCode2, bInterrupt);

	This call allows you to add a TAGID_CALL dma tag to the masterlist.  The tags parameters are
	defined by the parameters to the function.  So you can both call a display list and upload
	a block of data.  The 2 vifcodes are used to fill in the 2 words that are part of the dma tag
	(TTE=1 data).  The u32QWC quadwords of data pointed to by pData is copied directly after the dma
	tag.  This is a memcpy, so be aware that it will duplicate that data.

DMA Method 3 (high level):

	void RefData(pData, u32QWC, vifCode1, vifCode2, bInterrupt);

	Similar to the CallDisplayList() method, this adds a TAGID_REF to the masterlist.  The ref refers to
	the u32QWC quadwords of data pointed to by pData.  Again, the two vif codes are used to complete
	the tags quadword and are only used if TTE=1 (which it is always currently).  This does not copy
	the data, so be aware that you probably need to double buffer it.

DMA Method 4 (mid level):

	void* StartMiscData(void);
	void EndMiscData(void *endPtr);
	
	These 2 functions use a shared section of SPRAM for generating little chunks of display list.
	The chunk of SPRAM is something like 30 quadwords long so it should be long enough for most uses.
	The StartMiscData function returns a pointer to the spot in SPRAM where you should build your
	dma chainlet.  You then call EndMiscData and pass it a pointer to the word immediately following
	your chainlet.  This will automatically initiate a dma transfer from SPRAM to the masterlist.  This
	function can support you calling StartMiscData immediately after EndMiscData, but it does so by
	waiting for the prior transfer to complete.  If we find this is used heavily, we should probably
	provide it with a double buffer.

DMA Method 5 (low level):
	
	DMA_TO_MASTER_LIST(source, qwc);
	CHECK_LAST_FROM_SPR_DMA(source);

	This method is the basis for all the other methods.  To add something to the MasterList, you
	call DMA_TO_MASTER_LIST and pass it the SPRAM address of the chainlet to be added (as source)
	and the length of the data to be added in quadwords (as qwc).  If you are going to modify a
	source area in SPRAM that may have recently had DMA_TO_MASTER_LIST called on it, you should 
	first call CHECK_LAST_FROM_SPR_DMA(source) to verify that the dma has completed.  You must pass
	CHECK_LAST_FROM_SPR_DMA the same address that was passed to DMA_TO_MASTER_LIST.  Also, source
	MUST be in SPRAM.  There are some methods below to help you get it there.  Note, this method
	is made of macros instead of functions.

DMA Method 6 (slow, but doesnt use DMA):

	u_int* pu32MasterDisplayList;

	This method is available for times where you know the dma engine is busy.  This pointer points
	to the current append point in the master dma chain mapped into uncached memory (probably should
	be uncached accelerated).  You can freely access the memory as long as you dont go through the
	CPU's cache.  Be sure to adjust the pointer after you write to memory so that future writes dont
	trash your pointer.  This method is not supported in MFIFO mode.  This method is highly discouraged,
	unless you really know what your doing, because except in rare cases, your pretty much gauranteed a
	slowdown.



---------------------------------------------------
MasterList DMA Support methods
---------------------------------------------------

	APPEND4(addr, val);
	APPEND4f(addr, val);
	APPEND8(addr, val);
	APPEND_DMA((addr, src, qwc);
	DMA_TO_SPR(source, dest, qwc);
	DMA_FROM_SPR(source, dest, qwc);
	DMA_Wait(_chcr);

	These macros are the backbone of MasterList's dma system.

	APPEND*() these macros copy val to the SPRAM address pointed to by addr and move addr by the size
	of the data copied.  The differences between the macros are the size of the data, the format of
	the data, and the method used to get the data into SPRAM.  APPEND4 treats val as an unsigned word
	and copys it into SPRAM via the CPU.  APPEND4f treats val as a float word and copys it into SPRAM 
	via the CPU.  APPEND8 treats val as an unsigned 64 bit value and copys it into SPRAM with the CPU.
	APPEND_DMA copies qwc quadwords into SPRAM using the DMAC (Channel 9) (you should only use this
	with data that is > 4 quadwords in length, everything else can be copied faster via CPU).

	DMA_TO_SPR() is the basis for all dma to the SPRAM.  It first flushes the CPU D-cache in the range
	to be uploaded, then waits for any prior dmas to complete (on Channel 9), it then begins the DMA.

	DMA_FROM_SPR() is the basis for all dma from SPRAM.  It records the transfer address (for later use
	by CHECK_LAST_FROM_SPR_DMA(), waits for any prior Channel 8 transfers to complete, then begins
	the dma.


---------------------------------------------------
MasterList VIF1 Management functions
---------------------------------------------------

	bool GetFlushed(void);
	void SetFlushed(bool newValue);
	u_int GetBase(void);
	u_int GetOffset(void);
	void SetBase(u_int newBase);
	void SetOffset(u_int newOffset);
	bool IsBaseOffsetSame(u_int newBase, u_int newOffset);

	These are used by PS2Renderer to help determine if various microcodes can coexist without a VIF
	Flush code slowing things down.  Please read all of these to avoid problems.  Note that they refer
	to the VIF in the present tense, but of course they really refer to a point in the dma chain.

	SetFlushed - Tell MasterList whether or not a microcode is currently running.  If flushed=true,
	then there is no microcode running in VU1, if flushed=false, then there is a mircocode running.
	
	GetFlushed - get the value set by SetFlused()

	GetBase & GetOffset - get value set by SetBase & SetOffset

	SetBase & SetOffset - Tell MasterList what the current value of the BASE & OFFSET registers in the
	VIF are.  Please set these to -1 if your dma chain kicks a microcode but doesnt use base & offset,
	otherwise, set them if you change the BASE & OFFSET registers.

	IsBaseOffsetSame() - used to compare base & offset values to the current values to know if you
	need to set BASE & OFFSET.


---------------------------------------------------
MasterList frame count & toggle
---------------------------------------------------

	u_int GetFrameNumber(void);
	u_int GetFrameToggle(void);

	These 2 functions are useful for determining how many frames have elapsed since the game was loaded.
	GetFrameNumber goes up once for every call to MasterList::Render.  Also, GetFrameToggle always returns
	0 or 1.  It toggles with every call to MasterList::Render.


---------------------------------------------------
MasterList Path3 API
---------------------------------------------------

	void CallPath3DisplayList(void* pDisplayList, bool EOP = false, bool bInterrupt = false);
	void DoneWithPath3Data(void);

	Use these to add entries to the path 3 display list.  You should call CallPath3DisplayList()
	multiple times with EOP=false, until the last packet in you upload, then call it with
	EOP=true.  When you finish rendering using the textures, call DoneWithPath3Data().
	MasterList will actually see to it that your path3 chains get started when the prior call
	to DoneWihtPath3Data happens.  This allows you to dynamically upload textures without
	double buffering (but with stalling).  If you double buffer your textures, you should simply
	call DoneWithPath3Data immediately BEFORE calling CallPath3DisplayList instead of after.


