|
|
//================ Copyright (c) 1996-2009 Valve Corporation. All Rights Reserved. =================
//
//
//
//==================================================================================================
#include "dxabstract.h"
#include "tier0/platform.h"
#include "tier0/dbg.h"
#include "tier0/threadtools.h"
#include <stdarg.h>
#include "tier1/strtools.h"
#include "tier1/utlbuffer.h"
//#include "dx9asmtogl.h"
#include "dx9asmtogl2.h"
#include "mathlib/vmatrix.h"
#ifdef OSX
#include "glmgr/glmgr.h"
#include "appframework/icocoamgr.h"
extern ICocoaMgr *g_extCocoaMgr;
#include <Carbon/Carbon.h>
#endif
#include "tier0/icommandline.h"
#include "tier0/memdbgon.h"
#ifdef USE_ACTUAL_DX
#pragma comment( lib, "../../dx9sdk/lib/d3d9.lib" )
#pragma comment( lib, "../../dx9sdk/lib/d3dx9.lib" )
#else
#ifdef POSIX
#define strcat_s( a, b, c) V_strcat( a, c, b )
#endif
// ------------------------------------------------------------------------------------------------------------------------------ //
bool g_useASMTranslations = true; //static D3DToGL_ASM g_D3DToOpenGLTranslatorASM; // old translator retired
static D3DToGL g_D3DToOpenGLTranslatorASM; // same class as the GLSL one, just invoked with different options
bool g_useGLSLTranslations = true; static D3DToGL g_D3DToOpenGLTranslatorGLSL;
bool g_bUseControlFlow = false; // ------------------------------------------------------------------------------------------------------------------------------ //
void GlobalMemoryStatus( MEMORYSTATUS *pOut ) { //cheese: return 2GB physical
pOut->dwTotalPhys = (1<<31); }
void Sleep( unsigned int ms ) { Debugger(); ThreadSleep( ms ); }
bool IsIconic( VD3DHWND hWnd ) { // FIXME for now just act non-minimized all the time
//Debugger();
return false; }
void GetClientRect( void *hWnd, RECT *destRect ) { // the only useful answer this call can offer, is the size of the canvas.
// actually getting the window bounds is not useful.
// so, see if a D3D device is up and running, and if so,
// dig in and find out its backbuffer size and use that.
uint width, height; g_extCocoaMgr->RenderedSize( width, height, false ); // false = get them, don't set them
Assert( width!=0 && height!=0 ); destRect->left = 0; destRect->top = 0; destRect->right = width; destRect->bottom = height; //GLMPRINTF(( "-D- GetClientRect returning rect of (0,0, %d,%d)",width,height ));
return; }
BOOL ClientToScreen( VD3DHWND hWnd, LPPOINT pPoint ) { Debugger(); return true; }
void* GetCurrentThread() { Debugger(); return 0; }
void SetThreadAffinityMask( void *hThread, int nMask ) { Debugger(); }
bool GUID::operator==( const struct _GUID &other ) const { Debugger(); return memcmp( this, &other, sizeof( GUID ) ) == 0; }
// ------------------------------------------------------------------------------------------------------------------------------ //
#pragma mark ----- D3DXMATRIX operators
D3DXMATRIX D3DXMATRIX::operator*( const D3DXMATRIX &o ) const { D3DXMATRIX result; D3DXMatrixMultiply( &result, this, &o ); // this = lhs o = rhs result = this * o
return result; }
D3DXMATRIX::operator FLOAT* () { return (float*)this; }
float& D3DXMATRIX::operator()( int row, int column ) { return m[row][column]; }
const float& D3DXMATRIX::operator()( int row, int column ) const { return m[row][column]; }
// ------------------------------------------------------------------------------------------------------------------------------ //
#pragma mark ----- D3DXPLANE operators
float& D3DXPLANE::operator[]( int i ) { return ((float*)this)[i]; }
bool D3DXPLANE::operator==( const D3DXPLANE &o ) { return a == o.a && b == o.b && c == o.c && d == o.d; }
bool D3DXPLANE::operator!=( const D3DXPLANE &o ) { return !( *this == o ); }
D3DXPLANE::operator float*() { return (float*)this; }
D3DXPLANE::operator const float*() const { return (const float*)this; }
// ------------------------------------------------------------------------------------------------------------------------------ //
#pragma mark ----- D3DXVECTOR2 operators
D3DXVECTOR2::operator FLOAT* () { return (float*)this; }
D3DXVECTOR2::operator CONST FLOAT* () const { return (const float*)this; }
// ------------------------------------------------------------------------------------------------------------------------------ //
#pragma mark ----- D3DXVECTOR3 operators
D3DXVECTOR3::D3DXVECTOR3( float a, float b, float c ) { x = a; y = b; z = c; }
D3DXVECTOR3::operator FLOAT* () { return (float*)this; }
D3DXVECTOR3::operator CONST FLOAT* () const { return (const float*)this; }
// ------------------------------------------------------------------------------------------------------------------------------ //
#pragma mark ----- D3DXVECTOR4 operators
D3DXVECTOR4::D3DXVECTOR4( float a, float b, float c, float d ) { x = a; y = b; z = c; w = d; }
// ------------------------------------------------------------------------------------------------------------------------------ //
DWORD IDirect3DResource9::SetPriority(DWORD PriorityNew) { // Debugger();
// GLMPRINTF(( "-X- SetPriority" ));
// no-op city
return 0; }
// ------------------------------------------------------------------------------------------------------------------------------ //
#pragma mark ----- IDirect3DBaseTexture9
IDirect3DBaseTexture9::~IDirect3DBaseTexture9() { GLMPRINTF(( ">-A- ~IDirect3DBaseTexture9" ));
if (m_device) { GLMPRINTF(( "-A- ~IDirect3DBaseTexture9 taking normal delete path on %08x, device is %08x ", this, m_device )); m_device->ReleasedTexture( this );
if (m_tex) { GLMPRINTF(("-A- ~IDirect3DBaseTexture9 deleted '%s' @ %08x (GLM %08x) %s",m_tex->m_layout->m_layoutSummary, this, m_tex, m_tex->m_debugLabel ? m_tex->m_debugLabel : "" ));
m_tex->m_ctx->DelTex( m_tex ); m_tex = NULL; } else { GLMPRINTF(( "-A- ~IDirect3DBaseTexture9 : whoops, no tex to delete here ?" )); } m_device = NULL; // ** THIS ** is the only place to scrub this. Don't do it in the subclass destructors.
} else { GLMPRINTF(( "-A- ~IDirect3DBaseTexture9 taking strange delete path on %08x, device is %08x ", this, m_device )); }
GLMPRINTF(( "<-A- ~IDirect3DBaseTexture9" )); }
D3DRESOURCETYPE IDirect3DBaseTexture9::GetType() { return m_restype; //D3DRTYPE_TEXTURE;
}
DWORD IDirect3DBaseTexture9::GetLevelCount() { return m_tex->m_layout->m_mipCount; }
HRESULT IDirect3DBaseTexture9::GetLevelDesc(UINT Level,D3DSURFACE_DESC *pDesc) { Assert (Level < m_tex->m_layout->m_mipCount);
D3DSURFACE_DESC result = m_descZero; // then mutate it for the level of interest
GLMTexLayoutSlice *slice = &m_tex->m_layout->m_slices[ m_tex->CalcSliceIndex( 0, Level ) ];
result.Width = slice->m_xSize; result.Height = slice->m_ySize; *pDesc = result;
return S_OK; }
// ------------------------------------------------------------------------------------------------------------------------------ //
#pragma mark ----- IDirect3DTexture9
HRESULT IDirect3DDevice9::CreateTexture(UINT Width,UINT Height,UINT Levels,DWORD Usage,D3DFORMAT Format,D3DPOOL Pool,IDirect3DTexture9** ppTexture,VD3DHANDLE* pSharedHandle, char *pDebugLabel ) { GLMPRINTF((">-A-IDirect3DDevice9::CreateTexture")); IDirect3DTexture9 *dxtex = new IDirect3DTexture9; dxtex->m_restype = D3DRTYPE_TEXTURE; dxtex->m_device = this;
dxtex->m_descZero.Format = Format; dxtex->m_descZero.Type = D3DRTYPE_TEXTURE; dxtex->m_descZero.Usage = Usage; dxtex->m_descZero.Pool = Pool;
dxtex->m_descZero.MultiSampleType = D3DMULTISAMPLE_NONE; dxtex->m_descZero.MultiSampleQuality = 0; dxtex->m_descZero.Width = Width; dxtex->m_descZero.Height = Height; GLMTexLayoutKey key; memset( &key, 0, sizeof(key) ); key.m_texGLTarget = GL_TEXTURE_2D; key.m_texFormat = Format;
if (Levels>1) { key.m_texFlags |= kGLMTexMipped; }
// http://msdn.microsoft.com/en-us/library/bb172625(VS.85).aspx
// complain if any usage bits come down that I don't know.
uint knownUsageBits = (D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_RENDERTARGET | D3DUSAGE_DYNAMIC | D3DUSAGE_TEXTURE_SRGB | D3DUSAGE_DEPTHSTENCIL); if ( ( Usage & knownUsageBits ) != Usage ) { GLMDebugger(); } if ( Usage & D3DUSAGE_AUTOGENMIPMAP ) { key.m_texFlags |= kGLMTexMipped | kGLMTexMippedAuto; } if ( Usage & D3DUSAGE_DYNAMIC ) { // GLMPRINTF(("-X- DYNAMIC tex usage ignored..")); //FIXME
} if ( Usage & D3DUSAGE_TEXTURE_SRGB ) { key.m_texFlags |= kGLMTexSRGB; } if ( Usage & D3DUSAGE_RENDERTARGET ) { Assert( !(Usage & D3DUSAGE_DEPTHSTENCIL) ); key.m_texFlags |= kGLMTexRenderable; key.m_texFlags |= kGLMTexSRGB; // this catches callers of CreateTexture who set the "renderable" option - they get an SRGB tex
if (m_ctx->Caps().m_cantAttachSRGB) { // this config can't support SRGB render targets. quietly turn off the sRGB bit.
key.m_texFlags &= ~kGLMTexSRGB; } } key.m_xSize = Width; key.m_ySize = Height; key.m_zSize = 1; CGLMTex *tex = m_ctx->NewTex( &key, pDebugLabel ); if ( !tex ) { GLMDebugger(); } dxtex->m_tex = tex;
dxtex->m_srgbFlipCount = 0;
dxtex->m_surfZero = new IDirect3DSurface9; dxtex->m_surfZero->m_restype = (D3DRESOURCETYPE)0; // this is a ref to a tex, not the owner...
// do not do an AddRef here.
dxtex->m_surfZero->m_device = this;
dxtex->m_surfZero->m_desc = dxtex->m_descZero; dxtex->m_surfZero->m_tex = tex; dxtex->m_surfZero->m_face = 0; dxtex->m_surfZero->m_mip = 0; GLMPRINTF(("-A- IDirect3DDevice9::CreateTexture created '%s' @ %08x (GLM %08x) %s",tex->m_layout->m_layoutSummary, dxtex, tex, pDebugLabel ? pDebugLabel : "" )); *ppTexture = dxtex; GLMPRINTF(("<-A-IDirect3DDevice9::CreateTexture")); return S_OK; }
IDirect3DTexture9::~IDirect3DTexture9() { GLMPRINTF(( ">-A- IDirect3DTexture9" ));
// IDirect3DBaseTexture9::~IDirect3DBaseTexture9 frees up m_tex
// we take care of surfZero
if (m_device) { m_device->ReleasedTexture( this );
if (m_surfZero) { ULONG refc = m_surfZero->Release( 0, "~IDirect3DTexture9 public release (surfZero)" ); Assert( !refc ); m_surfZero = NULL; } // leave m_device alone!
}
GLMPRINTF(( "<-A- IDirect3DTexture9" )); }
HRESULT IDirect3DTexture9::LockRect(UINT Level,D3DLOCKED_RECT* pLockedRect,CONST RECT* pRect,DWORD Flags) { Debugger(); return S_OK; }
HRESULT IDirect3DTexture9::UnlockRect(UINT Level) { Debugger(); return S_OK; }
HRESULT IDirect3DTexture9::GetSurfaceLevel(UINT Level,IDirect3DSurface9** ppSurfaceLevel) { // we create and pass back a surface, and the client is on the hook to release it. tidy.
IDirect3DSurface9 *surf = new IDirect3DSurface9; surf->m_restype = (D3DRESOURCETYPE)0; // 0 is special and means this 'surface' does not own its m_tex
// Dicey...higher level code seems to want this and not want this. Are we missing some AddRef/Release behavior elsewhere?
// surf->AddRef();
surf->m_device = this->m_device; GLMTexLayoutSlice *slice = &m_tex->m_layout->m_slices[ m_tex->CalcSliceIndex( 0, Level ) ]; surf->m_desc = m_descZero; surf->m_desc.Width = slice->m_xSize; surf->m_desc.Height = slice->m_ySize; surf->m_tex = m_tex; surf->m_face = 0; surf->m_mip = Level;
*ppSurfaceLevel = surf;
return S_OK; }
// ------------------------------------------------------------------------------------------------------------------------------ //
#pragma mark ----- IDirect3DCubeTexture9
HRESULT IDirect3DDevice9::CreateCubeTexture(UINT EdgeLength,UINT Levels,DWORD Usage,D3DFORMAT Format,D3DPOOL Pool,IDirect3DCubeTexture9** ppCubeTexture,VD3DHANDLE* pSharedHandle, char *pDebugLabel) { GLMPRINTF((">-A- IDirect3DDevice9::CreateCubeTexture"));
IDirect3DCubeTexture9 *dxtex = new IDirect3DCubeTexture9; dxtex->m_restype = D3DRTYPE_CUBETEXTURE; dxtex->m_device = this;
dxtex->m_descZero.Format = Format; dxtex->m_descZero.Type = D3DRTYPE_CUBETEXTURE; dxtex->m_descZero.Usage = Usage; dxtex->m_descZero.Pool = Pool;
dxtex->m_descZero.MultiSampleType = D3DMULTISAMPLE_NONE; dxtex->m_descZero.MultiSampleQuality = 0; dxtex->m_descZero.Width = EdgeLength; dxtex->m_descZero.Height = EdgeLength; GLMTexLayoutKey key; memset( &key, 0, sizeof(key) ); key.m_texGLTarget = GL_TEXTURE_CUBE_MAP; key.m_texFormat = Format;
if (Levels>1) { key.m_texFlags |= kGLMTexMipped; }
// http://msdn.microsoft.com/en-us/library/bb172625(VS.85).aspx
// complain if any usage bits come down that I don't know.
uint knownUsageBits = (D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_RENDERTARGET | D3DUSAGE_DYNAMIC | D3DUSAGE_TEXTURE_SRGB); if ( (Usage & knownUsageBits) != Usage ) { GLMDebugger(); } if (Usage & D3DUSAGE_AUTOGENMIPMAP) { key.m_texFlags |= kGLMTexMipped | kGLMTexMippedAuto; } if (Usage & D3DUSAGE_RENDERTARGET) { key.m_texFlags |= kGLMTexRenderable; } if (Usage & D3DUSAGE_DYNAMIC) { //GLMPRINTF(("-X- DYNAMIC tex usage ignored..")); //FIXME
} if (Usage & D3DUSAGE_TEXTURE_SRGB) { key.m_texFlags |= kGLMTexSRGB; } key.m_xSize = EdgeLength; key.m_ySize = EdgeLength; key.m_zSize = 1; CGLMTex *tex = m_ctx->NewTex( &key, pDebugLabel ); if (!tex) { GLMDebugger(); } dxtex->m_tex = tex; dxtex->m_srgbFlipCount = 0;
for( int face = 0; face < 6; face ++) { dxtex->m_surfZero[face] = new IDirect3DSurface9; dxtex->m_surfZero[face]->m_restype = (D3DRESOURCETYPE)0; // 0 is special and means this 'surface' does not own its m_tex
// do not do an AddRef here.
dxtex->m_surfZero[face]->m_device = this; dxtex->m_surfZero[face]->m_desc = dxtex->m_descZero; dxtex->m_surfZero[face]->m_tex = tex; dxtex->m_surfZero[face]->m_face = face; dxtex->m_surfZero[face]->m_mip = 0; } GLMPRINTF(("-A- IDirect3DDevice9::CreateCubeTexture created '%s' @ %08x (GLM %08x)",tex->m_layout->m_layoutSummary, dxtex, tex )); *ppCubeTexture = dxtex; GLMPRINTF(("<-A- IDirect3DDevice9::CreateCubeTexture"));
return S_OK; }
IDirect3DCubeTexture9::~IDirect3DCubeTexture9() { GLMPRINTF(( ">-A- ~IDirect3DCubeTexture9" ));
if (m_device) { GLMPRINTF(( "-A- ~IDirect3DCubeTexture9 taking normal delete path on %08x, device is %08x, surfzero[0] is %08x ", this, m_device, m_surfZero[0] )); m_device->ReleasedTexture( this );
// let IDirect3DBaseTexture9::~IDirect3DBaseTexture9 free up m_tex
// we handle the surfZero array for the faces
for( int face = 0; face < 6; face ++) { if (m_surfZero[face]) { Assert( m_surfZero[face]->m_device = m_device ); ULONG refc = m_surfZero[face]->Release( 0, "~IDirect3DCubeTexture9 public release (surfZero)"); if ( refc!=0 ) { GLMPRINTF(( "-A- ~IDirect3DCubeTexture9 seeing non zero refcount on surfzero[%d] => %d ", face, refc )); } m_surfZero[face] = NULL; } } // leave m_device alone!
} else { GLMPRINTF(( "-A- ~IDirect3DCubeTexture9 taking strange delete path on %08x, device is %08x, surfzero[0] is %08x ", this, m_device, m_surfZero[0] )); }
GLMPRINTF(( "<-A- ~IDirect3DCubeTexture9" )); }
HRESULT IDirect3DCubeTexture9::GetCubeMapSurface(D3DCUBEMAP_FACES FaceType,UINT Level,IDirect3DSurface9** ppCubeMapSurface) { // we create and pass back a surface, and the client is on the hook to release it...
IDirect3DSurface9 *surf = new IDirect3DSurface9; surf->m_restype = (D3DRESOURCETYPE)0; // 0 is special and means this 'surface' does not own its m_tex
GLMTexLayoutSlice *slice = &m_tex->m_layout->m_slices[ m_tex->CalcSliceIndex( FaceType, Level ) ]; surf->m_device = this->m_device; surf->m_desc = m_descZero; surf->m_desc.Width = slice->m_xSize; surf->m_desc.Height = slice->m_ySize; surf->m_tex = m_tex; surf->m_face = FaceType; surf->m_mip = Level;
*ppCubeMapSurface = surf;
return S_OK; }
HRESULT IDirect3DCubeTexture9::GetLevelDesc(UINT Level,D3DSURFACE_DESC *pDesc) { Assert (Level < m_tex->m_layout->m_mipCount);
D3DSURFACE_DESC result = m_descZero; // then mutate it for the level of interest
GLMTexLayoutSlice *slice = &m_tex->m_layout->m_slices[ m_tex->CalcSliceIndex( 0, Level ) ];
result.Width = slice->m_xSize; result.Height = slice->m_ySize;
*pDesc = result;
return S_OK; }
// ------------------------------------------------------------------------------------------------------------------------------ //
#pragma mark ----- IDirect3DVolumeTexture9
HRESULT IDirect3DDevice9::CreateVolumeTexture(UINT Width,UINT Height,UINT Depth,UINT Levels,DWORD Usage,D3DFORMAT Format,D3DPOOL Pool,IDirect3DVolumeTexture9** ppVolumeTexture,VD3DHANDLE* pSharedHandle, char *pDebugLabel) { GLMPRINTF((">-A- IDirect3DDevice9::CreateVolumeTexture")); // set dxtex->m_restype to D3DRTYPE_VOLUMETEXTURE...
IDirect3DVolumeTexture9 *dxtex = new IDirect3DVolumeTexture9; dxtex->m_restype = D3DRTYPE_VOLUMETEXTURE; dxtex->m_device = this;
dxtex->m_descZero.Format = Format; dxtex->m_descZero.Type = D3DRTYPE_VOLUMETEXTURE; dxtex->m_descZero.Usage = Usage; dxtex->m_descZero.Pool = Pool;
dxtex->m_descZero.MultiSampleType = D3DMULTISAMPLE_NONE; dxtex->m_descZero.MultiSampleQuality = 0; dxtex->m_descZero.Width = Width; dxtex->m_descZero.Height = Height;
// also a volume specific desc
dxtex->m_volDescZero.Format = Format; dxtex->m_volDescZero.Type = D3DRTYPE_VOLUMETEXTURE; dxtex->m_volDescZero.Usage = Usage; dxtex->m_volDescZero.Pool = Pool;
dxtex->m_volDescZero.Width = Width; dxtex->m_volDescZero.Height = Height; dxtex->m_volDescZero.Depth = Depth; GLMTexLayoutKey key; memset( &key, 0, sizeof(key) ); key.m_texGLTarget = GL_TEXTURE_3D; key.m_texFormat = Format;
if (Levels>1) { key.m_texFlags |= kGLMTexMipped; }
// http://msdn.microsoft.com/en-us/library/bb172625(VS.85).aspx
// complain if any usage bits come down that I don't know.
uint knownUsageBits = (D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_RENDERTARGET | D3DUSAGE_DYNAMIC | D3DUSAGE_TEXTURE_SRGB); if ( (Usage & knownUsageBits) != Usage ) { Debugger(); } if (Usage & D3DUSAGE_AUTOGENMIPMAP) { key.m_texFlags |= kGLMTexMipped | kGLMTexMippedAuto; } if (Usage & D3DUSAGE_RENDERTARGET) { key.m_texFlags |= kGLMTexRenderable; } if (Usage & D3DUSAGE_DYNAMIC) { GLMPRINTF(("-X- DYNAMIC tex usage ignored..")); //FIXME
} if (Usage & D3DUSAGE_TEXTURE_SRGB) { key.m_texFlags |= kGLMTexSRGB; } key.m_xSize = Width; key.m_ySize = Height; key.m_zSize = Depth; CGLMTex *tex = m_ctx->NewTex( &key, pDebugLabel ); if (!tex) { Debugger(); } dxtex->m_tex = tex; dxtex->m_srgbFlipCount = 0;
dxtex->m_surfZero = new IDirect3DSurface9; dxtex->m_surfZero->m_restype = (D3DRESOURCETYPE)0; // this is a ref to a tex, not the owner...
// do not do an AddRef here.
dxtex->m_surfZero->m_device = this; dxtex->m_surfZero->m_desc = dxtex->m_descZero; dxtex->m_surfZero->m_tex = tex; dxtex->m_surfZero->m_face = 0; dxtex->m_surfZero->m_mip = 0; GLMPRINTF(("-A- IDirect3DDevice9::CreateVolumeTexture created '%s' @ %08x (GLM %08x)",tex->m_layout->m_layoutSummary, dxtex, tex )); *ppVolumeTexture = dxtex;
GLMPRINTF(("<-A- IDirect3DDevice9::CreateVolumeTexture"));
return S_OK; }
IDirect3DVolumeTexture9::~IDirect3DVolumeTexture9() { GLMPRINTF((">-A- ~IDirect3DVolumeTexture9"));
if (m_device) { m_device->ReleasedTexture( this );
// let IDirect3DBaseTexture9::~IDirect3DBaseTexture9 free up m_tex
// we handle m_surfZero
if (m_surfZero) { ULONG refc = m_surfZero->Release( 0, "~IDirect3DVolumeTexture9 public release (surfZero)" ); Assert( !refc ); m_surfZero = NULL; } // leave m_device alone!
}
GLMPRINTF(("<-A- ~IDirect3DVolumeTexture9")); }
HRESULT IDirect3DVolumeTexture9::LockBox(UINT Level,D3DLOCKED_BOX* pLockedVolume,CONST D3DBOX* pBox,DWORD Flags) { GLMTexLockParams lockreq; memset( &lockreq, 0, sizeof(lockreq) ); lockreq.m_tex = this->m_tex; lockreq.m_face = 0; lockreq.m_mip = Level;
lockreq.m_region.xmin = pBox->Left; lockreq.m_region.ymin = pBox->Top; lockreq.m_region.zmin = pBox->Front; lockreq.m_region.xmax = pBox->Right; lockreq.m_region.ymax = pBox->Bottom; lockreq.m_region.zmax = pBox->Back; char *lockAddress; int yStride; int zStride; lockreq.m_tex->Lock( &lockreq, &lockAddress, &yStride, &zStride );
pLockedVolume->RowPitch = yStride; pLockedVolume->SlicePitch = yStride; pLockedVolume->pBits = lockAddress; return S_OK; }
HRESULT IDirect3DVolumeTexture9::UnlockBox(UINT Level) { GLMTexLockParams lockreq; memset( &lockreq, 0, sizeof(lockreq) ); lockreq.m_tex = this->m_tex; lockreq.m_face = 0; lockreq.m_mip = Level;
this->m_tex->Unlock( &lockreq ); return S_OK; }
HRESULT IDirect3DVolumeTexture9::GetLevelDesc( UINT Level, D3DVOLUME_DESC *pDesc ) { if (Level > m_tex->m_layout->m_mipCount) { Debugger(); }
D3DVOLUME_DESC result = m_volDescZero; // then mutate it for the level of interest
GLMTexLayoutSlice *slice = &m_tex->m_layout->m_slices[ m_tex->CalcSliceIndex( 0, Level ) ];
result.Width = slice->m_xSize; result.Height = slice->m_ySize; result.Depth = slice->m_zSize; *pDesc = result;
return S_OK; }
// ------------------------------------------------------------------------------------------------------------------------------ //
#pragma mark ----- IDirect3DSurface9
IDirect3DSurface9::~IDirect3DSurface9() { // not much to do here, but good to verify that these things are being freed (and they are)
//GLMPRINTF(("-A- ~IDirect3DSurface9 - signpost"));
if (m_device) { GLMPRINTF(("-A- ~IDirect3DSurface9 - taking real delete path on %08x device %08x", this, m_device)); m_device->ReleasedSurface( this );
memset( &m_desc, 0, sizeof(m_desc) );
if (m_restype != 0) // signal that we are a surface that owns this tex (render target)
{ if (m_tex) { GLMPRINTF(("-A- ~IDirect3DSurface9 deleted '%s' @ %08x (GLM %08x) %s",m_tex->m_layout->m_layoutSummary, this, m_tex, m_tex->m_debugLabel ? m_tex->m_debugLabel : "" ));
m_tex->m_ctx->DelTex( m_tex ); m_tex = NULL; } else { GLMPRINTF(( "-A- ~IDirect3DSurface9 : whoops, no tex to delete here ?" )); } } else { m_tex = NULL; // we are just a view on the tex, we don't own the tex, do not delete it
}
m_face = m_mip = 0; m_device = NULL; } else { GLMPRINTF(("-A- ~IDirect3DSurface9 - taking strange delete path on %08x device %08x", this, m_device)); } }
HRESULT IDirect3DSurface9::LockRect(D3DLOCKED_RECT* pLockedRect,CONST RECT* pRect,DWORD Flags) { GLMTexLockParams lockreq; memset( &lockreq, 0, sizeof(lockreq) ); lockreq.m_tex = this->m_tex; lockreq.m_face = this->m_face; lockreq.m_mip = this->m_mip;
lockreq.m_region.xmin = pRect->left; lockreq.m_region.ymin = pRect->top; lockreq.m_region.zmin = 0; lockreq.m_region.xmax = pRect->right; lockreq.m_region.ymax = pRect->bottom; lockreq.m_region.zmax = 1; if ((Flags & (D3DLOCK_READONLY | D3DLOCK_NOSYSLOCK)) == (D3DLOCK_READONLY | D3DLOCK_NOSYSLOCK) ) { // smells like readback, force texel readout
lockreq.m_readback = true; } char *lockAddress; int yStride; int zStride; lockreq.m_tex->Lock( &lockreq, &lockAddress, &yStride, &zStride );
pLockedRect->Pitch = yStride; pLockedRect->pBits = lockAddress; return S_OK; }
HRESULT IDirect3DSurface9::UnlockRect() { GLMTexLockParams lockreq; memset( &lockreq, 0, sizeof(lockreq) ); lockreq.m_tex = this->m_tex; lockreq.m_face = this->m_face; lockreq.m_mip = this->m_mip;
lockreq.m_tex->Unlock( &lockreq );
return S_OK; }
HRESULT IDirect3DSurface9::GetDesc(D3DSURFACE_DESC *pDesc) { *pDesc = m_desc; return S_OK; }
// ------------------------------------------------------------------------------------------------------------------------------ //
#pragma mark ----- IDirect3D9 -------------------------------------------------------
IDirect3D9::~IDirect3D9() { GLMPRINTF(("-A- ~IDirect3D9 - signpost")); }
UINT IDirect3D9::GetAdapterCount() { GLMgr::NewGLMgr(); // init GL manager
GLMDisplayDB *db = g_extCocoaMgr->GetDisplayDB(); int dxAdapterCount = db->GetFakeAdapterCount();
return dxAdapterCount; }
HRESULT IDirect3D9::GetDeviceCaps(UINT Adapter,D3DDEVTYPE DeviceType,D3DCAPS9* pCaps) { // Generally called from "CShaderDeviceMgrDx8::ComputeCapsFromD3D" in ShaderDeviceDX8.cpp
// "Adapter" is used to index amongst the set of fake-adapters maintained in the display DB
GLMDisplayDB *db = g_extCocoaMgr->GetDisplayDB(); int glmRendererIndex = -1; int glmDisplayIndex = -1; GLMRendererInfoFields glmRendererInfo; GLMDisplayInfoFields glmDisplayInfo; bool result = db->GetFakeAdapterInfo( Adapter, &glmRendererIndex, &glmDisplayIndex, &glmRendererInfo, &glmDisplayInfo ); Assert (!result); // just leave glmRendererInfo filled out for subsequent code to look at as needed.
// fill in the pCaps record for adapter... we zero most of it and just fill in the fields that we think the caller wants.
Q_memset( pCaps, 0, sizeof(*pCaps) ); /* Device Info */ pCaps->DeviceType = D3DDEVTYPE_HAL;
/* Caps from DX7 Draw */ pCaps->Caps = 0; // does anyone look at this ?
pCaps->Caps2 = D3DCAPS2_DYNAMICTEXTURES; /* Cursor Caps */ pCaps->CursorCaps = 0; // nobody looks at this
/* 3D Device Caps */ pCaps->DevCaps = D3DDEVCAPS_HWTRANSFORMANDLIGHT;
pCaps->TextureCaps = D3DPTEXTURECAPS_CUBEMAP | D3DPTEXTURECAPS_MIPCUBEMAP | D3DPTEXTURECAPS_NONPOW2CONDITIONAL | D3DPTEXTURECAPS_PROJECTED; // D3DPTEXTURECAPS_NOPROJECTEDBUMPENV ?
// D3DPTEXTURECAPS_POW2 ?
// caller looks at POT support like this:
// pCaps->m_SupportsNonPow2Textures =
// ( !( caps.TextureCaps & D3DPTEXTURECAPS_POW2 ) ||
// ( caps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL ) );
// so we should set D3DPTEXTURECAPS_NONPOW2CONDITIONAL bit ?
pCaps->PrimitiveMiscCaps = 0; //only the HDR setup looks at this for D3DPMISCCAPS_SEPARATEALPHABLEND.
// ? D3DPMISCCAPS_SEPARATEALPHABLEND
// ? D3DPMISCCAPS_BLENDOP
// ? D3DPMISCCAPS_CLIPPLANESCALEDPOINTS
// ? D3DPMISCCAPS_CLIPTLVERTS D3DPMISCCAPS_COLORWRITEENABLE D3DPMISCCAPS_MASKZ D3DPMISCCAPS_TSSARGTEMP
pCaps->RasterCaps = D3DPRASTERCAPS_SCISSORTEST | D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS // ref'd in CShaderDeviceMgrDx8::ComputeCapsFromD3D
| D3DPRASTERCAPS_DEPTHBIAS // ref'd in CShaderDeviceMgrDx8::ComputeCapsFromD3D
; pCaps->TextureFilterCaps = D3DPTFILTERCAPS_MINFANISOTROPIC | D3DPTFILTERCAPS_MAGFANISOTROPIC; pCaps->MaxTextureWidth = 4096; pCaps->MaxTextureHeight = 4096; pCaps->MaxVolumeExtent = 1024; //guesses
pCaps->MaxTextureAspectRatio = 0; // imply no limit on AR
pCaps->MaxAnisotropy = glmRendererInfo.m_maxAniso; pCaps->TextureOpCaps = D3DTEXOPCAPS_ADD | D3DTEXOPCAPS_MODULATE2X; //guess
DWORD MaxTextureBlendStages; DWORD MaxSimultaneousTextures;
pCaps->VertexProcessingCaps = D3DVTXPCAPS_TEXGEN_SPHEREMAP; pCaps->MaxActiveLights = 8; // guess
// MaxUserClipPlanes. A bit complicated..
// it's difficult to make this fluid without teaching the engine about a cap that could change during run.
// start it out set to '2'.
// turn it off, if we're in GLSL mode but do not have native clip plane capability.
pCaps->MaxUserClipPlanes = 2; // assume good news
// is user asking for it to be off ?
if ( CommandLine()->CheckParm( "-nouserclip" ) ) { pCaps->MaxUserClipPlanes = 0; } g_bUseControlFlow = CommandLine()->CheckParm( "-glslcontrolflow" ); // are we ARB mode and not forcing GLSL control flow mode?
if ( CommandLine()->CheckParm( "-arbmode" ) && !g_bUseControlFlow ) { pCaps->MaxUserClipPlanes = 0; } pCaps->MaxVertexBlendMatrices = 0; // see if anyone cares
pCaps->MaxVertexBlendMatrixIndex = 0; // see if anyone cares
pCaps->MaxPrimitiveCount = 32768; // guess
pCaps->MaxStreams = 4; // guess
pCaps->VertexShaderVersion = 0x200; // model 2.0
pCaps->MaxVertexShaderConst = DXABSTRACT_VS_PARAM_SLOTS; // number of vertex shader constant registers
pCaps->PixelShaderVersion = 0x200; // model 2.0
// Here are the DX9 specific ones
pCaps->DevCaps2 = D3DDEVCAPS2_STREAMOFFSET; pCaps->PS20Caps.NumInstructionSlots = 512; // guess
// only examined once:
// pCaps->m_SupportsPixelShaders_2_b = ( ( caps.PixelShaderVersion & 0xffff ) >= 0x0200) && (caps.PS20Caps.NumInstructionSlots >= 512);
//pCaps->m_SupportsPixelShaders_2_b = 1;
pCaps->NumSimultaneousRTs = 1; // Will be at least 1
pCaps->MaxVertexShader30InstructionSlots = 0; pCaps->MaxPixelShader30InstructionSlots = 0;
#if ( defined ( POSIX ) && !defined( _PS3 ) )
pCaps->FakeSRGBWrite = !glmRendererInfo.m_hasGammaWrites; pCaps->CanDoSRGBReadFromRTs = !glmRendererInfo.m_cantAttachSRGB; pCaps->MixedSizeTargets = glmRendererInfo.m_hasMixedAttachmentSizes; pCaps->SRGBDecode = glmRendererInfo.m_hasSRGBDecode; #endif
return S_OK; }
HRESULT IDirect3D9::GetAdapterIdentifier( UINT Adapter, DWORD Flags, D3DADAPTER_IDENTIFIER9* pIdentifier ) { // Generally called from "CShaderDeviceMgrDx8::ComputeCapsFromD3D" in ShaderDeviceDX8.cpp
Assert( Flags == D3DENUM_WHQL_LEVEL ); // we're not handling any other queries than this yet
Q_memset( pIdentifier, 0, sizeof(*pIdentifier) );
GLMDisplayDB *db = g_extCocoaMgr->GetDisplayDB(); int glmRendererIndex = -1; int glmDisplayIndex = -1; GLMRendererInfoFields glmRendererInfo; GLMDisplayInfoFields glmDisplayInfo; // the D3D "Adapter" number feeds the fake adapter index
bool result = db->GetFakeAdapterInfo( Adapter, &glmRendererIndex, &glmDisplayIndex, &glmRendererInfo, &glmDisplayInfo ); Assert (!result);
Q_snprintf( pIdentifier->Driver, sizeof(pIdentifier->Driver), "OpenGL %s (%08x)", GLMDecode( eGL_RENDERER, glmRendererInfo.m_rendererID & 0x00FFFF00 ), glmRendererInfo.m_rendererID ); Q_snprintf( pIdentifier->Description, sizeof(pIdentifier->Description), "%s - %dx%d - %dMB VRAM", GLMDecode( eGL_RENDERER, glmRendererInfo.m_rendererID & 0x00FFFF00 ), glmDisplayInfo.m_displayPixelWidth, glmDisplayInfo.m_displayPixelHeight, glmRendererInfo.m_vidMemory >> 20 ); pIdentifier->VendorId = glmRendererInfo.m_pciVendorID; // 4318;
pIdentifier->DeviceId = glmRendererInfo.m_pciDeviceID; // 401;
pIdentifier->SubSysId = 0; // 3358668866;
pIdentifier->Revision = 0; // 162;
pIdentifier->VideoMemory = glmRendererInfo.m_vidMemory; // amount of video memory in bytes
#if 0
// this came from the shaderapigl effort
Q_strncpy( pIdentifier->Driver, "Fake-Video-Card", MAX_DEVICE_IDENTIFIER_STRING ); Q_strncpy( pIdentifier->Description, "Fake-Video-Card", MAX_DEVICE_IDENTIFIER_STRING ); pIdentifier->VendorId = 4318; pIdentifier->DeviceId = 401; pIdentifier->SubSysId = 3358668866; pIdentifier->Revision = 162; #endif
return S_OK; }
HRESULT IDirect3D9::CheckDeviceFormat(UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,DWORD Usage,D3DRESOURCETYPE RType,D3DFORMAT CheckFormat) { if (0) // hush for now, less spew
{ GLMPRINTF(("-X- ** IDirect3D9::CheckDeviceFormat: \n -- Adapter=%d || DeviceType=%4x:%s || AdapterFormat=%8x:%s\n -- RType %8x: %s\n -- CheckFormat %8x: %s\n -- Usage %8x: %s", Adapter, DeviceType, GLMDecode(eD3D_DEVTYPE, DeviceType), AdapterFormat, GLMDecode(eD3D_FORMAT, AdapterFormat), RType, GLMDecode(eD3D_RTYPE, RType), CheckFormat, GLMDecode(eD3D_FORMAT, CheckFormat), Usage, GLMDecodeMask( eD3D_USAGE, Usage ) )); }
HRESULT result = D3DERR_NOTAVAILABLE; // failure
DWORD knownUsageMask = D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL | D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_SRGBREAD | D3DUSAGE_QUERY_FILTER | D3DUSAGE_QUERY_SRGBWRITE | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING | D3DUSAGE_QUERY_VERTEXTEXTURE; // FramebufferSRGB stuff.
// basically a format is only allowed to have SRGB usage for writing, if you have the framebuffer SRGB extension.
// so, check for that capability with GLM adapter db, and if it's not there, don't mark that bit as usable in any of our formats.
GLMDisplayDB *db = g_extCocoaMgr->GetDisplayDB(); int glmRendererIndex = -1; int glmDisplayIndex = -1; GLMRendererInfoFields glmRendererInfo; GLMDisplayInfoFields glmDisplayInfo; bool dbresult = db->GetFakeAdapterInfo( Adapter, &glmRendererIndex, &glmDisplayIndex, &glmRendererInfo, &glmDisplayInfo ); Assert (!dbresult);
Assert ((Usage & knownUsageMask) == Usage);
DWORD legalUsage = 0; switch( AdapterFormat ) { case D3DFMT_X8R8G8B8: switch( RType ) { case D3DRTYPE_TEXTURE: switch( CheckFormat ) { case D3DFMT_DXT1: case D3DFMT_DXT3: case D3DFMT_DXT5: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER; legalUsage |= D3DUSAGE_QUERY_SRGBREAD; //open question: is auto gen of mipmaps is allowed or attempted on any DXT textures.
break;
case D3DFMT_A8R8G8B8: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER; legalUsage |= D3DUSAGE_RENDERTARGET | D3DUSAGE_QUERY_SRGBREAD | D3DUSAGE_QUERY_SRGBWRITE | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING; break;
case D3DFMT_R32F: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER; legalUsage |= D3DUSAGE_RENDERTARGET | D3DUSAGE_QUERY_SRGBREAD | D3DUSAGE_QUERY_SRGBWRITE | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING; break;
case D3DFMT_A16B16G16R16: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER; legalUsage |= D3DUSAGE_RENDERTARGET | D3DUSAGE_QUERY_SRGBREAD | D3DUSAGE_QUERY_SRGBWRITE | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING; break;
case D3DFMT_A16B16G16R16F: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_RENDERTARGET | D3DUSAGE_QUERY_SRGBREAD | D3DUSAGE_QUERY_SRGBWRITE;
if ( !glmRendererInfo.m_atiR5xx ) { legalUsage |= D3DUSAGE_QUERY_FILTER | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING; } break;
case D3DFMT_A32B32G32R32F: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_RENDERTARGET | D3DUSAGE_QUERY_SRGBREAD | D3DUSAGE_QUERY_SRGBWRITE;
if ( !glmRendererInfo.m_atiR5xx && !glmRendererInfo.m_nvG7x ) { legalUsage |= D3DUSAGE_QUERY_FILTER | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING; } break;
case D3DFMT_R5G6B5: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER; break;
//-----------------------------------------------------------
// these come in from TestTextureFormat in ColorFormatDX8.cpp which is being driven by InitializeColorInformation...
// which is going to try all 8 combinations of (vertex texturable / render targetable / filterable ) on every image format it knows.
case D3DFMT_R8G8B8: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER; legalUsage |= D3DUSAGE_QUERY_SRGBREAD; break; case D3DFMT_X8R8G8B8: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER; legalUsage |= D3DUSAGE_QUERY_SRGBREAD | D3DUSAGE_QUERY_SRGBWRITE; break;
// one and two channel textures... we'll have to fake these as four channel tex if we want to support them
case D3DFMT_L8: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER; break;
case D3DFMT_A8L8: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER; break;
case D3DFMT_A8: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER; break; // going to need to go back and double check all of these..
case D3DFMT_X1R5G5B5: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER; break; case D3DFMT_A4R4G4B4: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER; break;
case D3DFMT_A1R5G5B5: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER; break; case D3DFMT_V8U8: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER; break;
case D3DFMT_Q8W8V8U8: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER; // what the heck is QWVU8 ... ?
break;
case D3DFMT_X8L8V8U8: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER; // what the heck is XLVU8 ... ?
break;
// formats with depth...
case D3DFMT_D16: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL; // just a guess on the legal usages
break;
case D3DFMT_D24S8: legalUsage = D3DUSAGE_DYNAMIC | D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL; // just a guess on the legal usages
break;
// vendor formats... try marking these all invalid for now
case D3DFMT_NV_INTZ: case D3DFMT_NV_RAWZ: case D3DFMT_NV_NULL: case D3DFMT_ATI_D16: case D3DFMT_ATI_D24S8: case D3DFMT_ATI_2N: case D3DFMT_ATI_1N: legalUsage = 0; break;
//-----------------------------------------------------------
default: Assert(!"Unknown check format"); result = D3DERR_NOTAVAILABLE; break; }
if ((Usage & legalUsage) == Usage) { result = S_OK; } else { DWORD unsatBits = Usage & (~legalUsage); // clear the bits of the req that were legal, leaving the illegal ones
GLMPRINTF(( "-X- --> NOT OK: flags %8x:%s", unsatBits,GLMDecodeMask( eD3D_USAGE, unsatBits ) )); result = D3DERR_NOTAVAILABLE; } break; case D3DRTYPE_SURFACE: switch( CheckFormat ) { case 0x434f5441: case 0x41415353: result = D3DERR_NOTAVAILABLE; break; case D3DFMT_D24S8: result = S_OK; break; //** IDirect3D9::CheckDeviceFormat adapter=0, DeviceType= 1:D3DDEVTYPE_HAL, AdapterFormat= 5:D3DFMT_X8R8G8B8, RType= 1:D3DRTYPE_SURFACE, CheckFormat=434f5441:UNKNOWN
//** IDirect3D9::CheckDeviceFormat adapter=0, DeviceType= 1:D3DDEVTYPE_HAL, AdapterFormat= 5:D3DFMT_X8R8G8B8, RType= 1:D3DRTYPE_SURFACE, CheckFormat=41415353:UNKNOWN
//** IDirect3D9::CheckDeviceFormat adapter=0, DeviceType= 1:D3DDEVTYPE_HAL, AdapterFormat= 5:D3DFMT_X8R8G8B8, RType= 1:D3DRTYPE_SURFACE, CheckFormat=434f5441:UNKNOWN
//** IDirect3D9::CheckDeviceFormat adapter=0, DeviceType= 1:D3DDEVTYPE_HAL, AdapterFormat= 5:D3DFMT_X8R8G8B8, RType= 1:D3DRTYPE_SURFACE, CheckFormat=41415353:UNKNOWN
} break; default: Assert(!"Unknown resource type"); result = D3DERR_NOTAVAILABLE; break; } break; default: Assert(!"Unknown adapter format"); result = D3DERR_NOTAVAILABLE; break; } return result; }
UINT IDirect3D9::GetAdapterModeCount(UINT Adapter,D3DFORMAT Format) { GLMPRINTF(( "-X- IDirect3D9::GetAdapterModeCount: Adapter=%d || Format=%8x:%s", Adapter, Format, GLMDecode(eD3D_FORMAT, Format) ));
uint modeCount=0; GLMDisplayDB *db = g_extCocoaMgr->GetDisplayDB(); int glmRendererIndex = -1; int glmDisplayIndex = -1; GLMRendererInfoFields glmRendererInfo; GLMDisplayInfoFields glmDisplayInfo; // the D3D "Adapter" number feeds the fake adapter index
bool result = db->GetFakeAdapterInfo( Adapter, &glmRendererIndex, &glmDisplayIndex, &glmRendererInfo, &glmDisplayInfo ); Assert (!result);
modeCount = db->GetModeCount( glmRendererIndex, glmDisplayIndex ); GLMPRINTF(( "-X- --> result is %d", modeCount )); return modeCount + 1; // Add one on for 800 x 500, which we'll tack on as mode 0 below
}
HRESULT IDirect3D9::EnumAdapterModes( UINT Adapter, D3DFORMAT Format, UINT Mode, D3DDISPLAYMODE* pMode ) { GLMPRINTF(( "-X- IDirect3D9::EnumAdapterModes: Adapter=%d || Format=%8x:%s || Mode=%d", Adapter, Format, GLMDecode(eD3D_FORMAT, Format), Mode ));
Assert(Format==D3DFMT_X8R8G8B8);
GLMDisplayDB *db = g_extCocoaMgr->GetDisplayDB(); int glmRendererIndex = -1; int glmDisplayIndex = -1; GLMRendererInfoFields glmRendererInfo; GLMDisplayInfoFields glmDisplayInfo; GLMDisplayModeInfoFields glmModeInfo; // The D3D "Adapter" number feeds the fake adapter index
bool result = db->GetFakeAdapterInfo( Adapter, &glmRendererIndex, &glmDisplayIndex, &glmRendererInfo, &glmDisplayInfo ); Assert ( !result ); if ( result ) return D3DERR_NOTAVAILABLE;
bool result2 = db->GetModeInfo( glmRendererIndex, glmDisplayIndex, Mode == 0 ? 0 : Mode - 1, &glmModeInfo ); // End up asking Cocoa for mode zero twice
Assert( !result2 ); if ( result2 ) return D3DERR_NOTAVAILABLE;
pMode->Width = Mode == 0 ? 800 : glmModeInfo.m_modePixelWidth; // substitute in width of 800 on first "Mode zero"
pMode->Height = Mode == 0 ? 500 : glmModeInfo.m_modePixelHeight; // substitute in height of 500 on first "Mode zero"
pMode->RefreshRate = glmModeInfo.m_modeRefreshHz; // "adapter default"
pMode->Format = Format; // whatever you asked for ?
GLMPRINTF(( "-X- IDirect3D9::EnumAdapterModes returning mode size (%d,%d) and D3DFMT_X8R8G8B8", pMode->Width, pMode->Height )); return S_OK; }
HRESULT IDirect3D9::CheckDeviceType(UINT Adapter,D3DDEVTYPE DevType,D3DFORMAT AdapterFormat,D3DFORMAT BackBufferFormat,BOOL bWindowed) { //FIXME: we just say "OK" on any query
GLMPRINTF(( "-X- IDirect3D9::CheckDeviceType: Adapter=%d || DevType=%d:%s || AdapterFormat=%d:%s || BackBufferFormat=%d:%s || bWindowed=%d", Adapter, DevType, GLMDecode(eD3D_DEVTYPE,DevType), AdapterFormat, GLMDecode(eD3D_FORMAT, AdapterFormat), BackBufferFormat, GLMDecode(eD3D_FORMAT, BackBufferFormat), (int) bWindowed )); return S_OK; }
HRESULT IDirect3D9::GetAdapterDisplayMode(UINT Adapter,D3DDISPLAYMODE* pMode) { // asking what the current mode is
GLMPRINTF(("-X- IDirect3D9::GetAdapterDisplayMode: Adapter=%d", Adapter ));
GLMDisplayDB *db = g_extCocoaMgr->GetDisplayDB();
int glmRendererIndex = -1; int glmDisplayIndex = -1; GLMRendererInfoFields glmRendererInfo; GLMDisplayInfoFields glmDisplayInfo; GLMDisplayModeInfoFields glmModeInfo; // the D3D "Adapter" number feeds the fake adapter index
bool result = db->GetFakeAdapterInfo( Adapter, &glmRendererIndex, &glmDisplayIndex, &glmRendererInfo, &glmDisplayInfo ); Assert(!result); if (result) return D3DERR_INVALIDCALL;
int modeIndex = -1; // pass -1 as a mode index to find out about whatever the current mode is on the selected display
bool modeResult = db->GetModeInfo( glmRendererIndex, glmDisplayIndex, modeIndex, &glmModeInfo ); Assert (!modeResult); if (modeResult) return D3DERR_INVALIDCALL;
pMode->Width = glmModeInfo.m_modePixelWidth; pMode->Height = glmModeInfo.m_modePixelHeight; pMode->RefreshRate = glmModeInfo.m_modeRefreshHz; // "adapter default"
pMode->Format = D3DFMT_X8R8G8B8; //FIXME, this is a SWAG
return S_OK; }
HRESULT IDirect3D9::CheckDepthStencilMatch(UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,D3DFORMAT RenderTargetFormat,D3DFORMAT DepthStencilFormat) { GLMPRINTF(("-X- IDirect3D9::CheckDepthStencilMatch: Adapter=%d || DevType=%d:%s || AdapterFormat=%d:%s || RenderTargetFormat=%d:%s || DepthStencilFormat=%d:%s", Adapter, DeviceType, GLMDecode(eD3D_DEVTYPE,DeviceType), AdapterFormat, GLMDecode(eD3D_FORMAT, AdapterFormat), RenderTargetFormat, GLMDecode(eD3D_FORMAT, RenderTargetFormat), DepthStencilFormat, GLMDecode(eD3D_FORMAT, DepthStencilFormat) )); // one known request looks like this:
// AdapterFormat=5:D3DFMT_X8R8G8B8 || RenderTargetFormat=3:D3DFMT_A8R8G8B8 || DepthStencilFormat=2:D3DFMT_D24S8
// return S_OK for that one combo, Debugger() on anything else
HRESULT result = D3DERR_NOTAVAILABLE; // failure
switch( AdapterFormat ) { case D3DFMT_X8R8G8B8: { if ( (RenderTargetFormat == D3DFMT_A8R8G8B8) && (DepthStencilFormat == D3DFMT_D24S8) ) { result = S_OK; } } break; } Assert( result == S_OK );
return result; }
HRESULT IDirect3D9::CheckDeviceMultiSampleType( UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT SurfaceFormat,BOOL Windowed,D3DMULTISAMPLE_TYPE MultiSampleType,DWORD* pQualityLevels ) { GLMDisplayDB *db = g_extCocoaMgr->GetDisplayDB();
int glmRendererIndex = -1; int glmDisplayIndex = -1; GLMRendererInfoFields glmRendererInfo; GLMDisplayInfoFields glmDisplayInfo; GLMDisplayModeInfoFields glmModeInfo; // the D3D "Adapter" number feeds the fake adapter index
bool result = db->GetFakeAdapterInfo( Adapter, &glmRendererIndex, &glmDisplayIndex, &glmRendererInfo, &glmDisplayInfo ); Assert( !result ); if ( result ) return D3DERR_INVALIDCALL;
if ( !CommandLine()->FindParm("-glmenabletrustmsaa") ) { // These ghetto drivers don't get MSAA
if ( ( glmRendererInfo.m_nvG7x || glmRendererInfo.m_atiR5xx ) && ( MultiSampleType > D3DMULTISAMPLE_NONE ) ) { if ( pQualityLevels ) { *pQualityLevels = 0; } return D3DERR_NOTAVAILABLE; } }
switch ( MultiSampleType ) { case D3DMULTISAMPLE_NONE: // always return true
if ( pQualityLevels ) { *pQualityLevels = 1; } return S_OK; break;
case D3DMULTISAMPLE_2_SAMPLES: case D3DMULTISAMPLE_4_SAMPLES: case D3DMULTISAMPLE_6_SAMPLES: case D3DMULTISAMPLE_8_SAMPLES: // note the fact that the d3d enums for 2, 4, 6, 8 samples are equal to 2,4,6,8...
if (glmRendererInfo.m_maxSamples >= (int)MultiSampleType ) { if ( pQualityLevels ) { *pQualityLevels = 1; } return S_OK; } else { return D3DERR_NOTAVAILABLE; } break; default: if ( pQualityLevels ) { *pQualityLevels = 0; } return D3DERR_NOTAVAILABLE; break; } return D3DERR_NOTAVAILABLE; }
HRESULT IDirect3D9::CreateDevice(UINT Adapter,D3DDEVTYPE DeviceType,VD3DHWND hFocusWindow,DWORD BehaviorFlags,D3DPRESENT_PARAMETERS* pPresentationParameters,IDirect3DDevice9** ppReturnedDeviceInterface) { // constrain these inputs for the time being
// BackBufferFormat -> A8R8G8B8
// BackBufferCount -> 1;
// MultiSampleType -> D3DMULTISAMPLE_NONE
// AutoDepthStencilFormat -> D3DFMT_D24S8
// NULL out the return pointer so if we exit early it is not set
*ppReturnedDeviceInterface = NULL; // assume success unless something is sour
HRESULT result = S_OK; // relax this check for now
//if (pPresentationParameters->BackBufferFormat != D3DFMT_A8R8G8B8)
//{
// Debugger();
// result = -1;
//}
//rbarris 24Aug10 - relaxing this check - we don't care if the game asks for two backbuffers, it's moot
//if ( pPresentationParameters->BackBufferCount != 1 )
//{
// Debugger();
// result = D3DERR_NOTAVAILABLE;
//}
if ( pPresentationParameters->AutoDepthStencilFormat != D3DFMT_D24S8 ) { Debugger(); result = D3DERR_NOTAVAILABLE; }
if ( result == S_OK ) { // create an IDirect3DDevice9
// it will make a GLMContext and set up some drawables
IDirect3DDevice9Params devparams; memset( &devparams, 0, sizeof(devparams) ); devparams.m_adapter = Adapter; devparams.m_deviceType = DeviceType; devparams.m_focusWindow = hFocusWindow; // is this meaningful? is this a WindowRef ? follow it up the chain..
devparams.m_behaviorFlags = BehaviorFlags; devparams.m_presentationParameters = *pPresentationParameters;
IDirect3DDevice9 *dev = new IDirect3DDevice9; result = dev->Create( &devparams ); if ( result == S_OK ) { *ppReturnedDeviceInterface = dev; } } return result; }
// ------------------------------------------------------------------------------------------------------------------------------ //
#pragma mark ----- IDirect3DQuery9
HRESULT IDirect3DQuery9::Issue(DWORD dwIssueFlags) { // Flags field for Issue
// #define D3DISSUE_END (1 << 0) // Tells the runtime to issue the end of a query, changing it's state to "non-signaled".
// #define D3DISSUE_BEGIN (1 << 1) // Tells the runtime to issue the beginng of a query.
if (dwIssueFlags & D3DISSUE_BEGIN) { switch( m_type ) { case D3DQUERYTYPE_OCCLUSION: m_query->Start(); // drop "start counter" call into stream
break;
default: Assert(!"Can't use D3DISSUE_BEGIN on this query"); break; } } if (dwIssueFlags & D3DISSUE_END) { switch( m_type ) { case D3DQUERYTYPE_OCCLUSION: m_query->Stop(); // drop "end counter" call into stream
break; case D3DQUERYTYPE_EVENT: // End is very weird with respect to Events (fences).
// DX9 docs say to use End to put the fence in the stream. So we map End to GLM's Start.
// http://msdn.microsoft.com/en-us/library/ee422167(VS.85).aspx
m_query->Start(); // drop "set fence" into stream
break; } } return S_OK; }
HRESULT IDirect3DQuery9::GetData(void* pData,DWORD dwSize,DWORD dwGetDataFlags) { HRESULT result = -1; // GetData is not always called with the flush bit.
// if an answer is not yet available - return S_FALSE.
// if an answer is available - return S_OK and write the answer into *pData.
bool done = false; bool flush = (dwGetDataFlags & D3DGETDATA_FLUSH) != 0; // aka spin until done
// hmmm both of these paths are the same, maybe we could fold them up
if ( !m_query->IsStarted() ) { Assert(!"Can't GetData before issue/start"); printf("\n** IDirect3DQuery9::GetData: can't GetData before issue/start"); result = -1; } else if ( !m_query->IsStopped() ) { Assert(!"Can't GetData before issue-end/stop"); printf("\n** IDirect3DQuery9::GetData: can't GetData before issue-end/stop"); result = -1; } else { switch( m_type ) { case D3DQUERYTYPE_OCCLUSION: { // expectation - caller already did an issue begin (start) and an issue end (stop).
// we can probe using IsDone.
if (flush && (!m_ctx->Caps().m_hasPerfPackage1) ) { glFlush(); } do { done = m_query->IsDone(); if (done) { uint oqValue = 0; // or we could just pass pData directly to Complete...
m_query->Complete(&oqValue); if (pData) { *(uint*)pData = oqValue; } result = S_OK; } else { result = S_FALSE; } } while( flush && (!done) ); } break;
case D3DQUERYTYPE_EVENT: { // expectation - caller already did an issue end (for fence => start) but has not done anything that would call Stop.
// that's ok because Stop is a no-op for fences.
if (flush && (!m_ctx->Caps().m_hasPerfPackage1) ) { glFlush(); }
done = m_query->IsDone(); if (done) { m_query->Complete(NULL); // this will block on pre-SLGU
*(uint*)pData = 0; result = S_OK; } else { result = S_FALSE; } } break; } }
return result; }
// ------------------------------------------------------------------------------------------------------------------------------ //
#pragma mark ----- IDirect3DVertexBuffer9
HRESULT IDirect3DDevice9::CreateVertexBuffer(UINT Length,DWORD Usage,DWORD FVF,D3DPOOL Pool,IDirect3DVertexBuffer9** ppVertexBuffer,VD3DHANDLE* pSharedHandle) { GLMPRINTF(( ">-A- IDirect3DDevice9::CreateVertexBuffer" )); IDirect3DVertexBuffer9 *newbuff = new IDirect3DVertexBuffer9; newbuff->m_device = this; newbuff->m_ctx = m_ctx;
// FIXME need to find home or use for the Usage, FVF, Pool values passed in
uint options = 0; if (Usage&D3DUSAGE_DYNAMIC) { options |= GLMBufferOptionDynamic; } newbuff->m_vtxBuffer = m_ctx->NewBuffer( kGLMVertexBuffer, Length, options ) ; newbuff->m_vtxDesc.Type = D3DRTYPE_VERTEXBUFFER; newbuff->m_vtxDesc.Usage = Usage; newbuff->m_vtxDesc.Pool = Pool; newbuff->m_vtxDesc.Size = Length;
*ppVertexBuffer = newbuff; GLMPRINTF(( "<-A- IDirect3DDevice9::CreateVertexBuffer" ));
return S_OK; }
IDirect3DVertexBuffer9::~IDirect3DVertexBuffer9() { GLMPRINTF(( ">-A- ~IDirect3DVertexBuffer9" )); if (m_device) { m_device->ReleasedVertexBuffer( this );
if (m_ctx && m_vtxBuffer) { GLMPRINTF(( ">-A- ~IDirect3DVertexBuffer9 deleting m_vtxBuffer" )); m_ctx->DelBuffer( m_vtxBuffer ); m_vtxBuffer = NULL; GLMPRINTF(( "<-A- ~IDirect3DVertexBuffer9 deleting m_vtxBuffer - done" )); } m_device = NULL; } GLMPRINTF(( "<-A- ~IDirect3DVertexBuffer9" )); }
HRESULT IDirect3DVertexBuffer9::Lock(UINT OffsetToLock,UINT SizeToLock,void** ppbData,DWORD Flags) { // FIXME would be good to have "can't lock twice" logic
Assert( !(Flags & D3DLOCK_READONLY) ); // not impl'd
// Assert( !(Flags & D3DLOCK_NOSYSLOCK) ); // not impl'd - it triggers though
GLMBuffLockParams lockreq; lockreq.m_offset = OffsetToLock; lockreq.m_size = SizeToLock; lockreq.m_discard = (Flags & D3DLOCK_DISCARD) != 0; lockreq.m_nonblocking = ( (Flags & D3DLOCK_NOOVERWRITE) != 0 ) || lockreq.m_discard; m_vtxBuffer->Lock( &lockreq, (char**)ppbData );
GLMPRINTF(("-X- IDirect3DDevice9::Lock on D3D buf %p (GL name %d) offset %d, size %d => address %p", this, this->m_vtxBuffer->m_name, OffsetToLock, SizeToLock, *ppbData)); return S_OK; }
HRESULT IDirect3DVertexBuffer9::Unlock() { m_vtxBuffer->Unlock(); return S_OK; }
// ------------------------------------------------------------------------------------------------------------------------------ //
#pragma mark ----- IDirect3DIndexBuffer9
HRESULT IDirect3DDevice9::CreateIndexBuffer(UINT Length,DWORD Usage,D3DFORMAT Format,D3DPOOL Pool,IDirect3DIndexBuffer9** ppIndexBuffer,VD3DHANDLE* pSharedHandle) { GLMPRINTF(( ">-A- IDirect3DDevice9::CreateIndexBuffer" ));
// it is important to save all the create info, since GetDesc could get called later to query it
IDirect3DIndexBuffer9 *newbuff = new IDirect3DIndexBuffer9;
newbuff->m_device = this;
newbuff->m_restype = D3DRTYPE_INDEXBUFFER; // hmmmmmmm why are we not derived from d3dresource..
newbuff->m_ctx = m_ctx; // FIXME need to find home or use for the Usage, Format, Pool values passed in
uint options = 0; if (Usage&D3DUSAGE_DYNAMIC) { options |= GLMBufferOptionDynamic; }
newbuff->m_idxBuffer = m_ctx->NewBuffer( kGLMIndexBuffer, Length, options ) ; newbuff->m_idxDesc.Format = Format; newbuff->m_idxDesc.Type = D3DRTYPE_INDEXBUFFER; newbuff->m_idxDesc.Usage = Usage; newbuff->m_idxDesc.Pool = Pool; newbuff->m_idxDesc.Size = Length;
*ppIndexBuffer = newbuff;
GLMPRINTF(( "<-A- IDirect3DDevice9::CreateIndexBuffer" ));
return S_OK; }
IDirect3DIndexBuffer9::~IDirect3DIndexBuffer9() { GLMPRINTF(( ">-A- ~IDirect3DIndexBuffer9" )); if (m_device) { m_device->ReleasedIndexBuffer( this );
if (m_ctx && m_idxBuffer) { GLMPRINTF(( ">-A- ~IDirect3DIndexBuffer9 deleting m_idxBuffer" )); m_ctx->DelBuffer( m_idxBuffer ); GLMPRINTF(( "<-A- ~IDirect3DIndexBuffer9 deleting m_idxBuffer - done" )); } m_device = NULL; } else { } GLMPRINTF(( "<-A- ~IDirect3DIndexBuffer9" )); }
HRESULT IDirect3DIndexBuffer9::Lock(UINT OffsetToLock,UINT SizeToLock,void** ppbData,DWORD Flags) { // FIXME would be good to have "can't lock twice" logic
GLMBuffLockParams lockreq; lockreq.m_offset = OffsetToLock; lockreq.m_size = SizeToLock; lockreq.m_discard = (Flags & D3DLOCK_DISCARD) != 0; lockreq.m_nonblocking = ( (Flags & D3DLOCK_NOOVERWRITE) != 0 ) || lockreq.m_discard;
m_idxBuffer->Lock( &lockreq, (char**)ppbData );
return S_OK; }
HRESULT IDirect3DIndexBuffer9::Unlock() { m_idxBuffer->Unlock();
return S_OK; }
HRESULT IDirect3DIndexBuffer9::GetDesc(D3DINDEXBUFFER_DESC *pDesc) { *pDesc = m_idxDesc; return S_OK; }
// ------------------------------------------------------------------------------------------------------------------------------ //
#pragma mark ----- IDirect3DDevice9 -------------------------------------------------
void ConvertPresentationParamsToGLMDisplayParams( D3DPRESENT_PARAMETERS *d3dp, GLMDisplayParams *gldp ) { memset( gldp, 0, sizeof(*gldp) );
gldp->m_fsEnable = !d3dp->Windowed;
// see http://msdn.microsoft.com/en-us/library/ee416515(VS.85).aspx
// note that the values below are the only ones mentioned by Source engine; there are many others
switch(d3dp->PresentationInterval) { case D3DPRESENT_INTERVAL_ONE: gldp->m_vsyncEnable = true; // "The driver will wait for the vertical retrace period (the runtime will beam-follow to prevent tearing)."
break;
case D3DPRESENT_INTERVAL_IMMEDIATE: gldp->m_vsyncEnable = false; // "The runtime updates the window client area immediately and might do so more than once during the adapter refresh period."
break; default: gldp->m_vsyncEnable = true; // if I don't know it, you're getting vsync enabled.
break; } gldp->m_backBufferWidth = d3dp->BackBufferWidth; gldp->m_backBufferHeight = d3dp->BackBufferHeight; gldp->m_backBufferFormat = d3dp->BackBufferFormat; gldp->m_multiSampleCount = d3dp->MultiSampleType; // it's a count really
gldp->m_enableAutoDepthStencil = d3dp->EnableAutoDepthStencil; gldp->m_autoDepthStencilFormat = d3dp->AutoDepthStencilFormat;
gldp->m_fsRefreshHz = d3dp->FullScreen_RefreshRateInHz; // some fields in d3d PB we're not acting on yet...
// UINT BackBufferCount;
// DWORD MultiSampleQuality;
// D3DSWAPEFFECT SwapEffect;
// VD3DHWND hDeviceWindow;
// DWORD Flags;
}
HRESULT IDirect3DDevice9::Create( IDirect3DDevice9Params *params ) { GLMPRINTF((">-X-IDirect3DDevice9::Create")); HRESULT result = S_OK; // create an IDirect3DDevice9
// make a GLMContext and set up some drawables
m_params = *params; m_ctx = NULL; m_drawableFBO = NULL;
memset( m_rtSurfaces, 0, sizeof(m_rtSurfaces) ); m_dsSurface = NULL; m_defaultColorSurface = NULL; m_defaultDepthStencilSurface = NULL; memset( m_streams, 0, sizeof(m_streams) ); memset( m_textures, 0, sizeof(m_textures) ); memset( m_samplers, 0, sizeof(m_samplers) );
//============================================================================
// param block for GLM context create
GLMDisplayParams glmParams; ConvertPresentationParamsToGLMDisplayParams( ¶ms->m_presentationParameters, &glmParams );
glmParams.m_mtgl = true; // forget this idea -> (params->m_behaviorFlags & D3DCREATE_MULTITHREADED) != 0;
// the call above fills in a bunch of things, but doesn't know about anything outside of the presentation params.
// those tend to be the things that do not change after create, so we do those here in Create.
glmParams.m_focusWindow = params->m_focusWindow;
#if 0 //FIXME-HACK
// map the D3D "adapter" to a renderer/display pair
// (that GPU will have to stay set as-is for any subsequent mode changes)
int glmRendererIndex = -1; int glmDisplayIndex = -1; GLMRendererInfoFields glmRendererInfo; GLMDisplayInfoFields glmDisplayInfo; // the D3D "Adapter" number feeds the fake adapter index
bool adaptResult = GLMgr::aGLMgr()->GetDisplayDB()->GetFakeAdapterInfo( params->m_adapter, &glmRendererIndex, &glmDisplayIndex, &glmRendererInfo, &glmDisplayInfo ); Assert(!adaptResult);
glmParams.m_rendererIndex = glmRendererIndex; glmParams.m_displayIndex = glmDisplayIndex; // glmParams.m_modeIndex hmmmmm, client doesn't give us a mode number, just a resolution..
#endif
m_ctx = GLMgr::aGLMgr()->NewContext( &glmParams ); if (!m_ctx) { GLMPRINTF(("<-X- IDirect3DDevice9::Create (error out)")); return (HRESULT) -1; } // make an FBO to draw into and activate it.
m_drawableFBO = m_ctx->NewFBO();
m_ctx->SetDrawingFBO( m_drawableFBO ); // bind it to context. will receive attachments shortly.
m_ctx->BindFBOToCtx( m_drawableFBO, GL_READ_FRAMEBUFFER_EXT ); m_ctx->BindFBOToCtx( m_drawableFBO, GL_DRAW_FRAMEBUFFER_EXT );
// we create two IDirect3DSurface9's. These will be known as the internal render target 0 and the depthstencil.
GLMPRINTF(("-X- IDirect3DDevice9::Create making color render target...")); // color surface
result = this->CreateRenderTarget( m_params.m_presentationParameters.BackBufferWidth, // width
m_params.m_presentationParameters.BackBufferHeight, // height
m_params.m_presentationParameters.BackBufferFormat, // format
m_params.m_presentationParameters.MultiSampleType, // MSAA depth
m_params.m_presentationParameters.MultiSampleQuality, // MSAA quality
true, // lockable
&m_defaultColorSurface, // ppSurface
NULL // shared handle
);
if (result != S_OK) { GLMPRINTF(("<-X- IDirect3DDevice9::Create (error out)")); return result; } // do not do an AddRef..
GLMPRINTF(("-X- IDirect3DDevice9::Create making color render target complete -> %08x", m_defaultColorSurface ));
GLMPRINTF(("-X- IDirect3DDevice9::Create setting color render target...")); result = this->SetRenderTarget(0, m_defaultColorSurface); if (result != S_OK) { GLMPRINTF(("< IDirect3DDevice9::Create (error out)")); return result; } GLMPRINTF(("-X- IDirect3DDevice9::Create setting color render target complete."));
Assert (m_params.m_presentationParameters.EnableAutoDepthStencil);
GLMPRINTF(("-X- IDirect3DDevice9::Create making depth-stencil...")); result = CreateDepthStencilSurface( m_params.m_presentationParameters.BackBufferWidth, // width
m_params.m_presentationParameters.BackBufferHeight, // height
m_params.m_presentationParameters.AutoDepthStencilFormat, // format
m_params.m_presentationParameters.MultiSampleType, // MSAA depth
m_params.m_presentationParameters.MultiSampleQuality, // MSAA quality
TRUE, // enable z-buffer discard ????
&m_defaultDepthStencilSurface, // ppSurface
NULL // shared handle
); if (result != S_OK) { GLMPRINTF(("<-X- IDirect3DDevice9::Create (error out)")); return result; } // do not do an AddRef here..
GLMPRINTF(("-X- IDirect3DDevice9::Create making depth-stencil complete -> %08x", m_defaultDepthStencilSurface)); GLMPRINTF(("-X- Direct3DDevice9::Create setting depth-stencil render target...")); result = this->SetDepthStencilSurface(m_defaultDepthStencilSurface); if (result != S_OK) { GLMDebugger(); GLMPRINTF(("<-X- IDirect3DDevice9::Create (error out)")); return result; } GLMPRINTF(("-X- IDirect3DDevice9::Create setting depth-stencil render target complete."));
bool ready = m_drawableFBO->IsReady(); if (!ready) { GLMPRINTF(("<-X- IDirect3DDevice9::Create (error out)")); return (HRESULT)-1; }
// this next part really needs to be inside GLMContext.. or replaced with D3D style viewport setup calls.
m_ctx->GenDebugFontTex(); // blast the gl state mirror...
memset( &this->gl, 0, sizeof( this->gl ) );
GLScissorEnable_t defScissorEnable = { true }; GLScissorBox_t defScissorBox = { 0,0, m_params.m_presentationParameters.BackBufferWidth,m_params.m_presentationParameters.BackBufferHeight }; GLViewportBox_t defViewportBox = { 0,0, m_params.m_presentationParameters.BackBufferWidth,m_params.m_presentationParameters.BackBufferHeight }; GLViewportDepthRange_t defViewportDepthRange = { 0.1, 1000.0 }; GLCullFaceEnable_t defCullFaceEnable = { true }; GLCullFrontFace_t defCullFrontFace = { GL_CCW }; gl.m_ScissorEnable = defScissorEnable; gl.m_ScissorBox = defScissorBox; gl.m_ViewportBox = defViewportBox; gl.m_ViewportDepthRange = defViewportDepthRange; gl.m_CullFaceEnable = defCullFaceEnable; gl.m_CullFrontFace = defCullFrontFace;
gl.m_stateDirtyMask = (1<<kGLScissorEnable) | (1<<kGLScissorBox) | (1<<kGLViewportBox) | (1<<kGLViewportDepthRange) | (1<<kGLCullFaceEnable) | (1<<kGLCullFrontFace); GLMPRINTF(("<-X- IDirect3DDevice9::Create complete"));
// so GetClientRect can return sane answers
uint width, height; g_extCocoaMgr->RenderedSize( m_params.m_presentationParameters.BackBufferWidth, m_params.m_presentationParameters.BackBufferHeight, true ); // true = set
return result; }
IDirect3DDevice9::~IDirect3DDevice9() { GLMPRINTF(( "-D- IDirect3DDevice9::~IDirect3DDevice9 signpost" )); // want to know when this is called, if ever
}
#pragma mark ----- Basics - (IDirect3DDevice9)
HRESULT IDirect3DDevice9::Reset(D3DPRESENT_PARAMETERS* pPresentationParameters) { HRESULT result = S_OK;
// define the task of reset as:
// provide new drawable RT's for the backbuffer (color and depthstencil).
// fix up viewport / scissor..
// then pass the new presentation parameters through to GLM.
// (it will in turn notify appframework on the next present... which may be very soon, as mode changes are usually spotted inside Present() ).
// so some of this looks a lot like Create - we're just a subset of what it does.
// with a little work you could refactor this to be common code.
//------------------------------------------------------------------------------- absorb new presentation params..
m_params.m_presentationParameters = *pPresentationParameters; //------------------------------------------------------------------------------- color buffer..
// release old color surface if it's there..
if (m_defaultColorSurface) { ULONG refc = m_defaultColorSurface->Release( 0, "IDirect3DDevice9::Reset public release color surface" ); Assert( !refc ); m_defaultColorSurface = NULL; } GLMPRINTF(("-X- IDirect3DDevice9::Reset making new color render target...")); // color surface
result = this->CreateRenderTarget( m_params.m_presentationParameters.BackBufferWidth, // width
m_params.m_presentationParameters.BackBufferHeight, // height
m_params.m_presentationParameters.BackBufferFormat, // format
m_params.m_presentationParameters.MultiSampleType, // MSAA depth
m_params.m_presentationParameters.MultiSampleQuality, // MSAA quality
true, // lockable
&m_defaultColorSurface, // ppSurface
NULL // shared handle
);
if (result != S_OK) { GLMPRINTF(("<-X- IDirect3DDevice9::Reset (error out)")); return result; } // do not do an AddRef here..
GLMPRINTF(("-X- IDirect3DDevice9::Reset making color render target complete -> %08x", m_defaultColorSurface ));
GLMPRINTF(("-X- IDirect3DDevice9::Reset setting color render target...")); result = this->SetRenderTarget(0, m_defaultColorSurface); if (result != S_OK) { GLMPRINTF(("< IDirect3DDevice9::Reset (error out)")); return result; } GLMPRINTF(("-X- IDirect3DDevice9::Reset setting color render target complete."));
//-------------------------------------------------------------------------------depth stencil buffer
// release old depthstencil surface if it's there..
if (m_defaultDepthStencilSurface) { ULONG refc = m_defaultDepthStencilSurface->Release( 0, "IDirect3DDevice9::Reset public release depthstencil surface" ); Assert(!refc); m_defaultDepthStencilSurface = NULL; } Assert (m_params.m_presentationParameters.EnableAutoDepthStencil);
GLMPRINTF(("-X- IDirect3DDevice9::Reset making depth-stencil...")); result = CreateDepthStencilSurface( m_params.m_presentationParameters.BackBufferWidth, // width
m_params.m_presentationParameters.BackBufferHeight, // height
m_params.m_presentationParameters.AutoDepthStencilFormat, // format
m_params.m_presentationParameters.MultiSampleType, // MSAA depth
m_params.m_presentationParameters.MultiSampleQuality, // MSAA quality
TRUE, // enable z-buffer discard ????
&m_defaultDepthStencilSurface, // ppSurface
NULL // shared handle
); if (result != S_OK) { GLMPRINTF(("<-X- IDirect3DDevice9::Reset (error out)")); return result; } // do not do an AddRef here..
GLMPRINTF(("-X- IDirect3DDevice9::Reset making depth-stencil complete -> %08x", m_defaultDepthStencilSurface));
GLMPRINTF(("-X- IDirect3DDevice9::Reset setting depth-stencil render target...")); result = this->SetDepthStencilSurface(m_defaultDepthStencilSurface); if (result != S_OK) { GLMPRINTF(("<-X- IDirect3DDevice9::Reset (error out)")); return result; } GLMPRINTF(("-X- IDirect3DDevice9::Reset setting depth-stencil render target complete."));
bool ready = m_drawableFBO->IsReady(); if (!ready) { GLMPRINTF(("<-X- IDirect3DDevice9::Reset (error out)")); return D3DERR_DEVICELOST; }
//-------------------------------------------------------------------------------zap viewport and scissor to new backbuffer size
GLScissorEnable_t defScissorEnable = { true }; GLScissorBox_t defScissorBox = { 0,0, m_params.m_presentationParameters.BackBufferWidth,m_params.m_presentationParameters.BackBufferHeight }; GLViewportBox_t defViewportBox = { 0,0, m_params.m_presentationParameters.BackBufferWidth,m_params.m_presentationParameters.BackBufferHeight }; GLViewportDepthRange_t defViewportDepthRange = { 0.1, 1000.0 }; GLCullFaceEnable_t defCullFaceEnable = { true }; GLCullFrontFace_t defCullFrontFace = { GL_CCW }; gl.m_ScissorEnable = defScissorEnable; gl.m_ScissorBox = defScissorBox; gl.m_ViewportBox = defViewportBox; gl.m_ViewportDepthRange = defViewportDepthRange; gl.m_CullFaceEnable = defCullFaceEnable; gl.m_CullFrontFace = defCullFrontFace;
gl.m_stateDirtyMask |= (1<<kGLScissorEnable) | (1<<kGLScissorBox) | (1<<kGLViewportBox) | (1<<kGLViewportDepthRange) | (1<<kGLCullFaceEnable) | (1<<kGLCullFrontFace);
//-------------------------------------------------------------------------------finally, propagate new display params to GLM context
GLMDisplayParams glmParams; ConvertPresentationParamsToGLMDisplayParams( pPresentationParameters, &glmParams );
// steal back previously sent focus window...
glmParams.m_focusWindow = m_ctx->m_displayParams.m_focusWindow; Assert( glmParams.m_focusWindow != NULL );
// so GetClientRect can return sane answers
uint width, height; g_extCocoaMgr->RenderedSize( pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight, true ); // true = set
m_ctx->SetDisplayParams( &glmParams ); return S_OK; }
HRESULT IDirect3DDevice9::SetViewport(CONST D3DVIEWPORT9* pViewport) { GLMPRINTF(("-X- IDirect3DDevice9::SetViewport : minZ %f, maxZ %f",pViewport->MinZ, pViewport->MaxZ )); gl.m_ViewportBox.x = pViewport->X; gl.m_ViewportBox.width = pViewport->Width;
gl.m_ViewportBox.y = pViewport->Y; gl.m_ViewportBox.height = pViewport->Height;
gl.m_stateDirtyMask |= (1<<kGLViewportBox);
gl.m_ViewportDepthRange.near = pViewport->MinZ; gl.m_ViewportDepthRange.far = pViewport->MaxZ;
gl.m_stateDirtyMask |= (1<<kGLViewportDepthRange);
return S_OK; }
HRESULT IDirect3DDevice9::BeginScene() { m_ctx->BeginFrame();
return S_OK; }
HRESULT IDirect3DDevice9::EndScene() { m_ctx->EndFrame(); return S_OK; }
// stolen from glmgrbasics.cpp
enum ECarbonModKeyIndex { EcmdKeyBit = 8, /* command key down?*/ EshiftKeyBit = 9, /* shift key down?*/ EalphaLockBit = 10, /* alpha lock down?*/ EoptionKeyBit = 11, /* option key down?*/ EcontrolKeyBit = 12 /* control key down?*/ };
enum ECarbonModKeyMask { EcmdKey = 1 << EcmdKeyBit, EshiftKey = 1 << EshiftKeyBit, EalphaLock = 1 << EalphaLockBit, EoptionKey = 1 << EoptionKeyBit, EcontrolKey = 1 << EcontrolKeyBit };
ConVar gl_blitmode( "gl_blitmode", "1" ); ConVar dxa_nullrefresh_capslock( "dxa_nullrefresh_capslock", "0" );
HRESULT IDirect3DDevice9::Present(CONST RECT* pSourceRect,CONST RECT* pDestRect,VD3DHWND hDestWindowOverride,CONST RGNDATA* pDirtyRegion) { // before attempting to present a tex, make sure it's been resolved if it was MSAA.
// if we push that responsibility down to m_ctx->Present, it could probably do it without an extra copy.
// i.e. anticipate the blit from the resolvedtex to GL_BACK, and just do that instead.
if (dxa_nullrefresh_capslock.GetInt()) { if (GetCurrentKeyModifiers() & EalphaLock ) { return S_OK; } }
// no explicit ResolveTex call first - that got pushed down into GLMContext::Present
m_ctx->Present( m_defaultColorSurface->m_tex );
return S_OK; }
// Sanity-chedk the results
/*
// TODO, something like the following:
// safe because of early exit on NULL above
m_rtSurfaces[ RenderTargetIndex ]->AddRef();
*ppRenderTarget = m_rtSurfaces[ RenderTargetIndex ]; */
#pragma mark ----- Textures - (IDirect3DDevice9)
#pragma mark ( create functions for each texture are now adjacent to the rest of the methods for each texture class)
HRESULT IDirect3DDevice9::SetTexture(DWORD Stage,IDirect3DBaseTexture9* pTexture) { // texture sets are sent through immediately to GLM
// but we also latch the value so we know which TMU's are active.
// whuch can help FlushSamplers do less work.
// place new tex
m_textures[Stage] = pTexture; if (!pTexture) { m_ctx->SetSamplerTex( Stage, NULL ); } else { m_ctx->SetSamplerTex( Stage, pTexture->m_tex ); } return S_OK; }
HRESULT IDirect3DDevice9::GetTexture(DWORD Stage,IDirect3DBaseTexture9** ppTexture) { // if implemented, should it increase the ref count ??
GLMDebugger(); return S_OK; }
#pragma mark ----- RT's and Surfaces - (IDirect3DDevice9)
HRESULT IDirect3DDevice9::CreateRenderTarget(UINT Width,UINT Height,D3DFORMAT Format,D3DMULTISAMPLE_TYPE MultiSample,DWORD MultisampleQuality,BOOL Lockable,IDirect3DSurface9** ppSurface,VD3DHANDLE* pSharedHandle, char *pDebugLabel) { HRESULT result = S_OK; IDirect3DSurface9 *surf = new IDirect3DSurface9; surf->m_restype = D3DRTYPE_SURFACE;
surf->m_device = this; // always set device on creations!
GLMTexLayoutKey rtkey; memset( &rtkey, 0, sizeof(rtkey) ); rtkey.m_texGLTarget = GL_TEXTURE_2D; rtkey.m_xSize = Width; rtkey.m_ySize = Height; rtkey.m_zSize = 1;
rtkey.m_texFormat = Format; rtkey.m_texFlags = kGLMTexRenderable;
rtkey.m_texFlags |= kGLMTexSRGB; // all render target tex are SRGB mode
if (m_ctx->Caps().m_cantAttachSRGB) { // this config can't support SRGB render targets. quietly turn off the sRGB bit.
rtkey.m_texFlags &= ~kGLMTexSRGB; } if ( (MultiSample !=0) && (!m_ctx->Caps().m_nvG7x) ) { rtkey.m_texFlags |= kGLMTexMultisampled; rtkey.m_texSamples = MultiSample; // FIXME no support for "MS quality" yet
}
surf->m_tex = m_ctx->NewTex( &rtkey, pDebugLabel ); surf->m_face = 0; surf->m_mip = 0; //desc
surf->m_desc.Format = Format; surf->m_desc.Type = D3DRTYPE_SURFACE; surf->m_desc.Usage = 0; //FIXME ???????????
surf->m_desc.Pool = D3DPOOL_DEFAULT; //FIXME ???????????
surf->m_desc.MultiSampleType = MultiSample; surf->m_desc.MultiSampleQuality = MultisampleQuality; surf->m_desc.Width = Width; surf->m_desc.Height = Height;
*ppSurface = (result==S_OK) ? surf : NULL;
#if IUNKNOWN_ALLOC_SPEW
char scratch[1024]; sprintf(scratch,"RT %s", surf->m_tex->m_layout->m_layoutSummary ); surf->SetMark( true, scratch ); #endif
return result; }
HRESULT IDirect3DDevice9::SetRenderTarget(DWORD RenderTargetIndex,IDirect3DSurface9* pRenderTarget) { HRESULT result = S_OK;
GLMPRINTF(("-F- SetRenderTarget index=%d, surface=%8x (tex=%8x %s)", RenderTargetIndex, pRenderTarget, pRenderTarget ? pRenderTarget->m_tex : NULL, pRenderTarget ? pRenderTarget->m_tex->m_layout->m_layoutSummary : "" ));
// note that it is OK to pass NULL for pRenderTarget, it implies that you would like to detach any color buffer from that target index
// behaviors...
// if new surf is same as old surf, no change in refcount, in fact, it's early exit
IDirect3DSurface9 *oldTarget = m_rtSurfaces[RenderTargetIndex];
if (pRenderTarget == oldTarget) { GLMPRINTF(("-F- --> no change",RenderTargetIndex)); return S_OK; } // we now know that the new surf is not the same as the old surf.
// you can't assume either one is non NULL here though.
if (m_rtSurfaces[RenderTargetIndex]) { m_rtSurfaces[RenderTargetIndex]->Release( 1, "-A SetRenderTarget private release" ); // note this is the private refcount being lowered
}
if (pRenderTarget) { pRenderTarget->AddRef( 1, "+A SetRenderTarget private addref" ); // again, private refcount being raised
} m_rtSurfaces[RenderTargetIndex] = pRenderTarget; // emplace it whether NULL or not
if (!pRenderTarget) { GLMPRINTF(("-F- --> Setting NULL render target on index=%d ",RenderTargetIndex)); } else { GLMPRINTF(("-F- --> attaching index=%d on drawing FBO (%8x)",RenderTargetIndex, m_drawableFBO)); // attach color to FBO
GLMFBOTexAttachParams rtParams; memset( &rtParams, 0, sizeof(rtParams) ); rtParams.m_tex = pRenderTarget->m_tex; rtParams.m_face = pRenderTarget->m_face; rtParams.m_mip = pRenderTarget->m_mip; rtParams.m_zslice = 0; // FIXME if you ever want to be able to render to slices of a 3D tex..
m_drawableFBO->TexAttach( &rtParams, (EGLMFBOAttachment)(kAttColor0 + RenderTargetIndex) ); }
return result; }
HRESULT IDirect3DDevice9::GetRenderTarget(DWORD RenderTargetIndex,IDirect3DSurface9** ppRenderTarget) { if ( !m_rtSurfaces[ RenderTargetIndex ] ) return D3DERR_NOTFOUND; if ( ( RenderTargetIndex < 0 ) || ( RenderTargetIndex > 4 ) || !ppRenderTarget ) return D3DERR_INVALIDCALL;
// safe because of early exit on NULL above
m_rtSurfaces[ RenderTargetIndex ]->AddRef(0, "+B GetRenderTarget public addref"); // per http://msdn.microsoft.com/en-us/library/bb174404(VS.85).aspx
*ppRenderTarget = m_rtSurfaces[ RenderTargetIndex ]; return S_OK; }
HRESULT IDirect3DDevice9::CreateOffscreenPlainSurface(UINT Width,UINT Height,D3DFORMAT Format,D3DPOOL Pool,IDirect3DSurface9** ppSurface,VD3DHANDLE* pSharedHandle) { // set surf->m_restype to D3DRTYPE_SURFACE...
// this is almost identical to CreateRenderTarget..
HRESULT result = S_OK; IDirect3DSurface9 *surf = new IDirect3DSurface9; surf->m_restype = D3DRTYPE_SURFACE;
surf->m_device = this; // always set device on creations!
GLMTexLayoutKey rtkey; memset( &rtkey, 0, sizeof(rtkey) ); rtkey.m_texGLTarget = GL_TEXTURE_2D; rtkey.m_xSize = Width; rtkey.m_ySize = Height; rtkey.m_zSize = 1;
rtkey.m_texFormat = Format; rtkey.m_texFlags = kGLMTexRenderable;
surf->m_tex = m_ctx->NewTex( &rtkey, "offscreen plain surface" ); surf->m_face = 0; surf->m_mip = 0; //desc
surf->m_desc.Format = Format; surf->m_desc.Type = D3DRTYPE_SURFACE; surf->m_desc.Usage = 0; surf->m_desc.Pool = D3DPOOL_DEFAULT; surf->m_desc.MultiSampleType = D3DMULTISAMPLE_NONE; surf->m_desc.MultiSampleQuality = 0; surf->m_desc.Width = Width; surf->m_desc.Height = Height;
*ppSurface = (result==S_OK) ? surf : NULL; return result; }
HRESULT IDirect3DDevice9::CreateDepthStencilSurface(UINT Width,UINT Height,D3DFORMAT Format,D3DMULTISAMPLE_TYPE MultiSample,DWORD MultisampleQuality,BOOL Discard,IDirect3DSurface9** ppSurface,VD3DHANDLE* pSharedHandle) { HRESULT result = S_OK; IDirect3DSurface9 *surf = new IDirect3DSurface9; surf->m_restype = D3DRTYPE_SURFACE;
surf->m_device = this; // always set device on creations!
GLMTexLayoutKey depthkey; memset( &depthkey, 0, sizeof(depthkey) );
depthkey.m_texGLTarget = GL_TEXTURE_2D; depthkey.m_xSize = Width; depthkey.m_ySize = Height; depthkey.m_zSize = 1;
depthkey.m_texFormat = Format; depthkey.m_texFlags = kGLMTexRenderable | kGLMTexIsDepth | kGLMTexIsStencil;
if ( (MultiSample !=0) && (!m_ctx->Caps().m_nvG7x) ) { depthkey.m_texFlags |= kGLMTexMultisampled; depthkey.m_texSamples = MultiSample; // FIXME no support for "MS quality" yet
}
surf->m_tex = m_ctx->NewTex( &depthkey, "depth-stencil surface" ); surf->m_face = 0; surf->m_mip = 0;
//desc
surf->m_desc.Format = Format; surf->m_desc.Type = D3DRTYPE_SURFACE; surf->m_desc.Usage = 0; //FIXME ???????????
surf->m_desc.Pool = D3DPOOL_DEFAULT; //FIXME ???????????
surf->m_desc.MultiSampleType = MultiSample; surf->m_desc.MultiSampleQuality = MultisampleQuality; surf->m_desc.Width = Width; surf->m_desc.Height = Height;
*ppSurface = (result==S_OK) ? surf : NULL; return result; }
HRESULT IDirect3DDevice9::SetDepthStencilSurface(IDirect3DSurface9* pNewZStencil) { HRESULT result = S_OK;
GLMPRINTF(("-F- SetDepthStencilSurface, surface=%8x (tex=%8x %s)", pNewZStencil, pNewZStencil ? pNewZStencil->m_tex : NULL, pNewZStencil ? pNewZStencil->m_tex->m_layout->m_layoutSummary : "" ));
if (pNewZStencil) { pNewZStencil->AddRef(1, "+A SetDepthStencilSurface private addref"); }
if (m_dsSurface) { m_dsSurface->Release(1, "-A SetDepthStencilSurface private release"); // do not do a Release here..
}
if (m_dsSurface != pNewZStencil) { GLMPRINTF(("-F- --> attaching depthstencil %8x on drawing FBO (%8x)", pNewZStencil, m_drawableFBO));
m_dsSurface = pNewZStencil; // aka FBO attach
GLMFBOTexAttachParams depthParams; memset( &depthParams, 0, sizeof(depthParams) ); // NULL is OK - it means unbind the depth buffer
depthParams.m_tex = (pNewZStencil) ? pNewZStencil->m_tex : NULL; depthParams.m_face = 0; depthParams.m_mip = 0; depthParams.m_zslice= 0;
// brute force baby
// clear old attachments in all D/S categories
m_drawableFBO->TexDetach( kAttStencil ); m_drawableFBO->TexDetach( kAttDepth ); m_drawableFBO->TexDetach( kAttDepthStencil ); // select dest for new attachment
if (depthParams.m_tex!=NULL) { EGLMFBOAttachment destAttach = (depthParams.m_tex->m_layout->m_format->m_glDataFormat != 34041) ? kAttDepth : kAttDepthStencil; m_drawableFBO->TexAttach( &depthParams, destAttach ); // attach(NULL) is allowed to mean "detach".
} } else { GLMPRINTF(("-F- --> no change")); }
return result; }
HRESULT IDirect3DDevice9::GetDepthStencilSurface(IDirect3DSurface9** ppZStencilSurface) { if ( !ppZStencilSurface ) { return D3DERR_INVALIDCALL; } if ( !m_dsSurface ) { *ppZStencilSurface = NULL; return D3DERR_NOTFOUND; }
m_dsSurface->AddRef(0, "+B GetDepthStencilSurface public addref"); // per http://msdn.microsoft.com/en-us/library/bb174384(VS.85).aspx
*ppZStencilSurface = m_dsSurface;
return S_OK; }
HRESULT IDirect3DDevice9::GetRenderTargetData(IDirect3DSurface9* pRenderTarget,IDirect3DSurface9* pDestSurface) { // is it just a blit ?
this->StretchRect( pRenderTarget, NULL, pDestSurface, NULL, D3DTEXF_NONE ); // is this good enough ???
return S_OK; }
HRESULT IDirect3DDevice9::GetFrontBufferData(UINT iSwapChain,IDirect3DSurface9* pDestSurface) { Debugger(); return S_OK; }
HRESULT IDirect3DDevice9::StretchRect(IDirect3DSurface9* pSourceSurface,CONST RECT* pSourceRect,IDirect3DSurface9* pDestSurface,CONST RECT* pDestRect,D3DTEXTUREFILTERTYPE Filter) { // find relevant slices in GLM tex
CGLMTex *srcTex = pSourceSurface->m_tex; int srcSliceIndex = srcTex->CalcSliceIndex( pSourceSurface->m_face, pSourceSurface->m_mip ); GLMTexLayoutSlice *srcSlice = &srcTex->m_layout->m_slices[ srcSliceIndex ];
CGLMTex *dstTex = pDestSurface->m_tex; int dstSliceIndex = dstTex->CalcSliceIndex( pDestSurface->m_face, pDestSurface->m_mip ); GLMTexLayoutSlice *dstSlice = &dstTex->m_layout->m_slices[ dstSliceIndex ];
if ( dstTex->m_rboName != 0 ) { Assert(!"No path yet for blitting into an MSAA tex"); return S_OK; }
bool useFastBlit = (gl_blitmode.GetInt() != 0); if ( !useFastBlit && (srcTex->m_rboName !=0)) // old way, we do a resolve to scratch tex first (necessitating two step blit)
{ m_ctx->ResolveTex( srcTex, true ); }
// set up source/dest rect in GLM form
GLMRect srcRect, dstRect;
// d3d nomenclature:
// Y=0 is the visual top and also aligned with V=0.
srcRect.xmin = pSourceRect ? pSourceRect->left : 0; srcRect.xmax = pSourceRect ? pSourceRect->right : srcSlice->m_xSize; srcRect.ymin = pSourceRect ? pSourceRect->top : 0; srcRect.ymax = pSourceRect ? pSourceRect->bottom : srcSlice->m_ySize;
dstRect.xmin = pDestRect ? pDestRect->left : 0; dstRect.xmax = pDestRect ? pDestRect->right : dstSlice->m_xSize; dstRect.ymin = pDestRect ? pDestRect->top : 0; dstRect.ymax = pDestRect ? pDestRect->bottom : dstSlice->m_ySize;
GLenum filterGL = 0; switch(Filter) { case D3DTEXF_NONE: case D3DTEXF_POINT: filterGL = GL_NEAREST; break; case D3DTEXF_LINEAR: filterGL = GL_LINEAR; break; default: // D3DTEXF_ANISOTROPIC
Assert(!"Impl aniso stretch"); break; } if (useFastBlit) { m_ctx->Blit2( srcTex, &srcRect, pSourceSurface->m_face, pSourceSurface->m_mip, dstTex, &dstRect, pDestSurface->m_face, pDestSurface->m_mip, filterGL ); } else { m_ctx->BlitTex( srcTex, &srcRect, pSourceSurface->m_face, pSourceSurface->m_mip, dstTex, &dstRect, pDestSurface->m_face, pDestSurface->m_mip, filterGL ); } return S_OK; }
// This totally sucks, but this information can't be gleaned any
// other way when translating from D3D to GL at this level
//
// This returns a mask, since multiple GLSL "varyings" can be tagged with centroid
static uint32 CentroidMaskFromName( bool bPixelShader, const char *pName ) { if ( !pName ) return 0; if ( bPixelShader ) { if ( V_stristr( pName, "lightmappedpaint_ps" ) || V_stristr( pName, "lightmappedgeneric_ps" ) || V_stristr( pName, "flashlight_ps" ) ) { return (0x01 << 1); // iterator 1
} else if ( V_stristr( pName, "shadow_ps" ) ) { return (0x01 << 1) | (0x01 << 2) | (0x01 << 3); // iterators 1, 2 and 3
} else if ( V_stristr( pName, "water_ps" ) ) { return (0x01 << 5) | (0x01 << 6) | (0x01 << 7); // iterators 5, 6 and 7
} } else // vertex shader
{ // Vertex shaders also
if ( V_stristr( pName, "lightmappedgeneric_vs" ) || V_stristr( pName, "flashlight_vs" ) ) { return (0x01 << 1); // iterator 1
} else if ( V_stristr( pName, "shadow_vs" ) ) { return (0x01 << 1) | (0x01 << 2) | (0x01 << 3); // iterators 1, 2 and 3
} else if ( V_stristr( pName, "water_vs" ) ) { return (0x01 << 5) | (0x01 << 6) | (0x01 << 7); // iterators 5, 6 and 7
} } // This shader doesn't have any centroid iterators
return 0; }
// This totally sucks, but this information can't be gleaned any
// other way when translating from D3D to GL at this level
static int ShadowDepthSamplerFromName( const char *pName ) { if ( !pName ) return -1; if ( V_stristr( pName, "water_ps" ) ) { return 7; }
else if ( V_stristr( pName, "phong_ps" ) ) { return 4; } else if ( V_stristr( pName, "vertexlit_and_unlit_generic_bump_ps" ) ) { return 8; } else if ( V_stristr( pName, "vertexlit_and_unlit_generic_ps" ) ) { return 8; } else if ( V_stristr( pName, "eye_refract_ps" ) ) { return 6; } else if ( V_stristr( pName, "eyes_flashlight_ps" ) ) { return 4; } else if ( V_stristr( pName, "worldtwotextureblend_ps" ) ) { return 7; } else if ( V_stristr( pName, "teeth_flashlight_ps" ) ) { return 2; } else if ( V_stristr( pName, "flashlight_ps" ) ) // substring of above, make sure this comes last!!
{ return 7; } // This shader doesn't have a shadow depth map sampler
return -1; }
#pragma mark ----- Pixel Shaders - (IDirect3DDevice9)
HRESULT IDirect3DDevice9::CreatePixelShader(CONST DWORD* pFunction,IDirect3DPixelShader9** ppShader, const char *pShaderName, char *pDebugLabel) { HRESULT result = D3DERR_INVALIDCALL; *ppShader = NULL; int nShadowDepthSampler = ShadowDepthSamplerFromName( pShaderName ); uint32 nCentroidMask = CentroidMaskFromName( true, pShaderName ); if ( g_bUseControlFlow || !m_ctx->Caps().m_hasDualShaders ) { // either having control-flow 'on' or -glmdualshaders 'off' disqualifies ARB assembler mode
g_useASMTranslations = false; }
if ( ! (g_useASMTranslations || g_useGLSLTranslations) ) { Assert(!"Must set at least one translation option.."); *ppShader = NULL; return -1; } else { int numTranslations = (g_useASMTranslations!=0) + (g_useGLSLTranslations!=0); bool bVertexShader = false;
// we can do one or two translated forms. they go together in a single buffer with some markers to allow GLM to break it up.
// this also lets us mirror each set of translations to disk with a single file making it easier to view and edit side by side.
int maxTranslationSize = 50000; // size of any one translation
CUtlBuffer transbuf( 3000, numTranslations * maxTranslationSize, CUtlBuffer::TEXT_BUFFER ); CUtlBuffer tempbuf( 3000, maxTranslationSize, CUtlBuffer::TEXT_BUFFER );
if ( g_useASMTranslations ) { // no extra tag needed for ARBfp, just use the !!ARBfp marker
tempbuf.EnsureCapacity( maxTranslationSize ); g_D3DToOpenGLTranslatorASM.TranslateShader( (uint32 *) pFunction, &tempbuf, &bVertexShader, D3DToGL_OptionUseEnvParams, nShadowDepthSampler, 0, pDebugLabel );
// grow to encompass...
transbuf.PutString ( (char*)tempbuf.Base() ); transbuf.PutString( "\n\n" ); // whitespace
}
if ( g_useGLSLTranslations ) { transbuf.PutString( "//GLSLfp\n" ); // this is required so GLM can crack the text apart
// note the GLSL translator wants its own buffer
tempbuf.EnsureCapacity( maxTranslationSize ); uint glslPixelShaderOptions = D3DToGL_OptionGLSL | D3DToGL_OptionUseEnvParams;
// Fake SRGB mode - needed on R500, probably indefinitely.
// Do this stuff if caps show m_needsFakeSRGB=true and the sRGBWrite state is true
// (but not if it's engine_post which is special)
if (!m_ctx->Caps().m_hasGammaWrites) { if ( pShaderName ) { if ( !V_stristr( pShaderName, "engine_post" ) ) { glslPixelShaderOptions |= D3DToGL_OptionSRGBWriteSuffix; } } }
if (m_ctx->Caps().m_hasBindableUniforms) { glslPixelShaderOptions |= D3DToGL_OptionUseBindableUniforms; } g_D3DToOpenGLTranslatorGLSL.TranslateShader( (uint32 *) pFunction, &tempbuf, &bVertexShader, glslPixelShaderOptions, nShadowDepthSampler, nCentroidMask, pDebugLabel ); transbuf.PutString( (char*)tempbuf.Base() ); transbuf.PutString( "\n\n" ); // whitespace
} if ( bVertexShader ) { // don't cross the streams
Assert(!"Can't accept vertex shader in CreatePixelShader"); result = D3DERR_INVALIDCALL; } else { IDirect3DPixelShader9 *newprog = new IDirect3DPixelShader9; newprog->m_pixProgram = m_ctx->NewProgram( kGLMFragmentProgram, (char *)transbuf.Base() ) ;
newprog->m_device = this; //------ find the frag program metadata and extract it..
// find the highwater mark
char *highWaterPrefix = "//HIGHWATER-"; // try to arrange this so it can work with pure GLSL if needed
char *highWaterStr = strstr( (char *)transbuf.Base(), highWaterPrefix ); if (highWaterStr) { char *highWaterActualData = highWaterStr + strlen( highWaterPrefix ); int value = -1; sscanf( highWaterActualData, "%d", &value );
newprog->m_pixHighWater = value; newprog->m_pixProgram->m_descs[kGLMGLSL].m_highWater = value; } else { Assert(!"couldn't find sampler map in pixel shader"); } // find the sampler map
char *samplerMaskPrefix = "//SAMPLERMASK-"; // try to arrange this so it can work with pure GLSL if needed
char *samplerMaskStr = strstr( (char *)transbuf.Base(), samplerMaskPrefix ); if (samplerMaskStr) { char *samplerMaskActualData = samplerMaskStr + strlen( samplerMaskPrefix ); int value = -1; sscanf( samplerMaskActualData, "%04x", &value );
newprog->m_pixSamplerMask = value; newprog->m_pixProgram->m_samplerMask = value; // helps GLM maintain a better linked pair cache even when SRGB sampler state changes
} else { Assert(!"couldn't find sampler map in pixel shader"); } *ppShader = newprog; result = S_OK; } }
return result; }
IDirect3DPixelShader9::~IDirect3DPixelShader9() { GLMPRINTF(( ">-A- ~IDirect3DPixelShader9" ));
if (m_device) { m_device->ReleasedPixelShader( this );
if (m_pixProgram) { m_pixProgram->m_ctx->DelProgram( m_pixProgram ); m_pixProgram = NULL; } m_device = NULL; } GLMPRINTF(( "<-A- ~IDirect3DPixelShader9" )); }
HRESULT IDirect3DDevice9::SetPixelShader(IDirect3DPixelShader9* pShader) { if (pShader) { m_ctx->SetDrawingProgram( kGLMFragmentProgram, pShader->m_pixProgram ); } else { m_ctx->SetDrawingProgram( kGLMFragmentProgram, NULL ); } m_pixelShader = pShader;
return S_OK; }
HRESULT IDirect3DDevice9::SetPixelShaderConstantF(UINT StartRegister,CONST float* pConstantData,UINT Vector4fCount) { m_ctx->SetProgramParametersF( kGLMFragmentProgram, StartRegister, (float *)pConstantData, Vector4fCount );
return S_OK; }
HRESULT IDirect3DDevice9::SetPixelShaderConstantB(UINT StartRegister,CONST BOOL* pConstantData,UINT BoolCount) { GLMPRINTF(("-X- Ignoring IDirect3DDevice9::SetPixelShaderConstantB call, count was %d", BoolCount )); // actually no way to do this yet.
// m_ctx->SetProgramParametersB( kGLMFragmentProgram, StartRegister, pConstantData, BoolCount );
return S_OK; }
HRESULT IDirect3DDevice9::SetPixelShaderConstantI(UINT StartRegister,CONST int* pConstantData,UINT Vector4iCount) { GLMPRINTF(("-X- Ignoring IDirect3DDevice9::SetPixelShaderConstantI call, count was %d", Vector4iCount )); // m_ctx->SetProgramParametersI( kGLMFragmentProgram, StartRegister, pConstantData, Vector4iCount );
return S_OK; }
#pragma mark ----- Vertex Shaders - (IDirect3DDevice9)
HRESULT IDirect3DDevice9::CreateVertexShader(CONST DWORD* pFunction, IDirect3DVertexShader9** ppShader, const char *pShaderName, char *pDebugLabel) { HRESULT result = D3DERR_INVALIDCALL; *ppShader = NULL;
uint32 nCentroidMask = CentroidMaskFromName( false, pShaderName );
if ( g_bUseControlFlow || !m_ctx->Caps().m_hasDualShaders ) { // either having control-flow 'on' or -glmdualshaders 'off' disqualifies ARB assembler mode
g_useASMTranslations = false; } if ( ! (g_useASMTranslations || g_useGLSLTranslations) ) { Assert(!"Must set at least one translation option.."); *ppShader = NULL; return -1; } else { int numTranslations = (g_useASMTranslations!=0) + (g_useGLSLTranslations!=0); bool bVertexShader = false;
// we can do one or two translated forms. they go together in a single buffer with some markers to allow GLM to break it up.
// this also lets us mirror each set of translations to disk with a single file making it easier to view and edit side by side.
int maxTranslationSize = 500000; // size of any one translation
CUtlBuffer transbuf( 1000, numTranslations * maxTranslationSize, CUtlBuffer::TEXT_BUFFER ); CUtlBuffer tempbuf( 1000, maxTranslationSize, CUtlBuffer::TEXT_BUFFER );
if ( g_useASMTranslations ) { // no extra tag needed for ARBvp, just use the !!ARBvp marker
tempbuf.EnsureCapacity( maxTranslationSize );
uint asmTransOptions = D3DToGL_OptionUseEnvParams | D3DToGL_OptionDoFixupZ | D3DToGL_OptionDoFixupY; // D3DToGL_OptionDoUserClipPlanes not being set for asm yet, it generates NV VP 2..
g_D3DToOpenGLTranslatorASM.TranslateShader( (uint32 *) pFunction, &tempbuf, &bVertexShader, asmTransOptions, -1, 0, pDebugLabel );
// grow to encompass...
transbuf.PutString ( (char*)tempbuf.Base() ); transbuf.PutString( "\n\n" ); // whitespace
}
if ( g_useGLSLTranslations ) { transbuf.PutString( "//GLSLvp\n" ); // this is required so GLM can crack the text apart
// note the GLSL translator wants its own buffer
tempbuf.EnsureCapacity( maxTranslationSize ); uint glslVertexShaderOptions = D3DToGL_OptionGLSL | D3DToGL_OptionUseEnvParams | D3DToGL_OptionDoFixupZ | D3DToGL_OptionDoFixupY;
if ( g_bUseControlFlow ) { glslVertexShaderOptions |= D3DToGL_OptionAllowStaticControlFlow; }
if ( m_ctx->Caps().m_hasNativeClipVertexMode ) { // note the matched trickery over in IDirect3DDevice9::FlushStates -
// if on a chipset that does no have native gl_ClipVertex support, then
// omit writes to gl_ClipVertex, and instead submit plane equations that have been altered,
// and clipping will take place in GL space using gl_Position instead of gl_ClipVertex.
// note that this is very much a hack to mate up with ATI R5xx hardware constraints, and with older
// drivers even for later ATI parts like r6xx/r7xx. And it doesn't work on NV parts, so you really
// do have to choose the right way to go.
glslVertexShaderOptions |= D3DToGL_OptionDoUserClipPlanes; } if (m_ctx->Caps().m_hasBindableUniforms) { glslVertexShaderOptions |= D3DToGL_OptionUseBindableUniforms; } g_D3DToOpenGLTranslatorGLSL.TranslateShader( (uint32 *) pFunction, &tempbuf, &bVertexShader, glslVertexShaderOptions, -1, nCentroidMask, pDebugLabel ); transbuf.PutString( (char*)tempbuf.Base() ); transbuf.PutString( "\n\n" ); // whitespace
} if ( !bVertexShader ) { // don't cross the streams
Assert(!"Can't accept pixel shader in CreateVertexShader"); result = D3DERR_INVALIDCALL; } else { IDirect3DVertexShader9 *newprog = new IDirect3DVertexShader9;
newprog->m_device = this; newprog->m_vtxProgram = m_ctx->NewProgram( kGLMVertexProgram, (char *)transbuf.Base() ) ;
// find the highwater mark..
char *highWaterPrefix = "//HIGHWATER-"; // try to arrange this so it can work with pure GLSL if needed
char *highWaterStr = strstr( (char *)transbuf.Base(), highWaterPrefix ); if (highWaterStr) { char *highWaterActualData = highWaterStr + strlen( highWaterPrefix ); int value = -1; sscanf( highWaterActualData, "%d", &value );
newprog->m_vtxHighWater = value; newprog->m_vtxProgram->m_descs[kGLMGLSL].m_highWater = value; } else { Assert(!"couldn't find highwater mark in vertex shader"); } // find the attrib map..
char *attribMapPrefix = "//ATTRIBMAP-"; // try to arrange this so it can work with pure GLSL if needed
char *attribMapStr = strstr( (char *)transbuf.Base(), attribMapPrefix ); if (attribMapStr) { char *attribMapActualData = attribMapStr + strlen( attribMapPrefix ); for( int i=0; i<16; i++) { int value = -1; char *dataItem = attribMapActualData + (i*3); sscanf( dataItem, "%02x", &value ); if (value >=0) { // make sure it's not a terminator
if (value == 0xBB) { Debugger(); } } else { // probably an 'xx'... check
if ( (dataItem[0] != 'x') || (dataItem[1] != 'x') ) { Debugger(); // bad news
} else { value = 0xBB; // not likely to see one of these... "fog with usage index 11"
} } newprog->m_vtxAttribMap[i] = value; } } else { Debugger(); // that's bad...
} *ppShader = newprog; result = S_OK; } }
return result; }
IDirect3DVertexShader9::~IDirect3DVertexShader9() { GLMPRINTF(( ">-A- ~IDirect3DVertexShader9" ));
if (m_device) { m_device->ReleasedVertexShader( this );
if (m_vtxProgram) { m_vtxProgram->m_ctx->DelProgram( m_vtxProgram ); m_vtxProgram = NULL; } m_device = NULL; } else { }
GLMPRINTF(( "<-A- ~IDirect3DVertexShader9" )); }
HRESULT IDirect3DDevice9::SetVertexShader(IDirect3DVertexShader9* pShader) { if (pShader) { m_ctx->SetDrawingProgram( kGLMVertexProgram, pShader->m_vtxProgram ); } else { m_ctx->SetDrawingProgram( kGLMVertexProgram, NULL ); } m_vertexShader = pShader;
return S_OK; }
HRESULT IDirect3DDevice9::SetVertexShaderConstantF(UINT StartRegister,CONST float* pConstantData,UINT Vector4fCount) // groups of 4 floats!
{ m_ctx->SetProgramParametersF( kGLMVertexProgram, StartRegister, (float *)pConstantData, Vector4fCount ); return S_OK; }
HRESULT IDirect3DDevice9::SetVertexShaderConstantB(UINT StartRegister,CONST BOOL* pConstantData,UINT BoolCount) // individual bool count!
{ m_ctx->SetProgramParametersB( kGLMVertexProgram, StartRegister, (int *)pConstantData, BoolCount ); return S_OK; }
HRESULT IDirect3DDevice9::SetVertexShaderConstantI(UINT StartRegister,CONST int* pConstantData,UINT Vector4iCount) // groups of 4 ints!
{ m_ctx->SetProgramParametersI( kGLMVertexProgram, StartRegister, (int *)pConstantData, Vector4iCount ); return S_OK; }
#pragma mark ----- Shader Pairs - (IDirect3DDevice9)
// callers need to ifdef POSIX this, because this method does not exist on real DX9
HRESULT IDirect3DDevice9::LinkShaderPair( IDirect3DVertexShader9* vs, IDirect3DPixelShader9* ps ) { // these are really GLSL "shaders" not "programs" but the old reference to "program" persists due to the assembler heritage
if (vs->m_vtxProgram && ps->m_pixProgram) { m_ctx->LinkShaderPair( vs->m_vtxProgram, ps->m_pixProgram ); } return S_OK; }
// callers need to ifdef POSIX this, because this method does not exist on real DX9
//
HRESULT IDirect3DDevice9::QueryShaderPair( int index, GLMShaderPairInfo *infoOut ) { // these are really GLSL "shaders" not "programs" ...
m_ctx->QueryShaderPair( index, infoOut ); return S_OK; }
#pragma mark ----- Vertex Buffers and Vertex Declarations - (IDirect3DDevice9)
HRESULT IDirect3DDevice9::CreateVertexDeclaration(CONST D3DVERTEXELEMENT9* pVertexElements,IDirect3DVertexDeclaration9** ppDecl) { *ppDecl = NULL; // the goal here is to arrive at something which lets us quickly generate GLMVertexSetups.
// the information we don't have, that must be inferred from the decls, is:
// -> how many unique streams (buffers) are used - pure curiosity
// -> what the stride and offset is for each decl. Size you can figure out on the spot, stride requires surveying all the components in each stream first.
// so init an array of per-stream offsets to 0.
// each one is a cursor that gets bumped by decls.
uint streamOffsets[ D3D_MAX_STREAMS ]; uint streamCount = 0; uint attribMap[16]; uint attribMapIndex = 0; memset( attribMap, 0xFF, sizeof( attribMap ) ); memset( streamOffsets, 0, sizeof( streamOffsets ) );
IDirect3DVertexDeclaration9 *decl9 = new IDirect3DVertexDeclaration9; decl9->m_elemCount = 0; for (const D3DVERTEXELEMENT9 *src = pVertexElements; (src->Stream != 0xFF); src++) { // element
D3DVERTEXELEMENT9_GL *elem = &decl9->m_elements[ decl9->m_elemCount++ ];
// copy the D3D decl wholesale.
elem->m_dxdecl = *src; // latch current offset in this stream.
elem->m_gldecl.m_offset = streamOffsets[ elem->m_dxdecl.Stream ]; // figure out size of this attr and move the cursor
// if cursor was on zero, bump the active stream count
if (!streamOffsets[ elem->m_dxdecl.Stream ]) streamCount++; int bytes = 0; switch( elem->m_dxdecl.Type ) { case D3DDECLTYPE_FLOAT1: elem->m_gldecl.m_datasize = 1; elem->m_gldecl.m_datatype = GL_FLOAT; elem->m_gldecl.m_normalized=0; bytes = 4; break; case D3DDECLTYPE_FLOAT2: elem->m_gldecl.m_datasize = 2; elem->m_gldecl.m_datatype = GL_FLOAT; elem->m_gldecl.m_normalized=0; bytes = 8; break;
//case D3DVSDT_FLOAT3:
case D3DDECLTYPE_FLOAT3: elem->m_gldecl.m_datasize = 3; elem->m_gldecl.m_datatype = GL_FLOAT; elem->m_gldecl.m_normalized=0; bytes = 12; break; //case D3DVSDT_FLOAT4:
case D3DDECLTYPE_FLOAT4: elem->m_gldecl.m_datasize = 4; elem->m_gldecl.m_datatype = GL_FLOAT; elem->m_gldecl.m_normalized=0; bytes = 16; break; // case D3DVSDT_UBYTE4:
case D3DDECLTYPE_D3DCOLOR: case D3DDECLTYPE_UBYTE4: // Force this path since we're on 10.6.2 and can't rely on EXT_vertex_array_bgra
if ( 1 ) { // pass 4 UB's but we know this is out of order compared to D3DCOLOR data
elem->m_gldecl.m_datasize = 4; elem->m_gldecl.m_datatype = GL_UNSIGNED_BYTE; } else { // pass a GL BGRA color courtesy of http://www.opengl.org/registry/specs/ARB/vertex_array_bgra.txt
elem->m_gldecl.m_datasize = GL_BGRA; elem->m_gldecl.m_datatype = GL_UNSIGNED_BYTE; }
elem->m_gldecl.m_normalized = (elem->m_dxdecl.Type == D3DDECLTYPE_D3DCOLOR); bytes = 4; break; case D3DDECLTYPE_SHORT2: // pass 2 US's but we know this is out of order compared to D3DCOLOR data
elem->m_gldecl.m_datasize = 2; elem->m_gldecl.m_datatype = GL_UNSIGNED_SHORT;
elem->m_gldecl.m_normalized = 0; bytes = 4; break; default: Debugger(); return D3DERR_INVALIDCALL; break;
/*
typedef enum _D3DDECLTYPE { D3DDECLTYPE_FLOAT1 = 0, // 1D float expanded to (value, 0., 0., 1.)
D3DDECLTYPE_FLOAT2 = 1, // 2D float expanded to (value, value, 0., 1.)
D3DDECLTYPE_FLOAT3 = 2, // 3D float expanded to (value, value, value, 1.)
D3DDECLTYPE_FLOAT4 = 3, // 4D float
D3DDECLTYPE_D3DCOLOR = 4, // 4D packed unsigned bytes mapped to 0. to 1. range
// Input is in D3DCOLOR format (ARGB) expanded to (R, G, B, A)
D3DDECLTYPE_UBYTE4 = 5, // 4D unsigned byte
D3DDECLTYPE_SHORT2 = 6, // 2D signed short expanded to (value, value, 0., 1.)
D3DDECLTYPE_SHORT4 = 7, // 4D signed short
// The following types are valid only with vertex shaders >= 2.0
D3DDECLTYPE_UBYTE4N = 8, // Each of 4 bytes is normalized by dividing to 255.0
D3DDECLTYPE_SHORT2N = 9, // 2D signed short normalized (v[0]/32767.0,v[1]/32767.0,0,1)
D3DDECLTYPE_SHORT4N = 10, // 4D signed short normalized (v[0]/32767.0,v[1]/32767.0,v[2]/32767.0,v[3]/32767.0)
D3DDECLTYPE_USHORT2N = 11, // 2D unsigned short normalized (v[0]/65535.0,v[1]/65535.0,0,1)
D3DDECLTYPE_USHORT4N = 12, // 4D unsigned short normalized (v[0]/65535.0,v[1]/65535.0,v[2]/65535.0,v[3]/65535.0)
D3DDECLTYPE_UDEC3 = 13, // 3D unsigned 10 10 10 format expanded to (value, value, value, 1)
D3DDECLTYPE_DEC3N = 14, // 3D signed 10 10 10 format normalized and expanded to (v[0]/511.0, v[1]/511.0, v[2]/511.0, 1)
D3DDECLTYPE_FLOAT16_2 = 15, // Two 16-bit floating point values, expanded to (value, value, 0, 1)
D3DDECLTYPE_FLOAT16_4 = 16, // Four 16-bit floating point values
D3DDECLTYPE_UNUSED = 17, // When the type field in a decl is unused.
} D3DDECLTYPE; */ } // write the offset and move the cursor
elem->m_gldecl.m_offset = streamOffsets[elem->m_dxdecl.Stream]; streamOffsets[ elem->m_dxdecl.Stream ] += bytes; // cannot write m_stride yet, so zero it
elem->m_gldecl.m_stride = 0; elem->m_gldecl.m_buffer = NULL; // must be filled in at draw time..
// elem count was already bumped.
// update attrib map
attribMap[ attribMapIndex++ ] = (elem->m_dxdecl.Usage << 4) | (elem->m_dxdecl.UsageIndex); } // the loop is done, we now know how many active streams there are, how many atribs are active in the declaration,
// and how big each one is in terms of stride.
// all that is left is to go back and write the strides - the stride comes from the stream offset cursors accumulated earlier.
for( int j=0; j< decl9->m_elemCount; j++) { D3DVERTEXELEMENT9_GL *elem = &decl9->m_elements[ j ]; elem->m_gldecl.m_stride = streamOffsets[ elem->m_dxdecl.Stream ]; } *ppDecl = decl9; return S_OK; }
IDirect3DVertexDeclaration9::~IDirect3DVertexDeclaration9() { GLMPRINTF(("-A- ~IDirect3DVertexDeclaration9 signpost")); }
HRESULT IDirect3DDevice9::SetVertexDeclaration(IDirect3DVertexDeclaration9* pDecl) { // we just latch it. At draw time we combine the current vertex decl with the current stream set and generate a vertex setup for GLM.
// GLM can see what the differences are and act accordingly to adjust vert attrib bindings.
m_vertDecl = pDecl; return S_OK; }
HRESULT IDirect3DDevice9::SetFVF(DWORD FVF) { Debugger(); }
HRESULT IDirect3DDevice9::GetFVF(DWORD* pFVF) { Debugger(); }
#pragma mark ----- Vertex Buffers and Streams - (IDirect3DDevice9)
#pragma mark ----- Create function moved to be adjacent to other buffer methods
HRESULT IDirect3DDevice9::SetStreamSource(UINT StreamNumber,IDirect3DVertexBuffer9* pStreamData,UINT OffsetInBytes,UINT Stride) { // perfectly legal to see a vertex buffer of NULL get passed in here.
// so we need an array to track these.
// OK, we are being given the stride, we don't need to calc it..
GLMPRINTF(("-X- IDirect3DDevice9::SetStreamSource setting stream #%d to D3D buf %p (GL name %d); offset %d, stride %d", StreamNumber, pStreamData, (pStreamData) ? pStreamData->m_vtxBuffer->m_name: -1, OffsetInBytes, Stride)); if (pStreamData) { m_streams[ StreamNumber ].m_vtxBuffer = pStreamData; m_streams[ StreamNumber ].m_offset = OffsetInBytes; m_streams[ StreamNumber ].m_stride = Stride; } else { m_streams[ StreamNumber ].m_vtxBuffer = NULL; m_streams[ StreamNumber ].m_offset = 0; m_streams[ StreamNumber ].m_stride = 0; } }
#pragma mark ----- Index Buffers - (IDirect3DDevice9)
#pragma mark ----- Creatue function relocated to be adjacent to the rest of the index buffer methods
HRESULT IDirect3DDevice9::SetIndices(IDirect3DIndexBuffer9* pIndexData) { // just latch it.
m_indices.m_idxBuffer = pIndexData; }
#pragma mark ----- Release Handlers - (IDirect3DDevice9)
void IDirect3DDevice9::ReleasedTexture( IDirect3DBaseTexture9 *baseTex ) { // see if this texture is referenced in any of the texture units and scrub it if so.
for( int i=0; i<16; i++) { if (m_textures[i] == baseTex) { m_textures[i] = NULL; m_ctx->SetSamplerTex( i, NULL ); // texture sets go straight through to GLM, no dirty bit
} } }
void IDirect3DDevice9::ReleasedSurface( IDirect3DSurface9 *surface ) { for( int i=0; i<16; i++) { if (m_rtSurfaces[i]==surface) { // this was a surprise release... scrub it
m_rtSurfaces[i] = NULL; GLMPRINTF(( "-A- Scrubbed surface %08x from m_rtSurfaces[%d]", surface, i )); } } if( m_dsSurface == surface ) { m_dsSurface = NULL; GLMPRINTF(( "-A- Scrubbed surface %08x from m_dsSurface", surface )); } if ( m_defaultColorSurface == surface ) { m_defaultColorSurface = NULL; GLMPRINTF(( "-A- Scrubbed surface %08x from m_defaultColorSurface", surface )); } if ( m_defaultDepthStencilSurface == surface ) { m_defaultDepthStencilSurface = NULL; GLMPRINTF(( "-A- Scrubbed surface %08x from m_defaultDepthStencilSurface", surface )); } }
void IDirect3DDevice9::ReleasedPixelShader( IDirect3DPixelShader9 *pixelShader ) { if ( m_pixelShader == pixelShader ) { m_pixelShader = NULL; GLMPRINTF(( "-A- Scrubbed pixel shader %08x from m_pixelShader", pixelShader )); } }
void IDirect3DDevice9::ReleasedVertexShader( IDirect3DVertexShader9 *vertexShader ) { if ( m_vertexShader == vertexShader ) { m_vertexShader = NULL; GLMPRINTF(( "-A- Scrubbed vertex shader %08x from m_vertexShader", vertexShader )); } }
void IDirect3DDevice9::ReleasedVertexBuffer( IDirect3DVertexBuffer9 *vertexBuffer ) { for (int i=0; i< D3D_MAX_STREAMS; i++) { if ( m_streams[i].m_vtxBuffer == vertexBuffer ) { m_streams[i].m_vtxBuffer = NULL; GLMPRINTF(( "-A- Scrubbed vertex buffer %08x from m_streams[%d]", vertexBuffer, i )); } } }
void IDirect3DDevice9::ReleasedIndexBuffer( IDirect3DIndexBuffer9 *indexBuffer ) { if ( m_indices.m_idxBuffer == indexBuffer ) { m_indices.m_idxBuffer = NULL; GLMPRINTF(( "-A- Scrubbed index buffer %08x from m_indices", indexBuffer )); } }
void IDirect3DDevice9::ReleasedQuery( IDirect3DQuery9 *query ) { // nothing to do yet..
}
#pragma mark ----- Queries - (IDirect3DDevice9)
// note that detection of whether queries are supported is done by trying to create one.
// so for GL, be observant here of whether we have that capability or not.
// pretty much have this everywhere but i950.
HRESULT IDirect3DDevice9::CreateQuery(D3DQUERYTYPE Type,IDirect3DQuery9** ppQuery) { if (m_ctx->Caps().m_hasOcclusionQuery) { IDirect3DQuery9 *newquery = new IDirect3DQuery9; newquery->m_device = this; newquery->m_type = Type; newquery->m_ctx = m_ctx;
GLMQueryParams params; memset( ¶ms, 0, sizeof(params) ); bool known = false; switch(newquery->m_type) { case D3DQUERYTYPE_OCCLUSION: /* D3DISSUE_BEGIN, D3DISSUE_END */ // create an occlusion query
params.m_type = EOcclusion; break; case D3DQUERYTYPE_EVENT: /* D3DISSUE_END */ params.m_type = EFence; break; case D3DQUERYTYPE_RESOURCEMANAGER: /* D3DISSUE_END */ case D3DQUERYTYPE_TIMESTAMP: /* D3DISSUE_END */ case D3DQUERYTYPE_TIMESTAMPFREQ: /* D3DISSUE_END */ case D3DQUERYTYPE_INTERFACETIMINGS: /* D3DISSUE_BEGIN, D3DISSUE_END */ case D3DQUERYTYPE_PIXELTIMINGS: /* D3DISSUE_BEGIN, D3DISSUE_END */ case D3DQUERYTYPE_CACHEUTILIZATION: /* D3DISSUE_BEGIN, D3DISSUE_END */ Assert( !"Un-implemented query type" ); break; default: Assert( !"Unknown query type" ); break; } newquery->m_query = m_ctx->NewQuery( ¶ms ); *ppQuery = newquery; return S_OK; } else { *ppQuery = NULL; return -1; // failed
}
}
IDirect3DQuery9::~IDirect3DQuery9() { GLMPRINTF((">-A- ~IDirect3DQuery9"));
if (m_device) { m_device->ReleasedQuery( this );
if (m_query) { GLMPRINTF((">-A- ~IDirect3DQuery9 freeing m_query")); m_query->m_ctx->DelQuery( m_query ); m_query = NULL;
GLMPRINTF(("<-A- ~IDirect3DQuery9 freeing m_query done")); } m_device = NULL; } GLMPRINTF(("<-A- ~IDirect3DQuery9")); }
#pragma mark ----- Render States - (IDirect3DDevice9)
struct D3D_RSINFO { int m_class; D3DRENDERSTATETYPE m_state; DWORD m_defval; // m_class runs 0-3.
// 3 = must implement - fully general - "obey"
// 2 = implement setup to the default value (it has a GL effect but does not change later) "obey once"
// 1 = "fake implement" setup to the default value no GL effect, debug break if anything but default value comes through - "ignore"
// 0 = game never ever sets this one, break if someone even tries. "complain"
};
#define D3DRS_VALUE_LIMIT 210
bool g_D3DRS_INFO_unpacked_ready = false; // set to true after unpack
D3D_RSINFO g_D3DRS_INFO_unpacked[ D3DRS_VALUE_LIMIT+1 ];
#ifdef D3D_RSI
#error macro collision... rename this
#else
#define D3D_RSI(nclass,nstate,ndefval) { nclass, nstate, ndefval }
#endif
// FP conversions to hex courtesy of http://babbage.cs.qc.cuny.edu/IEEE-754/Decimal.html
#define CONST_DZERO 0x00000000
#define CONST_DONE 0x3F800000
#define CONST_D64 0x42800000
#define DONT_KNOW_YET 0x31415926
// see http://www.toymaker.info/Games/html/render_states.html
D3D_RSINFO g_D3DRS_INFO_packed[] = { // these do not have to be in any particular order. they get unpacked into the empty array above for direct indexing.
D3D_RSI( 3, D3DRS_ZENABLE, DONT_KNOW_YET ), // enable Z test (or W buffering)
D3D_RSI( 3, D3DRS_ZWRITEENABLE, DONT_KNOW_YET ), // enable Z write
D3D_RSI( 3, D3DRS_ZFUNC, DONT_KNOW_YET ), // select Z func
D3D_RSI( 3, D3DRS_COLORWRITEENABLE, TRUE ), // see transitiontable.cpp "APPLY_RENDER_STATE_FUNC( D3DRS_COLORWRITEENABLE, ColorWriteEnable )"
D3D_RSI( 3, D3DRS_CULLMODE, D3DCULL_CCW ), // backface cull control
D3D_RSI( 3, D3DRS_ALPHABLENDENABLE, DONT_KNOW_YET ), // ->CTransitionTable::ApplySeparateAlphaBlend and ApplyAlphaBlend
D3D_RSI( 3, D3DRS_BLENDOP, D3DBLENDOP_ADD ), D3D_RSI( 3, D3DRS_SRCBLEND, DONT_KNOW_YET ), D3D_RSI( 3, D3DRS_DESTBLEND, DONT_KNOW_YET ),
D3D_RSI( 1, D3DRS_SEPARATEALPHABLENDENABLE, FALSE ), // hit in CTransitionTable::ApplySeparateAlphaBlend
D3D_RSI( 1, D3DRS_SRCBLENDALPHA, D3DBLEND_ONE ), // going to demote these to class 1 until I figure out if they are implementable
D3D_RSI( 1, D3DRS_DESTBLENDALPHA, D3DBLEND_ZERO ), D3D_RSI( 1, D3DRS_BLENDOPALPHA, D3DBLENDOP_ADD ),
// what is the deal with alpha test... looks like it is inited to off.
D3D_RSI( 3, D3DRS_ALPHATESTENABLE, 0 ), D3D_RSI( 3, D3DRS_ALPHAREF, 0 ), D3D_RSI( 3, D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL ),
D3D_RSI( 3, D3DRS_STENCILENABLE, FALSE ), D3D_RSI( 3, D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP ), D3D_RSI( 3, D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP ), D3D_RSI( 3, D3DRS_STENCILPASS, D3DSTENCILOP_KEEP ), D3D_RSI( 3, D3DRS_STENCILFUNC, D3DCMP_ALWAYS ), D3D_RSI( 3, D3DRS_STENCILREF, 0 ), D3D_RSI( 3, D3DRS_STENCILMASK, 0xFFFFFFFF ), D3D_RSI( 3, D3DRS_STENCILWRITEMASK, 0xFFFFFFFF ),
D3D_RSI( 3, D3DRS_TWOSIDEDSTENCILMODE, FALSE ), D3D_RSI( 3, D3DRS_CCW_STENCILFAIL, D3DSTENCILOP_KEEP ), D3D_RSI( 3, D3DRS_CCW_STENCILZFAIL, D3DSTENCILOP_KEEP ), D3D_RSI( 3, D3DRS_CCW_STENCILPASS, D3DSTENCILOP_KEEP ), D3D_RSI( 3, D3DRS_CCW_STENCILFUNC, D3DCMP_ALWAYS ),
D3D_RSI( 3, D3DRS_FOGENABLE, FALSE ), // see CShaderAPIDx8::FogMode and friends - be ready to do the ARB fog linear option madness
D3D_RSI( 3, D3DRS_FOGCOLOR, 0 ), D3D_RSI( 3, D3DRS_FOGTABLEMODE, D3DFOG_NONE ), D3D_RSI( 3, D3DRS_FOGSTART, CONST_DZERO ), D3D_RSI( 3, D3DRS_FOGEND, CONST_DONE ), D3D_RSI( 3, D3DRS_FOGDENSITY, CONST_DZERO ), D3D_RSI( 3, D3DRS_RANGEFOGENABLE, FALSE ), D3D_RSI( 3, D3DRS_FOGVERTEXMODE, D3DFOG_NONE ), // watch out for CShaderAPIDx8::CommitPerPassFogMode....
D3D_RSI( 3, D3DRS_MULTISAMPLEANTIALIAS, TRUE ), D3D_RSI( 3, D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF ),
D3D_RSI( 3, D3DRS_SCISSORTESTENABLE, FALSE ), // heed IDirect3DDevice9::SetScissorRect
D3D_RSI( 3, D3DRS_DEPTHBIAS, CONST_DZERO ), D3D_RSI( 3, D3DRS_SLOPESCALEDEPTHBIAS, CONST_DZERO ),
D3D_RSI( 3, D3DRS_COLORWRITEENABLE1, 0x0000000f ), D3D_RSI( 3, D3DRS_COLORWRITEENABLE2, 0x0000000f ), D3D_RSI( 3, D3DRS_COLORWRITEENABLE3, 0x0000000f ),
D3D_RSI( 3, D3DRS_SRGBWRITEENABLE, 0 ), // heeded but ignored..
D3D_RSI( 2, D3DRS_CLIPPING, TRUE ), // um, yeah, clipping is enabled (?)
D3D_RSI( 3, D3DRS_CLIPPLANEENABLE, 0 ), // mask 1<<n of active user clip planes.
D3D_RSI( 0, D3DRS_LIGHTING, 0 ), // strange, someone turns it on then off again. move to class 0 and just ignore it (lie)?
D3D_RSI( 3, D3DRS_FILLMODE, D3DFILL_SOLID ),
D3D_RSI( 1, D3DRS_SHADEMODE, D3DSHADE_GOURAUD ), D3D_RSI( 1, D3DRS_LASTPIXEL, TRUE ), D3D_RSI( 1, D3DRS_DITHERENABLE, 0 ), //set to false by game, no one sets it to true
D3D_RSI( 1, D3DRS_SPECULARENABLE, FALSE ), D3D_RSI( 1, D3DRS_TEXTUREFACTOR, 0xFFFFFFFF ), // watch out for CShaderAPIDx8::Color3f et al.
D3D_RSI( 1, D3DRS_WRAP0, 0 ), D3D_RSI( 1, D3DRS_WRAP1, 0 ), D3D_RSI( 1, D3DRS_WRAP2, 0 ), D3D_RSI( 1, D3DRS_WRAP3, 0 ), D3D_RSI( 1, D3DRS_WRAP4, 0 ), D3D_RSI( 1, D3DRS_WRAP5, 0 ), D3D_RSI( 1, D3DRS_WRAP6, 0 ), D3D_RSI( 1, D3DRS_WRAP7, 0 ), D3D_RSI( 1, D3DRS_AMBIENT, 0 ), // FF lighting, no
D3D_RSI( 1, D3DRS_COLORVERTEX, TRUE ), // FF lighing again
D3D_RSI( 1, D3DRS_LOCALVIEWER, TRUE ), // FF lighting
D3D_RSI( 1, D3DRS_NORMALIZENORMALS, FALSE ), // FF mode I think. CShaderAPIDx8::SetVertexBlendState says it might switch this on when skinning is in play
D3D_RSI( 1, D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL ), // hit only in CShaderAPIDx8::ResetRenderState
D3D_RSI( 1, D3DRS_SPECULARMATERIALSOURCE, D3DMCS_COLOR2 ), D3D_RSI( 1, D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL ), D3D_RSI( 1, D3DRS_EMISSIVEMATERIALSOURCE, D3DMCS_MATERIAL ), D3D_RSI( 1, D3DRS_VERTEXBLEND, D3DVBF_DISABLE ), // also being set by CShaderAPIDx8::SetVertexBlendState, so might be FF
D3D_RSI( 1, D3DRS_POINTSIZE, CONST_DONE ), D3D_RSI( 1, D3DRS_POINTSIZE_MIN, CONST_DONE ), D3D_RSI( 1, D3DRS_POINTSPRITEENABLE, FALSE ), D3D_RSI( 1, D3DRS_POINTSCALEENABLE, FALSE ), D3D_RSI( 1, D3DRS_POINTSCALE_A, CONST_DONE ), D3D_RSI( 1, D3DRS_POINTSCALE_B, CONST_DZERO ), D3D_RSI( 1, D3DRS_POINTSCALE_C, CONST_DZERO ), D3D_RSI( 1, D3DRS_PATCHEDGESTYLE, D3DPATCHEDGE_DISCRETE ), D3D_RSI( 1, D3DRS_DEBUGMONITORTOKEN, D3DDMT_ENABLE ), D3D_RSI( 1, D3DRS_POINTSIZE_MAX, CONST_D64 ), D3D_RSI( 1, D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE ), D3D_RSI( 1, D3DRS_TWEENFACTOR, CONST_DZERO ), D3D_RSI( 1, D3DRS_POSITIONDEGREE, D3DDEGREE_CUBIC ), D3D_RSI( 1, D3DRS_NORMALDEGREE, D3DDEGREE_LINEAR ), D3D_RSI( 1, D3DRS_ANTIALIASEDLINEENABLE, FALSE ), // just ignore it
D3D_RSI( 1, D3DRS_MINTESSELLATIONLEVEL, CONST_DONE ), D3D_RSI( 1, D3DRS_MAXTESSELLATIONLEVEL, CONST_DONE ), D3D_RSI( 1, D3DRS_ADAPTIVETESS_X, CONST_DZERO ), D3D_RSI( 1, D3DRS_ADAPTIVETESS_Y, CONST_DZERO ), // Overridden as Alpha-to-coverage contrl
D3D_RSI( 1, D3DRS_ADAPTIVETESS_Z, CONST_DONE ), D3D_RSI( 1, D3DRS_ADAPTIVETESS_W, CONST_DZERO ), D3D_RSI( 1, D3DRS_ENABLEADAPTIVETESSELLATION, FALSE ), D3D_RSI( 1, D3DRS_BLENDFACTOR, 0xffffffff ), D3D_RSI( 1, D3DRS_WRAP8, 0 ), D3D_RSI( 1, D3DRS_WRAP9, 0 ), D3D_RSI( 1, D3DRS_WRAP10, 0 ), D3D_RSI( 1, D3DRS_WRAP11, 0 ), D3D_RSI( 1, D3DRS_WRAP12, 0 ), D3D_RSI( 1, D3DRS_WRAP13, 0 ), D3D_RSI( 1, D3DRS_WRAP14, 0 ), D3D_RSI( 1, D3DRS_WRAP15, 0 ), D3D_RSI( -1, (D3DRENDERSTATETYPE)0, 0 ) // terminator
};
void UnpackD3DRSITable( void ) { memset (g_D3DRS_INFO_unpacked, 0, sizeof(g_D3DRS_INFO_unpacked) ); for( D3D_RSINFO *packed = g_D3DRS_INFO_packed; packed->m_class >= 0; packed++ ) { if ( (packed->m_state <0) || (packed->m_state >= D3DRS_VALUE_LIMIT) ) { // bad
Debugger(); } else { // dispatch it to the unpacked array
g_D3DRS_INFO_unpacked[ packed->m_state ] = *packed; } } }
// convenience functions
GLenum D3DCompareFuncToGL( DWORD function ) { switch ( function ) { case D3DCMP_NEVER : return GL_NEVER; // Always fail the test.
case D3DCMP_LESS : return GL_LESS; // Accept the new pixel if its value is less than the value of the current pixel.
case D3DCMP_EQUAL : return GL_EQUAL; // Accept the new pixel if its value equals the value of the current pixel.
case D3DCMP_LESSEQUAL : return GL_LEQUAL; // Accept the new pixel if its value is less than or equal to the value of the current pixel. **
case D3DCMP_GREATER : return GL_GREATER; // Accept the new pixel if its value is greater than the value of the current pixel.
case D3DCMP_NOTEQUAL : return GL_NOTEQUAL; // Accept the new pixel if its value does not equal the value of the current pixel.
case D3DCMP_GREATEREQUAL: return GL_GEQUAL; // Accept the new pixel if its value is greater than or equal to the value of the current pixel.
case D3DCMP_ALWAYS : return GL_ALWAYS; // Always pass the test.
default : Debugger(); return 0xFFFFFFFF; } }
static GLenum D3DStencilOpToGL( DWORD operation ) { switch( operation ) { case D3DSTENCILOP_KEEP : return GL_KEEP; case D3DSTENCILOP_ZERO : return GL_ZERO; case D3DSTENCILOP_REPLACE : return GL_REPLACE; case D3DSTENCILOP_INCRSAT : return GL_INCR; case D3DSTENCILOP_DECRSAT : return GL_DECR; case D3DSTENCILOP_INVERT : return GL_INVERT; case D3DSTENCILOP_INCR : return GL_INCR_WRAP_EXT; case D3DSTENCILOP_DECR : return GL_DECR_WRAP_EXT; default : Debugger(); return 0xFFFFFFFF; } }
static GLenum D3DBlendFactorToGL( DWORD equation ) { switch (equation) { case D3DBLEND_ZERO : return GL_ZERO; // Blend factor is (0, 0, 0, 0).
case D3DBLEND_ONE : return GL_ONE; // Blend factor is (1, 1, 1, 1).
case D3DBLEND_SRCCOLOR : return GL_SRC_COLOR; // Blend factor is (Rs, Gs, Bs, As).
case D3DBLEND_INVSRCCOLOR : return GL_ONE_MINUS_SRC_COLOR; // Blend factor is (1 - Rs, 1 - Gs, 1 - Bs, 1 - As).
case D3DBLEND_SRCALPHA : return GL_SRC_ALPHA; // Blend factor is (As, As, As, As).
case D3DBLEND_INVSRCALPHA : return GL_ONE_MINUS_SRC_ALPHA; // Blend factor is ( 1 - As, 1 - As, 1 - As, 1 - As).
case D3DBLEND_DESTALPHA : return GL_DST_ALPHA; // Blend factor is (Ad Ad Ad Ad).
case D3DBLEND_INVDESTALPHA : return GL_ONE_MINUS_DST_ALPHA; // Blend factor is (1 - Ad 1 - Ad 1 - Ad 1 - Ad).
case D3DBLEND_DESTCOLOR : return GL_DST_COLOR; // Blend factor is (Rd, Gd, Bd, Ad).
case D3DBLEND_INVDESTCOLOR : return GL_ONE_MINUS_DST_COLOR; // Blend factor is (1 - Rd, 1 - Gd, 1 - Bd, 1 - Ad).
case D3DBLEND_SRCALPHASAT : return GL_SRC_ALPHA_SATURATE; // Blend factor is (f, f, f, 1); where f = min(As, 1 - Ad).
/*
// these are weird.... break if we hit them
case D3DBLEND_BOTHSRCALPHA : Assert(0); return GL_ZERO; // Obsolete. Starting with DirectX 6, you can achieve the same effect by setting the source and destination blend factors to D3DBLEND_SRCALPHA and D3DBLEND_INVSRCALPHA in separate calls.
case D3DBLEND_BOTHINVSRCALPHA: Assert(0); return GL_ZERO; // Source blend factor is (1 - As, 1 - As, 1 - As, 1 - As), and destination blend factor is (As, As, As, As); the destination blend selection is overridden. This blend mode is supported only for the D3DRS_SRCBLEND render state.
case D3DBLEND_BLENDFACTOR : Assert(0); return GL_ZERO; // Constant color blending factor used by the frame-buffer blender. This blend mode is supported only if D3DPBLENDCAPS_BLENDFACTOR is set in the SrcBlendCaps or DestBlendCaps members of D3DCAPS9.
dxabstract.h has not heard of these, so let them hit the debugger if they come through case D3DBLEND_INVBLENDFACTOR: //Inverted constant color-blending factor used by the frame-buffer blender. This blend mode is supported only if the D3DPBLENDCAPS_BLENDFACTOR bit is set in the SrcBlendCaps or DestBlendCaps members of D3DCAPS9.
case D3DBLEND_SRCCOLOR2: // Blend factor is (PSOutColor[1]r, PSOutColor[1]g, PSOutColor[1]b, not used). This flag is available in Direct3D 9Ex only.
case D3DBLEND_INVSRCCOLOR2: // Blend factor is (1 - PSOutColor[1]r, 1 - PSOutColor[1]g, 1 - PSOutColor[1]b, not used)). This flag is available in Direct3D 9Ex only.
*/ default: Debugger(); return 0xFFFFFFFF; break; } }
static GLenum D3DBlendOperationToGL( DWORD operation ) { switch (operation) { case D3DBLENDOP_ADD : return GL_FUNC_ADD; // The result is the destination added to the source. Result = Source + Destination
/* not covered by dxabstract.h..
case D3DBLENDOP_SUBTRACT : return GL_FUNC_SUBTRACT; // The result is the destination subtracted from to the source. Result = Source - Destination
case D3DBLENDOP_REVSUBTRACT : return GL_FUNC_REVERSE_SUBTRACT; // The result is the source subtracted from the destination. Result = Destination - Source
case D3DBLENDOP_MIN : return GL_MIN; // The result is the minimum of the source and destination. Result = MIN(Source, Destination)
case D3DBLENDOP_MAX : return GL_MAX; // The result is the maximum of the source and destination. Result = MAX(Source, Destination)
*/ default: Debugger(); return 0xFFFFFFFF; break; } }
HRESULT IDirect3DDevice9::SetRenderState( D3DRENDERSTATETYPE State, DWORD Value ) { char rsSpew = 1; char ignored = 0; if (!g_D3DRS_INFO_unpacked_ready) { UnpackD3DRSITable(); g_D3DRS_INFO_unpacked_ready = true; } if (State >= D3DRS_VALUE_LIMIT) { Debugger(); // bad
} else { D3D_RSINFO *info = &g_D3DRS_INFO_unpacked[ State ]; if (info->m_state != State) { Debugger(); // bad - we never set up that state in our list
}
if (rsSpew) { GLMPRINTF(("-X- IDirect3DDevice9::SetRenderState: set %s(%d) to %d(0x%08x) ( class %d, defval is %d(0x%08x) )", GLMDecode( eD3D_RSTATE,State),State, Value,Value, info->m_class, info->m_defval,info->m_defval )); } switch( info->m_class ) { case 0: // just ignore quietly. example: D3DRS_LIGHTING
ignored = 1; break; case 1: { // no GL response - and no error as long as the write value matches the default
if (Value != info->m_defval) { static char stop_here_1 = 0; if (stop_here_1) Debugger(); } } break; case 2:
// provide GL response, but only support known default value
if (Value != info->m_defval) { static char stop_here_2 = 0; if (stop_here_2) Debugger(); } // fall through to mode 3
case 3:
// full GL response, support any legal value
// note we're handling the class-2's as well.
switch(State) { case D3DRS_ZENABLE: // kGLDepthTestEnable
gl.m_DepthTestEnable.enable = Value; gl.m_stateDirtyMask |= (1<<kGLDepthTestEnable); break; case D3DRS_ZWRITEENABLE: // kGLDepthMask
gl.m_DepthMask.mask = Value; gl.m_stateDirtyMask |= (1<<kGLDepthMask); break; case D3DRS_ZFUNC: { // kGLDepthFunc
GLenum func = D3DCompareFuncToGL( Value ); gl.m_DepthFunc.func = func; gl.m_stateDirtyMask |= (1<<kGLDepthFunc); } break;
case D3DRS_COLORWRITEENABLE: // kGLColorMaskSingle
{ gl.m_ColorMaskSingle.r = ((Value & D3DCOLORWRITEENABLE_RED) != 0) ? 0xFF : 0x00; gl.m_ColorMaskSingle.g = ((Value & D3DCOLORWRITEENABLE_GREEN)!= 0) ? 0xFF : 0x00; gl.m_ColorMaskSingle.b = ((Value & D3DCOLORWRITEENABLE_BLUE) != 0) ? 0xFF : 0x00; gl.m_ColorMaskSingle.a = ((Value & D3DCOLORWRITEENABLE_ALPHA)!= 0) ? 0xFF : 0x00;
gl.m_stateDirtyMask |= (1<<kGLColorMaskSingle); } break; case D3DRS_COLORWRITEENABLE1: // kGLColorMaskMultiple
case D3DRS_COLORWRITEENABLE2: // kGLColorMaskMultiple
case D3DRS_COLORWRITEENABLE3: // kGLColorMaskMultiple
ignored = 1; break;
case D3DRS_CULLMODE: // kGLCullFaceEnable / kGLCullFrontFace
{ switch(Value) { case D3DCULL_NONE: gl.m_CullFaceEnable.enable = false; gl.m_CullFrontFace.value = GL_CCW; //doesn't matter
gl.m_stateDirtyMask |= (1<<kGLCullFaceEnable) | (1<<kGLCullFrontFace); break; case D3DCULL_CW: gl.m_CullFaceEnable.enable = true; gl.m_CullFrontFace.value = GL_CW; //origGL_CCW;
gl.m_stateDirtyMask |= (1<<kGLCullFaceEnable) | (1<<kGLCullFrontFace); break; case D3DCULL_CCW: gl.m_CullFaceEnable.enable = true; gl.m_CullFrontFace.value = GL_CCW; //origGL_CW;
gl.m_stateDirtyMask |= (1<<kGLCullFaceEnable) | (1<<kGLCullFrontFace); break;
default: Debugger(); break; } } break;
//-------------------------------------------------------------------------------------------- alphablend stuff
case D3DRS_ALPHABLENDENABLE: // kGLBlendEnable
gl.m_BlendEnable.enable = Value; gl.m_stateDirtyMask |= (1<<kGLBlendEnable); break; case D3DRS_BLENDOP: // kGLBlendEquation // D3D blend-op ==> GL blend equation
{ GLenum equation = D3DBlendOperationToGL( Value ); gl.m_BlendEquation.equation = equation; gl.m_stateDirtyMask |= (1<<kGLBlendEquation); } break; case D3DRS_SRCBLEND: // kGLBlendFactor // D3D blend-factor ==> GL blend factor
case D3DRS_DESTBLEND: // kGLBlendFactor
{ GLenum factor = D3DBlendFactorToGL( Value ); if (State==D3DRS_SRCBLEND) { gl.m_BlendFactor.srcfactor = factor; } else { gl.m_BlendFactor.dstfactor = factor; } gl.m_stateDirtyMask |= (1<<kGLBlendFactor); } break;
case D3DRS_SEPARATEALPHABLENDENABLE: case D3DRS_BLENDOPALPHA: case D3DRS_SRCBLENDALPHA: case D3DRS_DESTBLENDALPHA: ignored = 1; break;
case D3DRS_SRGBWRITEENABLE: // kGLBlendEnableSRGB
gl.m_BlendEnableSRGB.enable = Value; gl.m_stateDirtyMask |= (1<<kGLBlendEnableSRGB); break;
//-------------------------------------------------------------------------------------------- alphatest stuff
case D3DRS_ALPHATESTENABLE: gl.m_AlphaTestEnable.enable = Value; gl.m_stateDirtyMask |= (1<<kGLAlphaTestEnable); break; case D3DRS_ALPHAREF: gl.m_AlphaTestFunc.ref = Value / 255.0f; gl.m_stateDirtyMask |= (1<<kGLAlphaTestFunc); break; case D3DRS_ALPHAFUNC: { GLenum func = D3DCompareFuncToGL( Value );; gl.m_AlphaTestFunc.func = func; gl.m_stateDirtyMask |= (1<<kGLAlphaTestFunc); } break;
//-------------------------------------------------------------------------------------------- stencil stuff
case D3DRS_STENCILENABLE: // GLStencilTestEnable_t
{ gl.m_StencilTestEnable.enable = Value;
gl.m_stateDirtyMask |= (1<<kGLStencilTestEnable); } break;
case D3DRS_STENCILFAIL: // GLStencilOp_t "what do you do if stencil test fails"
{ GLenum stencilop = D3DStencilOpToGL( Value ); gl.m_StencilOp.sfail = stencilop;
gl.m_stateDirtyMask |= (1<<kGLStencilOp); } break; case D3DRS_STENCILZFAIL: // GLStencilOp_t "what do you do if stencil test passes *but* depth test fails, if depth test happened"
{ GLenum stencilop = D3DStencilOpToGL( Value ); gl.m_StencilOp.dpfail = stencilop;
gl.m_stateDirtyMask |= (1<<kGLStencilOp); } break; case D3DRS_STENCILPASS: // GLStencilOp_t "what do you do if stencil test and depth test both pass"
{ GLenum stencilop = D3DStencilOpToGL( Value ); gl.m_StencilOp.dppass = stencilop;
gl.m_stateDirtyMask |= (1<<kGLStencilOp); } break; case D3DRS_STENCILFUNC: // GLStencilFunc_t
{ GLenum stencilfunc = D3DCompareFuncToGL( Value ); gl.m_StencilFunc.frontfunc = gl.m_StencilFunc.backfunc = stencilfunc;
gl.m_stateDirtyMask |= (1<<kGLStencilFunc); } break;
case D3DRS_STENCILREF: // GLStencilFunc_t
{ gl.m_StencilFunc.ref = Value; gl.m_stateDirtyMask |= (1<<kGLStencilFunc); } break; case D3DRS_STENCILMASK: // GLStencilFunc_t
{ //if (Value==255)
//{
// Value = 0xFFFFFFFF; // mask blast
//}
gl.m_StencilFunc.mask = Value; gl.m_stateDirtyMask |= (1<<kGLStencilFunc); } break;
case D3DRS_STENCILWRITEMASK: // GLStencilWriteMask_t
{ //if (Value==255)
//{
// Value = 0xFFFFFFFF; // mask blast
//}
gl.m_StencilWriteMask.mask = Value; gl.m_stateDirtyMask |= (1<<kGLStencilWriteMask); } break;
//-------------------------------------------------------------------------------------------- two-sided stencil stuff
case D3DRS_TWOSIDEDSTENCILMODE: // -> GL_STENCIL_TEST_TWO_SIDE_EXT... not yet implemented ?
case D3DRS_CCW_STENCILFAIL: // GLStencilOp_t
case D3DRS_CCW_STENCILZFAIL: // GLStencilOp_t
case D3DRS_CCW_STENCILPASS: // GLStencilOp_t
case D3DRS_CCW_STENCILFUNC: // GLStencilFunc_t
ignored = 1; break;
case D3DRS_FOGENABLE: // none of these are implemented yet... erk
gl.m_FogEnable = (Value != 0); GLMPRINTF(("-D- fogenable = %d",Value )); //ignored = 1;
break;
case D3DRS_FOGCOLOR: case D3DRS_FOGTABLEMODE: case D3DRS_FOGSTART: case D3DRS_FOGEND: case D3DRS_FOGDENSITY: case D3DRS_RANGEFOGENABLE: case D3DRS_FOGVERTEXMODE: ignored = 1; break;
case D3DRS_MULTISAMPLEANTIALIAS: case D3DRS_MULTISAMPLEMASK: ignored = 1; break;
case D3DRS_SCISSORTESTENABLE: // kGLScissorEnable
{ gl.m_ScissorEnable.enable = Value; gl.m_stateDirtyMask |= (1<<kGLScissorEnable); } break;
case D3DRS_DEPTHBIAS: // kGLDepthBias
{ // the value in the dword is actually a float
float fvalue = *(float*)&Value; gl.m_DepthBias.units = fvalue;
gl.m_stateDirtyMask |= (1<<kGLDepthBias); } break; // good ref on these: http://aras-p.info/blog/2008/06/12/depth-bias-and-the-power-of-deceiving-yourself/
case D3DRS_SLOPESCALEDEPTHBIAS: { // the value in the dword is actually a float
float fvalue = *(float*)&Value; gl.m_DepthBias.factor = fvalue;
gl.m_stateDirtyMask |= (1<<kGLDepthBias); } break;
// Alpha to coverage
case D3DRS_CLIPPING: // ???? is clipping ever turned off ??
ignored = 1; break; case D3DRS_CLIPPLANEENABLE: // kGLClipPlaneEnable
// d3d packs all the enables into one word.
// we break that out so we don't do N glEnable calls to sync -
// GLM is tracking one unique enable per plane.
for( int i=0; i<kGLMUserClipPlanes; i++) { gl.m_ClipPlaneEnable[i].enable = (Value & (1<<i)) != 0; } gl.m_stateDirtyMask |= (1<<kGLClipPlaneEnable); break;
//-------------------------------------------------------------------------------------------- polygon/fill mode
case D3DRS_FILLMODE: GLuint mode = 0; switch(Value) { case D3DFILL_POINT: mode = GL_POINT; break; case D3DFILL_WIREFRAME: mode = GL_LINE; break; case D3DFILL_SOLID: mode = GL_FILL; break; default: Assert(!"unknown fill mode"); } gl.m_PolygonMode.values[0] = gl.m_PolygonMode.values[1] = mode; gl.m_stateDirtyMask |= (1<<kGLPolygonMode); break; } break; } }
if (rsSpew && ignored) { GLMPRINTF(("-X- (ignored)")); } //Debugger();
return S_OK; }
#pragma mark ----- Sampler States - (IDirect3DDevice9)
HRESULT IDirect3DDevice9::SetSamplerState( DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value ) { Assert(Sampler<16); // the D3D-to-GL translation has been moved to FlushSamplers since we want to do it at draw time
// so this call just stuffs values in slots.
D3DSamplerDesc *samp = &m_samplers[ Sampler ]; switch( Type ) { // addressing modes can be
// D3DTADDRESS_WRAP Tile the texture at every integer junction.
// D3DTADDRESS_MIRROR Similar to D3DTADDRESS_WRAP, except that the texture is flipped at every integer junction.
// D3DTADDRESS_CLAMP Texture coordinates outside the range [0.0, 1.0] are set to the texture color at 0.0 or 1.0, respectively.
// D3DTADDRESS_BORDER Texture coordinates outside the range [0.0, 1.0] are set to the border color.
// D3DTADDRESS_MIRRORONCE Similar to D3DTADDRESS_MIRROR and D3DTADDRESS_CLAMP.
// Takes the absolute value of the texture coordinate (thus, mirroring around 0),
// and then clamps to the maximum value. The most common usage is for volume textures,
// where support for the full D3DTADDRESS_MIRRORONCE texture-addressing mode is not
// necessary, but the data is symmetric around the one axis.
case D3DSAMP_ADDRESSU: case D3DSAMP_ADDRESSV: case D3DSAMP_ADDRESSW: samp->m_addressModes[ Type - (int)D3DSAMP_ADDRESSU ] = (D3DTEXTUREADDRESS)Value; break; case D3DSAMP_BORDERCOLOR: samp->m_borderColor = Value; break; case D3DSAMP_MAGFILTER: samp->m_magFilter = (D3DTEXTUREFILTERTYPE)Value; break; case D3DSAMP_MINFILTER: samp->m_minFilter = (D3DTEXTUREFILTERTYPE)Value; break; case D3DSAMP_MIPFILTER: samp->m_mipFilter = (D3DTEXTUREFILTERTYPE)Value; break; case D3DSAMP_MIPMAPLODBIAS: samp->m_mipmapBias = Value; break; // float in sheep's clothing - check this one out
case D3DSAMP_MAXMIPLEVEL: samp->m_maxMipLevel = Value; break; case D3DSAMP_MAXANISOTROPY: samp->m_maxAniso = Value; break; case D3DSAMP_SRGBTEXTURE: samp->m_srgb = Value; break; case D3DSAMP_SHADOWFILTER: samp->m_shadowFilter = Value; break; default: Assert(!"Unknown sampler parameter"); break;
} gl.m_samplerDirtyMask |= (1<<Sampler); // at draw time, push the dirty samplers down to GLM
return S_OK; }
HRESULT IDirect3DDevice9::FlushStates( uint mask ) { uint stateHitMask = gl.m_stateDirtyMask & mask;
// note that we will turn off all the bits that are set in the hit mask, once the work is done
// so no need to individually clear.
if ( stateHitMask & (1<<kGLAlphaTestEnable) ) m_ctx->WriteAlphaTestEnable( &gl.m_AlphaTestEnable );
if ( stateHitMask & (1<<kGLAlphaTestFunc) ) m_ctx->WriteAlphaTestFunc( &gl.m_AlphaTestFunc );
if ( stateHitMask & (1<<kGLCullFaceEnable) ) m_ctx->WriteCullFaceEnable( &gl.m_CullFaceEnable );
if ( stateHitMask & (1<<kGLCullFrontFace) ) m_ctx->WriteCullFrontFace( &gl.m_CullFrontFace );
if ( stateHitMask & (1<<kGLPolygonMode) ) m_ctx->WritePolygonMode( &gl.m_PolygonMode );
if ( stateHitMask & (1<<kGLDepthBias) ) m_ctx->WriteDepthBias( &gl.m_DepthBias );
if ( stateHitMask & (1<<kGLScissorEnable) ) m_ctx->WriteScissorEnable( &gl.m_ScissorEnable );
if ( stateHitMask & (1<<kGLScissorBox) ) m_ctx->WriteScissorBox( &gl.m_ScissorBox );
if ( stateHitMask & (1<<kGLViewportBox) ) m_ctx->WriteViewportBox( &gl.m_ViewportBox );
if ( stateHitMask & (1<<kGLViewportDepthRange) ) m_ctx->WriteViewportDepthRange( &gl.m_ViewportDepthRange );
if ( stateHitMask & (1<<kGLClipPlaneEnable) ) { for( int x=0; x<kGLMUserClipPlanes; x++) { m_ctx->WriteClipPlaneEnable( &gl.m_ClipPlaneEnable[x], x ); } }
if ( stateHitMask & (1<<kGLClipPlaneEquation) ) { for( int x=0; x<kGLMUserClipPlanes; x++) { GLClipPlaneEquation_t temp1; // Antonio's way
GLClipPlaneEquation_t temp2; // our way
// if we don't have native clip vertex support. then munge the plane coeffs
// this should engage on ALL ATI PARTS < 10.6.4
// and should continue to engage on R5xx forever.
if ( !m_ctx->Caps().m_hasNativeClipVertexMode ) { // hacked coeffs = { src->x, -src->y, 0.5f * src->z, src->w + (0.5f * src->z) };
// Antonio's trick - so we can use gl_Position as the clippee, not gl_ClipVertex.
GLClipPlaneEquation_t *equ = &gl.m_ClipPlaneEquation[x];
///////////////// temp1
temp1.x = equ->x; temp1.y = equ->y * -1.0; temp1.z = equ->z * 0.5; temp1.w = equ->w + (equ->z * 0.5);
//////////////// temp2
VMatrix mat1( 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 2, -1, 0, 0, 0, 1 ); //mat1 = mat1.Transpose();
VMatrix mat2; bool success = mat1.InverseGeneral( mat2 ); if (success) { VMatrix mat3; mat3 = mat2.Transpose();
VPlane origPlane( Vector( equ->x, equ->y, equ->z ), equ->w ); VPlane newPlane; newPlane = mat3 * origPlane /* * mat3 */; VPlane finalPlane = newPlane; temp2.x = newPlane.m_Normal.x; temp2.y = newPlane.m_Normal.y; temp2.z = newPlane.m_Normal.z; temp2.w = newPlane.m_Dist; } else { temp2.x = 0; temp2.y = 0; temp2.z = 0; temp2.w = 0; } } else { temp1 = temp2 = gl.m_ClipPlaneEquation[x]; }
if (1) //GLMKnob("caps-key",NULL)==0.0)
{ m_ctx->WriteClipPlaneEquation( &temp1, x ); // no caps lock = Antonio or classic
/*
if (x<1) { GLMPRINTF(( " plane %d √vers1[ %5.2f %5.2f %5.2f %5.2f ] vers2[ %5.2f %5.2f %5.2f %5.2f ]", x, temp1.x,temp1.y,temp1.z,temp1.w, temp2.x,temp2.y,temp2.z,temp2.w )); } */ } else { m_ctx->WriteClipPlaneEquation( &temp2, x ); // caps = our way or classic
/*
if (x<1) { GLMPRINTF(( " plane %d vers1[ %5.2f %5.2f %5.2f %5.2f ] √vers2[ %5.2f %5.2f %5.2f %5.2f ]", x, temp1.x,temp1.y,temp1.z,temp1.w, temp2.x,temp2.y,temp2.z,temp2.w )); } */ } } }
if ( stateHitMask & (1<<kGLColorMaskSingle) ) m_ctx->WriteColorMaskSingle( &gl.m_ColorMaskSingle );
// if ( stateHitMask & (1<<kGLColorMaskMultiple) )
// m_ctx->WriteColorMaskMultiple( &gl.m_ColorMaskMultiple ); // ???????????? hmmmmmmmm
if ( stateHitMask & (1<<kGLBlendEnable) ) m_ctx->WriteBlendEnable( &gl.m_BlendEnable );
if ( stateHitMask & (1<<kGLBlendFactor) ) m_ctx->WriteBlendFactor( &gl.m_BlendFactor );
if ( stateHitMask & (1<<kGLBlendEquation) ) m_ctx->WriteBlendEquation( &gl.m_BlendEquation );
if ( stateHitMask & (1<<kGLBlendColor) ) m_ctx->WriteBlendColor( &gl.m_BlendColor );
if ( stateHitMask & (1<<kGLBlendEnableSRGB) ) m_ctx->WriteBlendEnableSRGB( &gl.m_BlendEnableSRGB );
if ( stateHitMask & (1<<kGLDepthTestEnable) ) m_ctx->WriteDepthTestEnable( &gl.m_DepthTestEnable );
if ( stateHitMask & (1<<kGLDepthFunc) ) m_ctx->WriteDepthFunc( &gl.m_DepthFunc );
if ( stateHitMask & (1<<kGLDepthMask) ) m_ctx->WriteDepthMask( &gl.m_DepthMask );
if ( stateHitMask & (1<<kGLStencilTestEnable) ) m_ctx->WriteStencilTestEnable( &gl.m_StencilTestEnable );
if ( stateHitMask & (1<<kGLStencilFunc) ) m_ctx->WriteStencilFunc( &gl.m_StencilFunc );
if ( stateHitMask & (1<<kGLStencilOp) ) { m_ctx->WriteStencilOp( &gl.m_StencilOp,0 ); m_ctx->WriteStencilOp( &gl.m_StencilOp,1 ); // ********* need to recheck this
}
if ( stateHitMask & (1<<kGLStencilWriteMask) ) m_ctx->WriteStencilWriteMask( &gl.m_StencilWriteMask );
if ( stateHitMask & (1<<kGLClearColor) ) m_ctx->WriteClearColor( &gl.m_ClearColor );
if ( stateHitMask & (1<<kGLClearDepth) ) m_ctx->WriteClearDepth( &gl.m_ClearDepth );
if ( stateHitMask & (1<<kGLClearStencil) ) m_ctx->WriteClearStencil( &gl.m_ClearStencil ); gl.m_stateDirtyMask &= (~stateHitMask); }
// addressing modes
// 1 D3DTADDRESS_WRAP Tile the texture at every integer junction.
// D3DTADDRESS_MIRROR Similar to D3DTADDRESS_WRAP, except that the texture is flipped at every integer junction.
// 3 D3DTADDRESS_CLAMP Texture coordinates outside the range [0.0, 1.0] are set to the texture color at 0.0 or 1.0, respectively.
// 4 D3DTADDRESS_BORDER Texture coordinates outside the range [0.0, 1.0] are set to the border color.
// D3DTADDRESS_MIRRORONCE Similar to D3DTADDRESS_MIRROR and D3DTADDRESS_CLAMP.
// Takes the absolute value of the texture coordinate (thus, mirroring around 0),
// and then clamps to the maximum value. The most common usage is for volume textures,
// where support for the full D3DTADDRESS_MIRRORONCE texture-addressing mode is not
// necessary, but the data is symmetric around the one axis.
static GLenum dxtogl_addressMode[] = { (GLenum)-1, // no zero entry
GL_REPEAT, // from D3DTADDRESS_WRAP
(GLenum)-1, // no D3DTADDRESS_MIRROR support
GL_CLAMP_TO_EDGE, // from D3DTADDRESS_CLAMP
GL_CLAMP, // from D3DTADDRESS_BORDER
(GLenum)-1, // no D3DTADDRESS_MIRRORONCE support
};
/*
_D3DTEXTUREFILTERTYPE: D3DTEXF_NONE = 0, // filtering disabled (valid for mip filter only)
D3DTEXF_POINT = 1, // nearest
D3DTEXF_LINEAR = 2, // linear interpolation
D3DTEXF_ANISOTROPIC = 3, // anisotropic
*/
static GLenum dxtogl_magFilter[4] = // indexed by _D3DTEXTUREFILTERTYPE
{ GL_NEAREST, // D3DTEXF_NONE not applicable to mag filter but we handle it like POINT (mat_showmiplevels hits this)
GL_NEAREST, // D3DTEXF_POINT
GL_LINEAR, // D3DTEXF_LINEAR
GL_LINEAR, // D3DTEXF_ANISOTROPIC (aniso will be driven by setting maxAniso, not by a GL filter mode)
};
static GLenum dxtogl_minFilter[4][4] = // indexed by _D3DTEXTUREFILTERTYPE on both axes: [row is min filter][col is mip filter].
{ /* mip filter ---------------> D3DTEXF_NONE D3DTEXF_POINT D3DTEXF_LINEAR (D3DTEXF_ANISOTROPIC not applicable to mip filter)
/* min = D3DTEXF_NONE */ { GL_NEAREST, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, (GLenum)-1 }, // D3DTEXF_NONE we just treat like POINT
/* min = D3DTEXF_POINT */ { GL_NEAREST, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, (GLenum)-1 }, /* min = D3DTEXF_LINEAR */ { GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR, (GLenum)-1 }, /* min = D3DTEXF_ANISOTROPIC */ { GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR, (GLenum)-1 }, // no diff from prior row, set maxAniso to effect the sampling
};
HRESULT IDirect3DDevice9::FlushSamplers() { // a minor optimization we could do here would be to only write sampler state for
// TMU's that are active (i.e. consult m_textures)
uint activeSamplerMask = m_pixelShader ? m_pixelShader->m_pixSamplerMask : 0; // if no pixel shader bound at time of draw, act like it references no samplers
// (and avoid an access violation while yer at it)
// ho, we're not clearing the dirty mask for samplers as we go... need to do that...
uint samplerHitMask = gl.m_samplerDirtyMask; for( int index = 0; (index < 16) && (samplerHitMask !=0); index++) { uint nCurrentSamplerMask = 1<<index; // only push a sampler to GLM if the sampler is dirty *and* there is a live texture on that TMU
// else the values will sit quietly in the d3d sampler side until conditions permit pushing them
if ( ( samplerHitMask & nCurrentSamplerMask ) && ( m_textures[index] != NULL ) ) { // Clear that dirty bit before you forget...
gl.m_samplerDirtyMask &= (~nCurrentSamplerMask); // Translate from D3D sampler desc
D3DSamplerDesc *dxsamp = &m_samplers[ index ]; GLMTexSamplingParams *glsamp = &gl.m_samplers[ index ];
// Address modes
glsamp->m_addressModes[0] = dxtogl_addressMode[ dxsamp->m_addressModes[0] ]; glsamp->m_addressModes[1] = dxtogl_addressMode[ dxsamp->m_addressModes[1] ]; glsamp->m_addressModes[2] = dxtogl_addressMode[ dxsamp->m_addressModes[2] ];
// Border color
uint dxcolor = dxsamp->m_borderColor; glsamp->m_borderColor[0] = ((dxcolor >> 16) & 0xFF) / 255.0f; //R
glsamp->m_borderColor[1] = ((dxcolor >> 8) & 0xFF) / 255.0f; //G
glsamp->m_borderColor[2] = ((dxcolor ) & 0xFF) / 255.0f; //B
glsamp->m_borderColor[3] = ((dxcolor >> 24) & 0xFF) / 255.0f; //A
// mag filter - pretty easy
Assert( dxsamp->m_magFilter <= D3DTEXF_ANISOTROPIC ); Assert( dxsamp->m_magFilter >= D3DTEXF_POINT );
glsamp->m_magFilter = dxtogl_magFilter[ dxsamp->m_magFilter ]; // min filter - more involved
Assert( dxsamp->m_minFilter <= D3DTEXF_ANISOTROPIC ); Assert( dxsamp->m_minFilter >= D3DTEXF_POINT ); Assert( dxsamp->m_mipFilter <= D3DTEXF_LINEAR ); Assert( dxsamp->m_mipFilter >= D3DTEXF_NONE );
D3DTEXTUREFILTERTYPE mipFilterLimit = D3DTEXF_LINEAR; /*
if (GLMKnob("caps-key",NULL) > 0.0) { if (dxsamp->m_mipFilter > D3DTEXF_NONE) { // evil hack
glsamp->m_magFilter = GL_LINEAR_MIPMAP_NEAREST; } }
if (GLMKnob("option-key",NULL) > 0.0) { // limit to point
mipFilterLimit = D3DTEXF_POINT; } if (GLMKnob("control-key",NULL) > 0.0) { // limit to none
mipFilterLimit = D3DTEXF_NONE; } */
D3DTEXTUREFILTERTYPE mipFilterChoice = MIN( dxsamp->m_mipFilter, mipFilterLimit ); glsamp->m_minFilter = dxtogl_minFilter[ dxsamp->m_minFilter ][ mipFilterChoice ]; // should we check for mip filtering being requested on unmipped textures ? does it matter ?
// mipmap bias
glsamp->m_mipmapBias = dxsamp->m_mipmapBias;
// d3d "MAX MIP LEVEL" means the *largest size* MIP that will be selected. (max size)
// this is the same as GL's "MIN LOD level" which means the GL_TEXTURE_MIN_LOD level. (min index)
int texMipCount = m_textures[index]->m_tex->m_layout->m_mipCount; Assert( texMipCount >=1 ); glsamp->m_minMipLevel = dxsamp->m_maxMipLevel; // it says gl_minMipLevel because we're setting GL's "GL_TEXTURE_MIN_LOD" aka d3d's "maximum mip size index".
if (glsamp->m_minMipLevel >= texMipCount) { // clamp - you can't have the GL base tex level be higher than the index of the last mip
glsamp->m_minMipLevel = texMipCount - 1; }
// d3d has no idea of a "MIN MIP LEVEL" i.e. smallest size allowed.
// this would be expressed in GL by setting the GL_TEXTURE_MIN_LOD meaning largest index to select.
// for now, just set it to the index of the last mip.
glsamp->m_maxMipLevel = texMipCount-1; // d3d has no value for constraining how small we can sample.
// however we may need to set this more intelligently if textures are not being fully submitted.
// On OpenGL, GL_TEXTURE_MAX_ANISOTROPY_EXT needs to be 1 if we don't want aniso
glsamp->m_maxAniso = (dxsamp->m_minFilter != D3DTEXF_ANISOTROPIC) ? 1 : dxsamp->m_maxAniso;
// SRGB
glsamp->m_srgb = dxsamp->m_srgb != 0;
// Shadow compare mode
glsamp->m_compareMode = dxsamp->m_shadowFilter ? GL_COMPARE_R_TO_TEXTURE_ARB : GL_NONE; // write that sampler.
m_ctx->SetSamplerParams( index, glsamp ); samplerHitMask ^= nCurrentSamplerMask; //turn bit off
// finally, if the SRGB state of the sampler does not match the SRGB format of the underlying texture...
// ... and the tex is not a renderable...
// ... and it is possible to re-submit the tex in an sRGB format...
// ******** AND THE TEX IS ACTUALLY REFERENCED BY THE ACTIVE PIXEL SHADER *******
// fix it.
// else complain ?
if ( nCurrentSamplerMask & activeSamplerMask ) // don't do SRGB check on unreferenced textures.
{ bool bTexSRGB = (m_textures[index]->m_tex->m_layout->m_key.m_texFlags & kGLMTexSRGB) != 0; bool bMismatch = (bTexSRGB != glsamp->m_srgb); bool bSRGBCapableTex = false; // not yet known
bool bRenderableTex = false; // not yet known.
if ( bMismatch ) { bSRGBCapableTex = m_textures[index]->m_tex->m_layout->m_format->m_glIntFormatSRGB != 0; bRenderableTex = (m_textures[index]->m_tex->m_layout->m_key.m_texFlags & kGLMTexRenderable) != 0; // we can fix it if it's not a renderable, and an sRGB enabled format variation is available.
if ( bSRGBCapableTex && !bRenderableTex ) { char *pTexName = m_textures[index]->m_tex->m_debugLabel; if (!pTexName) pTexName = "-"; m_textures[index]->m_srgbFlipCount++; static bool bCheckedCommandline = false; static bool bPrintAllflips = false; static bool bPrintFirstflips = false; static bool bPrintFreqflips = false; static bool bPrintCrawls = false; static bool bPrintMaxCrawls = false; if ( !bCheckedCommandline ) { bPrintAllflips = CommandLine()->FindParm( "-glmspewallsrgbflips" ); bPrintFirstflips = CommandLine()->FindParm( "-glmspewfirstsrgbflips" ); bPrintFreqflips = CommandLine()->FindParm( "-glmspewfreqsrgbflips" ); bPrintCrawls = CommandLine()->FindParm( "-glmspewsrgbcrawls" ); bPrintMaxCrawls = CommandLine()->FindParm( "-glmspewsrgbmaxcrawls" ); bCheckedCommandline = true; } bool bPrintIt = bPrintAllflips; if ( bPrintFirstflips ) // report on first flip
{ bPrintIt = bPrintIt || m_textures[index]->m_srgbFlipCount==1; } if ( bPrintFreqflips ) // report on 50th flip
{ bPrintIt = bPrintIt || m_textures[index]->m_srgbFlipCount==50; } if ( bPrintIt ) { char *pFormatStr; pFormatStr = "srgb change (samp=%d): tex '%-30s' %08x %s (srgb=%d, %d times)"; if ( strlen( pTexName ) >= 30 ) { pFormatStr = "srgb change (samp=%d): tex '%s' %08x %s (srgb=%d, %d times)"; } printf( "\n" ); printf( pFormatStr, index, pTexName, m_textures[index], m_textures[index]->m_tex->m_layout->m_layoutSummary, (int)glsamp->m_srgb, m_textures[index]->m_srgbFlipCount ); if ( bPrintCrawls ) { static char *interesting_crawl_substrs[] = { "CShader::OnDrawElements", NULL }; // add more as needed
CStackCrawlParams cp; memset( &cp, 0, sizeof(cp) ); cp.m_frameLimit = 20; g_extCocoaMgr->GetStackCrawl(&cp); for( int i=0; i< cp.m_frameCount; i++) { // for each row of crawl, decide if name is interesting
bool bHit = bPrintMaxCrawls; for( char **match = interesting_crawl_substrs; (!bHit) && (*match != NULL); match++) { if (strstr(cp.m_crawlNames[i], *match)) { bHit = true; } } if ( bHit ) { printf( "\n\t%s", cp.m_crawlNames[i] ); } } printf( "\n"); } }
#if GLMDEBUG && 0
//"toi" = texture of interest
static char s_toi[256] = "colorcorrection"; if (strstr( pTexName, s_toi )) { // breakpoint on this if you like
GLMPRINTF(( "srgb change %d for %s", m_textures[index]->m_srgbFlipCount, pTexName )); } #endif
// re-submit the tex unless we're stifling it
if (!CommandLine()->FindParm( "-glmnosrgbflips" )) { m_textures[index]->m_tex->ResetSRGB( glsamp->m_srgb, false ); } } else { //GLMPRINTF(("-Z- srgb sampling conflict: NOT fixing tex %08x [%s] (srgb req: %d) because (tex-srgb-capable=%d tex-renderable=%d)", m_textures[index], m_textures[index]->m_tex->m_layout->m_layoutSummary, (int)glsamp->m_srgb, (int)bSRGBCapableTex, (int)bRenderableTex ));
// we just leave the sampler state where it is, and that's life
} } } } } }
HRESULT IDirect3DDevice9::FlushIndexBindings( void ) { // push index buffer state
m_ctx->SetIndexBuffer( m_indices.m_idxBuffer->m_idxBuffer ); }
#if 0
HRESULT IDirect3DDevice9::FlushVertexBindings( void ) { // push vertex buffer state for the current vertex decl
GLMVertexSetup setup; IDirect3DVertexDeclaration9 *vxdecl = m_vertDecl;
memset( &setup, 0, sizeof( setup ) );
// see if the elems in the vertex decl match the attrib map of the shader we're about to draw with.
// can we do this in a simple style that handles both matched and unmatched orderings?
// just pick up each elem from the decl.
// visit the same slot in the shader attrib map.
// if the usage/usageindex matches, you're good.
// if not, hunt through the shader attrib map and find it.
// if you can't find it, then the shader is not consuming that attribute - odd but not fatal ?
// the serious one is shader trying to consume an attrib that isn't being sourced.
// we can check for that though with a little more work (copy the shader attrib map and mark the attribs as each one gets satisfied)
unsigned char vshAttribMap[ 16 ]; uint activeAttribCount = 0; for( int i=0; i<16; i++) { vshAttribMap[i] = m_vertexShader->m_vtxAttribMap[i]; if (vshAttribMap[i] != 0xBB) { activeAttribCount++; // this counting could be done at shader creation time, or changed to a mask
} } for( int elemIndex=0; elemIndex<vxdecl->m_elemCount; elemIndex++) { D3DVERTEXELEMENT9_GL *srcelem = &vxdecl->m_elements[elemIndex]; int matchIndex = elemIndex; // initial guess - will iterate if this does not match
int tries = 0; // >16 means done
bool matched = false; do { if ( ((vshAttribMap[matchIndex] >>4) == srcelem->m_dxdecl.Usage) && ((vshAttribMap[matchIndex] & 0x0F) == srcelem->m_dxdecl.UsageIndex) ) { // hit
int attribIndex = matchIndex; int streamIndex = srcelem->m_dxdecl.Stream; GLMVertexAttributeDesc *dstAttr = &setup.m_attrs[ matchIndex ];
// copy whole thing
*dstAttr = srcelem->m_gldecl; // then fix buffer, stride, offset
dstAttr->m_buffer = m_streams[ streamIndex ].m_vtxBuffer->m_vtxBuffer; dstAttr->m_stride = m_streams[ streamIndex ].m_stride; dstAttr->m_offset += m_streams[ streamIndex ].m_offset;
// set mask
setup.m_attrMask |= (1<<attribIndex);
vshAttribMap[matchIndex] = 0xBB; // can't match it again...
activeAttribCount--; matched = true; // confirm we found it
tries = 999; // end the loop
} else { // miss.
// just skip ahead one slot and wrap. Increment the try count. Top of loop can try to match on it.
// if we run out of tries, it just means the vert decl is sourcing an attrib that the VS is not reading.
matchIndex = (matchIndex+1) & 15; tries++; } } while (tries<=16);
if ( !matched ) { // this one is somewhat innocuous so we just do the AssertOnce
if ( !CommandLine()->FindParm("-hushasserts") ) { AssertOnce( !"Vertex shader not consuming attribs that are sourced by decl"); } } }
if (activeAttribCount >0) { // this one is more serious
if ( !CommandLine()->FindParm("-hushasserts") ) { Assert( !"Vertex shader consuming attribs not sourced by decl"); } } // pass the whole shebang to GLM
m_ctx->SetVertexAttributes( &setup ); } #endif
HRESULT IDirect3DDevice9::FlushVertexBindings( uint baseVertexIndex ) { // push vertex buffer state for the current vertex decl
// in this variant we just walk the attrib map in the VS and do a pull for each one.
// if we can't find a match in the vertex decl, we may fall back to the secret 'dummy' VBO that GLM maintains
GLMVertexSetup setup; memset( &setup, 0, sizeof( setup ) );
IDirect3DVertexDeclaration9 *vxdecl = m_vertDecl; unsigned char *vshAttribMap = m_vertexShader->m_vtxAttribMap; // this loop could be tightened if we knew the number of live entries in the shader attrib map.
// which of course would be easy to do in the create shader function or even in the translator.
GLMVertexAttributeDesc *dstAttr = setup.m_attrs; for( int i=0; i<16; i++,dstAttr++ ) { unsigned char vshattrib = vshAttribMap[ i ]; if (vshattrib != 0xBB) { // try to find the match in the decl.
// idea: put some inverse table in the decl which could accelerate this search.
D3DVERTEXELEMENT9_GL *elem = m_vertDecl->m_elements; for( int j=0; j< m_vertDecl->m_elemCount; j++,elem++) { // if it matches, install it, change vshattrib so the code below does not trigger, then end the loop
if ( ((vshattrib>>4) == elem->m_dxdecl.Usage) && ((vshattrib & 0x0F) == elem->m_dxdecl.UsageIndex) ) { // targeting attribute #i in the setup with element data #j from the decl
*dstAttr = elem->m_gldecl; // then fix buffer, stride, offset - note that we honor the base vertex index here by fiddling the offset
int streamIndex = elem->m_dxdecl.Stream; dstAttr->m_buffer = m_streams[ streamIndex ].m_vtxBuffer->m_vtxBuffer; dstAttr->m_stride = m_streams[ streamIndex ].m_stride; dstAttr->m_offset += m_streams[ streamIndex ].m_offset + (baseVertexIndex * dstAttr->m_stride);
// set mask
setup.m_attrMask |= (1<<i); // end loop
vshattrib = 0xBB; j = 999; } } // if vshattrib is not 0xBB here, that means we could not find a source in the decl for it
if (vshattrib != 0xBB) { // fill out attr the same way as usual, we just pass NULL for the buffer and ask GLM to have mercy on us
dstAttr->m_buffer = NULL; dstAttr->m_stride = 0; dstAttr->m_offset = 0;
// only implement certain usages... if we haven't seen it before, stop.
switch( vshattrib >>4 ) // aka usage
{ case D3DDECLUSAGE_POSITION: case D3DDECLUSAGE_BLENDWEIGHT: case D3DDECLUSAGE_BLENDINDICES: Debugger(); break; case D3DDECLUSAGE_NORMAL: dstAttr->m_datasize = 3; dstAttr->m_datatype = GL_FLOAT; dstAttr->m_normalized = false; break; case D3DDECLUSAGE_PSIZE: Debugger(); break;
case D3DDECLUSAGE_TEXCOORD: dstAttr->m_datasize = 3; dstAttr->m_datatype = GL_FLOAT; dstAttr->m_normalized = false; break; case D3DDECLUSAGE_TANGENT: case D3DDECLUSAGE_BINORMAL: case D3DDECLUSAGE_TESSFACTOR: case D3DDECLUSAGE_PLUGH: Debugger(); break; case D3DDECLUSAGE_COLOR: dstAttr->m_datasize = 4; dstAttr->m_datatype = GL_UNSIGNED_BYTE; dstAttr->m_normalized = true; break; case D3DDECLUSAGE_FOG: case D3DDECLUSAGE_DEPTH: case D3DDECLUSAGE_SAMPLE: Debugger(); break; } } } }
// copy active program's vertex attrib map into the vert setup info
memcpy( &setup.m_vtxAttribMap, m_vertexShader->m_vtxAttribMap, sizeof( m_vertexShader->m_vtxAttribMap ) ); m_ctx->SetVertexAttributes( &setup ); }
HRESULT IDirect3DDevice9::FlushGLM( void ) { Debugger();// old routine not used now
}
HRESULT IDirect3DDevice9::DrawPrimitive(D3DPRIMITIVETYPE PrimitiveType,UINT StartVertex,UINT PrimitiveCount) { this->FlushStates( 0xFFFFFFFF );
Debugger(); return S_OK; }
// Type
// [in] Member of the D3DPRIMITIVETYPE enumerated type, describing the type of primitive to render. D3DPT_POINTLIST is not supported with this method. See Remarks.
// BaseVertexIndex
// [in] Offset from the start of the vertex buffer to the first vertex. See Scenario 4.
// MinIndex
// [in] Minimum vertex index for vertices used during this call. This is a zero based index relative to BaseVertexIndex.
// NumVertices
// [in] Number of vertices used during this call. The first vertex is located at index: BaseVertexIndex + MinIndex.
// StartIndex
// [in] Index of the first index to use when accesssing the vertex buffer. Beginning at StartIndex to index vertices from the vertex buffer.
// PrimitiveCount
// [in] Number of primitives to render. The number of vertices used is a function of the primitive count and the primitive type. The maximum number of primitives allowed is determined by checking the MaxPrimitiveCount member of the D3DCAPS9 structure.
HRESULT IDirect3DDevice9::DrawIndexedPrimitive( D3DPRIMITIVETYPE Type,INT BaseVertexIndex,UINT MinVertexIndex,UINT NumVertices,UINT startIndex,UINT primCount ) { this->FlushStates( 0xFFFFFFFF );
this->FlushSamplers();
this->FlushIndexBindings( ); this->FlushVertexBindings( BaseVertexIndex ); m_ctx->FlushDrawStates( true );
if (gl.m_FogEnable) { GLMPRINTF(("-D- IDirect3DDevice9::DrawIndexedPrimitive is seeing enabled fog...")); } switch(Type) { case D3DPT_POINTLIST: Debugger(); break;
case D3DPT_LINELIST: GLMPRINTF(("-X- IDirect3DDevice9::DrawIndexedPrimitive( D3DPT_LINELIST ) - ignored.")); // Debugger();
m_ctx->DrawRangeElements( (GLenum)GL_LINES, (GLuint)MinVertexIndex, (GLuint)(MinVertexIndex + NumVertices), (GLsizei)primCount*2, (GLenum)GL_UNSIGNED_SHORT, (const GLvoid *)(startIndex * sizeof(short)) ); break; case D3DPT_TRIANGLELIST: m_ctx->DrawRangeElements(GL_TRIANGLES, (GLuint)MinVertexIndex, (GLuint)(MinVertexIndex + NumVertices), (GLsizei)primCount*3, (GLenum)GL_UNSIGNED_SHORT, (const GLvoid *)(startIndex * sizeof(short)) ); break; case D3DPT_TRIANGLESTRIP: // enabled... Debugger();
m_ctx->DrawRangeElements(GL_TRIANGLE_STRIP, (GLuint)MinVertexIndex, (GLuint)(MinVertexIndex + NumVertices), (GLsizei)(2+primCount), (GLenum)GL_UNSIGNED_SHORT, (const GLvoid *)(startIndex * sizeof(short)) ); break; } return S_OK; }
HRESULT IDirect3DDevice9::DrawIndexedPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType,UINT MinVertexIndex,UINT NumVertices,UINT PrimitiveCount,CONST void* pIndexData,D3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,UINT VertexStreamZeroStride) { this->FlushStates( 0xFFFFFFFF );
Debugger(); return S_OK; }
BOOL IDirect3DDevice9::ShowCursor(BOOL bShow) { // FIXME NOP
//Debugger();
return TRUE; }
void d3drect_to_glmbox( D3DRECT *src, GLScissorBox_t *dst ) { // to convert from a d3d rect to a GL rect you have to fix up the vertical axis, since D3D Y=0 is the top, but GL Y=0 is the bottom.
// you can't fix it without knowing the height.
dst->width = src->x2 - src->x1; dst->x = src->x1; // left edge
dst->height = src->y2 - src->y1; dst->y = src->y1; // bottom edge - take large Y from d3d and subtract from surf height.
}
HRESULT IDirect3DDevice9::Clear(DWORD Count,CONST D3DRECT* pRects,DWORD Flags,D3DCOLOR Color,float Z,DWORD Stencil) { this->FlushStates( (1<<kGLViewportBox) | (1<<kGLViewportDepthRange) ); // i.e. viewport changes..
m_ctx->FlushDrawStates( false );
//debugging Color = (rand() | 0xFF0000FF) & 0xFF3F3FFF;
if (!Count) { // run clear with no added rectangle
m_ctx->Clear( (Flags&D3DCLEAR_TARGET)!=0, Color, (Flags&D3DCLEAR_ZBUFFER)!=0, Z, (Flags&D3DCLEAR_STENCIL)!=0, Stencil, NULL ); } else { GLScissorBox_t tempbox; // do the rects one by one and convert each one to GL form
for( int i=0; i<Count; i++) { D3DRECT d3dtempbox = pRects[i]; d3drect_to_glmbox( &d3dtempbox, &tempbox );
m_ctx->Clear( (Flags&D3DCLEAR_TARGET)!=0, Color, (Flags&D3DCLEAR_ZBUFFER)!=0, Z, (Flags&D3DCLEAR_STENCIL)!=0, Stencil, &tempbox ); } }
return S_OK; }
HRESULT IDirect3DDevice9::SetTransform(D3DTRANSFORMSTATETYPE State,CONST D3DMATRIX* pMatrix) { Debugger(); return S_OK; }
HRESULT IDirect3DDevice9::SetTextureStageState(DWORD Stage,D3DTEXTURESTAGESTATETYPE Type,DWORD Value) { Debugger(); return S_OK; }
HRESULT IDirect3DDevice9::ValidateDevice(DWORD* pNumPasses) { Debugger(); return S_OK; }
HRESULT IDirect3DDevice9::SetMaterial(CONST D3DMATERIAL9* pMaterial) { GLMPRINTF(("-X- IDirect3DDevice9::SetMaterial - ignored.")); // Debugger();
return S_OK; }
HRESULT IDirect3DDevice9::LightEnable(DWORD Index,BOOL Enable) { Debugger(); return S_OK; }
HRESULT IDirect3DDevice9::SetScissorRect(CONST RECT* pRect) { int nSurfaceHeight = m_drawableFBO->m_attach[ kAttColor0 ].m_tex->m_layout->m_key.m_ySize; GLScissorBox_t newScissorBox = { pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top }; gl.m_ScissorBox = newScissorBox; gl.m_stateDirtyMask |= (1<<kGLScissorBox); return S_OK; }
HRESULT IDirect3DDevice9::GetDeviceCaps(D3DCAPS9* pCaps) { Debugger(); return S_OK; }
HRESULT IDirect3DDevice9::TestCooperativeLevel() { // game calls this to see if device was lost.
// last I checked the device was still attached to the computer.
// so, return OK.
return S_OK; }
HRESULT IDirect3DDevice9::SetClipPlane(DWORD Index,CONST float* pPlane) { Assert(Index<2);
// We actually push the clip plane coeffs to two places
// - into a shader param for ARB mode
// - and into the API defined clip plane slots for GLSL mode.
// if ARB mode... THIS NEEDS TO GO... it's messing up the dirty ranges..
{ // this->SetVertexShaderConstantF( DXABSTRACT_VS_CLIP_PLANE_BASE+Index, pPlane, 1 ); // stash the clip plane values into shader param - translator knows where to look
} // if GLSL mode... latch it and let FlushStates push it out
{ GLClipPlaneEquation_t peq; peq.x = pPlane[0]; peq.y = pPlane[1]; peq.z = pPlane[2]; peq.w = pPlane[3];
gl.m_ClipPlaneEquation[ Index ] = peq; gl.m_stateDirtyMask |= (1<<kGLClipPlaneEquation);
// m_ctx->WriteClipPlaneEquation( &peq, Index );
}
return S_OK; }
HRESULT IDirect3DDevice9::EvictManagedResources() { GLMPRINTF(("-X- IDirect3DDevice9::EvictManagedResources --> IGNORED")); return S_OK; }
HRESULT IDirect3DDevice9::SetLight(DWORD Index,CONST D3DLIGHT9*) { Debugger(); return S_OK; }
void IDirect3DDevice9::SetGammaRamp(UINT iSwapChain,DWORD Flags,CONST D3DGAMMARAMP* pRamp) { // just slam it directly for the time being
// this code is OS X specific
CGTableCount sampleCount; CGDisplayErr cgErr;
CGGammaValue redt[256]; CGGammaValue grnt[256]; CGGammaValue blut[256]; for( int i=0; i<256; i++) { redt[i] = ((float)pRamp->red[i]) / 65535.0f; grnt[i] = ((float)pRamp->green[i]) / 65535.0f; blut[i] = ((float)pRamp->blue[i]) / 65535.0f; } cgErr = CGSetDisplayTransferByTable( 0, 256, redt, grnt, blut ); }
// ------------------------------------------------------------------------------------------------------------------------------ //
void* ID3DXBuffer::GetBufferPointer() { Debugger(); return NULL; }
DWORD ID3DXBuffer::GetBufferSize() { Debugger(); return 0; }
#pragma mark ----- More D3DX stuff
// ------------------------------------------------------------------------------------------------------------------------------ //
// D3DX stuff.
// ------------------------------------------------------------------------------------------------------------------------------ //
// matrix stack...
HRESULT D3DXCreateMatrixStack( DWORD Flags, LPD3DXMATRIXSTACK* ppStack) { *ppStack = new ID3DXMatrixStack; (*ppStack)->Create(); return S_OK; }
HRESULT ID3DXMatrixStack::Create() { m_stack.EnsureCapacity( 16 ); // 1KB ish
m_stack.AddToTail(); m_stackTop = 0; // top of stack is at index 0 currently
LoadIdentity(); return S_OK; }
D3DXMATRIX* ID3DXMatrixStack::GetTop() { return (D3DXMATRIX*)&m_stack[ m_stackTop ]; }
void ID3DXMatrixStack::Push() { D3DMATRIX temp = m_stack[ m_stackTop ]; m_stack.AddToTail( temp ); m_stackTop ++; }
void ID3DXMatrixStack::Pop() { int elem = m_stackTop--; m_stack.Remove( elem ); }
void ID3DXMatrixStack::LoadIdentity() { D3DXMATRIX *mat = GetTop();
D3DXMatrixIdentity( mat ); }
void ID3DXMatrixStack::LoadMatrix( const D3DXMATRIX *pMat ) { *(GetTop()) = *pMat; }
void ID3DXMatrixStack::MultMatrix( const D3DXMATRIX *pMat ) {
// http://msdn.microsoft.com/en-us/library/bb174057(VS.85).aspx
// This method right-multiplies the given matrix to the current matrix
// (transformation is about the current world origin).
// m_pstack[m_currentPos] = m_pstack[m_currentPos] * (*pMat);
// This method does not add an item to the stack, it replaces the current
// matrix with the product of the current matrix and the given matrix.
Debugger(); }
void ID3DXMatrixStack::MultMatrixLocal( const D3DXMATRIX *pMat ) { // http://msdn.microsoft.com/en-us/library/bb174058(VS.85).aspx
// This method left-multiplies the given matrix to the current matrix
// (transformation is about the local origin of the object).
// m_pstack[m_currentPos] = (*pMat) * m_pstack[m_currentPos];
// This method does not add an item to the stack, it replaces the current
// matrix with the product of the given matrix and the current matrix.
Debugger(); }
HRESULT ID3DXMatrixStack::ScaleLocal(FLOAT x, FLOAT y, FLOAT z) { // http://msdn.microsoft.com/en-us/library/bb174066(VS.85).aspx
// Scale the current matrix about the object origin.
// This method left-multiplies the current matrix with the computed
// scale matrix. The transformation is about the local origin of the object.
//
// D3DXMATRIX tmp;
// D3DXMatrixScaling(&tmp, x, y, z);
// m_stack[m_currentPos] = tmp * m_stack[m_currentPos];
Debugger(); }
HRESULT ID3DXMatrixStack::RotateAxisLocal(CONST D3DXVECTOR3* pV, FLOAT Angle) { // http://msdn.microsoft.com/en-us/library/bb174062(VS.85).aspx
// Left multiply the current matrix with the computed rotation
// matrix, counterclockwise about the given axis with the given angle.
// (rotation is about the local origin of the object)
// D3DXMATRIX tmp;
// D3DXMatrixRotationAxis( &tmp, pV, angle );
// m_stack[m_currentPos] = tmp * m_stack[m_currentPos];
// Because the rotation is left-multiplied to the matrix stack, the rotation
// is relative to the object's local coordinate space.
Debugger(); }
HRESULT ID3DXMatrixStack::TranslateLocal(FLOAT x, FLOAT y, FLOAT z) { // http://msdn.microsoft.com/en-us/library/bb174068(VS.85).aspx
// Left multiply the current matrix with the computed translation
// matrix. (transformation is about the local origin of the object)
// D3DXMATRIX tmp;
// D3DXMatrixTranslation( &tmp, x, y, z );
// m_stack[m_currentPos] = tmp * m_stack[m_currentPos];
Debugger(); }
const char* D3DXGetPixelShaderProfile( IDirect3DDevice9 *pDevice ) { Debugger(); return ""; }
D3DXMATRIX* D3DXMatrixMultiply( D3DXMATRIX *pOut, CONST D3DXMATRIX *pM1, CONST D3DXMATRIX *pM2 ) { D3DXMATRIX temp; for( int i=0; i<4; i++) { for( int j=0; j<4; j++) { temp.m[i][j] = (pM1->m[ i ][ 0 ] * pM2->m[ 0 ][ j ]) + (pM1->m[ i ][ 1 ] * pM2->m[ 1 ][ j ]) + (pM1->m[ i ][ 2 ] * pM2->m[ 2 ][ j ]) + (pM1->m[ i ][ 3 ] * pM2->m[ 3 ][ j ]); } } *pOut = temp; return pOut; }
// Transform a 3D vector by a given matrix, projecting the result back into w = 1
// http://msdn.microsoft.com/en-us/library/ee417622(VS.85).aspx
D3DXVECTOR3* D3DXVec3TransformCoord(D3DXVECTOR3 *pOut, CONST D3DXVECTOR3 *pV, CONST D3DXMATRIX *pM) { D3DXVECTOR3 vOut; vOut.x = vOut.y = vOut.z = 0.0f; float norm = (pM->m[0][3] * pV->x) + (pM->m[1][3] * pV->y) + (pM->m[2][3] *pV->z) + pM->m[3][3]; if ( norm ) { vOut.x = (pM->m[0][0] * pV->x + pM->m[1][0] * pV->y + pM->m[2][0] * pV->z + pM->m[3][0]) / norm; vOut.y = (pM->m[0][1] * pV->x + pM->m[1][1] * pV->y + pM->m[2][1] * pV->z + pM->m[3][1]) / norm; vOut.z = (pM->m[0][2] * pV->x + pM->m[1][2] * pV->y + pM->m[2][2] * pV->z + pM->m[3][2]) / norm; } *pOut = vOut;
return pOut; }
void D3DXMatrixIdentity( D3DXMATRIX *mat ) { for( int i=0; i<4; i++) { for( int j=0; j<4; j++) { mat->m[i][j] = (i==j) ? 1.0f : 0.0f; // 1's on the diagonal.
} } }
D3DXMATRIX* D3DXMatrixTranslation( D3DXMATRIX *pOut, FLOAT x, FLOAT y, FLOAT z ) { D3DXMatrixIdentity( pOut ); pOut->m[3][0] = x; pOut->m[3][1] = y; pOut->m[3][2] = z; return pOut; }
D3DXMATRIX* D3DXMatrixInverse( D3DXMATRIX *pOut, FLOAT *pDeterminant, CONST D3DXMATRIX *pM ) { Assert( sizeof( D3DXMATRIX ) == (16 * sizeof(float) ) ); Assert( sizeof( VMatrix ) == (16 * sizeof(float) ) ); Assert( pDeterminant == NULL ); // homey don't play that
VMatrix *origM = (VMatrix*)pM; VMatrix *destM = (VMatrix*)pOut; bool success = MatrixInverseGeneral( *origM, *destM ); Assert( success ); return pOut; }
D3DXMATRIX* D3DXMatrixTranspose( D3DXMATRIX *pOut, CONST D3DXMATRIX *pM ) { if (pOut != pM) { for( int i=0; i<4; i++) { for( int j=0; j<4; j++) { pOut->m[i][j] = pM->m[j][i]; } } } else { D3DXMATRIX temp = *pM; D3DXMatrixTranspose( pOut, &temp ); }
return NULL; }
D3DXPLANE* D3DXPlaneNormalize( D3DXPLANE *pOut, CONST D3DXPLANE *pP) { // not very different from normalizing a vector.
// figure out the square root of the sum-of-squares of the x,y,z components
// make sure that's non zero
// then divide all four components by that value
// or return some dummy plane like 0,0,1,0 if it fails
float len = sqrt( (pP->a * pP->a) + (pP->b * pP->b) + (pP->c * pP->c) ); if (len > 1e-10) //FIXME need a real epsilon here ?
{ pOut->a = pP->a / len; pOut->b = pP->b / len; pOut->c = pP->c / len; pOut->d = pP->d / len; } else { pOut->a = 0.0f; pOut->b = 0.0f; pOut->c = 1.0f; pOut->d = 0.0f; } return pOut; }
D3DXVECTOR4* D3DXVec4Transform( D3DXVECTOR4 *pOut, CONST D3DXVECTOR4 *pV, CONST D3DXMATRIX *pM ) { VMatrix *mat = (VMatrix*)pM; Vector4D *vIn = (Vector4D*)pV; Vector4D *vOut = (Vector4D*)pOut;
Vector4DMultiplyTranspose( *mat, *vIn, *vOut );
return pOut; }
D3DXVECTOR4* D3DXVec4Normalize( D3DXVECTOR4 *pOut, CONST D3DXVECTOR4 *pV ) { Vector4D *vIn = (Vector4D*) pV; Vector4D *vOut = (Vector4D*) pOut;
*vOut = *vIn; Vector4DNormalize( *vOut ); return pOut; }
D3DXMATRIX* D3DXMatrixOrthoOffCenterRH( D3DXMATRIX *pOut, FLOAT l, FLOAT r, FLOAT b, FLOAT t, FLOAT zn,FLOAT zf ) { Debugger(); return NULL; }
D3DXMATRIX* D3DXMatrixPerspectiveRH( D3DXMATRIX *pOut, FLOAT w, FLOAT h, FLOAT zn, FLOAT zf ) { Debugger(); return NULL; }
D3DXMATRIX* D3DXMatrixPerspectiveOffCenterRH( D3DXMATRIX *pOut, FLOAT l, FLOAT r, FLOAT b, FLOAT t, FLOAT zn, FLOAT zf ) { Debugger(); return NULL; }
D3DXPLANE* D3DXPlaneTransform( D3DXPLANE *pOut, CONST D3DXPLANE *pP, CONST D3DXMATRIX *pM ) { float *out = &pOut->a;
// dot dot dot
for( int x=0; x<4; x++ ) { out[x] = (pM->m[0][x] * pP->a) + (pM->m[1][x] * pP->b) + (pM->m[2][x] * pP->c) + (pM->m[3][x] * pP->d); } return pOut; }
// ------------------------------------------------------------------------------------------------------------------------------ //
IDirect3D9 *Direct3DCreate9(UINT SDKVersion) { GLMPRINTF(( "-X- Direct3DCreate9: %d", SDKVersion ));
return new IDirect3D9; }
// ------------------------------------------------------------------------------------------------------------------------------ //
void D3DPERF_SetOptions( DWORD dwOptions ) { }
HRESULT D3DXCompileShader( LPCSTR pSrcData, UINT SrcDataLen, CONST D3DXMACRO* pDefines, LPD3DXINCLUDE pInclude, LPCSTR pFunctionName, LPCSTR pProfile, DWORD Flags, LPD3DXBUFFER* ppShader, LPD3DXBUFFER* ppErrorMsgs, LPD3DXCONSTANTTABLE* ppConstantTable) { Debugger(); // is anyone calling this ?
return S_OK; }
#endif
|