You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1567 lines
42 KiB
1567 lines
42 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
// |
|
//===========================================================================// |
|
|
|
#ifdef D3D_ASYNC_SUPPORTED |
|
|
|
#ifndef D3DASYNC_H |
|
#define D3DASYNC_H |
|
|
|
#ifdef _WIN32 |
|
#pragma once |
|
#endif |
|
|
|
// Set this to 1 to allow d3d calls to be buffered and played back on another thread |
|
// Slamming this off - it's causing very hot D3D9 function calls to not be inlined and contain a bunch of unused code. (Does this code even work/add real value any more?) |
|
#define SHADERAPI_USE_SMP 0 |
|
|
|
// Set this to 1 to allow buffering of the whole frame to memory and then playback (singlethreaded). |
|
// This is for debugging only and is used to test the performance of just calling D3D and rendering without other CPU overhead. |
|
#define SHADERAPI_BUFFER_D3DCALLS 0 |
|
|
|
#if SHADERAPI_BUFFER_D3DCALLS && !SHADERAPI_USE_SMP |
|
# error "SHADERAPI_USE_SMP must be 1 for SHADERAPI_BUFFER_D3DCALLS to work!" |
|
#endif |
|
|
|
#include "recording.h" |
|
#include "strtools.h" |
|
#include "glmgr/dxabstract.h" |
|
|
|
#ifdef NDEBUG |
|
#define DO_D3D(x) Dx9Device()->x |
|
#else |
|
#define DO_D3D(x) Dx9Device()->x |
|
//#define DO_D3D(x) { HRESULT hr=Dx9Device()->x; Assert( !FAILED(hr) ); } |
|
#endif |
|
|
|
#define PUSHBUFFER_NELEMS 4096 |
|
|
|
enum PushBufferState |
|
{ |
|
PUSHBUFFER_AVAILABLE, |
|
PUSHBUFFER_BEING_FILLED, |
|
PUSHBUFFER_SUBMITTED, |
|
PUSHBUFFER_BEING_USED_FOR_LOCKEDDATA, |
|
}; |
|
|
|
class PushBuffer |
|
{ |
|
friend class D3DDeviceWrapper; |
|
|
|
volatile PushBufferState m_State; |
|
uint32 m_BufferData[PUSHBUFFER_NELEMS]; |
|
public: |
|
PushBuffer(void) |
|
{ |
|
m_State = PUSHBUFFER_AVAILABLE; |
|
} |
|
}; |
|
|
|
// When running multithreaded, lock for write calls actually return a pointer to temporary memory |
|
// buffer. When the buffer is later unlocked by the caller, data must be queued with the Unlock() |
|
// that lets the d3d thread know how much data to copy from where. One possible optimization for |
|
// things which write a lot of data into lock buffers woudl be to proviude a way for the caller to |
|
// occasionally check if the Lock() has been dequeued. If so, the the data pushed so far could be |
|
// copied asynchronously into the buffer, while the caller would be told to switch to writing |
|
// directly to the vertex buffer. |
|
// |
|
// another possibility would be lock()ing in advance for large ones, such as the world renderer, |
|
// or keeping multiple locked vb's open for meshbuilder. |
|
|
|
struct LockedBufferContext |
|
{ |
|
PushBuffer *m_pPushBuffer; // if a push buffer was used to hold |
|
// the temporary data, this will be non-null |
|
void *m_pMallocedMemory; // if memory had to be malloc'd, this will be set. |
|
|
|
size_t m_MallocSize; // # of bytes malloced if mallocedmem ptr non-null |
|
|
|
LockedBufferContext( void ) |
|
{ |
|
m_pPushBuffer = NULL; |
|
m_pMallocedMemory = NULL; |
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
// push buffer commands follow |
|
enum PushBufferCommand |
|
{ |
|
PBCMD_END, // at end of push buffer |
|
PBCMD_SET_RENDERSTATE, // state, val |
|
PBCMD_SET_TEXTURE, // stage, txtr |
|
PBCMD_DRAWPRIM, // prim type, start v, nprims |
|
PBCMD_DRAWINDEXEDPRIM, // prim type, baseidx, minidx, numv, starti, pcount |
|
PBCMD_SET_PIXEL_SHADER, // shaderptr |
|
PBCMD_SET_VERTEX_SHADER, // shaderptr |
|
PBCMD_SET_PIXEL_SHADER_CONSTANT, // startreg, nregs, data... |
|
PBCMD_SET_BOOLEAN_PIXEL_SHADER_CONSTANT, // startreg, nregs, data... |
|
PBCMD_SET_INTEGER_PIXEL_SHADER_CONSTANT, // startreg, nregs, data... |
|
PBCMD_SET_VERTEX_SHADER_CONSTANT, // startreg, nregs, data... |
|
PBCMD_SET_BOOLEAN_VERTEX_SHADER_CONSTANT, // startreg, nregs, data... |
|
PBCMD_SET_INTEGER_VERTEX_SHADER_CONSTANT, // startreg, nregs, data... |
|
PBCMD_SET_RENDER_TARGET, // idx, targetptr |
|
PBCMD_SET_DEPTH_STENCIL_SURFACE, // surfptr |
|
PBCMD_SET_STREAM_SOURCE, // idx, sptr, ofs, stride |
|
PBCMD_SET_INDICES, // idxbuffer |
|
PBCMD_SET_SAMPLER_STATE, // stage, state, val |
|
PBCMD_UNLOCK_VB, // vptr |
|
PBCMD_UNLOCK_IB, // idxbufptr |
|
PBCMD_SETVIEWPORT, // vp_struct |
|
PBCMD_CLEAR, // count, n rect structs, flags, color, z, stencil |
|
PBCMD_SET_VERTEXDECLARATION, // vdeclptr |
|
PBCMD_BEGIN_SCENE, // |
|
PBCMD_END_SCENE, // |
|
PBCMD_PRESENT, // complicated..see code |
|
PBCMD_SETCLIPPLANE, // idx, 4 floats |
|
PBCMD_STRETCHRECT, // see code |
|
PBCMD_ASYNC_LOCK_VB, // see code |
|
PBCMD_ASYNC_UNLOCK_VB, |
|
PBCMD_ASYNC_LOCK_IB, // see code |
|
PBCMD_ASYNC_UNLOCK_IB, |
|
PBCMD_SET_SCISSOR_RECT, // RECT |
|
}; |
|
|
|
|
|
|
|
#define N_DWORDS( x ) (( sizeof(x)+3)/sizeof( DWORD )) |
|
#define N_DWORDS_IN_PTR (N_DWORDS( void * )) |
|
|
|
class D3DDeviceWrapper |
|
{ |
|
private: |
|
IDirect3DDevice9 *m_pD3DDevice; |
|
bool m_bSupportsTessellation; |
|
int m_nCurrentTessLevel; |
|
TessellationMode_t m_nTessellationMode; |
|
|
|
#if SHADERAPI_USE_SMP |
|
uintptr_t m_pASyncThreadHandle; |
|
PushBuffer *m_pCurPushBuffer; |
|
uint32 *m_pOutputPtr; |
|
size_t m_PushBufferFreeSlots; |
|
#endif |
|
|
|
#if SHADERAPI_BUFFER_D3DCALLS |
|
bool m_bBufferingD3DCalls; |
|
# define SHADERAPI_BUFFER_MAXRENDERTARGETS 4 |
|
IDirect3DSurface9 *m_StoredRenderTargets[SHADERAPI_BUFFER_MAXRENDERTARGETS]; |
|
#endif |
|
|
|
PushBuffer *FindFreePushBuffer( PushBufferState newstate ); // find a free push buffer and change its state |
|
|
|
void GetPushBuffer(void); // set us up to point at a new push buffer |
|
void SubmitPushBufferAndGetANewOne(void); // submit the current push buffer |
|
void ExecutePushBuffer( PushBuffer const *pb); |
|
|
|
#if SHADERAPI_USE_SMP |
|
void Synchronize(void); // wait for all commands to be done |
|
#else |
|
FORCEINLINE void Synchronize(void) |
|
{ |
|
} |
|
#endif |
|
|
|
|
|
void SubmitIfNotBusy(void); |
|
|
|
#if SHADERAPI_USE_SMP |
|
template<class T> FORCEINLINE void PushStruct( PushBufferCommand cmd, T const *str ) |
|
{ |
|
int nwords=N_DWORDS( T ); |
|
AllocatePushBufferSpace( 1+ nwords ); |
|
m_pOutputPtr[0]=cmd; |
|
memcpy( m_pOutputPtr+1, str, sizeof( T ) ); |
|
m_pOutputPtr += 1+nwords; |
|
} |
|
|
|
FORCEINLINE void AllocatePushBufferSpace(size_t nSlots) |
|
{ |
|
// check for N slots of space, and decrement amount of space left |
|
if ( nSlots>m_PushBufferFreeSlots ) // out of room? |
|
{ |
|
SubmitPushBufferAndGetANewOne(); |
|
} |
|
m_PushBufferFreeSlots -= nSlots; |
|
} |
|
|
|
// simple methods for pushing a few words into output buffer |
|
FORCEINLINE void Push( PushBufferCommand cmd ) |
|
{ |
|
AllocatePushBufferSpace(1); |
|
m_pOutputPtr[0]=cmd; |
|
m_pOutputPtr++; |
|
} |
|
|
|
FORCEINLINE void Push( PushBufferCommand cmd, int arg1) |
|
{ |
|
AllocatePushBufferSpace(2); |
|
m_pOutputPtr[0]=cmd; |
|
m_pOutputPtr[1]=arg1; |
|
m_pOutputPtr += 2; |
|
} |
|
|
|
FORCEINLINE void Push( PushBufferCommand cmd, void *ptr ) |
|
{ |
|
AllocatePushBufferSpace(1+N_DWORDS_IN_PTR); |
|
*(m_pOutputPtr++)=cmd; |
|
*((void **) m_pOutputPtr)=ptr; |
|
m_pOutputPtr+=N_DWORDS_IN_PTR; |
|
} |
|
|
|
FORCEINLINE void Push( PushBufferCommand cmd, void *ptr, void *ptr1 ) |
|
{ |
|
AllocatePushBufferSpace(1+2*N_DWORDS_IN_PTR); |
|
*(m_pOutputPtr++)=cmd; |
|
*((void **) m_pOutputPtr)=ptr; |
|
m_pOutputPtr+=N_DWORDS_IN_PTR; |
|
*((void **) m_pOutputPtr)=ptr1; |
|
m_pOutputPtr+=N_DWORDS_IN_PTR; |
|
} |
|
|
|
FORCEINLINE void Push( PushBufferCommand cmd, void *arg1, uint32 arg2, uint32 arg3, uint32 arg4, |
|
void *arg5) |
|
{ |
|
AllocatePushBufferSpace(1+N_DWORDS_IN_PTR+1+1+1+N_DWORDS_IN_PTR); |
|
*(m_pOutputPtr++)=cmd; |
|
*((void **) m_pOutputPtr)=arg1; |
|
m_pOutputPtr+=N_DWORDS_IN_PTR; |
|
*(m_pOutputPtr++)=arg2; |
|
*(m_pOutputPtr++)=arg3; |
|
*(m_pOutputPtr++)=arg4; |
|
*((void **) m_pOutputPtr)=arg5; |
|
m_pOutputPtr+=N_DWORDS_IN_PTR; |
|
|
|
} |
|
|
|
FORCEINLINE void Push( PushBufferCommand cmd, uint32 arg1, void *ptr ) |
|
{ |
|
AllocatePushBufferSpace(2+N_DWORDS_IN_PTR); |
|
*(m_pOutputPtr++)=cmd; |
|
*(m_pOutputPtr++)=arg1; |
|
*((void **) m_pOutputPtr)=ptr; |
|
m_pOutputPtr+=N_DWORDS_IN_PTR; |
|
} |
|
|
|
FORCEINLINE void Push( PushBufferCommand cmd, uint32 arg1, void *ptr, int arg2, int arg3 ) |
|
{ |
|
AllocatePushBufferSpace( 4+N_DWORDS_IN_PTR ); |
|
*(m_pOutputPtr++)=cmd; |
|
*(m_pOutputPtr++)=arg1; |
|
*((void **) m_pOutputPtr)=ptr; |
|
m_pOutputPtr+=N_DWORDS_IN_PTR; |
|
m_pOutputPtr[0]=arg2; |
|
m_pOutputPtr[1]=arg3; |
|
m_pOutputPtr += 2; |
|
} |
|
|
|
FORCEINLINE void Push( PushBufferCommand cmd, int arg1, int arg2) |
|
{ |
|
AllocatePushBufferSpace(3); |
|
m_pOutputPtr[0]=cmd; |
|
m_pOutputPtr[1]=arg1; |
|
m_pOutputPtr[2]=arg2; |
|
m_pOutputPtr += 3; |
|
} |
|
|
|
FORCEINLINE void Push( PushBufferCommand cmd, int arg1, int arg2, int arg3) |
|
{ |
|
AllocatePushBufferSpace(4); |
|
m_pOutputPtr[0]=cmd; |
|
m_pOutputPtr[1]=arg1; |
|
m_pOutputPtr[2]=arg2; |
|
m_pOutputPtr[3]=arg3; |
|
m_pOutputPtr += 4; |
|
} |
|
|
|
FORCEINLINE void Push( PushBufferCommand cmd, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6 ) |
|
{ |
|
AllocatePushBufferSpace(7); |
|
m_pOutputPtr[0]=cmd; |
|
m_pOutputPtr[1]=arg1; |
|
m_pOutputPtr[2]=arg2; |
|
m_pOutputPtr[3]=arg3; |
|
m_pOutputPtr[4]=arg4; |
|
m_pOutputPtr[5]=arg5; |
|
m_pOutputPtr[6]=arg6; |
|
m_pOutputPtr += 7; |
|
} |
|
|
|
#else |
|
template<class T> FORCEINLINE void PushStruct( PushBufferCommand cmd, T const *str ) |
|
{ |
|
} |
|
|
|
FORCEINLINE void AllocatePushBufferSpace(size_t nSlots) |
|
{ |
|
} |
|
|
|
// simple methods for pushing a few words into output buffer |
|
FORCEINLINE void Push( PushBufferCommand cmd ) |
|
{ |
|
} |
|
|
|
FORCEINLINE void Push( PushBufferCommand cmd, int arg1) |
|
{ |
|
} |
|
|
|
FORCEINLINE void Push( PushBufferCommand cmd, void *ptr ) |
|
{ |
|
} |
|
|
|
FORCEINLINE void Push( PushBufferCommand cmd, void *ptr, void *ptr1 ) |
|
{ |
|
} |
|
|
|
FORCEINLINE void Push( PushBufferCommand cmd, void *arg1, uint32 arg2, uint32 arg3, uint32 arg4, |
|
void *arg5) |
|
{ |
|
} |
|
|
|
FORCEINLINE void Push( PushBufferCommand cmd, uint32 arg1, void *ptr ) |
|
{ |
|
} |
|
|
|
FORCEINLINE void Push( PushBufferCommand cmd, uint32 arg1, void *ptr, int arg2, int arg3 ) |
|
{ |
|
} |
|
|
|
FORCEINLINE void Push( PushBufferCommand cmd, int arg1, int arg2) |
|
{ |
|
} |
|
|
|
FORCEINLINE void Push( PushBufferCommand cmd, int arg1, int arg2, int arg3) |
|
{ |
|
} |
|
|
|
FORCEINLINE void Push( PushBufferCommand cmd, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6 ) |
|
{ |
|
} |
|
|
|
#endif |
|
|
|
FORCEINLINE bool ASyncMode(void) const |
|
{ |
|
#if SHADERAPI_USE_SMP |
|
# if SHADERAPI_BUFFER_D3DCALLS |
|
return m_bBufferingD3DCalls; |
|
# else |
|
return (m_pASyncThreadHandle != 0 ); |
|
# endif |
|
#else |
|
return false; |
|
#endif |
|
} |
|
|
|
FORCEINLINE IDirect3DDevice9* Dx9Device(void) const |
|
{ |
|
return m_pD3DDevice; |
|
} |
|
|
|
void AsynchronousLock( IDirect3DVertexBuffer9* vb, size_t offset, size_t size, void **ptr, |
|
DWORD flags, |
|
LockedBufferContext *lb); |
|
|
|
void AsynchronousLock( IDirect3DIndexBuffer9* ib, size_t offset, size_t size, void **ptr, |
|
DWORD flags, |
|
LockedBufferContext *lb); |
|
|
|
// handlers for push buffer contexts |
|
void HandleAsynchronousLockVBCommand( uint32 const *dptr ); |
|
void HandleAsynchronousUnLockVBCommand( uint32 const *dptr ); |
|
void HandleAsynchronousLockIBCommand( uint32 const *dptr ); |
|
void HandleAsynchronousUnLockIBCommand( uint32 const *dptr ); |
|
|
|
public: |
|
|
|
#if SHADERAPI_BUFFER_D3DCALLS |
|
void ExecuteAllWork( void ); |
|
#endif |
|
void RunThread( void ); // this is what the worker thread runs |
|
|
|
void SetASyncMode( bool onoff ); |
|
|
|
|
|
bool IsActive( void )const |
|
{ |
|
return m_pD3DDevice != NULL; |
|
} |
|
|
|
void D3DeviceWrapper(void) |
|
{ |
|
m_pD3DDevice = 0; |
|
#if SHADERAPI_USE_SMP |
|
m_pASyncThreadHandle = 0; |
|
#endif |
|
#if SHADERAPI_BUFFER_D3DCALLS |
|
m_bBufferingD3DCalls = false; |
|
#endif |
|
} |
|
|
|
void SetDevicePtr(IDirect3DDevice9 *pD3DDev ) |
|
{ |
|
m_pD3DDevice = pD3DDev; |
|
} |
|
|
|
void SetSupportsTessellation( bool bSupportsTessellation ) |
|
{ |
|
m_bSupportsTessellation = bSupportsTessellation; |
|
} |
|
|
|
void ShutDownDevice(void) |
|
{ |
|
if ( ASyncMode() ) |
|
{ |
|
// sync w/ thread |
|
} |
|
m_pD3DDevice = 0; |
|
} |
|
|
|
void FORCEINLINE SetDepthStencilSurface( IDirect3DSurface9 *new_stencil ) |
|
{ |
|
if ( ASyncMode() ) |
|
Push( PBCMD_SET_DEPTH_STENCIL_SURFACE, new_stencil ); |
|
else |
|
DO_D3D( SetDepthStencilSurface( new_stencil ) ); |
|
} |
|
|
|
HRESULT CreateCubeTexture( |
|
UINT EdgeLength, |
|
UINT Levels, |
|
DWORD Usage, |
|
D3DFORMAT Format, |
|
D3DPOOL Pool, |
|
IDirect3DCubeTexture9 ** ppCubeTexture, |
|
HANDLE* pSharedHandle, |
|
char *debugLabel = NULL // <-- OK to not pass this arg, only passed through on DX_TO_GL_ABSTRACTION |
|
) |
|
{ |
|
Synchronize(); |
|
return m_pD3DDevice->CreateCubeTexture( EdgeLength, Levels, Usage, Format, Pool, |
|
ppCubeTexture, pSharedHandle |
|
#if defined( DX_TO_GL_ABSTRACTION ) |
|
,debugLabel |
|
#endif |
|
); |
|
} |
|
|
|
HRESULT CreateVolumeTexture( |
|
UINT Width, |
|
UINT Height, |
|
UINT Depth, |
|
UINT Levels, |
|
DWORD Usage, |
|
D3DFORMAT Format, |
|
D3DPOOL Pool, |
|
IDirect3DVolumeTexture9** ppVolumeTexture, |
|
HANDLE* pSharedHandle, |
|
char *debugLabel = NULL // <-- OK to not pass this arg, only passed through on DX_TO_GL_ABSTRACTION |
|
) |
|
{ |
|
Synchronize(); |
|
return m_pD3DDevice->CreateVolumeTexture( Width, Height, Depth, Levels, |
|
Usage, Format, Pool, ppVolumeTexture, |
|
pSharedHandle |
|
#if defined( DX_TO_GL_ABSTRACTION ) |
|
,debugLabel |
|
#endif |
|
); |
|
} |
|
|
|
HRESULT CreateOffscreenPlainSurface( UINT Width, |
|
UINT Height, |
|
D3DFORMAT Format, |
|
D3DPOOL Pool, |
|
IDirect3DSurface9** ppSurface, |
|
HANDLE* pSharedHandle) |
|
{ |
|
Synchronize(); |
|
return m_pD3DDevice->CreateOffscreenPlainSurface( Width, Height, Format, Pool, |
|
ppSurface, pSharedHandle); |
|
} |
|
|
|
HRESULT CreateTexture( |
|
UINT Width, |
|
UINT Height, |
|
UINT Levels, |
|
DWORD Usage, |
|
D3DFORMAT Format, |
|
D3DPOOL Pool, |
|
IDirect3DTexture9** ppTexture, |
|
HANDLE* pSharedHandle, |
|
char *debugLabel = NULL // <-- OK to not pass this arg, only passed through on DX_TO_GL_ABSTRACTION |
|
) |
|
{ |
|
Synchronize(); |
|
return m_pD3DDevice->CreateTexture( Width, Height, Levels, Usage, |
|
Format, Pool, ppTexture, pSharedHandle |
|
#if defined( DX_TO_GL_ABSTRACTION ) |
|
,debugLabel |
|
#endif |
|
); |
|
} |
|
|
|
HRESULT GetRenderTargetData( |
|
IDirect3DSurface9* pRenderTarget, |
|
IDirect3DSurface9* pDestSurface |
|
) |
|
{ |
|
Synchronize(); |
|
return m_pD3DDevice->GetRenderTargetData( pRenderTarget, pDestSurface ); |
|
} |
|
|
|
|
|
void GetDeviceCaps( D3DCAPS9 * pCaps ) |
|
{ |
|
Synchronize(); |
|
m_pD3DDevice->GetDeviceCaps( pCaps ); |
|
} |
|
|
|
LPCSTR GetPixelShaderProfile( void ) |
|
{ |
|
Synchronize(); |
|
return D3DXGetPixelShaderProfile( m_pD3DDevice ); |
|
} |
|
|
|
HRESULT TestCooperativeLevel( void ) |
|
{ |
|
// hack! We are going to assume that calling this immediately when in buffered mode isn't going to cause problems. |
|
#if !SHADERAPI_BUFFER_D3DCALLS |
|
Synchronize(); |
|
#endif |
|
return m_pD3DDevice->TestCooperativeLevel(); |
|
} |
|
|
|
HRESULT GetFrontBufferData( UINT iSwapChain, IDirect3DSurface9 * pDestSurface ) |
|
{ |
|
Synchronize(); |
|
return m_pD3DDevice->GetFrontBufferData( iSwapChain, pDestSurface ); |
|
} |
|
|
|
void SetGammaRamp( int swapchain, int flags, D3DGAMMARAMP const *pRamp) |
|
{ |
|
Synchronize(); |
|
m_pD3DDevice->SetGammaRamp( swapchain, flags, pRamp); |
|
} |
|
|
|
HRESULT GetTexture( DWORD Stage, IDirect3DBaseTexture9 ** ppTexture ) |
|
{ |
|
Synchronize(); |
|
return m_pD3DDevice->GetTexture( Stage, ppTexture ); |
|
} |
|
|
|
HRESULT GetFVF( DWORD * pFVF ) |
|
{ |
|
Synchronize(); |
|
return m_pD3DDevice->GetFVF( pFVF ); |
|
} |
|
|
|
HRESULT GetDepthStencilSurface( |
|
IDirect3DSurface9 ** ppZStencilSurface |
|
) |
|
{ |
|
Synchronize(); |
|
return m_pD3DDevice->GetDepthStencilSurface( ppZStencilSurface ); |
|
} |
|
|
|
FORCEINLINE void SetClipPlane( int idx, float const * pplane) |
|
{ |
|
RECORD_COMMAND( DX8_SET_CLIP_PLANE, 5 ); |
|
RECORD_INT( idx ); |
|
RECORD_FLOAT( pplane[0] ); |
|
RECORD_FLOAT( pplane[1] ); |
|
RECORD_FLOAT( pplane[2] ); |
|
RECORD_FLOAT( pplane[3] ); |
|
#if SHADERAPI_USE_SMP |
|
if ( ASyncMode() ) |
|
{ |
|
AllocatePushBufferSpace( 6 ); |
|
m_pOutputPtr[0]=PBCMD_SETCLIPPLANE; |
|
m_pOutputPtr[1]=idx; |
|
memcpy(m_pOutputPtr+2,pplane, 4*sizeof(float) ); |
|
m_pOutputPtr += 6; |
|
} |
|
else |
|
#endif |
|
DO_D3D( SetClipPlane( idx, pplane ) ); |
|
} |
|
|
|
FORCEINLINE void SetVertexDeclaration( IDirect3DVertexDeclaration9 *decl ) |
|
{ |
|
RECORD_COMMAND( DX8_SET_VERTEX_DECLARATION, 1 ); |
|
RECORD_INT( ( int ) decl ); |
|
|
|
#if SHADERAPI_USE_SMP |
|
if ( ASyncMode() ) |
|
{ |
|
Push( PBCMD_SET_VERTEXDECLARATION, decl ); |
|
} |
|
else |
|
#endif |
|
DO_D3D( SetVertexDeclaration( decl ) ); |
|
} |
|
|
|
FORCEINLINE void SetViewport( D3DVIEWPORT9 const *vp ) |
|
{ |
|
RECORD_COMMAND( DX8_SET_VIEWPORT, 1 ); |
|
RECORD_STRUCT( vp, sizeof( *vp )); |
|
|
|
#if SHADERAPI_USE_SMP |
|
if ( ASyncMode() ) |
|
PushStruct( PBCMD_SETVIEWPORT, vp ); |
|
else |
|
#endif |
|
DO_D3D( SetViewport( vp ) ); |
|
} |
|
|
|
HRESULT GetRenderTarget( |
|
DWORD RenderTargetIndex, |
|
IDirect3DSurface9 ** ppRenderTarget) |
|
{ |
|
#if SHADERAPI_BUFFER_D3DCALLS |
|
if ( ASyncMode() ) |
|
{ |
|
Assert( RenderTargetIndex >= 0 && RenderTargetIndex < SHADERAPI_BUFFER_MAXRENDERTARGETS ); |
|
*ppRenderTarget = m_StoredRenderTargets[RenderTargetIndex]; |
|
return D3D_OK; |
|
} |
|
#endif |
|
Synchronize(); |
|
return m_pD3DDevice->GetRenderTarget( RenderTargetIndex, ppRenderTarget ); |
|
} |
|
|
|
HRESULT CreateQuery( D3DQUERYTYPE Type, IDirect3DQuery9** ppQuery ) |
|
{ |
|
Synchronize(); |
|
return m_pD3DDevice->CreateQuery( Type, ppQuery ); |
|
} |
|
|
|
HRESULT CreateRenderTarget( |
|
UINT Width, |
|
UINT Height, |
|
D3DFORMAT Format, |
|
D3DMULTISAMPLE_TYPE MultiSample, |
|
DWORD MultisampleQuality, |
|
BOOL Lockable, |
|
IDirect3DSurface9** ppSurface, |
|
HANDLE* pSharedHandle |
|
) |
|
{ |
|
Synchronize(); |
|
return m_pD3DDevice->CreateRenderTarget( Width, Height, Format, MultiSample, |
|
MultisampleQuality, Lockable, ppSurface, |
|
pSharedHandle); |
|
} |
|
|
|
HRESULT CreateDepthStencilSurface( |
|
UINT Width, |
|
UINT Height, |
|
D3DFORMAT Format, |
|
D3DMULTISAMPLE_TYPE MultiSample, |
|
DWORD MultisampleQuality, |
|
BOOL Discard, |
|
IDirect3DSurface9** ppSurface, |
|
HANDLE* pSharedHandle |
|
) |
|
{ |
|
Synchronize(); |
|
return m_pD3DDevice->CreateDepthStencilSurface( Width, Height, Format, MultiSample, |
|
MultisampleQuality, Discard, ppSurface, |
|
pSharedHandle ); |
|
} |
|
|
|
|
|
FORCEINLINE void SetRenderTarget( int idx, IDirect3DSurface9 *new_rt ) |
|
{ |
|
if (ASyncMode()) |
|
{ |
|
Push( PBCMD_SET_RENDER_TARGET, idx, new_rt ); |
|
#if SHADERAPI_BUFFER_D3DCALLS |
|
m_StoredRenderTargets[idx] = new_rt; |
|
#endif |
|
} |
|
else |
|
{ |
|
// NOTE: If the debug runtime breaks here on the shadow depth render target that is normal. dx9 doesn't directly support shadow |
|
// depth texturing so we are forced to initialize this texture without the render target flagr |
|
DO_D3D( SetRenderTarget( idx, new_rt) ); |
|
} |
|
} |
|
|
|
FORCEINLINE void LightEnable( int lidx, bool onoff ) |
|
{ |
|
RECORD_COMMAND( DX8_LIGHT_ENABLE, 2 ); |
|
RECORD_INT( lidx ); |
|
RECORD_INT( onoff ); |
|
|
|
Synchronize(); |
|
DO_D3D( LightEnable( lidx, onoff ) ); |
|
} |
|
|
|
FORCEINLINE void SetRenderState( D3DRENDERSTATETYPE state, DWORD val ) |
|
{ |
|
// Assert( state >= 0 && state < MAX_NUM_RENDERSTATES ); |
|
RECORD_RENDER_STATE( state, val ); |
|
if (ASyncMode()) |
|
{ |
|
Push( PBCMD_SET_RENDERSTATE, state, val ); |
|
} |
|
else |
|
DO_D3D( SetRenderState( state, val ) ); |
|
} |
|
|
|
FORCEINLINE void SetRenderStateInline( D3DRENDERSTATETYPE state, DWORD val ) |
|
{ |
|
// Assert( state >= 0 && state < MAX_NUM_RENDERSTATES ); |
|
RECORD_RENDER_STATE( state, val ); |
|
if (ASyncMode()) |
|
{ |
|
SetRenderState( state, val ); |
|
} |
|
else |
|
{ |
|
#ifdef DX_TO_GL_ABSTRACTION |
|
DO_D3D( SetRenderStateInline( state, val ) ); |
|
#else |
|
DO_D3D( SetRenderState( state, val ) ); |
|
#endif |
|
} |
|
} |
|
|
|
FORCEINLINE void SetScissorRect( const RECT *pScissorRect ) |
|
{ |
|
RECORD_COMMAND( DX8_SET_SCISSOR_RECT, 1 ); |
|
RECORD_STRUCT( pScissorRect, 4 * sizeof(LONG) ); |
|
#if SHADERAPI_USE_SMP |
|
if ( ASyncMode() ) |
|
{ |
|
AllocatePushBufferSpace( 5 ); |
|
m_pOutputPtr[0] = PBCMD_SET_SCISSOR_RECT; |
|
memcpy( m_pOutputPtr + 1, pScissorRect, sizeof( *pScissorRect ) ); |
|
} |
|
else |
|
#endif |
|
DO_D3D( SetScissorRect( pScissorRect ) ); |
|
} |
|
|
|
FORCEINLINE void SetVertexShaderConstantF( UINT StartRegister, CONST float * pConstantData, |
|
UINT Vector4fCount) |
|
{ |
|
RECORD_COMMAND( DX8_SET_VERTEX_SHADER_CONSTANT, 3 ); |
|
RECORD_INT( StartRegister ); |
|
RECORD_INT( Vector4fCount ); |
|
RECORD_STRUCT( pConstantData, Vector4fCount * 4 * sizeof(float) ); |
|
#if SHADERAPI_USE_SMP |
|
if ( ASyncMode() ) |
|
{ |
|
AllocatePushBufferSpace(3+4*Vector4fCount); |
|
m_pOutputPtr[0]=PBCMD_SET_VERTEX_SHADER_CONSTANT; |
|
m_pOutputPtr[1]=StartRegister; |
|
m_pOutputPtr[2]=Vector4fCount; |
|
memcpy(m_pOutputPtr+3,pConstantData,sizeof(float)*4*Vector4fCount); |
|
m_pOutputPtr+=3+4*Vector4fCount; |
|
} |
|
else |
|
#endif |
|
DO_D3D( SetVertexShaderConstantF( StartRegister, pConstantData, Vector4fCount ) ); |
|
} |
|
|
|
FORCEINLINE void SetVertexShaderConstantB( UINT StartRegister, CONST int * pConstantData, |
|
UINT BoolCount) |
|
{ |
|
RECORD_COMMAND( DX8_SET_VERTEX_SHADER_CONSTANT, 3 ); |
|
RECORD_INT( StartRegister ); |
|
RECORD_INT( BoolCount ); |
|
RECORD_STRUCT( pConstantData, BoolCount * sizeof(int) ); |
|
#if SHADERAPI_USE_SMP |
|
if ( ASyncMode() ) |
|
{ |
|
AllocatePushBufferSpace(3+BoolCount); |
|
m_pOutputPtr[0]=PBCMD_SET_BOOLEAN_VERTEX_SHADER_CONSTANT; |
|
m_pOutputPtr[1]=StartRegister; |
|
m_pOutputPtr[2]=BoolCount; |
|
memcpy(m_pOutputPtr+3,pConstantData,sizeof(int)*BoolCount); |
|
m_pOutputPtr+=3+BoolCount; |
|
} |
|
else |
|
#endif |
|
DO_D3D( SetVertexShaderConstantB( StartRegister, pConstantData, BoolCount ) ); |
|
} |
|
|
|
FORCEINLINE void SetVertexShaderConstantI( UINT StartRegister, CONST int * pConstantData, |
|
UINT Vector4IntCount) |
|
{ |
|
RECORD_COMMAND( DX8_SET_VERTEX_SHADER_CONSTANT, 3 ); |
|
RECORD_INT( StartRegister ); |
|
RECORD_INT( Vector4IntCount ); |
|
RECORD_STRUCT( pConstantData, Vector4IntCount * 4 * sizeof(int) ); |
|
#if SHADERAPI_USE_SMP |
|
if ( ASyncMode() ) |
|
{ |
|
AllocatePushBufferSpace(3+4*Vector4IntCount); |
|
m_pOutputPtr[0]=PBCMD_SET_INTEGER_VERTEX_SHADER_CONSTANT; |
|
m_pOutputPtr[1]=StartRegister; |
|
m_pOutputPtr[2]=Vector4IntCount; |
|
memcpy(m_pOutputPtr+3,pConstantData,sizeof(int)*4*Vector4IntCount); |
|
m_pOutputPtr+=3+4*Vector4IntCount; |
|
} |
|
else |
|
#endif |
|
DO_D3D( SetVertexShaderConstantI( StartRegister, pConstantData, Vector4IntCount ) ); |
|
} |
|
|
|
FORCEINLINE void SetPixelShaderConstantF( UINT StartRegister, CONST float * pConstantData, |
|
UINT Vector4fCount) |
|
{ |
|
RECORD_COMMAND( DX8_SET_PIXEL_SHADER_CONSTANT, 3 ); |
|
RECORD_INT( StartRegister ); |
|
RECORD_INT( Vector4fCount ); |
|
RECORD_STRUCT( pConstantData, Vector4fCount * 4 * sizeof(float) ); |
|
#if SHADERAPI_USE_SMP |
|
if ( ASyncMode() ) |
|
{ |
|
AllocatePushBufferSpace(3+4*Vector4fCount); |
|
m_pOutputPtr[0]=PBCMD_SET_PIXEL_SHADER_CONSTANT; |
|
m_pOutputPtr[1]=StartRegister; |
|
m_pOutputPtr[2]=Vector4fCount; |
|
memcpy(m_pOutputPtr+3,pConstantData,sizeof(float)*4*Vector4fCount); |
|
m_pOutputPtr+=3+4*Vector4fCount; |
|
} |
|
else |
|
#endif |
|
DO_D3D( SetPixelShaderConstantF( StartRegister, pConstantData, Vector4fCount ) ); |
|
} |
|
|
|
FORCEINLINE void SetPixelShaderConstantB( UINT StartRegister, CONST int * pConstantData, |
|
UINT BoolCount) |
|
{ |
|
RECORD_COMMAND( DX8_SET_PIXEL_SHADER_CONSTANT, 3 ); |
|
RECORD_INT( StartRegister ); |
|
RECORD_INT( BoolCount ); |
|
RECORD_STRUCT( pConstantData, BoolCount * sizeof(int) ); |
|
#if SHADERAPI_USE_SMP |
|
if ( ASyncMode() ) |
|
{ |
|
AllocatePushBufferSpace(3+BoolCount); |
|
m_pOutputPtr[0]=PBCMD_SET_BOOLEAN_PIXEL_SHADER_CONSTANT; |
|
m_pOutputPtr[1]=StartRegister; |
|
m_pOutputPtr[2]=BoolCount; |
|
memcpy(m_pOutputPtr+3,pConstantData,sizeof(int)*BoolCount); |
|
m_pOutputPtr+=3+BoolCount; |
|
} |
|
else |
|
#endif |
|
DO_D3D( SetPixelShaderConstantB( StartRegister, pConstantData, BoolCount ) ); |
|
} |
|
|
|
FORCEINLINE void SetPixelShaderConstantI( UINT StartRegister, CONST int * pConstantData, |
|
UINT Vector4IntCount) |
|
{ |
|
RECORD_COMMAND( DX8_SET_PIXEL_SHADER_CONSTANT, 3 ); |
|
RECORD_INT( StartRegister ); |
|
RECORD_INT( Vector4IntCount ); |
|
RECORD_STRUCT( pConstantData, Vector4IntCount * 4 * sizeof(int) ); |
|
#if SHADERAPI_USE_SMP |
|
if ( ASyncMode() ) |
|
{ |
|
AllocatePushBufferSpace(3+4*Vector4IntCount); |
|
m_pOutputPtr[0]=PBCMD_SET_INTEGER_PIXEL_SHADER_CONSTANT; |
|
m_pOutputPtr[1]=StartRegister; |
|
m_pOutputPtr[2]=Vector4IntCount; |
|
memcpy(m_pOutputPtr+3,pConstantData,sizeof(int)*4*Vector4IntCount); |
|
m_pOutputPtr+=3+4*Vector4IntCount; |
|
} |
|
else |
|
#endif |
|
DO_D3D( SetPixelShaderConstantI( StartRegister, pConstantData, Vector4IntCount ) ); |
|
} |
|
|
|
HRESULT StretchRect( IDirect3DSurface9 * pSourceSurface, |
|
CONST RECT * pSourceRect, |
|
IDirect3DSurface9 * pDestSurface, |
|
CONST RECT * pDestRect, |
|
D3DTEXTUREFILTERTYPE Filter ) |
|
{ |
|
#if SHADERAPI_USE_SMP |
|
if ( ASyncMode() ) |
|
{ |
|
AllocatePushBufferSpace(1+1+1+N_DWORDS( RECT )+1+1+N_DWORDS( RECT ) + 1); |
|
*(m_pOutputPtr++)=PBCMD_STRETCHRECT; |
|
*(m_pOutputPtr++)=(int) pSourceSurface; |
|
*(m_pOutputPtr++)=(pSourceRect != NULL); |
|
if (pSourceRect) |
|
{ |
|
memcpy(m_pOutputPtr,pSourceRect,sizeof(RECT)); |
|
} |
|
m_pOutputPtr+=N_DWORDS(RECT); |
|
*(m_pOutputPtr++)=(int) pDestSurface; |
|
*(m_pOutputPtr++)=(pDestRect != NULL); |
|
if (pDestRect) |
|
memcpy(m_pOutputPtr,pDestRect,sizeof(RECT)); |
|
m_pOutputPtr+=N_DWORDS(RECT); |
|
*(m_pOutputPtr++)=Filter; |
|
return S_OK; // !bug! |
|
} |
|
else |
|
#endif |
|
return m_pD3DDevice-> |
|
StretchRect( pSourceSurface, pSourceRect, pDestSurface, pDestRect, Filter ); |
|
} |
|
|
|
|
|
FORCEINLINE void BeginScene(void) |
|
{ |
|
RECORD_COMMAND( DX8_BEGIN_SCENE, 0 ); |
|
if ( ASyncMode() ) |
|
Push( PBCMD_BEGIN_SCENE ); |
|
else |
|
DO_D3D( BeginScene() ); |
|
} |
|
|
|
FORCEINLINE void EndScene(void) |
|
{ |
|
RECORD_COMMAND( DX8_END_SCENE, 0 ); |
|
if ( ASyncMode() ) |
|
Push( PBCMD_END_SCENE ); |
|
else |
|
DO_D3D( EndScene() ); |
|
} |
|
|
|
FORCEINLINE HRESULT Lock( IDirect3DVertexBuffer9* vb, size_t offset, size_t size, void **ptr, DWORD flags ) |
|
{ |
|
Assert( size ); // lock size of 0 = unknown entire size of buffer = bad |
|
Synchronize(); |
|
|
|
HRESULT hr = vb->Lock(offset, size, ptr, flags); |
|
switch (hr) |
|
{ |
|
case D3DERR_INVALIDCALL: |
|
Warning( "D3DERR_INVALIDCALL - Vertex Buffer Lock Failed in %s on line %d(offset %d, size %d, flags 0x%x)\n", V_UnqualifiedFileName(__FILE__), __LINE__, offset, size, flags ); |
|
break; |
|
case D3DERR_DRIVERINTERNALERROR: |
|
Warning( "D3DERR_DRIVERINTERNALERROR - Vertex Buffer Lock Failed in %s on line %d (offset %d, size %d, flags 0x%x)\n", V_UnqualifiedFileName(__FILE__), __LINE__, offset, size, flags ); |
|
break; |
|
case D3DERR_OUTOFVIDEOMEMORY: |
|
Warning( "D3DERR_OUTOFVIDEOMEMORY - Vertex Buffer Lock Failed in %s on line %d (offset %d, size %d, flags 0x%x)\n", V_UnqualifiedFileName(__FILE__), __LINE__, offset, size, flags ); |
|
break; |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
|
|
FORCEINLINE HRESULT Lock( IDirect3DVertexBuffer9* vb, size_t offset, size_t size, void **ptr, |
|
DWORD flags, |
|
LockedBufferContext *lb) |
|
{ |
|
|
|
HRESULT hr = D3D_OK; |
|
|
|
// asynchronous write-only dynamic vb lock |
|
if ( ASyncMode() ) |
|
{ |
|
AsynchronousLock( vb, offset, size, ptr, flags, lb ); |
|
} |
|
else |
|
{ |
|
hr = vb->Lock(offset, size, ptr, flags); |
|
switch (hr) |
|
{ |
|
case D3DERR_INVALIDCALL: |
|
Warning( "D3DERR_INVALIDCALL - Vertex Buffer Lock Failed in %s on line %d(offset %d, size %d, flags 0x%x)\n", V_UnqualifiedFileName(__FILE__), __LINE__, offset, size, flags ); |
|
break; |
|
case D3DERR_DRIVERINTERNALERROR: |
|
Warning( "D3DERR_DRIVERINTERNALERROR - Vertex Buffer Lock Failed in %s on line %d (offset %d, size %d, flags 0x%x)\n", V_UnqualifiedFileName(__FILE__), __LINE__, offset, size, flags ); |
|
break; |
|
case D3DERR_OUTOFVIDEOMEMORY: |
|
Warning( "D3DERR_OUTOFVIDEOMEMORY - Vertex Buffer Lock Failed in %s on line %d (offset %d, size %d, flags 0x%x)\n", V_UnqualifiedFileName(__FILE__), __LINE__, offset, size, flags ); |
|
break; |
|
} |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
FORCEINLINE HRESULT Lock( IDirect3DIndexBuffer9* ib, size_t offset, size_t size, void **ptr, DWORD flags) |
|
{ |
|
HRESULT hr = D3D_OK; |
|
|
|
Synchronize(); |
|
|
|
hr = ib->Lock(offset, size, ptr, flags); |
|
switch (hr) |
|
{ |
|
case D3DERR_INVALIDCALL: |
|
Warning( "D3DERR_INVALIDCALL - Index Buffer Lock Failed in %s on line %d(offset %d, size %d, flags 0x%x)\n", V_UnqualifiedFileName(__FILE__), __LINE__, offset, size, flags ); |
|
break; |
|
case D3DERR_DRIVERINTERNALERROR: |
|
Warning( "D3DERR_DRIVERINTERNALERROR - Index Buffer Lock Failed in %s on line %d (offset %d, size %d, flags 0x%x)\n", V_UnqualifiedFileName(__FILE__), __LINE__, offset, size, flags ); |
|
break; |
|
case D3DERR_OUTOFVIDEOMEMORY: |
|
Warning( "D3DERR_OUTOFVIDEOMEMORY - Index Buffer Lock Failed in %s on line %d (offset %d, size %d, flags 0x%x)\n", V_UnqualifiedFileName(__FILE__), __LINE__, offset, size, flags ); |
|
break; |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
// asycnhronous lock of index buffer |
|
FORCEINLINE HRESULT Lock( IDirect3DIndexBuffer9* ib, size_t offset, size_t size, void **ptr, DWORD flags, |
|
LockedBufferContext * lb) |
|
{ |
|
HRESULT hr = D3D_OK; |
|
|
|
if ( ASyncMode() ) |
|
AsynchronousLock( ib, offset, size, ptr, flags, lb ); |
|
else |
|
{ |
|
hr = ib->Lock(offset, size, ptr, flags); |
|
switch (hr) |
|
{ |
|
case D3DERR_INVALIDCALL: |
|
Warning( "D3DERR_INVALIDCALL - Index Buffer Lock Failed in %s on line %d(offset %d, size %d, flags 0x%x)\n", V_UnqualifiedFileName(__FILE__), __LINE__, offset, size, flags ); |
|
break; |
|
case D3DERR_DRIVERINTERNALERROR: |
|
Warning( "D3DERR_DRIVERINTERNALERROR - Index Buffer Lock Failed in %s on line %d (offset %d, size %d, flags 0x%x)\n", V_UnqualifiedFileName(__FILE__), __LINE__, offset, size, flags ); |
|
break; |
|
case D3DERR_OUTOFVIDEOMEMORY: |
|
Warning( "D3DERR_OUTOFVIDEOMEMORY - Index Buffer Lock Failed in %s on line %d (offset %d, size %d, flags 0x%x)\n", V_UnqualifiedFileName(__FILE__), __LINE__, offset, size, flags ); |
|
break; |
|
} |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
#ifndef DX_TO_GL_ABSTRACTION |
|
FORCEINLINE HRESULT UpdateSurface( IDirect3DSurface9* pSourceSurface, CONST RECT* pSourceRect, IDirect3DSurface9* pDestSurface, CONST POINT* pDestPoint ) |
|
{ |
|
return m_pD3DDevice->UpdateSurface( pSourceSurface, pSourceRect, pDestSurface, pDestPoint ); |
|
} |
|
#endif |
|
|
|
void Release( IDirect3DIndexBuffer9* ib ) |
|
{ |
|
Synchronize(); |
|
ib->Release(); |
|
} |
|
|
|
void Release( IDirect3DVertexBuffer9* vb ) |
|
{ |
|
Synchronize(); |
|
vb->Release(); |
|
} |
|
|
|
FORCEINLINE void Unlock( IDirect3DVertexBuffer9* vb ) |
|
{ |
|
// needed for d3d on pc only |
|
if ( ASyncMode() ) |
|
Push(PBCMD_UNLOCK_VB, vb); |
|
else |
|
{ |
|
HRESULT hr = vb->Unlock( ); |
|
|
|
if ( FAILED(hr) ) |
|
{ |
|
Warning( "Vertex Buffer Unlock Failed in %s on line %d\n", V_UnqualifiedFileName(__FILE__), __LINE__ ); |
|
} |
|
} |
|
} |
|
|
|
FORCEINLINE void Unlock( IDirect3DVertexBuffer9* vb, LockedBufferContext *lb, size_t unlock_size) |
|
{ |
|
// needed for d3d on pc only |
|
#if SHADERAPI_USE_SMP |
|
if ( ASyncMode() ) |
|
{ |
|
AllocatePushBufferSpace( 1+N_DWORDS_IN_PTR+N_DWORDS( LockedBufferContext )+1 ); |
|
*(m_pOutputPtr++)=PBCMD_ASYNC_UNLOCK_VB; |
|
*((IDirect3DVertexBuffer9* *) m_pOutputPtr)=vb; |
|
m_pOutputPtr+=N_DWORDS_IN_PTR; |
|
*((LockedBufferContext *) m_pOutputPtr)=*lb; |
|
m_pOutputPtr+=N_DWORDS( LockedBufferContext ); |
|
*(m_pOutputPtr++)=unlock_size; |
|
} |
|
else |
|
#endif |
|
{ |
|
HRESULT hr = vb->Unlock(); |
|
|
|
if ( FAILED(hr) ) |
|
{ |
|
Warning( "Vertex Buffer Unlock Failed in %s on line %d\n", V_UnqualifiedFileName(__FILE__), __LINE__ ); |
|
} |
|
} |
|
} |
|
|
|
FORCEINLINE void Unlock( IDirect3DIndexBuffer9* ib ) |
|
{ |
|
// needed for d3d on pc only |
|
if ( ASyncMode() ) |
|
Push(PBCMD_UNLOCK_IB, ib); |
|
else |
|
{ |
|
HRESULT hr = ib->Unlock(); |
|
|
|
if ( FAILED(hr) ) |
|
{ |
|
Warning( "Index Buffer Unlock Failed in %s on line %d\n", V_UnqualifiedFileName(__FILE__), __LINE__ ); |
|
} |
|
} |
|
} |
|
|
|
FORCEINLINE void Unlock( IDirect3DIndexBuffer9* ib, LockedBufferContext *lb, size_t unlock_size) |
|
{ |
|
// needed for d3d on pc only |
|
#if SHADERAPI_USE_SMP |
|
if ( ASyncMode() ) |
|
{ |
|
AllocatePushBufferSpace( 1+N_DWORDS_IN_PTR+N_DWORDS( LockedBufferContext )+1 ); |
|
*(m_pOutputPtr++)=PBCMD_ASYNC_UNLOCK_IB; |
|
*((IDirect3DIndexBuffer9* *) m_pOutputPtr)=ib; |
|
m_pOutputPtr+=N_DWORDS_IN_PTR; |
|
*((LockedBufferContext *) m_pOutputPtr)=*lb; |
|
m_pOutputPtr+=N_DWORDS( LockedBufferContext ); |
|
*(m_pOutputPtr++)=unlock_size; |
|
} |
|
else |
|
#endif |
|
{ |
|
HRESULT hr = ib->Unlock( ); |
|
|
|
if ( FAILED(hr) ) |
|
{ |
|
Warning( "Index Buffer Unlock Failed in %s on line %d\n", V_UnqualifiedFileName(__FILE__), __LINE__ ); |
|
} |
|
} |
|
} |
|
|
|
void ShowCursor( bool onoff) |
|
{ |
|
Synchronize(); |
|
DO_D3D( ShowCursor(onoff) ); |
|
} |
|
|
|
FORCEINLINE void Clear( int count, D3DRECT const *pRects, int Flags, D3DCOLOR color, float Z, int stencil) |
|
{ |
|
#if SHADERAPI_USE_SMP |
|
if ( ASyncMode() ) |
|
{ |
|
int n_rects_words = count * N_DWORDS( D3DRECT ); |
|
AllocatePushBufferSpace( 2 + n_rects_words + 4 ); |
|
*(m_pOutputPtr++) = PBCMD_CLEAR; |
|
*(m_pOutputPtr++) = count; |
|
if ( count ) |
|
{ |
|
memcpy( m_pOutputPtr, pRects, count * sizeof( D3DRECT ) ); |
|
m_pOutputPtr += n_rects_words; |
|
} |
|
*(m_pOutputPtr++) = Flags; |
|
*( (D3DCOLOR *) m_pOutputPtr ) = color; |
|
m_pOutputPtr++; |
|
*( (float *) m_pOutputPtr ) = Z; |
|
m_pOutputPtr++; |
|
*(m_pOutputPtr++) = stencil; |
|
} |
|
else |
|
#endif |
|
DO_D3D( Clear(count, pRects, Flags, color, Z, stencil) ); |
|
} |
|
|
|
HRESULT Reset( D3DPRESENT_PARAMETERS *parms) |
|
{ |
|
RECORD_COMMAND( DX8_RESET, 1 ); |
|
RECORD_STRUCT( parms, sizeof(*parms) ); |
|
Synchronize(); |
|
return m_pD3DDevice->Reset( parms ); |
|
} |
|
|
|
void Release( void ) |
|
{ |
|
Synchronize(); |
|
DO_D3D( Release() ); |
|
} |
|
|
|
FORCEINLINE void SetTexture(int stage, IDirect3DBaseTexture9 *txtr) |
|
{ |
|
RECORD_COMMAND( DX8_SET_TEXTURE, 3 ); |
|
RECORD_INT( stage ); |
|
RECORD_INT( -1 ); |
|
RECORD_INT( -1 ); |
|
if (ASyncMode()) |
|
{ |
|
Push( PBCMD_SET_TEXTURE, stage, txtr ); |
|
} |
|
else |
|
DO_D3D( SetTexture( stage, txtr) ); |
|
} |
|
void SetTransform( D3DTRANSFORMSTATETYPE mtrx_id, D3DXMATRIX const *mt) |
|
{ |
|
RECORD_COMMAND( DX8_SET_TRANSFORM, 2 ); |
|
RECORD_INT( mtrx_id ); |
|
RECORD_STRUCT( mt, sizeof(D3DXMATRIX) ); |
|
Synchronize(); |
|
DO_D3D( SetTransform( mtrx_id, mt) ); |
|
} |
|
|
|
FORCEINLINE void SetSamplerState( int stage, D3DSAMPLERSTATETYPE state, DWORD val) |
|
{ |
|
RECORD_SAMPLER_STATE( stage, state, val ); |
|
if ( ASyncMode() ) |
|
Push( PBCMD_SET_SAMPLER_STATE, stage, state, val ); |
|
else |
|
DO_D3D( SetSamplerState( stage, state, val) ); |
|
} |
|
|
|
void SetFVF( int fvf) |
|
{ |
|
Synchronize(); |
|
DO_D3D( SetFVF( fvf) ); |
|
} |
|
|
|
FORCEINLINE void SetTextureStageState( int stage, D3DTEXTURESTAGESTATETYPE state, DWORD val ) |
|
{ |
|
RECORD_TEXTURE_STAGE_STATE( stage, state, val ); |
|
Synchronize(); |
|
DO_D3D( SetTextureStageState( stage, state, val) ); |
|
} |
|
|
|
FORCEINLINE void DrawPrimitive( |
|
D3DPRIMITIVETYPE PrimitiveType, |
|
UINT StartVertex, |
|
UINT PrimitiveCount |
|
) |
|
{ |
|
RECORD_COMMAND( DX8_DRAW_PRIMITIVE, 3 ); |
|
RECORD_INT( PrimitiveType ); |
|
RECORD_INT( StartVertex ); |
|
RECORD_INT( PrimitiveCount ); |
|
if ( ASyncMode() ) |
|
{ |
|
Push( PBCMD_DRAWPRIM, PrimitiveType, StartVertex, PrimitiveCount ); |
|
SubmitIfNotBusy(); |
|
} |
|
else |
|
DO_D3D( DrawPrimitive( PrimitiveType, StartVertex, PrimitiveCount ) ); |
|
|
|
} |
|
|
|
HRESULT CreateVertexDeclaration( |
|
CONST D3DVERTEXELEMENT9* pVertexElements, |
|
IDirect3DVertexDeclaration9** ppDecl |
|
) |
|
{ |
|
Synchronize(); |
|
return m_pD3DDevice->CreateVertexDeclaration( pVertexElements, ppDecl ); |
|
} |
|
|
|
|
|
HRESULT ValidateDevice( DWORD * pNumPasses ) |
|
{ |
|
Synchronize(); |
|
return m_pD3DDevice->ValidateDevice( pNumPasses ); |
|
} |
|
|
|
|
|
|
|
HRESULT CreateVertexShader( |
|
CONST DWORD * pFunction, |
|
IDirect3DVertexShader9** ppShader, |
|
const char *pShaderName, |
|
char *debugLabel = NULL |
|
) |
|
{ |
|
Synchronize(); |
|
#ifdef DX_TO_GL_ABSTRACTION |
|
return m_pD3DDevice->CreateVertexShader( pFunction, ppShader, pShaderName, debugLabel ); |
|
#else |
|
return m_pD3DDevice->CreateVertexShader( pFunction, ppShader ); |
|
#endif |
|
} |
|
|
|
HRESULT CreatePixelShader( |
|
CONST DWORD * pFunction, |
|
IDirect3DPixelShader9** ppShader, |
|
const char *pShaderName, |
|
char *debugLabel = NULL |
|
) |
|
{ |
|
Synchronize(); |
|
#ifdef DX_TO_GL_ABSTRACTION |
|
return m_pD3DDevice->CreatePixelShader( pFunction, ppShader, pShaderName, debugLabel ); |
|
#else |
|
return m_pD3DDevice->CreatePixelShader( pFunction, ppShader ); |
|
#endif |
|
} |
|
|
|
|
|
FORCEINLINE void SetIndices( |
|
IDirect3DIndexBuffer9 * pIndexData |
|
) |
|
{ |
|
if ( ASyncMode() ) |
|
Push( PBCMD_SET_INDICES, pIndexData ); |
|
else |
|
DO_D3D( SetIndices( pIndexData ) ); |
|
} |
|
|
|
FORCEINLINE void SetStreamSource( |
|
UINT StreamNumber, |
|
IDirect3DVertexBuffer9 * pStreamData, |
|
UINT OffsetInBytes, |
|
UINT Stride |
|
) |
|
{ |
|
if ( ASyncMode() ) |
|
Push( PBCMD_SET_STREAM_SOURCE, StreamNumber, pStreamData, OffsetInBytes, Stride ); |
|
else |
|
DO_D3D( SetStreamSource( StreamNumber, pStreamData, OffsetInBytes, Stride ) ); |
|
} |
|
|
|
|
|
HRESULT CreateVertexBuffer( |
|
UINT Length, |
|
DWORD Usage, |
|
DWORD FVF, |
|
D3DPOOL Pool, |
|
IDirect3DVertexBuffer9** ppVertexBuffer, |
|
HANDLE* pSharedHandle |
|
) |
|
{ |
|
Synchronize(); |
|
return m_pD3DDevice->CreateVertexBuffer( Length, Usage, FVF, |
|
Pool, ppVertexBuffer, pSharedHandle ); |
|
} |
|
|
|
HRESULT CreateIndexBuffer( |
|
UINT Length, |
|
DWORD Usage, |
|
D3DFORMAT Format, |
|
D3DPOOL Pool, |
|
IDirect3DIndexBuffer9** ppIndexBuffer, |
|
HANDLE* pSharedHandle |
|
) |
|
{ |
|
Synchronize(); |
|
return m_pD3DDevice->CreateIndexBuffer( Length, Usage, Format, Pool, ppIndexBuffer, |
|
pSharedHandle ); |
|
} |
|
|
|
|
|
FORCEINLINE void DrawIndexedPrimitive( |
|
D3DPRIMITIVETYPE Type, |
|
INT BaseVertexIndex, |
|
UINT MinIndex, |
|
UINT NumVertices, |
|
UINT StartIndex, |
|
UINT PrimitiveCount ) |
|
{ |
|
RECORD_COMMAND( DX8_DRAW_INDEXED_PRIMITIVE, 6 ); |
|
RECORD_INT( Type ); |
|
RECORD_INT( BaseVertexIndex ); |
|
RECORD_INT( MinIndex ); |
|
RECORD_INT( NumVertices ); |
|
RECORD_INT( StartIndex ); |
|
RECORD_INT( PrimitiveCount ); |
|
if ( ASyncMode() ) |
|
{ |
|
Push(PBCMD_DRAWINDEXEDPRIM, |
|
Type, BaseVertexIndex, MinIndex, NumVertices, StartIndex, PrimitiveCount ); |
|
// SubmitIfNotBusy(); |
|
} |
|
else |
|
{ |
|
DO_D3D( DrawIndexedPrimitive( Type, BaseVertexIndex, MinIndex, NumVertices, StartIndex, PrimitiveCount ) ); |
|
} |
|
} |
|
|
|
#ifndef DX_TO_GL_ABSTRACTION |
|
FORCEINLINE void DrawTessellatedIndexedPrimitive( INT BaseVertexIndex, UINT MinIndex, UINT NumVertices, |
|
UINT StartIndex, UINT PrimitiveCount ) |
|
{ |
|
// Setup our stream-source frequencies |
|
DO_D3D( SetStreamSourceFreq( 0, D3DSTREAMSOURCE_INDEXEDDATA | PrimitiveCount ) ); |
|
DO_D3D( SetStreamSourceFreq( VertexStreamSpec_t::STREAM_MORPH, D3DSTREAMSOURCE_INSTANCEDATA | 1ul ) ); |
|
DO_D3D( SetStreamSourceFreq( VertexStreamSpec_t::STREAM_SUBDQUADS, D3DSTREAMSOURCE_INSTANCEDATA | 1ul ) ); |
|
|
|
int nIndicesPerPatch = ( ( ( m_nCurrentTessLevel + 1 ) * 2 + 2 ) * m_nCurrentTessLevel ) - 2; |
|
int nVerticesPerPatch = m_nCurrentTessLevel + 1; |
|
nVerticesPerPatch *= nVerticesPerPatch; |
|
int nPrimitiveCount = nIndicesPerPatch - 2; |
|
DO_D3D( DrawIndexedPrimitive( D3DPT_TRIANGLESTRIP, 0, 0, nVerticesPerPatch, 0, nPrimitiveCount ) ); |
|
|
|
// Disable instancing |
|
DO_D3D( SetStreamSourceFreq( 0, 1ul ) ); |
|
DO_D3D( SetStreamSourceFreq( VertexStreamSpec_t::STREAM_MORPH, 1ul ) ); |
|
DO_D3D( SetStreamSourceFreq( VertexStreamSpec_t::STREAM_SUBDQUADS, 1ul ) ); |
|
} |
|
|
|
FORCEINLINE void DrawTessellatedPrimitive( UINT StartVertex, UINT PrimitiveCount ) |
|
{ |
|
|
|
// Setup our stream-source frequencies |
|
DO_D3D( SetStreamSourceFreq( 0, D3DSTREAMSOURCE_INDEXEDDATA | PrimitiveCount ) ); |
|
DO_D3D( SetStreamSourceFreq( VertexStreamSpec_t::STREAM_MORPH, D3DSTREAMSOURCE_INSTANCEDATA | 1ul ) ); |
|
DO_D3D( SetStreamSourceFreq( VertexStreamSpec_t::STREAM_SUBDQUADS, D3DSTREAMSOURCE_INSTANCEDATA | 1ul ) ); |
|
|
|
int nIndicesPerPatch = ( ( ( m_nCurrentTessLevel + 1 ) * 2 + 2 ) * m_nCurrentTessLevel ) - 2; |
|
int nVerticesPerPatch = m_nCurrentTessLevel + 1; |
|
nVerticesPerPatch *= nVerticesPerPatch; |
|
int nPrimitiveCount = nIndicesPerPatch - 2; |
|
DO_D3D( DrawIndexedPrimitive( D3DPT_TRIANGLESTRIP, 0, 0, nVerticesPerPatch, 0, nPrimitiveCount ) ); |
|
|
|
// Disable instancing |
|
DO_D3D( SetStreamSourceFreq( 0, 1ul ) ); |
|
DO_D3D( SetStreamSourceFreq( VertexStreamSpec_t::STREAM_MORPH, 1ul ) ); |
|
DO_D3D( SetStreamSourceFreq( VertexStreamSpec_t::STREAM_SUBDQUADS, 1ul ) ); |
|
} |
|
|
|
FORCEINLINE void SetTessellationLevel( float level ) |
|
{ |
|
// Track our current tessellation level |
|
m_nCurrentTessLevel = (int)ceil( level ); |
|
} |
|
#endif |
|
|
|
void SetMaterial( D3DMATERIAL9 const *mat) |
|
{ |
|
RECORD_COMMAND( DX8_SET_MATERIAL, 1 ); |
|
RECORD_STRUCT( &mat, sizeof(mat) ); |
|
Synchronize(); |
|
DO_D3D( SetMaterial( mat ) ); |
|
} |
|
|
|
FORCEINLINE void SetPixelShader( IDirect3DPixelShader9 *pShader ) |
|
{ |
|
RECORD_COMMAND( DX8_SET_PIXEL_SHADER, 1 ); |
|
RECORD_INT( ( int ) pShader ); |
|
if ( ASyncMode() ) |
|
Push( PBCMD_SET_PIXEL_SHADER, pShader ); |
|
else |
|
DO_D3D( SetPixelShader( pShader ) ); |
|
} |
|
|
|
FORCEINLINE void SetVertexShader( IDirect3DVertexShader9 *pShader ) |
|
{ |
|
if ( ASyncMode() ) |
|
Push( PBCMD_SET_VERTEX_SHADER, pShader ); |
|
else |
|
DO_D3D( SetVertexShader( pShader ) ); |
|
} |
|
|
|
#ifdef DX_TO_GL_ABSTRACTION |
|
FORCEINLINE HRESULT LinkShaderPair( IDirect3DVertexShader9* vs, IDirect3DPixelShader9* ps ) |
|
{ |
|
Assert ( !ASyncMode() ); |
|
return DO_D3D( LinkShaderPair( vs, ps ) ); |
|
} |
|
|
|
HRESULT QueryShaderPair( int index, GLMShaderPairInfo *infoOut ) |
|
{ |
|
Assert ( !ASyncMode() ); |
|
return DO_D3D( QueryShaderPair( index, infoOut ) ); |
|
} |
|
|
|
void SetMaxUsedVertexShaderConstantsHint( uint nMaxReg ) |
|
{ |
|
Assert( !ASyncMode() ); |
|
DO_D3D( SetMaxUsedVertexShaderConstantsHint( nMaxReg ) ); |
|
} |
|
|
|
#endif |
|
|
|
void EvictManagedResources( void ) |
|
{ |
|
if (m_pD3DDevice) // people call this before creating the device |
|
{ |
|
Synchronize(); |
|
DO_D3D( EvictManagedResources() ); |
|
} |
|
} |
|
|
|
void SetLight( int i, D3DLIGHT9 const *l) |
|
{ |
|
RECORD_COMMAND( DX8_SET_LIGHT, 2 ); |
|
RECORD_INT( i ); |
|
RECORD_STRUCT( l, sizeof(*l) ); |
|
|
|
Synchronize(); |
|
DO_D3D( SetLight(i, l) ); |
|
} |
|
|
|
void DrawIndexedPrimitiveUP( D3DPRIMITIVETYPE PrimitiveType, |
|
UINT MinVertexIndex, |
|
UINT NumVertices, |
|
UINT PrimitiveCount, |
|
CONST void * pIndexData, |
|
D3DFORMAT IndexDataFormat, |
|
CONST void* pVertexStreamZeroData, |
|
UINT VertexStreamZeroStride ) |
|
{ |
|
Synchronize(); |
|
DO_D3D( DrawIndexedPrimitiveUP( PrimitiveType, MinVertexIndex, NumVertices, PrimitiveCount, |
|
pIndexData, IndexDataFormat, pVertexStreamZeroData, |
|
VertexStreamZeroStride ) ); |
|
} |
|
|
|
HRESULT Present( |
|
CONST RECT * pSourceRect, |
|
CONST RECT * pDestRect, |
|
VD3DHWND hDestWindowOverride, |
|
CONST RGNDATA * pDirtyRegion) |
|
{ |
|
RECORD_COMMAND( DX8_PRESENT, 0 ); |
|
#if SHADERAPI_USE_SMP |
|
if ( ASyncMode() ) |
|
{ |
|
// need to deal with ret code here |
|
AllocatePushBufferSpace(1+1+ |
|
N_DWORDS( RECT )+1+N_DWORDS( RECT )+1+1+N_DWORDS( RGNDATA )); |
|
*(m_pOutputPtr++)=PBCMD_PRESENT; |
|
*(m_pOutputPtr++)=( pSourceRect != NULL ); |
|
if (pSourceRect) |
|
memcpy(m_pOutputPtr, pSourceRect, sizeof( RECT ) ); |
|
m_pOutputPtr+=N_DWORDS( RECT ); |
|
*(m_pOutputPtr++)=( pDestRect != NULL ); |
|
if (pDestRect) |
|
memcpy(m_pOutputPtr, pDestRect, sizeof( RECT ) ); |
|
m_pOutputPtr+=N_DWORDS( RECT ); |
|
*(m_pOutputPtr++)=(uint32) hDestWindowOverride; |
|
*(m_pOutputPtr++)=( pDirtyRegion != NULL ); |
|
if (pDirtyRegion) |
|
memcpy(m_pOutputPtr, pDirtyRegion, sizeof( RGNDATA )); |
|
m_pOutputPtr+=N_DWORDS( RGNDATA ); |
|
return S_OK; // not good - caller wants to here about lost devices |
|
} |
|
else |
|
#endif |
|
return m_pD3DDevice->Present( pSourceRect, pDestRect, |
|
hDestWindowOverride, pDirtyRegion ); |
|
} |
|
|
|
|
|
#if defined( DX_TO_GL_ABSTRACTION ) |
|
|
|
void AcquireThreadOwnership( ) |
|
{ |
|
m_pD3DDevice->AcquireThreadOwnership(); |
|
} |
|
|
|
void ReleaseThreadOwnership( ) |
|
{ |
|
m_pD3DDevice->ReleaseThreadOwnership(); |
|
} |
|
|
|
#endif |
|
|
|
}; |
|
|
|
#endif // D3DASYNC_H |
|
|
|
#endif // #if D3D_ASYNC_SUPPORTED
|
|
|