summaryrefslogtreecommitdiff
path: root/materialsystem/shaderapidx9/d3d_async.h
diff options
context:
space:
mode:
Diffstat (limited to 'materialsystem/shaderapidx9/d3d_async.h')
-rw-r--r--materialsystem/shaderapidx9/d3d_async.h1567
1 files changed, 1567 insertions, 0 deletions
diff --git a/materialsystem/shaderapidx9/d3d_async.h b/materialsystem/shaderapidx9/d3d_async.h
new file mode 100644
index 0000000..7deb2f3
--- /dev/null
+++ b/materialsystem/shaderapidx9/d3d_async.h
@@ -0,0 +1,1567 @@
+//========= 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