You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5762 lines
183 KiB
5762 lines
183 KiB
//================ 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
|
|
|