2020-09-30 17:17:25 +02:00

420 lines
12 KiB
C

/*==========================================================================;
*
* Copyright (C) 2000 - 2002 Microsoft Corporation. All Rights Reserved.
*
* File: xmetal.h
* Content: Xbox low-level graphics helpers
*
****************************************************************************/
#ifndef _XMETAL_H_
#define _XMETAL_H_
#ifdef __cplusplus
extern "C"
{
#endif
/****************************************************************************
*
* Debug helpers
*
****************************************************************************/
#if DBG
ULONG _cdecl DbgPrint(PCH Format, ...);
#define ERROR(msg) \
{ \
DbgPrint msg; \
DbgPrint("\n"); \
_asm { int 3 }; \
}
#else !DBG
#define ERROR(x) {}
#endif !DBG
/****************************************************************************
*
* Memory
*
****************************************************************************/
#ifdef FASTPUSHER
#define XMETAL_MEMORY_TYPE_VIDEO 0x80000000
#define XMETAL_MEMORY_TYPE_CONTIGUOUS 0x80000000
#else
#define XMETAL_MEMORY_TYPE_VIDEO 0xF0000000
#define XMETAL_MEMORY_TYPE_CONTIGUOUS 0xF0000000
#endif
#define XMETAL_MAX_PHYSICAL_OFFSET 0x08000000
#if DBG
// Verify that the memory address is a virtual address to a write
// combined mapping of contiguous memory.
//
static __forceinline void XMETAL_DebugVerifyContiguous(
void *pv
)
{
DWORD Type = (DWORD)pv & 0xF0000000;
if (Type != XMETAL_MEMORY_TYPE_CONTIGUOUS &&
Type != XMETAL_MEMORY_TYPE_VIDEO)
{
ERROR(("DebugVerifyContiguous - the address is not a write combined mapping to contiguous memory."));
}
if (((DWORD)pv & 0x0FFFFFFF) > XMETAL_MAX_PHYSICAL_OFFSET)
{
ERROR(("DebugVerifyContiguous - the address is not a write combined mapping to contiguous memory."));
}
}
// Verify that the offset is a valid physical memory offset and can be
// accessed by the graphics processor.
//
static __forceinline void XMETAL_DebugVerifyPhysical(
DWORD Offset
)
{
if (Offset > XMETAL_MAX_PHYSICAL_OFFSET)
{
ERROR(("DebugVerifyPhysical - Not a valid physical memory offset."));
}
}
#else !DBG
static __forceinline void XMETAL_DebugVerifyContiguous(void *pv) { }
static __forceinline void XMETAL_DebugVerifyPhysical(DWORD offset) { }
#endif !DBG
// Map from a write-combined pointer to a physical memory offset.
static __forceinline DWORD XMETAL_MapToPhysicalOffset(
void *pv
)
{
XMETAL_DebugVerifyContiguous(pv);
return ((DWORD)pv) & (XMETAL_MAX_PHYSICAL_OFFSET - 1);
}
// Map from a physical memory offset to a contiguous memory
// address.
//
static __forceinline void *XMETAL_MapToContiguousAddress(
DWORD Offset
)
{
XMETAL_DebugVerifyPhysical(Offset);
return (void *)(XMETAL_MEMORY_TYPE_CONTIGUOUS | Offset);
}
// Map from a physical memory offset to a video memory address. This method
// is temporary and will change to return the exact same value at the
// contiguous address on the final hardware.
//
static __forceinline void *XMETAL_MapToVideoAddress(
DWORD Offset
)
{
XMETAL_DebugVerifyPhysical(Offset);
return (void *)(XMETAL_MEMORY_TYPE_VIDEO | Offset);
}
/****************************************************************************
*
* Push Buffer
*
****************************************************************************/
//
// DOC: Push buffer usage.
//
// All graphics processor commands are queued up in the push buffer. This
// buffer is created by Direct3D_CreateDevice at is set to the size specified
// by Direct3D_SetPushBufferSize. The push buffer is a circular queue.
//
// All commands are pushed as a 4-byte method descriptor which contains the
// command value and a count, followed by that number of 4 byte values.
// Consecutively-numbered commands can be combined simply by providing
// extra values on the end of the first command.
//
// Space in the push buffer can be reserved by calling XMETAL_StartPush,
// which returns a pointer where the commands should be stored. The space
// is actually committed by calling XMETAL_EndPush. Not all of the
// reserved space needs to be used and, in fact, will not be used most of
// the time.
//
// The XMETAL_Push* methods write information into the push buffer. They
// must be used as all of the push buffer methods perform debug checks
// (in the debug build only) to ensure that the reserved space is not
// overrun, that there are no holes, etc.
//
// Multiple commands can be written into the push buffer at a time but the
// push buffer pointer must be manually incremented for each command.
//
// Example:
//
// void PushStuff()
// {
// XMETAL_PushBuffer *pPusher = g_pPushBuffer;
//
// PPUSH pPush = XMETAL_StartPush(pPusher); /* reserves 128 DWORDS */
//
// XMETAL_Push1(pPush, CMD_1, 0); /* method, value */
// XMETAL_Push2(pPush + 2, CMD_3, 1, 2); /* method, value, value */
//
// XMETAL_PushCount(pPush + 5, CMD_10, 3); /* method, 3 values */
//
// *(pPush + 6) = 0; // Value for CMD_10
// *(pPush + 7) = 1; // Value for CMD_11
// *(pPush + 8) = 2; // Value for CMD_12
//
// XMETAL_EndPush(pPusher, pPush + 9); /* commits 9 dwords */
// }
//
//
/*
* Push buffer allocator
*/
// All writes to the push-buffer should be using a 'volatile' type,
// otherwise the compiler may be allowed to do the writes out-of-order,
// which is bad for write-combining performance.
//
typedef volatile DWORD* PPUSH;
// Describes the available space in the push buffer. This structure should
// never be manipulated directly; space should be allocated through the
// StartPush/EndPush methods.
//
typedef struct _XMETAL_PushBuffer
{
PPUSH m_pPut;
PPUSH m_pThreshold;
} XMETAL_PushBuffer;
// The global push buffer pointer. This pointer is set when
// Direct3D_CreateDevice is called and will not change unless the device is
// destroyed.
//
extern XMETAL_PushBuffer *g_pPushBuffer;
// Reserve a specific number of DWORDs in the push buffer and return a pointer
// to the beginning of the reserved block. This method is not as efficient
// as XMETAL_StartPush and should only be called if more than 128 DWORDs are
// required.
//
// This method cannot fail but may block until there is enough space
// in the push buffer to process the reservation.
//
DWORD * WINAPI XMETAL_StartPushCount(XMETAL_PushBuffer *pPushBuffer, DWORD count);
// Commit the space actually used in the push buffer. Pass in the pointer
// in the push buffer immediately after the last pushed command. It is not
// necessary to use all of the space reserved in the push buffer.
//
#if DBG
void WINAPI XMETAL_EndPush(XMETAL_PushBuffer *pPushBuffer, PPUSH pPush);
#else !DBG
static __forceinline void XMETAL_EndPush(XMETAL_PushBuffer *pPushBuffer, PPUSH pPush)
{
pPushBuffer->m_pPut = pPush;
}
#endif !DBG
/*
* Method pushing helpers. This uses '+' instead of '|' because it's more
* friendly to macros that include add operations.
*/
#define XMETAL_PUSHER_METHOD(method, count) \
(((count) << 18) + (method))
#if !DBG
//----------------------------------------------------------------------------
// PushedRaw - Call this to advance the push pointer after having copied
// raw data into the pusher buffer
//
static __forceinline VOID XMETAL_PushedRaw(
PPUSH pPushNext)
{
}
//----------------------------------------------------------------------------
// Push1 - Push one dword
//
static __forceinline VOID XMETAL_Push1(
PPUSH pPush,
DWORD method,
DWORD value)
{
pPush[0] = XMETAL_PUSHER_METHOD(method, 1);
pPush[1] = value;
}
//----------------------------------------------------------------------------
// Push2 - Push two dwords
//
static __forceinline VOID XMETAL_Push2(
PPUSH pPush,
DWORD method,
DWORD a,
DWORD b)
{
pPush[0] = XMETAL_PUSHER_METHOD(method, 2);
pPush[1] = a;
pPush[2] = b;
}
//----------------------------------------------------------------------------
// Push3 - Push three dwords
//
static __forceinline VOID XMETAL_Push3(
PPUSH pPush,
DWORD method,
DWORD a,
DWORD b,
DWORD c)
{
pPush[0] = XMETAL_PUSHER_METHOD(method, 3);
pPush[1] = a;
pPush[2] = b;
pPush[3] = c;
}
//----------------------------------------------------------------------------
// Push4 - Push four dwords
//
static __forceinline VOID XMETAL_Push4(
PPUSH pPush,
DWORD method,
DWORD a,
DWORD b,
DWORD c,
DWORD d)
{
pPush[0] = XMETAL_PUSHER_METHOD(method, 4);
pPush[1] = a;
pPush[2] = b;
pPush[3] = c;
pPush[4] = d;
}
//----------------------------------------------------------------------------
// Push1f - Push one float
//
static __forceinline VOID XMETAL_Push1f(
PPUSH pPush,
DWORD method,
FLOAT value)
{
pPush[0] = XMETAL_PUSHER_METHOD(method, 1);
((FLOAT*) pPush)[1] = value;
}
//----------------------------------------------------------------------------
// Push2f - Push two floats
//
static __forceinline VOID XMETAL_Push2f(
PPUSH pPush,
DWORD method,
FLOAT a,
FLOAT b)
{
pPush[0] = XMETAL_PUSHER_METHOD(method, 2);
((FLOAT*) pPush)[1] = a;
((FLOAT*) pPush)[2] = b;
}
//----------------------------------------------------------------------------
// Push3f - Push three floats
//
static __forceinline VOID XMETAL_Push3f(
PPUSH pPush,
DWORD method,
FLOAT a,
FLOAT b,
FLOAT c)
{
pPush[0] = XMETAL_PUSHER_METHOD(method, 3);
((FLOAT*) pPush)[1] = a;
((FLOAT*) pPush)[2] = b;
((FLOAT*) pPush)[3] = c;
}
//----------------------------------------------------------------------------
// Push4f - Push four floats
//
static __forceinline VOID XMETAL_Push4f(
PPUSH pPush,
DWORD method,
FLOAT a,
FLOAT b,
FLOAT c,
FLOAT d)
{
pPush[0] = XMETAL_PUSHER_METHOD(method, 4);
((FLOAT*) pPush)[1] = a;
((FLOAT*) pPush)[2] = b;
((FLOAT*) pPush)[3] = c;
((FLOAT*) pPush)[4] = d;
}
//----------------------------------------------------------------------------
// PushCount - Just push the method, with a specified count of data to follow
//
static __forceinline VOID XMETAL_PushCount(
PPUSH pPush,
DWORD method,
DWORD count)
{
pPush[0] = XMETAL_PUSHER_METHOD(method, count);
}
#else DBG
//----------------------------------------------------------------------------
// For debug, we have out-of-line routines which do a bunch of extra checks:
//
VOID WINAPI XMETAL_PushedRaw(PPUSH pPushNext);
VOID WINAPI XMETAL_Push1(PPUSH pPush, DWORD method, DWORD value);
VOID WINAPI XMETAL_Push2(PPUSH pPush, DWORD method, DWORD a, DWORD b);
VOID WINAPI XMETAL_Push3(PPUSH pPush, DWORD method, DWORD a, DWORD b, DWORD c);
VOID WINAPI XMETAL_Push4(PPUSH pPush, DWORD method, DWORD a, DWORD b, DWORD c, DWORD d);
VOID WINAPI XMETAL_Push1f(PPUSH pPush, DWORD method, FLOAT value);
VOID WINAPI XMETAL_Push2f(PPUSH pPush, DWORD method, FLOAT a, FLOAT b);
VOID WINAPI XMETAL_Push3f(PPUSH pPush, DWORD method, FLOAT a, FLOAT b, FLOAT c);
VOID WINAPI XMETAL_Push4f(PPUSH pPush, DWORD method, FLOAT a, FLOAT b, FLOAT c, FLOAT d);
VOID WINAPI XMETAL_PushCount(PPUSH pPush, DWORD method, DWORD count);
#endif DBG
#ifdef __cplusplus
}
#endif __cplusplus
#endif _XMETAL_H_