#ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* Clean interface file for replacement dma manager for PS2 */ /* Force a platform signifier if required */ #if (!defined(__R5900__) && !defined(RWCROSS)) #define RWCROSS #endif /* (!defined(__R5900__) && !defined(RWCROSS)) */ /* DMA pkt type masks */ /** * \ingroup sky2dma * \ref RWDMA_PKT_TYPE_MASK is the mask used to extract a packet type from * the \ref _rwDMAAddPkt type argument. */ #define RWDMA_PKT_TYPE_MASK 0x000000ff /** * \ingroup sky2dma * \ref RWDMA_MOD_MASK is the mask used to extract the transfer mode from * the \ref _rwDMAAddPkt type argument. Interleave mode is not supported. */ #define RWDMA_MOD_MASK 0x00000300 /* TTE overlaps RWDMA_PKT_IMM_MASK, but are mutually exclusive */ /** * \ingroup sky2dma * \ref RWDMA_MOD_TTE_MASK is the mask used to extract the transfer mode * including the chain mode TTE bit from the \ref _rwDMAAddPkt type argument. * Interleave mode is not supported. */ #define RWDMA_MOD_TTE_MASK 0x00001300 /** * \ingroup sky2dma * \ref RWDMA_PKT_IMM_MASK is the mask used to extract an immediate integer * argument required by some packet types from the \ref _rwDMAAddPkt type * argument. */ #define RWDMA_PKT_IMM_MASK 0x0ffff000 /* Sort of dma we want */ /** * \ingroup sky2dma * \ref RWDMA_MOD_NORM indicates that normal mode DMA should be used. The * quad word count should be stored in the \ref RWDMA_PKT_IMM_MASK field. */ #define RWDMA_MOD_NORM 0x0000 /** * \ingroup sky2dma * \ref RWDMA_MOD_CHAIN indicates that source chain mode DMA should be used. */ #define RWDMA_MOD_CHAIN 0x0100 /* No support for interleave transfers */ /** * \ingroup sky2dma * \ref RWDMA_MOD_CHAIN_TTE indicates that source chain mode with TTE DMA * should be used. */ #define RWDMA_MOD_CHAIN_TTE 0x1100 /* Amount of shift to match mod field of Dn_CHCR reg */ #define RWDMA_MOD_SHIFT 6 /* Packet type vars */ /** * \ingroup sky2dma * \ref RWDMA_PKT_GIF_NORM is used to request a transfer on DMA channel 2. */ #define RWDMA_PKT_GIF_NORM 0x02 /** * \ingroup sky2dma * \ref RWDMA_PKT_VIF_NORM is used to request a transfer on DMA channel 1. */ #define RWDMA_PKT_VIF_NORM 0x01 #define RWDMA_PKT_ASYNC 0x20 /** * \ingroup sky2dma * \ref RWDMA_FIXUP is passed to \ref _rwDMAOpenVIFPkt to request a path 2 * packet. */ #define RWDMA_FIXUP 0x80000000 /* Fake packets */ #define RWDMA_PKT_FLIP0 0x40 #define RWDMA_PKT_FLIP1 0x41 /** * \ingroup sky2dma * \ref RWDMA_PKT_RASUREF is used to add a reference count decrement * packet. When this packet is "dispatched" it will decrement the 32 bit * number pointed to by the address argument of \ref _rwDMAAddPkt by the * number in the \ref RWDMA_PKT_IMM_MASK field. If this number is 0, 1 is * assumed. In general, it is better to use \ref _rwDMAAddPURef, rather than * this type. */ #define RWDMA_PKT_RASUREF 0x42 #define RWDMA_PKT_NULL 0x43 /** * \ingroup sky2dma * \ref RWDMA_PKT_CALL is used to add a call back of type \ref rwDMACallback * to the chain. When this packet is "dispatched" it will call the function * specified by the address argument of \ref _rwDMAAddPkt with interrupts * disabled. */ #define RWDMA_PKT_CALL 0x4f /** * \ingroup sky2dma * \ref rwDMACallback is the type of the function called when a * \ref RWDMA_PKT_CALL packet is "dispatched". The function is invoked with * interrupts disabled. If the callback needs to perform more work than can * reasonably occur within an interrupt handler, it should raise another * thread and then return FALSE. * * \param inHandler Indicates if the callback occurred from the context of an * interrupt handler. * \return TRUE if the next packet may be dispatched. If FALSE is returned, * \ref _rwDMACallbackRestart must eventually be called to restart * dispatch. */ typedef RwBool (*rwDMACallback)(RwBool inHandler); typedef void (*rwDMAYieldCallback)(RwBool blocked, RwUInt32 freeSpace); /* Jump to new memory block */ #define RWDMA_PKT_GOTO 0x7f /* Immediate constant. Used by RWDMA_PKT_RASUREF and RWDMA_MODE_NORM mode */ /** * \ingroup sky2dma * \ref RWDMA_PKT_IMM_SHIFT is the shift required to move an integer into * the \ref RWDMA_PKT_IMM_MASK field. */ #define RWDMA_PKT_IMM_SHIFT 12 /** * \ingroup sky2dma * \ref RWDMA_PKT_IMM_MAX is the maximum immediate argument that may be * specified as part of the type argument to \ref _rwDMAAddPkt */ #define RWDMA_PKT_IMM_MAX (RWDMA_PKT_IMM_MASK>>RWDMA_PKT_IMM_SHIFT) /* The single defines we actually use */ /** * \ingroup sky2dma * \ref RWDMA_PKT_GIF is used to request a transfer on DMA channel 2 * using chain mode. */ #define RWDMA_PKT_GIF (RWDMA_PKT_GIF_NORM | RWDMA_MOD_CHAIN) #define RWDMA_PKT_AGIF (RWDMA_PKT_GIF_NORM | RWDMA_MOD_CHAIN \ | RWDMA_PKT_ASYNC) /** * \ingroup sky2dma * \ref RWDMA_PKT_VIF_TTE is used to request a transfer on DMA channel 1 * using chain mode with TTE enabled. */ #define RWDMA_PKT_VIF_TTE (RWDMA_PKT_VIF_NORM | RWDMA_MOD_CHAIN_TTE) #define RWDMA_PKT_AVIF (RWDMA_PKT_VIF_NORM | RWDMA_MOD_CHAIN_TTE \ | RWDMA_PKT_ASYNC) /* The following external vars are currently used to point to current pks */ extern RwUInt128 *_rwDMAPktPtr; /* main pkt pointer */ extern RwUInt128 *_rwDMAAsyncPktPtr; /* Used for Gif pkt which may be open at the same time as the main pkt */ /* Points to the current MaskPath3 gate slot. Needs to be set to NULL before a Path 2 image upload is added to the chain. This prevents an async upload on Path 3 from clashing with the Path 2 blit. A Path 2 image upload must be preceeded by a FLUSHA to ensure that any Path 3 image upload has completed */ extern RwUInt128 *_rwDMAGateSlot; #ifndef DOXYGEN /* This is in preparation of VUCONTINUE. Until that scheme becomes standard, source customers can rebuild with RWDMA_EXTRA_SLOT defined to get and extra slot variable with the same adjustment behaviour as _rwDMAGateSlot */ #define RWDMA_EXTRA_SLOTx extern RwUInt128 *_rwDMAPktSlot; #endif /* !DOXYGEN */ #ifdef RWCROSS extern RwUInt32 _rwDMAFakeScratchPad; #endif /* RWCROSS */ /* Address modifiers */ #ifndef RWCROSS #define RWDMA_UNCACHED (0x20000000U) #define RWDMA_UNCACHEACCL (0x30000000U) #define RWDMA_SCRATCHPAD (0x70000000U) #else /* !RWCROSS */ #define RWDMA_UNCACHED (0x00000000U) #define RWDMA_UNCACHEACCL (0x00000000U) #define RWDMA_SCRATCHPAD (_rwDMAFakeScratchPad) #endif /* !RWCROSS */ /* Interrupt macros */ #ifndef RWCROSS #define RWDMA_CRITICAL_SECTION_BEGIN() \ do \ { \ RwUInt32 stat; \ /* __volatile__ to prevent the code being removed */ \ __asm__ __volatile__ (".set noreorder ; \ 1: di; \ sync.p ; \ mfc0 %0, $12 ; \ and %0, %0, %1 ; \ nop ; \ bne %0, $0, 1b ; \ nop ; \ .set reorder" \ : "=r&" (stat) : "r" (0x00010000) : "memory" ); \ /* "memory" clobber to prevent code motion */ \ } \ while(0) /* In some instances a sync.p might be required */ #define RWDMA_CRITICAL_SECTION_END() \ __asm__ __volatile__("ei" : : : "memory") #else /* !RWCROSS */ /** * \ingroup sky2dma * \hideinitializer * \ref RWDMA_CRITICAL_SECTION_BEGIN is used to mark the beginning of a * critical section in the code, for example a reference count increment. * */ #define RWDMA_CRITICAL_SECTION_BEGIN() /** * \ingroup sky2dma * \hideinitializer * \ref RWDMA_CRITICAL_SECTION_END is used to mark the end of a * critical section in the code. * */ #define RWDMA_CRITICAL_SECTION_END() #endif /* !RWCROSS */ /* Type of access via _rwDMAAsyncPktPtr */ #define RWDMA_ASYNC_MEM_TYPE RWDMA_UNCACHEACCL /* define this to use scratchpad for packet building the main chains */ #define RWDMA_BUILD_IN_SPR /* If we aren't building is SPR, what type of access would we like? */ #ifndef RWDMA_BUILD_IN_SPR #define RWDMA_PKT_MEM_TYPE RWDMA_UNCACHEACCL #endif /* !RWDMA_BUILD_IN_SPR */ /* Macros to make scratchpad usage more transparent in application code */ /** * \ingroup sky2dma * \ref RWDMA_SPR_MAX_PKT_SIZE is the maximum quad word packet chunk that can * be built at one time. */ #define RWDMA_SPR_MAX_PKT_SIZE (511) #define RWDMA_SPR_DBUF_OFFSET (512<<4) #ifndef RWCROSS /* Asumption: Interrupts on the SPR channels are not enabled CIS bit is cleared before transfer starts */ /* We have to do the bus breaking CHCR check first as application code may not leave the CIS bit set, so we would spin forever */ #define RWDMA_SPR_WAIT_ON_FROM() \ do \ { \ /* First check breaks bus */ \ if (*(volatile RwUInt32*)(0x1000d000) & 0x100) \ { \ /* Set up PCR so only chan 8 is seen in cpcond line */ \ *(volatile RwUInt32*)(0x1000e020) = 0x100; \ /* Local labels work in CW 2.7.1, so we can use them for both gcc \ and cw code. The latest gcc, won't add nops if no reorder is \ specified, so we have the correct number to make branches \ work reliably */ \ asm __volatile__ ( ".set noreorder ; sync.l; sync.p; 1: nop; nop;" \ " nop; nop; nop; bc0f 1b; nop; .set reorder" ); \ } \ } \ while (0) #define RWDMA_SPR_WAIT_ON_TO() \ do \ { \ /* First check breaks bus */ \ if (*(volatile RwUInt32*)(0x1000d400) & 0x100) \ { \ /* Set up PCR so only chan 9 is seen in cpcond line */ \ *(volatile RwUInt32*)(0x1000e020) = 0x200; \ /* Local labels work in CW 2.7.1, so we can use them for both gcc \ and cw code. The latest gcc, won't add nops if no reorder is \ specified, so we have the correct number to make branches \ work reliably */ \ asm __volatile__ ( ".set noreorder ; sync.l; sync.p; 1: nop; nop;" \ " nop; nop; nop; bc0f 1b; nop; .set reorder" ); \ /* a bus break is required to get round a h/w bug */ \ while (*(volatile RwUInt32*)(0x1000d400) & 0x100) ; \ } \ } \ while (0) /* These should only be called once dma on the appropriate channel is stopped */ #define RWDMA_SPR_CPY_FROM(DST, SRC, SIZE) \ do \ { \ /* RWASSERT(!(*(volatile RwUInt32*)(0x1000d000) & 0x100)); */ \ /* Clear CIS8 */ \ *(volatile RwUInt32*)(0x1000e100) = 0x100; \ /* Set D8_SADR */ \ *(volatile RwUInt32*)(0x1000d080) = (RwUInt32)(SRC); \ /* Set D8_MADR */ \ *(volatile RwUInt32*)(0x1000d010) = (RwUInt32)(DST); \ /* Set D8_QWC */ \ *(volatile RwUInt32*)(0x1000d020) = (RwUInt32)(SIZE); \ /* Kick D8_CHCR */ \ *(volatile RwUInt32*)(0x1000d000) = 0x100; \ asm __volatile__ ( ".set noreorder ; sync.l; sync.p; .set reorder" ); \ } \ while(0) #define RWDMA_SPR_CPY_TO(DST, SRC, SIZE) \ do \ { \ /* RWASSERT(!(*(volatile RwUInt32*)(0x1000d400) & 0x100)); */ \ /* Clear CIS9 */ \ *(volatile RwUInt32*)(0x1000e100) = 0x200; \ /* Set D9_SADR */ \ *(volatile RwUInt32*)(0x1000d480) = (RwUInt32)(DST); \ /* Set D9_MADR */ \ *(volatile RwUInt32*)(0x1000d410) = (RwUInt32)(SRC); \ /* Set D9_QWC */ \ *(volatile RwUInt32*)(0x1000d420) = (RwUInt32)(SIZE); \ /* Kick D9_CHCR */ \ *(volatile RwUInt32*)(0x1000d400) = 0x100; \ asm __volatile__ ( ".set noreorder ; sync.l; sync.p; .set reorder" ); \ } \ while(0) #else /* !RWCROSS */ /** * \ingroup sky2dma * \hideinitializer * \ref RWDMA_SPR_WAIT_ON_FROM waits until a transfer on channel 8 completes. * It assumes that interrupts on the channel are not enabled and that CIS8 * was cleared before the transfer started. */ #define RWDMA_SPR_WAIT_ON_FROM() /* memcpy is synchronous */ /** * \ingroup sky2dma * \hideinitializer * \ref RWDMA_SPR_WAIT_ON_TO waits until a transfer on channel 9 completes. * It assumes that interrupts on the channel are not enabled and that CIS9 * was cleared before the transfer started. */ #define RWDMA_SPR_WAIT_ON_TO() /* memcpy is synchronous */ /** * \ingroup sky2dma * \hideinitializer * \ref RWDMA_SPR_CPY_FROM is used to copy SIZE quad words to memory. This * should only be used when channel 8 is not busy. */ #define RWDMA_SPR_CPY_FROM(DST, SRC, SIZE) \ memcpy((void*)(DST), (void*)(SRC), (size_t)((SIZE)<<4)) /** * \ingroup sky2dma * \hideinitializer * \ref RWDMA_SPR_CPY_TO is used to copy SIZE quad words to SPR. This should * only be used when channel 9 is not busy. */ #define RWDMA_SPR_CPY_TO(DST, SRC, SIZE) \ memcpy((void*)((RwUInt32)(DST) | RWDMA_SCRATCHPAD), (void*)(SRC), \ (size_t)((SIZE)<<4)) #endif /* !RWCROSS */ /* Support for VSYNC frame flip */ extern RwUInt8 _rwDMAUseHalfOffset; extern volatile RwUInt8 _rwDMACurrentHalfOffset; extern volatile RwUInt8 _rwDMANumFlipsInQueue; extern volatile RwUInt8 _rwDMAFlipPending; extern RwUInt8 _rwDMAFlipId; #ifndef RWCROSS #ifndef __GNUC__ #define RWDMA_HALF_OFFSET_MACRO(_result) \ do \ { \ if (_rwDMAUseHalfOffset) \ { \ RWDMA_CRITICAL_SECTION_BEGIN(); \ (_result) = (_rwDMACurrentHalfOffset \ ^ (_rwDMANumFlipsInQueue&1) \ ^ _rwDMAFlipPending); \ RWDMA_CRITICAL_SECTION_END(); \ } \ else \ { \ (_result) = 0l; \ } \ } \ while (0) /* Inline is a bit dubious. Really this is the __MWERKS__ arm */ static inline RwInt64 _rwDMAhalfOffset(void) { RwInt64 result; RWDMA_HALF_OFFSET_MACRO(result); return(result); } #define RWDMA_HALF_OFFSET() _rwDMAhalfOffset() #else /* !__GNUC__ */ #define RWDMA_HALF_OFFSET() \ (_rwDMAUseHalfOffset? \ ({RwInt64 __res; \ RWDMA_CRITICAL_SECTION_BEGIN(); \ __res = (_rwDMACurrentHalfOffset ^ (_rwDMANumFlipsInQueue&1) \ ^ _rwDMAFlipPending); \ RWDMA_CRITICAL_SECTION_END(); \ __res;}) \ : 0l) #define RWDMA_HALF_OFFSET_MACRO(_result) \ (_result) = RWDMA_HALF_OFFSET() #endif /* !__GNUC__ */ #else /* !RWCROSS */ /** * \ingroup sky2dma * \hideinitializer * \ref RWDMA_HALF_OFFSET returns the value of the half offset required in * this frame to take account of interlacing. It should be used when building * values for the GS XYOFFSET registers. * */ #define RWDMA_HALF_OFFSET() \ (0l) #define RWDMA_HALF_OFFSET_MACRO(_result) \ (_result) = 0l #endif /* !RWCROSS */ #if (!defined(RWCROSS)) || defined (DOXYGEN) /* We can only do this is Sony's libgraph.h and eeregs.h have been included */ #if (defined(_LIBGRAPH_H) && defined(_EEREGS_H_)) || defined(DOXYGEN) #ifndef DOXYGEN typedef struct rwDMAReadCircuitOneTag { tGS_DISPFB1 dispfb10; tGS_DISPLAY1 display10; tGS_DISPFB1 dispfb11; tGS_DISPLAY1 display11; } rwDMAReadCircuitOne; struct rwDMA_flipData { sceGsDBuffDc db; /* Support for read circuit 1, which is missing in sceGsDBuffDc */ rwDMAReadCircuitOne tcaaDisp; /* Display Env when ((DGET_GS_CSR() >> 12) & 0x2) Initially a copy of db.disp */ sceGsDispEnv disp1[2]; /* Support for read circuit 1, when ((DGET_GS_CSR() >> 12) & 0x2) Initially a copy of tcaaDisp */ rwDMAReadCircuitOne tcaaDisp1; /* Pointers to blit packets. Used if not NULL. Selected as (rwDMAFlipId | ((DGET_GS_CSR() >> 12) & 0x2)) */ RwUInt128 *dmaPkt[4]; }; #endif /* !DOXYGEN */ /** * \ingroup sky2dma * \ref rwDMA_flipData holds the data used by the VSYNC handler to flip * frames. The display env is updated from dc, read circuit 1 from tcaaDisp, * and if non NULL, the DMA packet pointed to by * dmaPkt[(rwDMAFlipId | ((DGET_GS_CSR() >> 12) & 0x2))] will be dispatched * to DMA channel 2 using chain mode. * * \warning To get access to this, libgraph.h has to have been included * before rwcore.h. */ typedef struct rwDMA_flipData rwDMA_flipData; extern rwDMA_flipData _rwDMAFlipData; #endif /* (defined(_LIBGRAPH_H) && defined(_EEREGS_H_)) || defined(DOXYGEN) */ #endif /* (!defined(RWCROSS)) || defined (DOXYGEN) */ /* Local Blocking macros. These permit a local var to be used which improves code generation. This code assumes that the compiler will do the right things with respect to static const */ #if (!defined(COPTIMIZE) || COPTIMIZE) && ! defined(DOXYGEN) static const RwBool _rwDMAInPkt = 0; static const RwBool _rwDMAInAsyncPkt = 0; /* These have to be here to permit the code to compile. In fact, no references will be generated */ extern RwUInt128 *_rwDMA_local_rwDMAPktPtr; extern RwUInt128 *_rwDMA_local_rwDMAAsyncPktPtr; #define RWDMA_LOCAL_BLOCK_BEGIN() \ do \ { \ static const RwBool _rwDMAInPkt = 1; \ RwUInt128 *_rwDMA_local_rwDMAPktPtr = _rwDMAPktPtr; #define RWDMA_LOCAL_BLOCK_END() \ _rwDMAPktPtr = _rwDMA_local_rwDMAPktPtr; \ } \ while(0) #define RWDMA_ADD_TO_PKT(A) \ do \ { \ if (_rwDMAInPkt) \ *_rwDMA_local_rwDMAPktPtr++ = (A); \ else \ *_rwDMAPktPtr++ = (A); \ } \ while(0) #define RWDMA_LOCAL_ASYNC_BLOCK_BEGIN() \ do \ { \ static const RwBool _rwDMAInAsyncPkt = 1; \ RwUInt128 *_rwDMA_local_rwDMAAsyncPktPtr = _rwDMAAsyncPktPtr; #define RWDMA_LOCAL_ASYNC_BLOCK_END() \ _rwDMAAsyncPktPtr = _rwDMA_local_rwDMAAsyncPktPtr; \ } \ while(0) #define RWDMA_ADD_TO_ASYNC_PKT(A) \ do \ { \ if (_rwDMAInAsyncPkt) \ *_rwDMA_local_rwDMAAsyncPktPtr++ = (A); \ else \ *_rwDMAAsyncPktPtr++ = (A); \ } \ while(0) #else /* (!defined(COPTIMIZE) || COPTIMIZE) && ! defined(DOXYGEN) */ /** * \ingroup sky2dma * \hideinitializer * \ref RWDMA_LOCAL_BLOCK_BEGIN can be used to make the code generated for * a sequence of \ref RWDMA_ADD_TO_PKT macros more efficient. The code * segment should be bracketed by \ref RWDMA_LOCAL_BLOCK_BEGIN and * \ref RWDMA_LOCAL_BLOCK_END. It works by shadowing the global packet pointer * in a local variable. As such, no code that depends on the global pointer, * such as calls to functions that use \ref RWDMA_ADD_TO_PKT, should be used * within the bracketed block. */ #define RWDMA_LOCAL_BLOCK_BEGIN() \ do \ { /** * \ingroup sky2dma * \hideinitializer * \ref RWDMA_LOCAL_BLOCK_END is used to close a \ref RWDMA_LOCAL_BLOCK_BEGIN * code block. */ #define RWDMA_LOCAL_BLOCK_END() \ } \ while(0) /** * \ingroup sky2dma * \hideinitializer * \ref RWDMA_ADD_TO_PKT is used to add a quadword to a packet opened by * \ref _rwDMAOpenGIFPkt or \ref _rwDMAOpenVIFPkt. */ #define RWDMA_ADD_TO_PKT(A) \ *_rwDMAPktPtr++ = (A) /** * \ingroup sky2dma * \hideinitializer * \ref RWDMA_LOCAL_ASYNC_BLOCK_BEGIN can be used to make the code generated * for a sequence of \ref RWDMA_ADD_TO_ASYNC_PKT macros more efficient. The * code segment should be bracketed by \ref RWDMA_LOCAL_ASYNC_BLOCK_BEGIN and * \ref RWDMA_LOCAL_ASYNC_BLOCK_END. It works by shadowing the global packet * pointer in a local variable. As such, no code that depends on the global * pointer, such as calls to functions that use \ref RWDMA_ADD_TO_ASYNC_PKT, * should be used within the bracketed block. */ #define RWDMA_LOCAL_ASYNC_BLOCK_BEGIN() \ do \ { /** * \ingroup sky2dma * \hideinitializer * \ref RWDMA_LOCAL_ASYNC_BLOCK_END is used to close a * \ref RWDMA_LOCAL_ASYNC_BLOCK_BEGIN code block. */ #define RWDMA_LOCAL_ASYNC_BLOCK_END() \ } \ while(0) /** * \ingroup sky2dma * \hideinitializer * \ref RWDMA_ADD_TO_ASYNC_PKT is used to add a quadword to a packet opened by * \ref _rwDMAAddImageUpload. */ #define RWDMA_ADD_TO_ASYNC_PKT(A) \ *_rwDMAAsyncPktPtr++ = (A) #endif /* (!defined(COPTIMIZE) || COPTIMIZE) && ! defined(DOXYGEN) */ extern void _rwDMAYieldCallbackSet(rwDMAYieldCallback callback); extern void _rwDMAMinVsyncCntSet(RwUInt8 minCnt); extern RwBool _rwDMACallbackRestart(void); extern void _rwDMAClosePkt(void); extern void _rwDMAForceBufferSwap(void); extern void _rwDMAAddPkt(void *addr, RwUInt32 type); extern void _rwDMAAddPkt2(void *addrVif, void *addrGif); extern void _rwDMAAddPURef(RwInt32 *ptr); extern void _rwDMAReqFlip(void *addr, RwUInt8 id); extern void _rwDMAWaitQueue(void); extern RwBool _rwDMAOpenGIFPkt(/* RwUInt32 type, */ RwUInt32 size); extern RwBool _rwDMAOpenVIFPkt(RwUInt32 type, RwUInt32 size); extern RwUInt128 *_rwDMADMAAlloca(RwUInt32 size, RwBool sprFlush); extern RwUInt128 *_rwDMADMAPktAllocHigh(RwUInt32 size, RwBool sprFlush); extern RwBool _rwDMAAddImageUpload(RwBool parallel, RwUInt32 size); extern RwBool _rwDMAHook(void); extern void _rwDMAUnhook(void); extern RwBool _rwDMADmaOpen(void); extern void _rwDMADmaClose(void); extern RwBool _rwDMAPreAlloc(RwUInt32 siz, RwUInt16 PURSiz, RwUInt128 *optBuf); #ifdef RWMETRICS #ifdef RWCROSS #define _rwDMAMetricsReset() #define _rwDMAMetricsGet() (NULL) #else /* RWCROSS */ extern void _rwDMAMetricsReset(void); /* Inherited. Not a regular type name, but it does begin Rw... */ extern RwSkyMetrics *_rwDMAMetricsGet(void); #endif /* RWCROSS */ #endif /* RWMETRICS */ #ifdef __cplusplus } #endif /* __cplusplus */