3708 lines
122 KiB
C++
3708 lines
122 KiB
C++
//========= Copyright Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose:
|
|
//
|
|
// $NoKeywords: $
|
|
//
|
|
//===========================================================================//
|
|
#define DISABLE_PROTECTED_THINGS
|
|
#include "locald3dtypes.h"
|
|
|
|
#include "shaderdevicedx8.h"
|
|
#include "shaderapi/ishaderutil.h"
|
|
#include "shaderapidx8_global.h"
|
|
#include "filesystem.h"
|
|
#include "tier0/icommandline.h"
|
|
#include "tier2/tier2.h"
|
|
#include "shadershadowdx8.h"
|
|
#include "colorformatdx8.h"
|
|
#include "materialsystem/IShader.h"
|
|
#include "shaderapidx8.h"
|
|
#include "shaderapidx8_global.h"
|
|
#include "imeshdx8.h"
|
|
#include "materialsystem/materialsystem_config.h"
|
|
#include "vertexshaderdx8.h"
|
|
#include "recording.h"
|
|
#include "winutils.h"
|
|
#include "tier0/vprof_telemetry.h"
|
|
|
|
#if defined ( DX_TO_GL_ABSTRACTION )
|
|
// Placed here so inlines placed in dxabstract.h can access gGL
|
|
COpenGLEntryPoints *gGL = NULL;
|
|
#endif
|
|
|
|
#define D3D_BATCH_PERF_ANALYSIS 0
|
|
|
|
#if D3D_BATCH_PERF_ANALYSIS
|
|
#if defined( DX_TO_GL_ABSTRACTION )
|
|
#error Cannot enable D3D_BATCH_PERF_ANALYSIS when using DX_TO_GL_ABSTRACTION, use GL_BATCH_PERF_ANALYSIS instead.
|
|
#endif
|
|
// Define this if you want all d3d9 interfaces hooked and run through the dx9hook.h shim interfaces. For profiling, etc.
|
|
#define DO_DX9_HOOK
|
|
#endif
|
|
|
|
#ifdef DO_DX9_HOOK
|
|
|
|
#if D3D_BATCH_PERF_ANALYSIS
|
|
ConVar d3d_batch_vis( "d3d_batch_vis", "0" );
|
|
ConVar d3d_batch_vis_abs_scale( "d3d_batch_vis_abs_scale", ".050" );
|
|
ConVar d3d_present_vis_abs_scale( "d3d_batch_vis_abs_scale", ".050" );
|
|
ConVar d3d_batch_vis_y_scale( "d3d_batch_vis_y_scale", "0.0" );
|
|
uint64 g_nTotalD3DCalls, g_nTotalD3DCycles;
|
|
static double s_rdtsc_to_ms;
|
|
#endif
|
|
|
|
#include "dx9hook.h"
|
|
#endif
|
|
|
|
#ifndef _X360
|
|
#include "wmi.h"
|
|
#endif
|
|
|
|
#if defined( _X360 )
|
|
#include "xbox/xbox_console.h"
|
|
#include "xbox/xbox_win32stubs.h"
|
|
#endif
|
|
|
|
|
|
//#define DX8_COMPATABILITY_MODE
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Globals
|
|
//-----------------------------------------------------------------------------
|
|
static CShaderDeviceMgrDx8 g_ShaderDeviceMgrDx8;
|
|
CShaderDeviceMgrDx8* g_pShaderDeviceMgrDx8 = &g_ShaderDeviceMgrDx8;
|
|
|
|
#ifndef SHADERAPIDX10
|
|
|
|
// In the shaderapidx10.dll, we use its version of IShaderDeviceMgr.
|
|
EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CShaderDeviceMgrDx8, IShaderDeviceMgr,
|
|
SHADER_DEVICE_MGR_INTERFACE_VERSION, g_ShaderDeviceMgrDx8 )
|
|
|
|
#endif
|
|
|
|
#if defined( _X360 )
|
|
IDirect3D9 *m_pD3D;
|
|
#endif
|
|
|
|
IDirect3DDevice *g_pD3DDevice = NULL;
|
|
|
|
#if defined(IS_WINDOWS_PC) && defined(SHADERAPIDX9)
|
|
// HACK: need to pass knowledge of D3D9Ex usage into callers of D3D Create* methods
|
|
// so they do not try to specify D3DPOOL_MANAGED, which is unsupported in D3D9Ex
|
|
bool g_ShaderDeviceUsingD3D9Ex = false;
|
|
static ConVar mat_supports_d3d9ex( "mat_supports_d3d9ex", "0", FCVAR_HIDDEN );
|
|
#endif
|
|
|
|
// hook into mat_forcedynamic from the engine.
|
|
static ConVar mat_forcedynamic( "mat_forcedynamic", "0", FCVAR_CHEAT );
|
|
|
|
// this is hooked into the engines convar
|
|
ConVar mat_debugalttab( "mat_debugalttab", "0", FCVAR_CHEAT );
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Device manager
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// constructor, destructor
|
|
//-----------------------------------------------------------------------------
|
|
CShaderDeviceMgrDx8::CShaderDeviceMgrDx8()
|
|
{
|
|
m_pD3D = NULL;
|
|
m_bObeyDxCommandlineOverride = true;
|
|
m_bAdapterInfoIntialized = false;
|
|
|
|
#if defined( PIX_INSTRUMENTATION ) && defined ( DX_TO_GL_ABSTRACTION ) && defined( _WIN32 )
|
|
m_hD3D9 = NULL;
|
|
m_pBeginEvent = NULL;
|
|
m_pEndEvent = NULL;
|
|
m_pSetMarker = NULL;
|
|
m_pSetOptions = NULL;
|
|
#endif
|
|
}
|
|
|
|
CShaderDeviceMgrDx8::~CShaderDeviceMgrDx8()
|
|
{
|
|
}
|
|
|
|
#ifdef OSX
|
|
#include <Carbon/Carbon.h>
|
|
#endif
|
|
//-----------------------------------------------------------------------------
|
|
// Connect, disconnect
|
|
//-----------------------------------------------------------------------------
|
|
bool CShaderDeviceMgrDx8::Connect( CreateInterfaceFn factory )
|
|
{
|
|
LOCK_SHADERAPI();
|
|
|
|
if ( !BaseClass::Connect( factory ) )
|
|
return false;
|
|
|
|
#if defined ( DX_TO_GL_ABSTRACTION )
|
|
gGL = ToGLConnectLibraries( factory );
|
|
#endif
|
|
|
|
#if defined(IS_WINDOWS_PC) && defined(SHADERAPIDX9) && !defined(RECORDING) && !defined( DX_TO_GL_ABSTRACTION )
|
|
m_pD3D = NULL;
|
|
|
|
// Attempt to create a D3D9Ex device (Windows Vista and later) if possible
|
|
bool bD3D9ExForceDisable = ( CommandLine()->FindParm( "-nod3d9ex" ) != 0 ) ||
|
|
( CommandLine()->ParmValue( "-dxlevel", 95 ) < 90 );
|
|
|
|
bool bD3D9ExAvailable = false;
|
|
if ( HMODULE hMod = ::LoadLibraryA( "d3d9.dll" ) )
|
|
{
|
|
typedef HRESULT ( WINAPI *CreateD3D9ExFunc_t )( UINT, IUnknown** );
|
|
if ( CreateD3D9ExFunc_t pfnCreateD3D9Ex = (CreateD3D9ExFunc_t) ::GetProcAddress( hMod, "Direct3DCreate9Ex" ) )
|
|
{
|
|
IUnknown *pD3D9Ex = NULL;
|
|
if ( (*pfnCreateD3D9Ex)( D3D_SDK_VERSION, &pD3D9Ex ) == S_OK && pD3D9Ex )
|
|
{
|
|
bD3D9ExAvailable = true;
|
|
if ( bD3D9ExForceDisable )
|
|
{
|
|
pD3D9Ex->Release();
|
|
}
|
|
else
|
|
{
|
|
g_ShaderDeviceUsingD3D9Ex = true;
|
|
// The following is more "correct" but incompatible with the Steam overlay:
|
|
//pD3D9Ex->QueryInterface( IID_IDirect3D9, (void**) &m_pD3D );
|
|
//pD3D9Ex->Release();
|
|
m_pD3D = static_cast< IDirect3D9* >( pD3D9Ex );
|
|
}
|
|
}
|
|
}
|
|
::FreeLibrary( hMod );
|
|
}
|
|
|
|
if ( !m_pD3D )
|
|
{
|
|
g_ShaderDeviceUsingD3D9Ex = false;
|
|
m_pD3D = Direct3DCreate9(D3D_SDK_VERSION);
|
|
}
|
|
|
|
mat_supports_d3d9ex.SetValue( bD3D9ExAvailable ? 1 : 0 );
|
|
#else
|
|
#if defined( DO_DX9_HOOK )
|
|
m_pD3D = Direct3DCreate9Hook(D3D_SDK_VERSION);
|
|
#else
|
|
m_pD3D = Direct3DCreate9(D3D_SDK_VERSION);
|
|
#endif
|
|
#endif
|
|
|
|
if ( !m_pD3D )
|
|
{
|
|
Warning( "Failed to create D3D9!\n" );
|
|
return false;
|
|
}
|
|
|
|
#if defined( PIX_INSTRUMENTATION ) && defined ( DX_TO_GL_ABSTRACTION ) && defined( _WIN32 )
|
|
// This is a little odd, but AMD PerfStudio hooks D3D9.DLL and intercepts all of the D3DPERF API's (even for OpenGL apps).
|
|
// So dynamically load d3d9.dll and get the address of these exported functions.
|
|
if ( !m_hD3D9 )
|
|
{
|
|
m_hD3D9 = LoadLibraryA("d3d9.dll");
|
|
}
|
|
if ( m_hD3D9 )
|
|
{
|
|
Plat_DebugString( "PIX_INSTRUMENTATION: Loaded d3d9.dll\n" );
|
|
printf( "PIX_INSTRUMENTATION: Loaded d3d9.dll\n" );
|
|
|
|
m_pBeginEvent = (D3DPERF_BeginEvent_FuncPtr)GetProcAddress( m_hD3D9, "D3DPERF_BeginEvent" );
|
|
m_pEndEvent = (D3DPERF_EndEvent_FuncPtr)GetProcAddress( m_hD3D9, "D3DPERF_EndEvent" );
|
|
m_pSetMarker = (D3DPERF_SetMarker_FuncPtr)GetProcAddress( m_hD3D9, "D3DPERF_SetOptions" );
|
|
m_pSetOptions = (D3DPERF_SetOptions_FuncPtr)GetProcAddress( m_hD3D9, "D3DPERF_SetMarker" );
|
|
}
|
|
#endif
|
|
|
|
// FIXME: Want this to be here, but we can't because Steam
|
|
// hasn't had it's application ID set up yet.
|
|
|
|
// InitAdapterInfo();
|
|
return true;
|
|
}
|
|
|
|
void CShaderDeviceMgrDx8::Disconnect()
|
|
{
|
|
LOCK_SHADERAPI();
|
|
|
|
#if defined( PIX_INSTRUMENTATION ) && defined ( DX_TO_GL_ABSTRACTION ) && defined( _WIN32 )
|
|
if ( m_hD3D9 )
|
|
{
|
|
m_pBeginEvent = NULL;
|
|
m_pEndEvent = NULL;
|
|
m_pSetMarker = NULL;
|
|
m_pSetOptions = NULL;
|
|
|
|
FreeLibrary( m_hD3D9 );
|
|
m_hD3D9 = NULL;
|
|
}
|
|
#endif
|
|
|
|
if ( m_pD3D )
|
|
{
|
|
m_pD3D->Release();
|
|
m_pD3D = 0;
|
|
}
|
|
|
|
#if defined ( DX_TO_GL_ABSTRACTION )
|
|
ToGLDisconnectLibraries();
|
|
#endif
|
|
|
|
BaseClass::Disconnect();
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Initialization
|
|
//-----------------------------------------------------------------------------
|
|
InitReturnVal_t CShaderDeviceMgrDx8::Init( )
|
|
{
|
|
// FIXME: Remove call to InitAdapterInfo once Steam startup issues are resolved.
|
|
// Do it in Connect instead.
|
|
InitAdapterInfo();
|
|
|
|
return INIT_OK;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Shutdown
|
|
//-----------------------------------------------------------------------------
|
|
void CShaderDeviceMgrDx8::Shutdown( )
|
|
{
|
|
LOCK_SHADERAPI();
|
|
|
|
// FIXME: Make PIX work
|
|
|
|
// BeginPIXEvent( PIX_VALVE_ORANGE, "Shutdown" );
|
|
|
|
if ( g_pShaderAPI )
|
|
{
|
|
g_pShaderAPI->OnDeviceShutdown();
|
|
}
|
|
|
|
if ( g_pShaderDevice )
|
|
{
|
|
g_pShaderDevice->ShutdownDevice();
|
|
g_pMaterialSystemHardwareConfig = NULL;
|
|
}
|
|
|
|
// EndPIXEvent();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Inline methods
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Initialize adapter information
|
|
//-----------------------------------------------------------------------------
|
|
void CShaderDeviceMgrDx8::InitAdapterInfo()
|
|
{
|
|
if ( m_bAdapterInfoIntialized )
|
|
return;
|
|
|
|
m_bAdapterInfoIntialized = true;
|
|
m_Adapters.RemoveAll();
|
|
|
|
Assert(m_pD3D);
|
|
int nCount = m_pD3D->GetAdapterCount( );
|
|
for( int i = 0; i < nCount; ++i )
|
|
{
|
|
int j = m_Adapters.AddToTail();
|
|
AdapterInfo_t &info = m_Adapters[j];
|
|
|
|
#ifdef _DEBUG
|
|
memset( &info.m_ActualCaps, 0xDD, sizeof(info.m_ActualCaps) );
|
|
#endif
|
|
|
|
info.m_ActualCaps.m_bDeviceOk = ComputeCapsFromD3D( &info.m_ActualCaps, i );
|
|
if ( !info.m_ActualCaps.m_bDeviceOk )
|
|
continue;
|
|
|
|
ReadDXSupportLevels( info.m_ActualCaps );
|
|
|
|
// Read dxsupport.cfg which has config overrides for particular cards.
|
|
ReadHardwareCaps( info.m_ActualCaps, info.m_ActualCaps.m_nMaxDXSupportLevel );
|
|
|
|
// What's in "-shader" overrides dxsupport.cfg
|
|
const char *pShaderParam = CommandLine()->ParmValue( "-shader" );
|
|
if ( pShaderParam )
|
|
{
|
|
Q_strncpy( info.m_ActualCaps.m_pShaderDLL, pShaderParam, sizeof( info.m_ActualCaps.m_pShaderDLL ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------
|
|
// Code to detect support for texture border color (widely supported but the caps
|
|
// bit is messed up in drivers due to a stupid WHQL test that requires this to work
|
|
// with float textures which we don't generally care about wrt this address mode)
|
|
//--------------------------------------------------------------------------------
|
|
void CShaderDeviceMgrDx8::CheckBorderColorSupport( HardwareCaps_t *pCaps, int nAdapter )
|
|
{
|
|
#ifdef DX_TO_GL_ABSTRACTION
|
|
if( true )
|
|
#else
|
|
if( IsX360() )
|
|
#endif
|
|
{
|
|
pCaps->m_bSupportsBorderColor = true;
|
|
}
|
|
else // Most PC parts do this, but let's not deal with that yet (JasonM)
|
|
{
|
|
pCaps->m_bSupportsBorderColor = false;
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------
|
|
// Vendor-dependent code to detect support for various flavors of shadow mapping
|
|
//--------------------------------------------------------------------------------
|
|
void CShaderDeviceMgrDx8::CheckVendorDependentShadowMappingSupport( HardwareCaps_t *pCaps, int nAdapter )
|
|
{
|
|
// Set a default null texture format...may be overridden below by IHV-specific surface type
|
|
pCaps->m_NullTextureFormat = IMAGE_FORMAT_ARGB8888;
|
|
if ( m_pD3D->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, D3DFMT_X8R8G8B8, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE, D3DFMT_R5G6B5 ) == S_OK )
|
|
{
|
|
pCaps->m_NullTextureFormat = IMAGE_FORMAT_RGB565;
|
|
}
|
|
|
|
#if defined( _X360 )
|
|
pCaps->m_ShadowDepthTextureFormat = ReverseDepthOnX360() ? IMAGE_FORMAT_X360_DST24F : IMAGE_FORMAT_X360_DST24;
|
|
pCaps->m_bSupportsShadowDepthTextures = true;
|
|
pCaps->m_bSupportsFetch4 = false;
|
|
return;
|
|
#elif defined ( DX_TO_GL_ABSTRACTION )
|
|
// We may want to only do this on the higher-end Mac SKUs, since it's not free...
|
|
pCaps->m_ShadowDepthTextureFormat = IMAGE_FORMAT_NV_DST16; // This format shunts us down the right shader combo path
|
|
|
|
pCaps->m_bSupportsShadowDepthTextures = true;
|
|
|
|
pCaps->m_bSupportsFetch4 = false;
|
|
return;
|
|
#endif
|
|
|
|
if ( IsPC() || !IsX360() )
|
|
{
|
|
bool bToolsMode = IsWindows() && ( CommandLine()->CheckParm( "-tools" ) != NULL );
|
|
bool bFound16Bit = false;
|
|
|
|
if ( ( pCaps->m_VendorID == VENDORID_NVIDIA ) && ( pCaps->m_SupportsShaderModel_3_0 ) ) // ps_3_0 parts from nVidia
|
|
{
|
|
// First, test for null texture support
|
|
if ( m_pD3D->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, D3DFMT_X8R8G8B8, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE, NVFMT_NULL ) == S_OK )
|
|
{
|
|
pCaps->m_NullTextureFormat = IMAGE_FORMAT_NV_NULL;
|
|
}
|
|
|
|
//
|
|
// NVIDIA has two no-PCF formats (these are not filtering modes, but surface formats
|
|
// NVFMT_RAWZ is supported by NV4x (not supported here yet...requires a dp3 to reconstruct in shader code, which doesn't seem to work)
|
|
// NVFMT_INTZ is supported on newer chips as of G8x (just read like ATI non-fetch4 mode)
|
|
//
|
|
/*
|
|
if ( m_pD3D->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, D3DFMT_X8R8G8B8, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE, NVFMT_INTZ ) == S_OK )
|
|
{
|
|
pCaps->m_ShadowDepthTextureFormat = IMAGE_FORMAT_NV_INTZ;
|
|
pCaps->m_bSupportsFetch4 = false;
|
|
pCaps->m_bSupportsShadowDepthTextures = true;
|
|
return;
|
|
}
|
|
*/
|
|
if ( m_pD3D->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, D3DFMT_X8R8G8B8, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, D3DFMT_D16 ) == S_OK )
|
|
{
|
|
pCaps->m_ShadowDepthTextureFormat = IMAGE_FORMAT_NV_DST16;
|
|
pCaps->m_bSupportsFetch4 = false;
|
|
pCaps->m_bSupportsShadowDepthTextures = true;
|
|
bFound16Bit = true;
|
|
|
|
if ( !bToolsMode ) // Tools will continue on and try for 24 bit...
|
|
return;
|
|
}
|
|
|
|
if ( m_pD3D->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, D3DFMT_X8R8G8B8, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, D3DFMT_D24S8 ) == S_OK )
|
|
{
|
|
pCaps->m_ShadowDepthTextureFormat = IMAGE_FORMAT_NV_DST24;
|
|
pCaps->m_bSupportsFetch4 = false;
|
|
pCaps->m_bSupportsShadowDepthTextures = true;
|
|
return;
|
|
}
|
|
|
|
if ( bFound16Bit ) // Found 16 bit but not 24
|
|
return;
|
|
}
|
|
else if ( ( pCaps->m_VendorID == VENDORID_ATI ) && pCaps->m_SupportsPixelShaders_2_b ) // ps_2_b parts from ATI
|
|
{
|
|
// Initially, check for Fetch4 (tied to ATIFMT_D24S8 support)
|
|
pCaps->m_bSupportsFetch4 = false;
|
|
if ( m_pD3D->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, D3DFMT_X8R8G8B8, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, ATIFMT_D24S8 ) == S_OK )
|
|
{
|
|
pCaps->m_bSupportsFetch4 = true;
|
|
}
|
|
|
|
if ( m_pD3D->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, D3DFMT_X8R8G8B8, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, ATIFMT_D16 ) == S_OK ) // Prefer 16-bit
|
|
{
|
|
pCaps->m_ShadowDepthTextureFormat = IMAGE_FORMAT_ATI_DST16;
|
|
pCaps->m_bSupportsShadowDepthTextures = true;
|
|
bFound16Bit = true;
|
|
|
|
if ( !bToolsMode ) // Tools will continue on and try for 24 bit...
|
|
return;
|
|
}
|
|
|
|
if ( m_pD3D->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, D3DFMT_X8R8G8B8, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, ATIFMT_D24S8 ) == S_OK )
|
|
{
|
|
pCaps->m_ShadowDepthTextureFormat = IMAGE_FORMAT_ATI_DST24;
|
|
pCaps->m_bSupportsShadowDepthTextures = true;
|
|
return;
|
|
}
|
|
|
|
if ( bFound16Bit ) // Found 16 bit but not 24
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Other vendor or old hardware
|
|
pCaps->m_ShadowDepthTextureFormat = IMAGE_FORMAT_UNKNOWN;
|
|
pCaps->m_bSupportsShadowDepthTextures = false;
|
|
pCaps->m_bSupportsFetch4 = false;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Vendor-dependent code to detect Alpha To Coverage Backdoors
|
|
//-----------------------------------------------------------------------------
|
|
void CShaderDeviceMgrDx8::CheckVendorDependentAlphaToCoverage( HardwareCaps_t *pCaps, int nAdapter )
|
|
{
|
|
pCaps->m_bSupportsAlphaToCoverage = false;
|
|
|
|
// Bail out on OpenGL
|
|
#ifdef DX_TO_GL_ABSTRACTION
|
|
pCaps->m_bSupportsAlphaToCoverage = true;
|
|
pCaps->m_AlphaToCoverageEnableValue = TRUE;
|
|
pCaps->m_AlphaToCoverageDisableValue = FALSE;
|
|
pCaps->m_AlphaToCoverageState = D3DRS_ADAPTIVETESS_Y; // Just match the NVIDIA state hackery
|
|
return;
|
|
#endif
|
|
|
|
if ( pCaps->m_nDXSupportLevel < 90 )
|
|
return;
|
|
|
|
#ifdef _X360
|
|
{
|
|
pCaps->m_bSupportsAlphaToCoverage = true;
|
|
pCaps->m_AlphaToCoverageEnableValue = TRUE;
|
|
pCaps->m_AlphaToCoverageDisableValue = FALSE;
|
|
pCaps->m_AlphaToCoverageState = D3DRS_ALPHATOMASKENABLE;
|
|
return;
|
|
}
|
|
#endif // _X360
|
|
|
|
if ( pCaps->m_VendorID == VENDORID_NVIDIA )
|
|
{
|
|
// nVidia has two modes...assume SSAA is superior to MSAA and hence more desirable (though it's probably not)
|
|
//
|
|
// Currently, they only seem to expose any of this on 7800 and up though older parts certainly
|
|
// support at least the MSAA mode since they support it on OpenGL via the arb_multisample extension
|
|
bool bNVIDIA_MSAA = false;
|
|
bool bNVIDIA_SSAA = false;
|
|
|
|
if ( m_pD3D->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, // Check MSAA version
|
|
D3DFMT_X8R8G8B8, 0, D3DRTYPE_SURFACE,
|
|
(D3DFORMAT)MAKEFOURCC('A', 'T', 'O', 'C')) == S_OK )
|
|
{
|
|
bNVIDIA_MSAA = true;
|
|
}
|
|
|
|
if ( m_pD3D->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, // Check SSAA version
|
|
D3DFMT_X8R8G8B8, 0, D3DRTYPE_SURFACE,
|
|
(D3DFORMAT)MAKEFOURCC('S', 'S', 'A', 'A')) == S_OK )
|
|
{
|
|
bNVIDIA_SSAA = true;
|
|
}
|
|
|
|
// nVidia pitches SSAA but we prefer ATOC
|
|
if ( bNVIDIA_MSAA )// || bNVIDIA_SSAA )
|
|
{
|
|
// if ( bNVIDIA_SSAA )
|
|
// m_AlphaToCoverageEnableValue = MAKEFOURCC('S', 'S', 'A', 'A');
|
|
// else
|
|
pCaps->m_AlphaToCoverageEnableValue = MAKEFOURCC('A', 'T', 'O', 'C');
|
|
|
|
pCaps->m_AlphaToCoverageState = D3DRS_ADAPTIVETESS_Y;
|
|
pCaps->m_AlphaToCoverageDisableValue = (DWORD)D3DFMT_UNKNOWN;
|
|
pCaps->m_bSupportsAlphaToCoverage = true;
|
|
return;
|
|
}
|
|
}
|
|
else if ( pCaps->m_VendorID == VENDORID_ATI )
|
|
{
|
|
// Supported on all ATI parts...just go ahead and set the state when appropriate
|
|
pCaps->m_AlphaToCoverageState = D3DRS_POINTSIZE;
|
|
pCaps->m_AlphaToCoverageEnableValue = MAKEFOURCC('A','2','M','1');
|
|
pCaps->m_AlphaToCoverageDisableValue = MAKEFOURCC('A','2','M','0');
|
|
pCaps->m_bSupportsAlphaToCoverage = true;
|
|
return;
|
|
}
|
|
}
|
|
|
|
ConVar mat_hdr_level( "mat_hdr_level", "2", FCVAR_ARCHIVE );
|
|
ConVar mat_slopescaledepthbias_shadowmap( "mat_slopescaledepthbias_shadowmap", "16", FCVAR_CHEAT );
|
|
#ifdef DX_TO_GL_ABSTRACTION
|
|
ConVar mat_depthbias_shadowmap( "mat_depthbias_shadowmap", "20", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY );
|
|
#else
|
|
ConVar mat_depthbias_shadowmap( "mat_depthbias_shadowmap", "0.0005", FCVAR_CHEAT );
|
|
#endif
|
|
|
|
// For testing Fast Clip
|
|
ConVar mat_fastclip( "mat_fastclip", "0", FCVAR_CHEAT );
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Determine capabilities
|
|
//-----------------------------------------------------------------------------
|
|
bool CShaderDeviceMgrDx8::ComputeCapsFromD3D( HardwareCaps_t *pCaps, int nAdapter )
|
|
{
|
|
D3DCAPS caps;
|
|
D3DADAPTER_IDENTIFIER9 ident;
|
|
HRESULT hr;
|
|
|
|
// NOTE: When getting the caps, we want to be limited by the hardware
|
|
// even if we're running with software T&L...
|
|
hr = m_pD3D->GetDeviceCaps( nAdapter, DX8_DEVTYPE, &caps );
|
|
if ( FAILED( hr ) )
|
|
return false;
|
|
|
|
hr = m_pD3D->GetAdapterIdentifier( nAdapter, D3DENUM_WHQL_LEVEL, &ident );
|
|
if ( FAILED( hr ) )
|
|
return false;
|
|
|
|
if ( IsOpenGL() )
|
|
{
|
|
if ( !ident.DeviceId && !ident.VendorId )
|
|
{
|
|
ident.DeviceId = 1; // fake default device/vendor ID for OpenGL
|
|
ident.VendorId = 1;
|
|
}
|
|
}
|
|
|
|
// Intended for debugging only
|
|
if ( CommandLine()->CheckParm( "-force_device_id" ) )
|
|
{
|
|
const char *pDevID = CommandLine()->ParmValue( "-force_device_id", "" );
|
|
if ( pDevID )
|
|
{
|
|
int nDevID = V_atoi( pDevID ); // use V_atoi for hex support
|
|
if ( nDevID > 0 )
|
|
{
|
|
ident.DeviceId = nDevID;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Intended for debugging only
|
|
if ( CommandLine()->CheckParm( "-force_vendor_id" ) )
|
|
{
|
|
const char *pVendorID = CommandLine()->ParmValue( "-force_vendor_id", "" );
|
|
if ( pVendorID )
|
|
{
|
|
int nVendorID = V_atoi( pVendorID ); // use V_atoi for hex support
|
|
if ( pVendorID > 0 )
|
|
{
|
|
ident.VendorId = nVendorID;
|
|
}
|
|
}
|
|
}
|
|
|
|
Q_strncpy( pCaps->m_pDriverName, ident.Description, MATERIAL_ADAPTER_NAME_LENGTH );
|
|
pCaps->m_VendorID = ident.VendorId;
|
|
pCaps->m_DeviceID = ident.DeviceId;
|
|
pCaps->m_SubSysID = ident.SubSysId;
|
|
pCaps->m_Revision = ident.Revision;
|
|
|
|
pCaps->m_nDriverVersionHigh = ident.DriverVersion.HighPart;
|
|
pCaps->m_nDriverVersionLow = ident.DriverVersion.LowPart;
|
|
|
|
pCaps->m_pShaderDLL[0] = 0;
|
|
pCaps->m_nMaxViewports = 1;
|
|
|
|
pCaps->m_PreferDynamicTextures = ( caps.Caps2 & D3DCAPS2_DYNAMICTEXTURES ) ? 1 : 0;
|
|
|
|
pCaps->m_HasProjectedBumpEnv = ( caps.TextureCaps & D3DPTEXTURECAPS_NOPROJECTEDBUMPENV ) == 0;
|
|
|
|
pCaps->m_HasSetDeviceGammaRamp = (caps.Caps2 & D3DCAPS2_CANCALIBRATEGAMMA) != 0;
|
|
pCaps->m_SupportsVertexShaders = ((caps.VertexShaderVersion >> 8) & 0xFF) >= 1;
|
|
pCaps->m_SupportsPixelShaders = ((caps.PixelShaderVersion >> 8) & 0xFF) >= 1;
|
|
|
|
pCaps->m_bScissorSupported = ( caps.RasterCaps & D3DPRASTERCAPS_SCISSORTEST ) != 0;
|
|
|
|
#if defined( DX8_COMPATABILITY_MODE )
|
|
pCaps->m_SupportsPixelShaders_1_4 = false;
|
|
pCaps->m_SupportsPixelShaders_2_0 = false;
|
|
pCaps->m_SupportsPixelShaders_2_b = false;
|
|
pCaps->m_SupportsVertexShaders_2_0 = false;
|
|
pCaps->m_SupportsShaderModel_3_0 = false;
|
|
pCaps->m_SupportsMipmappedCubemaps = false;
|
|
#else
|
|
pCaps->m_SupportsPixelShaders_1_4 = ( caps.PixelShaderVersion & 0xffff ) >= 0x0104;
|
|
pCaps->m_SupportsPixelShaders_2_0 = ( caps.PixelShaderVersion & 0xffff ) >= 0x0200;
|
|
pCaps->m_SupportsPixelShaders_2_b = ( ( caps.PixelShaderVersion & 0xffff ) >= 0x0200) && (caps.PS20Caps.NumInstructionSlots >= 512); // More caps to this, but this will do
|
|
pCaps->m_SupportsVertexShaders_2_0 = ( caps.VertexShaderVersion & 0xffff ) >= 0x0200;
|
|
pCaps->m_SupportsShaderModel_3_0 = ( caps.PixelShaderVersion & 0xffff ) >= 0x0300;
|
|
pCaps->m_SupportsMipmappedCubemaps = ( caps.TextureCaps & D3DPTEXTURECAPS_MIPCUBEMAP ) ? true : false;
|
|
#endif
|
|
|
|
// Slam this off for OpenGL
|
|
if ( IsOpenGL() )
|
|
{
|
|
pCaps->m_SupportsShaderModel_3_0 = false;
|
|
}
|
|
|
|
// Slam 3.0 shaders off for Intel
|
|
if ( pCaps->m_VendorID == VENDORID_INTEL )
|
|
{
|
|
pCaps->m_SupportsShaderModel_3_0 = false;
|
|
}
|
|
|
|
pCaps->m_MaxVertexShader30InstructionSlots = 0;
|
|
pCaps->m_MaxPixelShader30InstructionSlots = 0;
|
|
|
|
if ( pCaps->m_SupportsShaderModel_3_0 )
|
|
{
|
|
pCaps->m_MaxVertexShader30InstructionSlots = caps.MaxVertexShader30InstructionSlots;
|
|
pCaps->m_MaxPixelShader30InstructionSlots = caps.MaxPixelShader30InstructionSlots;
|
|
}
|
|
|
|
if( CommandLine()->CheckParm( "-nops2b" ) )
|
|
{
|
|
pCaps->m_SupportsPixelShaders_2_b = false;
|
|
}
|
|
|
|
pCaps->m_bSoftwareVertexProcessing = false;
|
|
if ( IsWindows() && CommandLine()->CheckParm( "-mat_softwaretl" ) )
|
|
{
|
|
pCaps->m_bSoftwareVertexProcessing = true;
|
|
}
|
|
|
|
if ( IsWindows() && !( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT ) )
|
|
{
|
|
// no hardware t&l. . use software
|
|
pCaps->m_bSoftwareVertexProcessing = true;
|
|
}
|
|
|
|
// Set mat_forcedynamic if software vertex processing since the software vp pipe has
|
|
// problems with sparse vertex buffers (it transforms the whole thing.)
|
|
if ( pCaps->m_bSoftwareVertexProcessing )
|
|
{
|
|
mat_forcedynamic.SetValue( 1 );
|
|
}
|
|
|
|
if ( pCaps->m_bSoftwareVertexProcessing )
|
|
{
|
|
pCaps->m_SupportsVertexShaders = true;
|
|
pCaps->m_SupportsVertexShaders_2_0 = true;
|
|
}
|
|
|
|
#ifdef OSX
|
|
// Static control flow is disabled by default on OSX (the Mac version of togl has known bugs preventing this path from working properly that we've fixed in togl linux/win)
|
|
pCaps->m_bSupportsStaticControlFlow = CommandLine()->CheckParm( "-glslcontrolflow" ) != NULL;
|
|
#else
|
|
pCaps->m_bSupportsStaticControlFlow = !CommandLine()->CheckParm( "-noglslcontrolflow" );
|
|
#endif
|
|
|
|
// NOTE: Texture stages is a fixed-function concept
|
|
// NOTE: Normally, the number of texture units == the number of texture
|
|
// stages except for NVidia hardware, which reports more stages than units.
|
|
// The reason for this is because they expose the inner hardware pixel
|
|
// pipeline through the extra stages. The only thing we use stages for
|
|
// in the hardware is for configuring the color + alpha args + ops.
|
|
pCaps->m_NumSamplers = caps.MaxSimultaneousTextures;
|
|
pCaps->m_NumTextureStages = caps.MaxTextureBlendStages;
|
|
if ( pCaps->m_SupportsPixelShaders_2_0 )
|
|
{
|
|
pCaps->m_NumSamplers = 16;
|
|
}
|
|
else
|
|
{
|
|
Assert( pCaps->m_NumSamplers <= pCaps->m_NumTextureStages );
|
|
}
|
|
|
|
// Clamp
|
|
pCaps->m_NumSamplers = min( pCaps->m_NumSamplers, (int)MAX_SAMPLERS );
|
|
pCaps->m_NumTextureStages = min( pCaps->m_NumTextureStages, (int)MAX_TEXTURE_STAGES );
|
|
|
|
if ( D3DSupportsCompressedTextures() )
|
|
{
|
|
pCaps->m_SupportsCompressedTextures = COMPRESSED_TEXTURES_ON;
|
|
}
|
|
else
|
|
{
|
|
pCaps->m_SupportsCompressedTextures = COMPRESSED_TEXTURES_OFF;
|
|
}
|
|
|
|
pCaps->m_bSupportsAnisotropicFiltering = (caps.TextureFilterCaps & D3DPTFILTERCAPS_MINFANISOTROPIC) != 0;
|
|
pCaps->m_bSupportsMagAnisotropicFiltering = (caps.TextureFilterCaps & D3DPTFILTERCAPS_MAGFANISOTROPIC) != 0;
|
|
|
|
// OpenGL does not support this--at least not on OSX which is the primary GL target, so just don't use that path on GL at all.
|
|
#if !defined( DX_TO_GL_ABSTRACTION )
|
|
pCaps->m_bCanStretchRectFromTextures = ( ( caps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES ) != 0 ) && ( pCaps->m_VendorID != VENDORID_INTEL );
|
|
#else
|
|
pCaps->m_bCanStretchRectFromTextures = false;
|
|
#endif
|
|
|
|
pCaps->m_nMaxAnisotropy = pCaps->m_bSupportsAnisotropicFiltering ? caps.MaxAnisotropy : 1;
|
|
|
|
pCaps->m_SupportsCubeMaps = ( caps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP ) ? true : false;
|
|
pCaps->m_SupportsNonPow2Textures =
|
|
( !( caps.TextureCaps & D3DPTEXTURECAPS_POW2 ) ||
|
|
( caps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL ) );
|
|
|
|
Assert( caps.TextureCaps & D3DPTEXTURECAPS_PROJECTED );
|
|
|
|
if ( pCaps->m_bSoftwareVertexProcessing )
|
|
{
|
|
// This should be pushed down based on pixel shaders.
|
|
pCaps->m_NumVertexShaderConstants = 256;
|
|
pCaps->m_NumBooleanVertexShaderConstants = pCaps->m_SupportsPixelShaders_2_0 ? 16 : 0; // 2.0 parts have 16 bool vs registers
|
|
pCaps->m_NumBooleanPixelShaderConstants = pCaps->m_SupportsPixelShaders_2_0 ? 16 : 0; // 2.0 parts have 16 bool ps registers
|
|
pCaps->m_NumIntegerVertexShaderConstants = pCaps->m_SupportsPixelShaders_2_0 ? 16 : 0; // 2.0 parts have 16 bool vs registers
|
|
pCaps->m_NumIntegerPixelShaderConstants = pCaps->m_SupportsPixelShaders_2_0 ? 16 : 0; // 2.0 parts have 16 bool ps registers
|
|
}
|
|
else
|
|
{
|
|
pCaps->m_NumVertexShaderConstants = caps.MaxVertexShaderConst;
|
|
if ( CommandLine()->FindParm( "-limitvsconst" ) )
|
|
{
|
|
pCaps->m_NumVertexShaderConstants = min( 256, pCaps->m_NumVertexShaderConstants );
|
|
}
|
|
pCaps->m_NumBooleanVertexShaderConstants = pCaps->m_SupportsPixelShaders_2_0 ? 16 : 0; // 2.0 parts have 16 bool vs registers
|
|
pCaps->m_NumBooleanPixelShaderConstants = pCaps->m_SupportsPixelShaders_2_0 ? 16 : 0; // 2.0 parts have 16 bool ps registers
|
|
|
|
// This is a little misleading...this is really 16 int4 registers
|
|
pCaps->m_NumIntegerVertexShaderConstants = pCaps->m_SupportsPixelShaders_2_0 ? 16 : 0; // 2.0 parts have 16 bool vs registers
|
|
pCaps->m_NumIntegerPixelShaderConstants = pCaps->m_SupportsPixelShaders_2_0 ? 16 : 0; // 2.0 parts have 16 bool ps registers
|
|
}
|
|
|
|
if ( pCaps->m_SupportsPixelShaders )
|
|
{
|
|
if ( pCaps->m_SupportsPixelShaders_2_0 )
|
|
{
|
|
pCaps->m_NumPixelShaderConstants = 32;
|
|
}
|
|
else
|
|
{
|
|
pCaps->m_NumPixelShaderConstants = 8;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pCaps->m_NumPixelShaderConstants = 0;
|
|
}
|
|
|
|
pCaps->m_SupportsHardwareLighting = (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) != 0;
|
|
|
|
pCaps->m_MaxNumLights = caps.MaxActiveLights;
|
|
if ( pCaps->m_MaxNumLights > MAX_NUM_LIGHTS )
|
|
{
|
|
pCaps->m_MaxNumLights = MAX_NUM_LIGHTS;
|
|
}
|
|
|
|
if ( IsOpenGL() )
|
|
{
|
|
// Set according to control flow bit on OpenGL
|
|
pCaps->m_MaxNumLights = MIN( pCaps->m_MaxNumLights, ( pCaps->m_bSupportsStaticControlFlow && pCaps->m_SupportsPixelShaders_2_b ) ? MAX_NUM_LIGHTS : ( MAX_NUM_LIGHTS - 2 ) );
|
|
}
|
|
|
|
if ( pCaps->m_bSoftwareVertexProcessing )
|
|
{
|
|
pCaps->m_SupportsHardwareLighting = true;
|
|
pCaps->m_MaxNumLights = 2;
|
|
}
|
|
pCaps->m_MaxTextureWidth = caps.MaxTextureWidth;
|
|
pCaps->m_MaxTextureHeight = caps.MaxTextureHeight;
|
|
pCaps->m_MaxTextureDepth = caps.MaxVolumeExtent ? caps.MaxVolumeExtent : 1;
|
|
pCaps->m_MaxTextureAspectRatio = caps.MaxTextureAspectRatio;
|
|
if ( pCaps->m_MaxTextureAspectRatio == 0 )
|
|
{
|
|
pCaps->m_MaxTextureAspectRatio = max( pCaps->m_MaxTextureWidth, pCaps->m_MaxTextureHeight);
|
|
}
|
|
pCaps->m_MaxPrimitiveCount = caps.MaxPrimitiveCount;
|
|
pCaps->m_MaxBlendMatrices = caps.MaxVertexBlendMatrices;
|
|
pCaps->m_MaxBlendMatrixIndices = caps.MaxVertexBlendMatrixIndex;
|
|
|
|
bool addSupported = (caps.TextureOpCaps & D3DTEXOPCAPS_ADD) != 0;
|
|
bool modSupported = (caps.TextureOpCaps & D3DTEXOPCAPS_MODULATE2X) != 0;
|
|
|
|
pCaps->m_bNeedsATICentroidHack = false;
|
|
pCaps->m_bDisableShaderOptimizations = false;
|
|
|
|
pCaps->m_SupportsMipmapping = true;
|
|
pCaps->m_SupportsOverbright = true;
|
|
|
|
// Thank you to all you driver writers who actually correctly return caps
|
|
if ( !modSupported || !addSupported )
|
|
{
|
|
Assert( 0 );
|
|
pCaps->m_SupportsOverbright = false;
|
|
}
|
|
|
|
// Check if ZBias and SlopeScaleDepthBias are supported. .if not, tweak the projection matrix instead
|
|
// for polyoffset.
|
|
pCaps->m_ZBiasAndSlopeScaledDepthBiasSupported =
|
|
( ( caps.RasterCaps & D3DPRASTERCAPS_DEPTHBIAS) != 0 ) &&
|
|
( ( caps.RasterCaps & D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS ) != 0 );
|
|
if ( IsX360() )
|
|
{
|
|
// driver lies, force it
|
|
pCaps->m_ZBiasAndSlopeScaledDepthBiasSupported = true;
|
|
}
|
|
|
|
// Spheremapping supported?
|
|
pCaps->m_bSupportsSpheremapping = (caps.VertexProcessingCaps & D3DVTXPCAPS_TEXGEN_SPHEREMAP) != 0;
|
|
|
|
// How many user clip planes?
|
|
pCaps->m_MaxUserClipPlanes = caps.MaxUserClipPlanes;
|
|
if ( CommandLine()->CheckParm( "-nouserclip" ) /* || (IsOpenGL() && (!CommandLine()->FindParm("-glslmode"))) || r_emulategl.GetBool() */ )
|
|
{
|
|
// rbarris 03Feb10: this now ignores POSIX / -glslmode / r_emulategl because we're defaulting GLSL mode "on".
|
|
// so this will mean that the engine will always ask for user clip planes.
|
|
// this will misbehave under ARB mode, since ARB shaders won't respect that state.
|
|
// it's difficult to make this fluid without teaching the engine about a cap that could change during run.
|
|
|
|
pCaps->m_MaxUserClipPlanes = 0;
|
|
}
|
|
|
|
if ( pCaps->m_MaxUserClipPlanes > MAXUSERCLIPPLANES )
|
|
{
|
|
pCaps->m_MaxUserClipPlanes = MAXUSERCLIPPLANES;
|
|
}
|
|
|
|
pCaps->m_FakeSRGBWrite = false;
|
|
pCaps->m_CanDoSRGBReadFromRTs = true;
|
|
pCaps->m_bSupportsGLMixedSizeTargets = false;
|
|
#ifdef DX_TO_GL_ABSTRACTION
|
|
// using #if because we're referencing fields in the RHS which don't exist in Windows headers for the caps9 struct
|
|
pCaps->m_FakeSRGBWrite = caps.FakeSRGBWrite != 0;
|
|
pCaps->m_CanDoSRGBReadFromRTs = caps.CanDoSRGBReadFromRTs != 0;
|
|
pCaps->m_bSupportsGLMixedSizeTargets = caps.MixedSizeTargets != 0;
|
|
#endif
|
|
|
|
// Query for SRGB support as needed for our DX 9 stuff
|
|
if ( IsPC() || !IsX360() )
|
|
{
|
|
pCaps->m_SupportsSRGB = ( D3D()->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_SRGBREAD, D3DRTYPE_TEXTURE, D3DFMT_DXT1 ) == S_OK);
|
|
|
|
if ( pCaps->m_SupportsSRGB )
|
|
{
|
|
pCaps->m_SupportsSRGB = ( D3D()->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_SRGBREAD | D3DUSAGE_QUERY_SRGBWRITE, D3DRTYPE_TEXTURE, D3DFMT_A8R8G8B8 ) == S_OK);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// 360 does support it, but is queried in the wrong manner, so force it
|
|
pCaps->m_SupportsSRGB = true;
|
|
}
|
|
|
|
if ( CommandLine()->CheckParm( "-nosrgb" ) )
|
|
{
|
|
pCaps->m_SupportsSRGB = false;
|
|
}
|
|
|
|
pCaps->m_bSupportsVertexTextures = ( D3D()->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, D3DFMT_X8R8G8B8,
|
|
D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R32F ) == S_OK );
|
|
|
|
if ( IsOpenGL() )
|
|
{
|
|
pCaps->m_bSupportsVertexTextures = false;
|
|
}
|
|
|
|
// FIXME: vs30 has a fixed setting here at 4.
|
|
// Future hardware will need some other way of computing this.
|
|
pCaps->m_nVertexTextureCount = pCaps->m_bSupportsVertexTextures ? 4 : 0;
|
|
|
|
// FIXME: How do I actually compute this?
|
|
pCaps->m_nMaxVertexTextureDimension = pCaps->m_bSupportsVertexTextures ? 4096 : 0;
|
|
|
|
// Does the device support filterable int16 textures?
|
|
bool bSupportsInteger16Textures =
|
|
( D3D()->CheckDeviceFormat( nAdapter, DX8_DEVTYPE,
|
|
D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_FILTER,
|
|
D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16 ) == S_OK );
|
|
|
|
// Does the device support filterable fp16 textures?
|
|
bool bSupportsFloat16Textures =
|
|
( D3D()->CheckDeviceFormat( nAdapter, DX8_DEVTYPE,
|
|
D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_FILTER,
|
|
D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F ) == S_OK );
|
|
|
|
// Does the device support blendable fp16 render targets?
|
|
bool bSupportsFloat16RenderTargets =
|
|
( D3D()->CheckDeviceFormat( nAdapter, DX8_DEVTYPE,
|
|
D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING | D3DUSAGE_RENDERTARGET,
|
|
D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F ) == S_OK );
|
|
|
|
// Essentially a proxy for a DX10 device running DX9 code path
|
|
pCaps->m_bSupportsFloat32RenderTargets = ( D3D()->CheckDeviceFormat( nAdapter, DX8_DEVTYPE,
|
|
D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING | D3DUSAGE_RENDERTARGET,
|
|
D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F ) == S_OK );
|
|
|
|
pCaps->m_bFogColorSpecifiedInLinearSpace = false;
|
|
pCaps->m_bFogColorAlwaysLinearSpace = false;
|
|
|
|
// Assume not DX10. Check below.
|
|
pCaps->m_bDX10Card = false;
|
|
pCaps->m_bDX10Blending = false;
|
|
|
|
if ( IsOpenGL() && ( pCaps->m_VendorID == 1 ) )
|
|
{
|
|
// Linux/Win OpenGL - always assume the device supports DX10 style blending
|
|
pCaps->m_bFogColorAlwaysLinearSpace = true;
|
|
pCaps->m_bDX10Card = true;
|
|
pCaps->m_bDX10Blending = true;
|
|
}
|
|
|
|
// NVidia wants fog color to be specified in linear space
|
|
if ( IsPC() && pCaps->m_SupportsSRGB )
|
|
{
|
|
if ( pCaps->m_VendorID == VENDORID_NVIDIA )
|
|
{
|
|
pCaps->m_bFogColorSpecifiedInLinearSpace = true;
|
|
|
|
if ( IsOpenGL() )
|
|
{
|
|
// If we're not the Quadro 4500 or GeForce 7x000, we're an NVIDIA DX10 part on MacOS
|
|
if ( !( (pCaps->m_DeviceID == 0x009d) || ( (pCaps->m_DeviceID >= 0x0391) && (pCaps->m_DeviceID <= 0x0395) ) ) )
|
|
{
|
|
pCaps->m_bFogColorAlwaysLinearSpace = true;
|
|
pCaps->m_bDX10Card = true;
|
|
pCaps->m_bDX10Blending = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// On G80 and later, always specify in linear space
|
|
if ( pCaps->m_bSupportsFloat32RenderTargets )
|
|
{
|
|
pCaps->m_bFogColorAlwaysLinearSpace = true;
|
|
pCaps->m_bDX10Card = true;
|
|
pCaps->m_bDX10Blending = true;
|
|
}
|
|
}
|
|
}
|
|
else if ( pCaps->m_VendorID == VENDORID_ATI )
|
|
{
|
|
if ( IsOpenGL() )
|
|
{
|
|
// If we're not a Radeon X1x00 (device IDs in this range), we're a DX10 chip
|
|
if ( !( (pCaps->m_DeviceID >= 0x7109) && (pCaps->m_DeviceID <= 0x7291) ) )
|
|
{
|
|
pCaps->m_bFogColorSpecifiedInLinearSpace = true;
|
|
pCaps->m_bFogColorAlwaysLinearSpace = true;
|
|
pCaps->m_bDX10Card = true;
|
|
pCaps->m_bDX10Blending = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Check for DX10 part
|
|
pCaps->m_bDX10Card = pCaps->m_SupportsShaderModel_3_0 &&
|
|
( pCaps->m_MaxVertexShader30InstructionSlots > 1024 ) &&
|
|
( pCaps->m_MaxPixelShader30InstructionSlots > 512 ) ;
|
|
|
|
// On ATI, DX10 card means DX10 blending
|
|
pCaps->m_bDX10Blending = pCaps->m_bDX10Card;
|
|
|
|
if( pCaps->m_bDX10Blending )
|
|
{
|
|
pCaps->m_bFogColorSpecifiedInLinearSpace = true;
|
|
pCaps->m_bFogColorAlwaysLinearSpace = true;
|
|
}
|
|
}
|
|
}
|
|
else if ( pCaps->m_VendorID == VENDORID_INTEL )
|
|
{
|
|
// Intel does not have performant vertex textures
|
|
pCaps->m_bDX10Card = false;
|
|
|
|
// Intel supports DX10 SRGB on Broadwater and better
|
|
// The two checks are for devices from GMA generation (0x29A2-0x2A43) and HD graphics (0x0042-0x2500)
|
|
pCaps->m_bDX10Blending = ( ( pCaps->m_DeviceID >= 0x29A2 ) && ( pCaps->m_DeviceID <= 0x2A43 ) ) ||
|
|
( ( pCaps->m_DeviceID >= 0x0042 ) && ( pCaps->m_DeviceID <= 0x2500 ) );
|
|
|
|
if( pCaps->m_bDX10Blending )
|
|
{
|
|
pCaps->m_bFogColorSpecifiedInLinearSpace = true;
|
|
pCaps->m_bFogColorAlwaysLinearSpace = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Do we have everything necessary to run with integer HDR? Note that
|
|
// even if we don't support integer 16-bit/component textures, we
|
|
// can still run in this mode if fp16 textures are supported.
|
|
bool bSupportsIntegerHDR = pCaps->m_SupportsPixelShaders_2_0 &&
|
|
pCaps->m_SupportsVertexShaders_2_0 &&
|
|
// (caps.Caps3 & D3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD) &&
|
|
// (caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND) &&
|
|
( bSupportsInteger16Textures || bSupportsFloat16Textures ) &&
|
|
pCaps->m_SupportsSRGB;
|
|
|
|
// Do we have everything necessary to run with float HDR?
|
|
bool bSupportsFloatHDR = pCaps->m_SupportsShaderModel_3_0 &&
|
|
// (caps.Caps3 & D3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD) &&
|
|
// (caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND) &&
|
|
bSupportsFloat16Textures &&
|
|
bSupportsFloat16RenderTargets &&
|
|
pCaps->m_SupportsSRGB &&
|
|
!IsX360();
|
|
|
|
pCaps->m_MaxHDRType = HDR_TYPE_NONE;
|
|
if ( bSupportsFloatHDR )
|
|
pCaps->m_MaxHDRType = HDR_TYPE_FLOAT;
|
|
else
|
|
if ( bSupportsIntegerHDR )
|
|
pCaps->m_MaxHDRType = HDR_TYPE_INTEGER;
|
|
|
|
if ( bSupportsFloatHDR && ( mat_hdr_level.GetInt() == 3 ) )
|
|
{
|
|
pCaps->m_HDRType = HDR_TYPE_FLOAT;
|
|
}
|
|
else if ( bSupportsIntegerHDR )
|
|
{
|
|
pCaps->m_HDRType = HDR_TYPE_INTEGER;
|
|
}
|
|
else
|
|
{
|
|
pCaps->m_HDRType = HDR_TYPE_NONE;
|
|
}
|
|
|
|
pCaps->m_bColorOnSecondStream = caps.MaxStreams > 1;
|
|
|
|
pCaps->m_bSupportsStreamOffset = ( ( caps.DevCaps2 & D3DDEVCAPS2_STREAMOFFSET ) && // Tie these caps together since we want to filter out
|
|
pCaps->m_SupportsPixelShaders_2_0 ); // any DX8 parts which export D3DDEVCAPS2_STREAMOFFSET
|
|
|
|
pCaps->m_flMinGammaControlPoint = 0.0f;
|
|
pCaps->m_flMaxGammaControlPoint = 65535.0f;
|
|
pCaps->m_nGammaControlPointCount = 256;
|
|
|
|
// Compute the effective DX support level based on all the other caps
|
|
ComputeDXSupportLevel( *pCaps );
|
|
int nCmdlineMaxDXLevel = CommandLine()->ParmValue( "-maxdxlevel", 0 );
|
|
if ( IsOpenGL() && ( nCmdlineMaxDXLevel > 0 ) )
|
|
{
|
|
// Prevent customers from slamming us below DX level 90 in OpenGL mode.
|
|
nCmdlineMaxDXLevel = MAX( nCmdlineMaxDXLevel, 90 );
|
|
}
|
|
if( nCmdlineMaxDXLevel > 0 )
|
|
{
|
|
pCaps->m_nMaxDXSupportLevel = min( pCaps->m_nMaxDXSupportLevel, nCmdlineMaxDXLevel );
|
|
}
|
|
pCaps->m_nDXSupportLevel = pCaps->m_nMaxDXSupportLevel;
|
|
|
|
int nModelIndex = pCaps->m_nDXSupportLevel < 90 ? VERTEX_SHADER_MODEL - 10 : VERTEX_SHADER_MODEL;
|
|
pCaps->m_MaxVertexShaderBlendMatrices = (pCaps->m_NumVertexShaderConstants - nModelIndex) / 3;
|
|
|
|
if ( pCaps->m_MaxVertexShaderBlendMatrices > NUM_MODEL_TRANSFORMS )
|
|
{
|
|
pCaps->m_MaxVertexShaderBlendMatrices = NUM_MODEL_TRANSFORMS;
|
|
}
|
|
|
|
CheckBorderColorSupport( pCaps, nAdapter );
|
|
|
|
// This may get more complex if we start using multiple flavors of compressed vertex - for now it's "on or off"
|
|
pCaps->m_SupportsCompressedVertices = ( pCaps->m_nDXSupportLevel >= 90 ) && ( pCaps->m_CanDoSRGBReadFromRTs ) ? VERTEX_COMPRESSION_ON : VERTEX_COMPRESSION_NONE;
|
|
if ( CommandLine()->CheckParm( "-no_compressed_verts" ) ) // m_CanDoSRGBReadFromRTs limits us to Snow Leopard or later on OSX
|
|
{
|
|
pCaps->m_SupportsCompressedVertices = VERTEX_COMPRESSION_NONE;
|
|
}
|
|
|
|
// Various vendor-dependent checks...
|
|
CheckVendorDependentAlphaToCoverage( pCaps, nAdapter );
|
|
CheckVendorDependentShadowMappingSupport( pCaps, nAdapter );
|
|
|
|
// If we're not on a 3.0 part, these values are more appropriate (X800 & X850 parts from ATI do shadow mapping but not 3.0 )
|
|
if ( !IsOpenGL() )
|
|
{
|
|
if ( !pCaps->m_SupportsShaderModel_3_0 )
|
|
{
|
|
mat_slopescaledepthbias_shadowmap.SetValue( 5.9f );
|
|
mat_depthbias_shadowmap.SetValue( 0.003f );
|
|
}
|
|
}
|
|
|
|
if( pCaps->m_MaxUserClipPlanes == 0 )
|
|
{
|
|
pCaps->m_UseFastClipping = true;
|
|
}
|
|
|
|
pCaps->m_MaxSimultaneousRenderTargets = caps.NumSimultaneousRTs;
|
|
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Compute the effective DX support level based on all the other caps
|
|
//-----------------------------------------------------------------------------
|
|
void CShaderDeviceMgrDx8::ComputeDXSupportLevel( HardwareCaps_t &caps )
|
|
{
|
|
// NOTE: Support level is actually DX level * 10 + subversion
|
|
// So, 70 = DX7, 80 = DX8, 81 = DX8 w/ 1.4 pixel shaders
|
|
// 90 = DX9 w/ 2.0 pixel shaders
|
|
// 95 = DX9 w/ 3.0 pixel shaders and vertex textures
|
|
// 98 = DX9 XBox360
|
|
// NOTE: 82 = NVidia nv3x cards, which can't run dx9 fast
|
|
|
|
// FIXME: Improve this!! There should be a whole list of features
|
|
// we require in order to be considered a DX7 board, DX8 board, etc.
|
|
|
|
if ( IsX360() )
|
|
{
|
|
caps.m_nMaxDXSupportLevel = 98;
|
|
return;
|
|
}
|
|
|
|
bool bIsOpenGL = IsOpenGL();
|
|
|
|
if ( caps.m_SupportsShaderModel_3_0 && !bIsOpenGL ) // Note that we don't tie vertex textures to 30 shaders anymore
|
|
{
|
|
caps.m_nMaxDXSupportLevel = 95;
|
|
return;
|
|
}
|
|
|
|
// NOTE: sRGB is currently required for DX90 because it isn't doing
|
|
// gamma correctly if that feature doesn't exist
|
|
if ( caps.m_SupportsVertexShaders_2_0 && caps.m_SupportsPixelShaders_2_0 && caps.m_SupportsSRGB )
|
|
{
|
|
caps.m_nMaxDXSupportLevel = 90;
|
|
return;
|
|
}
|
|
|
|
if ( caps.m_SupportsPixelShaders && caps.m_SupportsVertexShaders )// && caps.m_bColorOnSecondStream)
|
|
{
|
|
if (caps.m_SupportsPixelShaders_1_4)
|
|
{
|
|
caps.m_nMaxDXSupportLevel = 81;
|
|
return;
|
|
}
|
|
caps.m_nMaxDXSupportLevel = 80;
|
|
return;
|
|
}
|
|
|
|
if( caps.m_SupportsCubeMaps && ( caps.m_MaxBlendMatrices >= 2 ) )
|
|
{
|
|
caps.m_nMaxDXSupportLevel = 70;
|
|
return;
|
|
}
|
|
|
|
if ( ( caps.m_NumSamplers >= 2) && caps.m_SupportsMipmapping )
|
|
{
|
|
caps.m_nMaxDXSupportLevel = 60;
|
|
return;
|
|
}
|
|
|
|
Assert( 0 );
|
|
// we don't support this!
|
|
caps.m_nMaxDXSupportLevel = 50;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Gets the number of adapters...
|
|
//-----------------------------------------------------------------------------
|
|
int CShaderDeviceMgrDx8::GetAdapterCount() const
|
|
{
|
|
// FIXME: Remove call to InitAdapterInfo once Steam startup issues are resolved.
|
|
const_cast<CShaderDeviceMgrDx8*>( this )->InitAdapterInfo();
|
|
|
|
return m_Adapters.Count();
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Returns info about each adapter
|
|
//-----------------------------------------------------------------------------
|
|
void CShaderDeviceMgrDx8::GetAdapterInfo( int nAdapter, MaterialAdapterInfo_t& info ) const
|
|
{
|
|
// FIXME: Remove call to InitAdapterInfo once Steam startup issues are resolved.
|
|
const_cast<CShaderDeviceMgrDx8*>( this )->InitAdapterInfo();
|
|
|
|
Assert( ( nAdapter >= 0 ) && ( nAdapter < m_Adapters.Count() ) );
|
|
const HardwareCaps_t &caps = m_Adapters[ nAdapter ].m_ActualCaps;
|
|
memcpy( &info, &caps, sizeof(MaterialAdapterInfo_t) );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Sets the adapter
|
|
//-----------------------------------------------------------------------------
|
|
bool CShaderDeviceMgrDx8::SetAdapter( int nAdapter, int nAdapterFlags )
|
|
{
|
|
LOCK_SHADERAPI();
|
|
|
|
// FIXME:
|
|
// g_pShaderDeviceDx8->m_bReadPixelsEnabled = (nAdapterFlags & MATERIAL_INIT_READ_PIXELS_ENABLED) != 0;
|
|
|
|
// Set up hardware information for this adapter...
|
|
g_pShaderDeviceDx8->m_DeviceType = (nAdapterFlags & MATERIAL_INIT_REFERENCE_RASTERIZER) ?
|
|
D3DDEVTYPE_REF : D3DDEVTYPE_HAL;
|
|
|
|
g_pShaderDeviceDx8->m_DisplayAdapter = nAdapter;
|
|
if ( g_pShaderDeviceDx8->m_DisplayAdapter >= (UINT)GetAdapterCount() )
|
|
{
|
|
g_pShaderDeviceDx8->m_DisplayAdapter = 0;
|
|
}
|
|
|
|
#ifdef NVPERFHUD
|
|
// hack for nvperfhud
|
|
g_pShaderDeviceDx8->m_DisplayAdapter = m_pD3D->GetAdapterCount() - 1;
|
|
g_pShaderDeviceDx8->m_DeviceType = D3DDEVTYPE_REF;
|
|
#endif
|
|
|
|
// backward compat
|
|
if ( !g_pShaderDeviceDx8->OnAdapterSet() )
|
|
return false;
|
|
|
|
// if ( !g_pShaderDeviceDx8->Init() )
|
|
// {
|
|
// Warning( "Unable to initialize dx8 device!\n" );
|
|
// return false;
|
|
// }
|
|
|
|
g_pShaderDevice = g_pShaderDeviceDx8;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Returns the number of modes
|
|
//-----------------------------------------------------------------------------
|
|
int CShaderDeviceMgrDx8::GetModeCount( int nAdapter ) const
|
|
{
|
|
LOCK_SHADERAPI();
|
|
Assert( m_pD3D && (nAdapter < GetAdapterCount() ) );
|
|
|
|
#if !defined( _X360 )
|
|
// fixme - what format should I use here?
|
|
return m_pD3D->GetAdapterModeCount( nAdapter, D3DFMT_X8R8G8B8 );
|
|
#else
|
|
return 1; // Only one mode, which is the current mode set in the 360 dashboard. Going to fill it in with exactly what the 360 is set to.
|
|
#endif
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Returns mode information..
|
|
//-----------------------------------------------------------------------------
|
|
void CShaderDeviceMgrDx8::GetModeInfo( ShaderDisplayMode_t* pInfo, int nAdapter, int nMode ) const
|
|
{
|
|
Assert( pInfo->m_nVersion == SHADER_DISPLAY_MODE_VERSION );
|
|
|
|
LOCK_SHADERAPI();
|
|
Assert( m_pD3D && (nAdapter < GetAdapterCount() ) );
|
|
Assert( nMode < GetModeCount( nAdapter ) );
|
|
|
|
#if !defined( _X360 )
|
|
HRESULT hr;
|
|
D3DDISPLAYMODE d3dInfo;
|
|
|
|
// fixme - what format should I use here?
|
|
hr = D3D()->EnumAdapterModes( nAdapter, D3DFMT_X8R8G8B8, nMode, &d3dInfo );
|
|
Assert( !FAILED(hr) );
|
|
|
|
pInfo->m_nWidth = d3dInfo.Width;
|
|
pInfo->m_nHeight = d3dInfo.Height;
|
|
pInfo->m_Format = ImageLoader::D3DFormatToImageFormat( d3dInfo.Format );
|
|
pInfo->m_nRefreshRateNumerator = d3dInfo.RefreshRate;
|
|
pInfo->m_nRefreshRateDenominator = 1;
|
|
#else
|
|
pInfo->m_Format = ImageLoader::D3DFormatToImageFormat( D3DFMT_X8R8G8B8 );
|
|
pInfo->m_nRefreshRateNumerator = 60;
|
|
pInfo->m_nRefreshRateDenominator = 1;
|
|
|
|
pInfo->m_nWidth = GetSystemMetrics( SM_CXSCREEN );
|
|
pInfo->m_nHeight = GetSystemMetrics( SM_CYSCREEN );
|
|
#endif
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Returns the current mode information for an adapter
|
|
//-----------------------------------------------------------------------------
|
|
void CShaderDeviceMgrDx8::GetCurrentModeInfo( ShaderDisplayMode_t* pInfo, int nAdapter ) const
|
|
{
|
|
Assert( pInfo->m_nVersion == SHADER_DISPLAY_MODE_VERSION );
|
|
|
|
LOCK_SHADERAPI();
|
|
Assert( D3D() );
|
|
|
|
HRESULT hr;
|
|
D3DDISPLAYMODE mode = { 0 };
|
|
#if !defined( _X360 )
|
|
hr = D3D()->GetAdapterDisplayMode( nAdapter, &mode );
|
|
Assert( !FAILED(hr) );
|
|
#else
|
|
if ( !g_pD3DDevice )
|
|
{
|
|
// the console has no prior display or mode until its created
|
|
mode.Width = GetSystemMetrics( SM_CXSCREEN );
|
|
mode.Height = GetSystemMetrics( SM_CYSCREEN );
|
|
mode.RefreshRate = 60;
|
|
mode.Format = D3DFMT_X8R8G8B8;
|
|
}
|
|
else
|
|
{
|
|
hr = g_pD3DDevice->GetDisplayMode( 0, &mode );
|
|
Assert( !FAILED(hr) );
|
|
}
|
|
#endif
|
|
|
|
pInfo->m_nWidth = mode.Width;
|
|
pInfo->m_nHeight = mode.Height;
|
|
pInfo->m_Format = ImageLoader::D3DFormatToImageFormat( mode.Format );
|
|
pInfo->m_nRefreshRateNumerator = mode.RefreshRate;
|
|
pInfo->m_nRefreshRateDenominator = 1;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Sets the video mode
|
|
//-----------------------------------------------------------------------------
|
|
CreateInterfaceFn CShaderDeviceMgrDx8::SetMode( void *hWnd, int nAdapter, const ShaderDeviceInfo_t& mode )
|
|
{
|
|
LOCK_SHADERAPI();
|
|
|
|
Assert( nAdapter < GetAdapterCount() );
|
|
int nDXLevel = mode.m_nDXLevel != 0 ? mode.m_nDXLevel : m_Adapters[nAdapter].m_ActualCaps.m_nDXSupportLevel;
|
|
if ( m_bObeyDxCommandlineOverride )
|
|
{
|
|
nDXLevel = CommandLine()->ParmValue( "-dxlevel", nDXLevel );
|
|
m_bObeyDxCommandlineOverride = false;
|
|
}
|
|
if ( nDXLevel > m_Adapters[nAdapter].m_ActualCaps.m_nMaxDXSupportLevel )
|
|
{
|
|
nDXLevel = m_Adapters[nAdapter].m_ActualCaps.m_nMaxDXSupportLevel;
|
|
}
|
|
nDXLevel = GetClosestActualDXLevel( nDXLevel );
|
|
|
|
if ( nDXLevel >= 100 )
|
|
return NULL;
|
|
|
|
bool bReacquireResourcesNeeded = false;
|
|
if ( g_pShaderDevice )
|
|
{
|
|
bReacquireResourcesNeeded = IsPC();
|
|
g_pShaderDevice->ReleaseResources();
|
|
}
|
|
|
|
if ( g_pShaderAPI )
|
|
{
|
|
g_pShaderAPI->OnDeviceShutdown();
|
|
g_pShaderAPI = NULL;
|
|
}
|
|
|
|
if ( g_pShaderDevice )
|
|
{
|
|
g_pShaderDevice->ShutdownDevice();
|
|
g_pShaderDevice = NULL;
|
|
}
|
|
|
|
g_pShaderShadow = NULL;
|
|
|
|
ShaderDeviceInfo_t adjustedMode = mode;
|
|
adjustedMode.m_nDXLevel = nDXLevel;
|
|
if ( !g_pShaderDeviceDx8->InitDevice( hWnd, nAdapter, adjustedMode ) )
|
|
return NULL;
|
|
|
|
if ( !g_pShaderAPIDX8->OnDeviceInit() )
|
|
return NULL;
|
|
|
|
g_pShaderDevice = g_pShaderDeviceDx8;
|
|
g_pShaderAPI = g_pShaderAPIDX8;
|
|
g_pShaderShadow = g_pShaderShadowDx8;
|
|
|
|
if ( bReacquireResourcesNeeded )
|
|
{
|
|
g_pShaderDevice->ReacquireResources();
|
|
}
|
|
|
|
return ShaderInterfaceFactory;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Validates the mode...
|
|
//-----------------------------------------------------------------------------
|
|
bool CShaderDeviceMgrDx8::ValidateMode( int nAdapter, const ShaderDeviceInfo_t &info ) const
|
|
{
|
|
if ( nAdapter >= (int)D3D()->GetAdapterCount() )
|
|
return false;
|
|
|
|
ShaderDisplayMode_t displayMode;
|
|
|
|
if ( info.m_bWindowed )
|
|
{
|
|
// windowed mode always appears on the primary display, so we should use that adapter's
|
|
// settings
|
|
GetCurrentModeInfo( &displayMode, 0 );
|
|
|
|
// make sure the window fits within the current video mode
|
|
if ( ( info.m_DisplayMode.m_nWidth > displayMode.m_nWidth ) ||
|
|
( info.m_DisplayMode.m_nHeight > displayMode.m_nHeight ) )
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
GetCurrentModeInfo( &displayMode, nAdapter );
|
|
}
|
|
|
|
// Make sure the image format requested is valid
|
|
ImageFormat backBufferFormat = FindNearestSupportedBackBufferFormat( nAdapter,
|
|
DX8_DEVTYPE, displayMode.m_Format, info.m_DisplayMode.m_Format, info.m_bWindowed );
|
|
return ( backBufferFormat != IMAGE_FORMAT_UNKNOWN );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Returns the amount of video memory in bytes for a particular adapter
|
|
//-----------------------------------------------------------------------------
|
|
int CShaderDeviceMgrDx8::GetVidMemBytes( int nAdapter ) const
|
|
{
|
|
#if defined( _X360 )
|
|
return 256*1024*1024;
|
|
#elif defined (DX_TO_GL_ABSTRACTION)
|
|
D3DADAPTER_IDENTIFIER9 devIndentifier;
|
|
D3D()->GetAdapterIdentifier( nAdapter, D3DENUM_WHQL_LEVEL, &devIndentifier );
|
|
return devIndentifier.VideoMemory;
|
|
#else
|
|
// FIXME: This currently ignores the adapter
|
|
uint64 nBytes = ::GetVidMemBytes();
|
|
if ( nBytes > INT_MAX )
|
|
return INT_MAX;
|
|
return nBytes;
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Shader device
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#if 0
|
|
// FIXME: Enable after I've separated it out from shaderapidx8 a little better
|
|
static CShaderDeviceDx8 s_ShaderDeviceDX8;
|
|
CShaderDeviceDx8* g_pShaderDeviceDx8 = &s_ShaderDeviceDX8;
|
|
#endif
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Constructor, destructor
|
|
//-----------------------------------------------------------------------------
|
|
CShaderDeviceDx8::CShaderDeviceDx8()
|
|
{
|
|
g_pD3DDevice = NULL;
|
|
for ( int i = 0; i < ARRAYSIZE(m_pFrameSyncQueryObject); i++ )
|
|
{
|
|
m_pFrameSyncQueryObject[i] = NULL;
|
|
m_bQueryIssued[i] = false;
|
|
}
|
|
m_pFrameSyncTexture = NULL;
|
|
m_bQueuedDeviceLost = false;
|
|
m_DeviceState = DEVICE_STATE_OK;
|
|
m_bOtherAppInitializing = false;
|
|
m_IsResizing = false;
|
|
m_bPendingVideoModeChange = false;
|
|
m_DeviceSupportsCreateQuery = -1;
|
|
m_bUsingStencil = false;
|
|
m_bResourcesReleased = false;
|
|
m_iStencilBufferBits = 0;
|
|
m_NonInteractiveRefresh.m_Mode = MATERIAL_NON_INTERACTIVE_MODE_NONE;
|
|
m_NonInteractiveRefresh.m_pVertexShader = NULL;
|
|
m_NonInteractiveRefresh.m_pPixelShader = NULL;
|
|
m_NonInteractiveRefresh.m_pPixelShaderStartup = NULL;
|
|
m_NonInteractiveRefresh.m_pPixelShaderStartupPass2 = NULL;
|
|
m_NonInteractiveRefresh.m_pVertexDecl = NULL;
|
|
m_NonInteractiveRefresh.m_nPacifierFrame = 0;
|
|
m_numReleaseResourcesRefCount = 0;
|
|
}
|
|
|
|
CShaderDeviceDx8::~CShaderDeviceDx8()
|
|
{
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Computes device creation paramters
|
|
//-----------------------------------------------------------------------------
|
|
static DWORD ComputeDeviceCreationFlags( D3DCAPS& caps, bool bSoftwareVertexProcessing )
|
|
{
|
|
// Find out what type of device to make
|
|
bool bPureDeviceSupported = (caps.DevCaps & D3DDEVCAPS_PUREDEVICE) != 0;
|
|
|
|
DWORD nDeviceCreationFlags;
|
|
if ( !bSoftwareVertexProcessing )
|
|
{
|
|
nDeviceCreationFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING;
|
|
if ( bPureDeviceSupported )
|
|
{
|
|
nDeviceCreationFlags |= D3DCREATE_PUREDEVICE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nDeviceCreationFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
|
|
}
|
|
nDeviceCreationFlags |= D3DCREATE_FPU_PRESERVE;
|
|
|
|
#ifdef _X360
|
|
nDeviceCreationFlags |= D3DCREATE_BUFFER_2_FRAMES;
|
|
#endif
|
|
|
|
return nDeviceCreationFlags;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Computes the supersample flags
|
|
//-----------------------------------------------------------------------------
|
|
D3DMULTISAMPLE_TYPE CShaderDeviceDx8::ComputeMultisampleType( int nSampleCount )
|
|
{
|
|
switch (nSampleCount)
|
|
{
|
|
#if !defined( _X360 )
|
|
case 2: return D3DMULTISAMPLE_2_SAMPLES;
|
|
case 3: return D3DMULTISAMPLE_3_SAMPLES;
|
|
case 4: return D3DMULTISAMPLE_4_SAMPLES;
|
|
case 5: return D3DMULTISAMPLE_5_SAMPLES;
|
|
case 6: return D3DMULTISAMPLE_6_SAMPLES;
|
|
case 7: return D3DMULTISAMPLE_7_SAMPLES;
|
|
case 8: return D3DMULTISAMPLE_8_SAMPLES;
|
|
case 9: return D3DMULTISAMPLE_9_SAMPLES;
|
|
case 10: return D3DMULTISAMPLE_10_SAMPLES;
|
|
case 11: return D3DMULTISAMPLE_11_SAMPLES;
|
|
case 12: return D3DMULTISAMPLE_12_SAMPLES;
|
|
case 13: return D3DMULTISAMPLE_13_SAMPLES;
|
|
case 14: return D3DMULTISAMPLE_14_SAMPLES;
|
|
case 15: return D3DMULTISAMPLE_15_SAMPLES;
|
|
case 16: return D3DMULTISAMPLE_16_SAMPLES;
|
|
#else
|
|
case 2: return D3DMULTISAMPLE_2_SAMPLES;
|
|
case 4: return D3DMULTISAMPLE_4_SAMPLES;
|
|
#endif
|
|
default:
|
|
case 0:
|
|
case 1:
|
|
return D3DMULTISAMPLE_NONE;
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Sets the present parameters
|
|
//-----------------------------------------------------------------------------
|
|
void CShaderDeviceDx8::SetPresentParameters( void* hWnd, int nAdapter, const ShaderDeviceInfo_t &info )
|
|
{
|
|
ShaderDisplayMode_t mode;
|
|
g_pShaderDeviceMgr->GetCurrentModeInfo( &mode, nAdapter );
|
|
|
|
HRESULT hr;
|
|
ZeroMemory( &m_PresentParameters, sizeof(m_PresentParameters) );
|
|
|
|
m_PresentParameters.Windowed = info.m_bWindowed;
|
|
m_PresentParameters.SwapEffect = info.m_bUsingMultipleWindows ? D3DSWAPEFFECT_COPY : D3DSWAPEFFECT_DISCARD;
|
|
|
|
// for 360, we want to create it ourselves for hierarchical z support
|
|
m_PresentParameters.EnableAutoDepthStencil = IsX360() ? FALSE : TRUE;
|
|
|
|
// What back-buffer format should we use?
|
|
ImageFormat backBufferFormat = FindNearestSupportedBackBufferFormat( nAdapter,
|
|
DX8_DEVTYPE, m_AdapterFormat, info.m_DisplayMode.m_Format, info.m_bWindowed );
|
|
|
|
// What depth format should we use?
|
|
m_bUsingStencil = info.m_bUseStencil;
|
|
if ( info.m_nDXLevel >= 80 )
|
|
{
|
|
// always stencil for dx9/hdr
|
|
m_bUsingStencil = true;
|
|
}
|
|
#if defined( _X360 )
|
|
D3DFORMAT nDepthFormat = ReverseDepthOnX360() ? D3DFMT_D24FS8 : D3DFMT_D24S8;
|
|
#else
|
|
D3DFORMAT nDepthFormat = m_bUsingStencil ? D3DFMT_D24S8 : D3DFMT_D24X8;
|
|
#endif
|
|
m_PresentParameters.AutoDepthStencilFormat = FindNearestSupportedDepthFormat(
|
|
nAdapter, m_AdapterFormat, backBufferFormat, nDepthFormat );
|
|
m_PresentParameters.hDeviceWindow = (VD3DHWND)hWnd;
|
|
|
|
// store how many stencil buffer bits we have available with the depth/stencil buffer
|
|
switch( m_PresentParameters.AutoDepthStencilFormat )
|
|
{
|
|
case D3DFMT_D24S8:
|
|
m_iStencilBufferBits = 8;
|
|
break;
|
|
#if defined( _X360 )
|
|
case D3DFMT_D24FS8:
|
|
m_iStencilBufferBits = 8;
|
|
break;
|
|
#else
|
|
case D3DFMT_D24X4S4:
|
|
m_iStencilBufferBits = 4;
|
|
break;
|
|
case D3DFMT_D15S1:
|
|
m_iStencilBufferBits = 1;
|
|
break;
|
|
#endif
|
|
default:
|
|
m_iStencilBufferBits = 0;
|
|
m_bUsingStencil = false; //couldn't acquire a stencil buffer
|
|
};
|
|
|
|
if ( IsX360() || !info.m_bWindowed )
|
|
{
|
|
bool useDefault = ( info.m_DisplayMode.m_nWidth == 0 ) || ( info.m_DisplayMode.m_nHeight == 0 );
|
|
m_PresentParameters.BackBufferCount = 1;
|
|
m_PresentParameters.BackBufferWidth = useDefault ? mode.m_nWidth : info.m_DisplayMode.m_nWidth;
|
|
m_PresentParameters.BackBufferHeight = useDefault ? mode.m_nHeight : info.m_DisplayMode.m_nHeight;
|
|
m_PresentParameters.BackBufferFormat = ImageLoader::ImageFormatToD3DFormat( backBufferFormat );
|
|
#if defined( _X360 )
|
|
m_PresentParameters.FrontBufferFormat = D3DFMT_LE_X8R8G8B8;
|
|
#endif
|
|
if ( !info.m_bWaitForVSync || CommandLine()->FindParm( "-forcenovsync" ) )
|
|
{
|
|
m_PresentParameters.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
|
|
}
|
|
else
|
|
{
|
|
m_PresentParameters.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
|
|
}
|
|
|
|
m_PresentParameters.FullScreen_RefreshRateInHz = info.m_DisplayMode.m_nRefreshRateDenominator ?
|
|
info.m_DisplayMode.m_nRefreshRateNumerator / info.m_DisplayMode.m_nRefreshRateDenominator : D3DPRESENT_RATE_DEFAULT;
|
|
|
|
#if defined( _X360 )
|
|
XVIDEO_MODE videoMode;
|
|
XGetVideoMode( &videoMode );
|
|
|
|
// want 30 for 60Hz, and 25 for 50Hz (PAL)
|
|
int nNewFpsMax = ( ( int )( videoMode.RefreshRate + 0.5f ) ) >> 1;
|
|
// slam to either 30 or 25 so that we don't end up with any other cases.
|
|
if( nNewFpsMax < 26 )
|
|
{
|
|
nNewFpsMax = 25;
|
|
}
|
|
else
|
|
{
|
|
nNewFpsMax = 30;
|
|
}
|
|
DevMsg( "*******Monitor refresh is %f, setting fps_max to %d*********\n", videoMode.RefreshRate, nNewFpsMax );
|
|
ConVarRef fps_max( "fps_max" );
|
|
fps_max.SetValue( nNewFpsMax );
|
|
|
|
// setup hardware scaling - should be native 720p upsampling to 1080i
|
|
if ( info.m_bScaleToOutputResolution )
|
|
{
|
|
m_PresentParameters.VideoScalerParameters.ScalerSourceRect.x2 = m_PresentParameters.BackBufferWidth;
|
|
m_PresentParameters.VideoScalerParameters.ScalerSourceRect.y2 = m_PresentParameters.BackBufferHeight;
|
|
m_PresentParameters.VideoScalerParameters.ScaledOutputWidth = videoMode.dwDisplayWidth;
|
|
m_PresentParameters.VideoScalerParameters.ScaledOutputHeight = videoMode.dwDisplayHeight;
|
|
DevMsg( "VIDEO SCALING: scaling from %dx%d to %dx%d\n", ( int )m_PresentParameters.BackBufferWidth, ( int )m_PresentParameters.BackBufferHeight,
|
|
( int )videoMode.dwDisplayWidth, ( int )videoMode.dwDisplayHeight );
|
|
}
|
|
else
|
|
{
|
|
DevMsg( "VIDEO SCALING: No scaling: %dx%d\n", ( int )m_PresentParameters.BackBufferWidth, ( int )m_PresentParameters.BackBufferHeight );
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
// NJS: We are seeing a lot of time spent in present in some cases when this isn't set.
|
|
m_PresentParameters.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
|
|
if ( info.m_bResizing )
|
|
{
|
|
if ( info.m_bLimitWindowedSize &&
|
|
( info.m_nWindowedSizeLimitWidth < mode.m_nWidth || info.m_nWindowedSizeLimitHeight < mode.m_nHeight ) )
|
|
{
|
|
// When using material system in windowed resizing apps, it's
|
|
// sometimes not a good idea to allocate stuff as big as the screen
|
|
// video cards can soo run out of resources
|
|
m_PresentParameters.BackBufferWidth = info.m_nWindowedSizeLimitWidth;
|
|
m_PresentParameters.BackBufferHeight = info.m_nWindowedSizeLimitHeight;
|
|
}
|
|
else
|
|
{
|
|
// When in resizing windowed mode,
|
|
// we want to allocate enough memory to deal with any resizing...
|
|
m_PresentParameters.BackBufferWidth = mode.m_nWidth;
|
|
m_PresentParameters.BackBufferHeight = mode.m_nHeight;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_PresentParameters.BackBufferWidth = info.m_DisplayMode.m_nWidth;
|
|
m_PresentParameters.BackBufferHeight = info.m_DisplayMode.m_nHeight;
|
|
}
|
|
m_PresentParameters.BackBufferFormat = ImageLoader::ImageFormatToD3DFormat( backBufferFormat );
|
|
m_PresentParameters.BackBufferCount = 1;
|
|
}
|
|
|
|
if ( info.m_nAASamples > 0 && ( m_PresentParameters.SwapEffect == D3DSWAPEFFECT_DISCARD ) )
|
|
{
|
|
D3DMULTISAMPLE_TYPE multiSampleType = ComputeMultisampleType( info.m_nAASamples );
|
|
DWORD nQualityLevel;
|
|
|
|
// FIXME: Should we add the quality level to the ShaderAdapterMode_t struct?
|
|
// 16x on nVidia refers to CSAA or "Coverage Sampled Antialiasing"
|
|
const HardwareCaps_t &adapterCaps = g_ShaderDeviceMgrDx8.GetHardwareCaps( nAdapter );
|
|
if ( ( info.m_nAASamples == 16 ) && ( adapterCaps.m_VendorID == VENDORID_NVIDIA ) )
|
|
{
|
|
multiSampleType = ComputeMultisampleType(4);
|
|
hr = D3D()->CheckDeviceMultiSampleType( nAdapter, DX8_DEVTYPE,
|
|
m_PresentParameters.BackBufferFormat, m_PresentParameters.Windowed,
|
|
multiSampleType, &nQualityLevel ); // 4x at highest quality level
|
|
|
|
if ( !FAILED( hr ) && ( nQualityLevel == 16 ) )
|
|
{
|
|
nQualityLevel = nQualityLevel - 1; // Highest quality level triggers 16x CSAA
|
|
}
|
|
else
|
|
{
|
|
nQualityLevel = 0; // No CSAA
|
|
}
|
|
}
|
|
else // Regular MSAA on any old vendor
|
|
{
|
|
hr = D3D()->CheckDeviceMultiSampleType( nAdapter, DX8_DEVTYPE,
|
|
m_PresentParameters.BackBufferFormat, m_PresentParameters.Windowed,
|
|
multiSampleType, &nQualityLevel );
|
|
|
|
nQualityLevel = 0;
|
|
}
|
|
|
|
if ( !FAILED( hr ) )
|
|
{
|
|
m_PresentParameters.MultiSampleType = multiSampleType;
|
|
m_PresentParameters.MultiSampleQuality = nQualityLevel;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_PresentParameters.MultiSampleType = D3DMULTISAMPLE_NONE;
|
|
m_PresentParameters.MultiSampleQuality = 0;
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Initializes, shuts down the D3D device
|
|
//-----------------------------------------------------------------------------
|
|
bool CShaderDeviceDx8::InitDevice( void* hwnd, int nAdapter, const ShaderDeviceInfo_t &info )
|
|
{
|
|
//Debugger();
|
|
|
|
// good place to run some self tests.
|
|
//#if OSX
|
|
//{
|
|
// extern void GLMgrSelfTests( void );
|
|
// GLMgrSelfTests();
|
|
//}
|
|
//#endif
|
|
|
|
// windowed
|
|
if ( !CreateD3DDevice( (VD3DHWND)hwnd, nAdapter, info ) )
|
|
return false;
|
|
|
|
// Hook up our own windows proc to get at messages to tell us when
|
|
// other instances of the material system are trying to set the mode
|
|
InstallWindowHook( (VD3DHWND)m_hWnd );
|
|
return true;
|
|
}
|
|
|
|
void CShaderDeviceDx8::ShutdownDevice()
|
|
{
|
|
if ( IsPC() && IsActive() )
|
|
{
|
|
Dx9Device()->Release();
|
|
|
|
#ifdef STUBD3D
|
|
delete ( CStubD3DDevice * )Dx9Device();
|
|
#endif
|
|
|
|
g_pD3DDevice = NULL;
|
|
|
|
RemoveWindowHook( (VD3DHWND)m_hWnd );
|
|
m_hWnd = 0;
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Are we using graphics?
|
|
//-----------------------------------------------------------------------------
|
|
bool CShaderDeviceDx8::IsUsingGraphics() const
|
|
{
|
|
//*****LOCK_SHADERAPI();
|
|
return IsActive();
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Returns the current adapter in use
|
|
//-----------------------------------------------------------------------------
|
|
int CShaderDeviceDx8::GetCurrentAdapter() const
|
|
{
|
|
LOCK_SHADERAPI();
|
|
return m_DisplayAdapter;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Returns the current adapter in use
|
|
//-----------------------------------------------------------------------------
|
|
char *CShaderDeviceDx8::GetDisplayDeviceName()
|
|
{
|
|
if( m_sDisplayDeviceName.IsEmpty() )
|
|
{
|
|
D3DADAPTER_IDENTIFIER9 ident;
|
|
// On Win10, this function is getting called with m_nAdapter still initialized to -1.
|
|
// It's failing, and m_sDisplayDeviceName has garbage, and tf2 fails to launch.
|
|
// To repro this, run "hl2.exe -dev -fullscreen -game tf" on Win10.
|
|
HRESULT hr = D3D()->GetAdapterIdentifier( Max( m_nAdapter, 0 ), 0, &ident );
|
|
if ( FAILED(hr) )
|
|
{
|
|
Assert( false );
|
|
ident.DeviceName[0] = 0;
|
|
}
|
|
m_sDisplayDeviceName = ident.DeviceName;
|
|
}
|
|
return m_sDisplayDeviceName.GetForModify();
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Use this to spew information about the 3D layer
|
|
//-----------------------------------------------------------------------------
|
|
void CShaderDeviceDx8::SpewDriverInfo() const
|
|
{
|
|
LOCK_SHADERAPI();
|
|
HRESULT hr;
|
|
D3DCAPS caps;
|
|
D3DADAPTER_IDENTIFIER9 ident;
|
|
|
|
RECORD_COMMAND( DX8_GET_DEVICE_CAPS, 0 );
|
|
|
|
RECORD_COMMAND( DX8_GET_ADAPTER_IDENTIFIER, 2 );
|
|
RECORD_INT( m_nAdapter );
|
|
RECORD_INT( 0 );
|
|
|
|
Dx9Device()->GetDeviceCaps( &caps );
|
|
hr = D3D()->GetAdapterIdentifier( m_nAdapter, D3DENUM_WHQL_LEVEL, &ident );
|
|
|
|
Warning("Shader API Driver Info:\n\nDriver : %s Version : %lld\n",
|
|
ident.Driver, ident.DriverVersion.QuadPart );
|
|
Warning("Driver Description : %s\n", ident.Description );
|
|
Warning("Chipset version %d %d %d %d\n\n",
|
|
ident.VendorId, ident.DeviceId, ident.SubSysId, ident.Revision );
|
|
|
|
ShaderDisplayMode_t mode;
|
|
g_pShaderDeviceMgr->GetCurrentModeInfo( &mode, m_nAdapter );
|
|
Warning("Display mode : %d x %d (%s)\n",
|
|
mode.m_nWidth, mode.m_nHeight, ImageLoader::GetName( mode.m_Format ) );
|
|
Warning("Vertex Shader Version : %d.%d Pixel Shader Version : %d.%d\n",
|
|
(caps.VertexShaderVersion >> 8) & 0xFF, caps.VertexShaderVersion & 0xFF,
|
|
(caps.PixelShaderVersion >> 8) & 0xFF, caps.PixelShaderVersion & 0xFF);
|
|
Warning("\nDevice Caps :\n");
|
|
Warning("CANBLTSYSTONONLOCAL %s CANRENDERAFTERFLIP %s HWRASTERIZATION %s\n",
|
|
(caps.DevCaps & D3DDEVCAPS_CANBLTSYSTONONLOCAL) ? " Y " : " N ",
|
|
(caps.DevCaps & D3DDEVCAPS_CANRENDERAFTERFLIP) ? " Y " : " N ",
|
|
(caps.DevCaps & D3DDEVCAPS_HWRASTERIZATION) ? " Y " : "*N*" );
|
|
Warning("HWTRANSFORMANDLIGHT %s NPATCHES %s PUREDEVICE %s\n",
|
|
(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) ? " Y " : " N ",
|
|
(caps.DevCaps & D3DDEVCAPS_NPATCHES) ? " Y " : " N ",
|
|
(caps.DevCaps & D3DDEVCAPS_PUREDEVICE) ? " Y " : " N " );
|
|
Warning("SEPARATETEXTUREMEMORIES %s TEXTURENONLOCALVIDMEM %s TEXTURESYSTEMMEMORY %s\n",
|
|
(caps.DevCaps & D3DDEVCAPS_SEPARATETEXTUREMEMORIES) ? "*Y*" : " N ",
|
|
(caps.DevCaps & D3DDEVCAPS_TEXTURENONLOCALVIDMEM) ? " Y " : " N ",
|
|
(caps.DevCaps & D3DDEVCAPS_TEXTURESYSTEMMEMORY) ? " Y " : " N " );
|
|
Warning("TEXTUREVIDEOMEMORY %s TLVERTEXSYSTEMMEMORY %s TLVERTEXVIDEOMEMORY %s\n",
|
|
(caps.DevCaps & D3DDEVCAPS_TEXTUREVIDEOMEMORY) ? " Y " : "*N*",
|
|
(caps.DevCaps & D3DDEVCAPS_TLVERTEXSYSTEMMEMORY) ? " Y " : "*N*",
|
|
(caps.DevCaps & D3DDEVCAPS_TLVERTEXVIDEOMEMORY) ? " Y " : " N " );
|
|
|
|
Warning("\nPrimitive Caps :\n");
|
|
Warning("BLENDOP %s CLIPPLANESCALEDPOINTS %s CLIPTLVERTS %s\n",
|
|
(caps.PrimitiveMiscCaps & D3DPMISCCAPS_BLENDOP) ? " Y " : " N ",
|
|
(caps.PrimitiveMiscCaps & D3DPMISCCAPS_CLIPPLANESCALEDPOINTS) ? " Y " : " N ",
|
|
(caps.PrimitiveMiscCaps & D3DPMISCCAPS_CLIPTLVERTS) ? " Y " : " N " );
|
|
Warning("COLORWRITEENABLE %s MASKZ %s TSSARGTEMP %s\n",
|
|
(caps.PrimitiveMiscCaps & D3DPMISCCAPS_COLORWRITEENABLE) ? " Y " : " N ",
|
|
(caps.PrimitiveMiscCaps & D3DPMISCCAPS_MASKZ) ? " Y " : "*N*",
|
|
(caps.PrimitiveMiscCaps & D3DPMISCCAPS_TSSARGTEMP) ? " Y " : " N " );
|
|
|
|
Warning("\nRaster Caps :\n");
|
|
Warning("FOGRANGE %s FOGTABLE %s FOGVERTEX %s ZFOG %s WFOG %s\n",
|
|
(caps.RasterCaps & D3DPRASTERCAPS_FOGRANGE) ? " Y " : " N ",
|
|
(caps.RasterCaps & D3DPRASTERCAPS_FOGTABLE) ? " Y " : " N ",
|
|
(caps.RasterCaps & D3DPRASTERCAPS_FOGVERTEX) ? " Y " : " N ",
|
|
(caps.RasterCaps & D3DPRASTERCAPS_ZFOG) ? " Y " : " N ",
|
|
(caps.RasterCaps & D3DPRASTERCAPS_WFOG) ? " Y " : " N " );
|
|
Warning("MIPMAPLODBIAS %s WBUFFER %s ZBIAS %s ZTEST %s\n",
|
|
(caps.RasterCaps & D3DPRASTERCAPS_MIPMAPLODBIAS) ? " Y " : " N ",
|
|
(caps.RasterCaps & D3DPRASTERCAPS_WBUFFER) ? " Y " : " N ",
|
|
(caps.RasterCaps & D3DPRASTERCAPS_DEPTHBIAS) ? " Y " : " N ",
|
|
(caps.RasterCaps & D3DPRASTERCAPS_ZTEST) ? " Y " : "*N*" );
|
|
|
|
Warning("Size of Texture Memory : %d kb\n", g_pHardwareConfig->Caps().m_TextureMemorySize / 1024 );
|
|
Warning("Max Texture Dimensions : %d x %d\n",
|
|
caps.MaxTextureWidth, caps.MaxTextureHeight );
|
|
if (caps.MaxTextureAspectRatio != 0)
|
|
Warning("Max Texture Aspect Ratio : *%d*\n", caps.MaxTextureAspectRatio );
|
|
Warning("Max Textures : %d Max Stages : %d\n",
|
|
caps.MaxSimultaneousTextures, caps.MaxTextureBlendStages );
|
|
|
|
Warning("\nTexture Caps :\n");
|
|
Warning("ALPHA %s CUBEMAP %s MIPCUBEMAP %s SQUAREONLY %s\n",
|
|
(caps.TextureCaps & D3DPTEXTURECAPS_ALPHA) ? " Y " : " N ",
|
|
(caps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP) ? " Y " : " N ",
|
|
(caps.TextureCaps & D3DPTEXTURECAPS_MIPCUBEMAP) ? " Y " : " N ",
|
|
(caps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY) ? "*Y*" : " N " );
|
|
|
|
Warning( "vendor id: 0x%x\n", g_pHardwareConfig->ActualCaps().m_VendorID );
|
|
Warning( "device id: 0x%x\n", g_pHardwareConfig->ActualCaps().m_DeviceID );
|
|
|
|
Warning( "SHADERAPI CAPS:\n" );
|
|
Warning( "m_NumSamplers: %d\n", g_pHardwareConfig->Caps().m_NumSamplers );
|
|
Warning( "m_NumTextureStages: %d\n", g_pHardwareConfig->Caps().m_NumTextureStages );
|
|
Warning( "m_HasSetDeviceGammaRamp: %s\n", g_pHardwareConfig->Caps().m_HasSetDeviceGammaRamp ? "yes" : "no" );
|
|
Warning( "m_SupportsVertexShaders (1.1): %s\n", g_pHardwareConfig->Caps().m_SupportsVertexShaders ? "yes" : "no" );
|
|
Warning( "m_SupportsVertexShaders_2_0: %s\n", g_pHardwareConfig->Caps().m_SupportsVertexShaders_2_0 ? "yes" : "no" );
|
|
Warning( "m_SupportsPixelShaders (1.1): %s\n", g_pHardwareConfig->Caps().m_SupportsPixelShaders ? "yes" : "no" );
|
|
Warning( "m_SupportsPixelShaders_1_4: %s\n", g_pHardwareConfig->Caps().m_SupportsPixelShaders_1_4 ? "yes" : "no" );
|
|
Warning( "m_SupportsPixelShaders_2_0: %s\n", g_pHardwareConfig->Caps().m_SupportsPixelShaders_2_0 ? "yes" : "no" );
|
|
Warning( "m_SupportsPixelShaders_2_b: %s\n", g_pHardwareConfig->Caps().m_SupportsPixelShaders_2_b ? "yes" : "no" );
|
|
Warning( "m_SupportsShaderModel_3_0: %s\n", g_pHardwareConfig->Caps().m_SupportsShaderModel_3_0 ? "yes" : "no" );
|
|
|
|
switch( g_pHardwareConfig->Caps().m_SupportsCompressedTextures )
|
|
{
|
|
case COMPRESSED_TEXTURES_ON:
|
|
Warning( "m_SupportsCompressedTextures: COMPRESSED_TEXTURES_ON\n" );
|
|
break;
|
|
case COMPRESSED_TEXTURES_OFF:
|
|
Warning( "m_SupportsCompressedTextures: COMPRESSED_TEXTURES_ON\n" );
|
|
break;
|
|
case COMPRESSED_TEXTURES_NOT_INITIALIZED:
|
|
Warning( "m_SupportsCompressedTextures: COMPRESSED_TEXTURES_NOT_INITIALIZED\n" );
|
|
break;
|
|
default:
|
|
Assert( 0 );
|
|
break;
|
|
}
|
|
Warning( "m_SupportsCompressedVertices: %d\n", g_pHardwareConfig->Caps().m_SupportsCompressedVertices );
|
|
Warning( "m_bSupportsAnisotropicFiltering: %s\n", g_pHardwareConfig->Caps().m_bSupportsAnisotropicFiltering ? "yes" : "no" );
|
|
Warning( "m_nMaxAnisotropy: %d\n", g_pHardwareConfig->Caps().m_nMaxAnisotropy );
|
|
Warning( "m_MaxTextureWidth: %d\n", g_pHardwareConfig->Caps().m_MaxTextureWidth );
|
|
Warning( "m_MaxTextureHeight: %d\n", g_pHardwareConfig->Caps().m_MaxTextureHeight );
|
|
Warning( "m_MaxTextureAspectRatio: %d\n", g_pHardwareConfig->Caps().m_MaxTextureAspectRatio );
|
|
Warning( "m_MaxPrimitiveCount: %d\n", g_pHardwareConfig->Caps().m_MaxPrimitiveCount );
|
|
Warning( "m_ZBiasAndSlopeScaledDepthBiasSupported: %s\n", g_pHardwareConfig->Caps().m_ZBiasAndSlopeScaledDepthBiasSupported ? "yes" : "no" );
|
|
Warning( "m_SupportsMipmapping: %s\n", g_pHardwareConfig->Caps().m_SupportsMipmapping ? "yes" : "no" );
|
|
Warning( "m_SupportsOverbright: %s\n", g_pHardwareConfig->Caps().m_SupportsOverbright ? "yes" : "no" );
|
|
Warning( "m_SupportsCubeMaps: %s\n", g_pHardwareConfig->Caps().m_SupportsCubeMaps ? "yes" : "no" );
|
|
Warning( "m_NumPixelShaderConstants: %d\n", g_pHardwareConfig->Caps().m_NumPixelShaderConstants );
|
|
Warning( "m_NumVertexShaderConstants: %d\n", g_pHardwareConfig->Caps().m_NumVertexShaderConstants );
|
|
Warning( "m_NumBooleanVertexShaderConstants: %d\n", g_pHardwareConfig->Caps().m_NumBooleanVertexShaderConstants );
|
|
Warning( "m_NumIntegerVertexShaderConstants: %d\n", g_pHardwareConfig->Caps().m_NumIntegerVertexShaderConstants );
|
|
Warning( "m_TextureMemorySize: %d\n", g_pHardwareConfig->Caps().m_TextureMemorySize );
|
|
Warning( "m_MaxNumLights: %d\n", g_pHardwareConfig->Caps().m_MaxNumLights );
|
|
Warning( "m_SupportsHardwareLighting: %s\n", g_pHardwareConfig->Caps().m_SupportsHardwareLighting ? "yes" : "no" );
|
|
Warning( "m_MaxBlendMatrices: %d\n", g_pHardwareConfig->Caps().m_MaxBlendMatrices );
|
|
Warning( "m_MaxBlendMatrixIndices: %d\n", g_pHardwareConfig->Caps().m_MaxBlendMatrixIndices );
|
|
Warning( "m_MaxVertexShaderBlendMatrices: %d\n", g_pHardwareConfig->Caps().m_MaxVertexShaderBlendMatrices );
|
|
Warning( "m_SupportsMipmappedCubemaps: %s\n", g_pHardwareConfig->Caps().m_SupportsMipmappedCubemaps ? "yes" : "no" );
|
|
Warning( "m_SupportsNonPow2Textures: %s\n", g_pHardwareConfig->Caps().m_SupportsNonPow2Textures ? "yes" : "no" );
|
|
Warning( "m_nDXSupportLevel: %d\n", g_pHardwareConfig->Caps().m_nDXSupportLevel );
|
|
Warning( "m_PreferDynamicTextures: %s\n", g_pHardwareConfig->Caps().m_PreferDynamicTextures ? "yes" : "no" );
|
|
Warning( "m_HasProjectedBumpEnv: %s\n", g_pHardwareConfig->Caps().m_HasProjectedBumpEnv ? "yes" : "no" );
|
|
Warning( "m_MaxUserClipPlanes: %d\n", g_pHardwareConfig->Caps().m_MaxUserClipPlanes );
|
|
Warning( "m_SupportsSRGB: %s\n", g_pHardwareConfig->Caps().m_SupportsSRGB ? "yes" : "no" );
|
|
switch( g_pHardwareConfig->Caps().m_HDRType )
|
|
{
|
|
case HDR_TYPE_NONE:
|
|
Warning( "m_HDRType: HDR_TYPE_NONE\n" );
|
|
break;
|
|
case HDR_TYPE_INTEGER:
|
|
Warning( "m_HDRType: HDR_TYPE_INTEGER\n" );
|
|
break;
|
|
case HDR_TYPE_FLOAT:
|
|
Warning( "m_HDRType: HDR_TYPE_FLOAT\n" );
|
|
break;
|
|
default:
|
|
Assert( 0 );
|
|
break;
|
|
}
|
|
Warning( "m_bSupportsSpheremapping: %s\n", g_pHardwareConfig->Caps().m_bSupportsSpheremapping ? "yes" : "no" );
|
|
Warning( "m_UseFastClipping: %s\n", g_pHardwareConfig->Caps().m_UseFastClipping ? "yes" : "no" );
|
|
Warning( "m_pShaderDLL: %s\n", g_pHardwareConfig->Caps().m_pShaderDLL );
|
|
Warning( "m_bNeedsATICentroidHack: %s\n", g_pHardwareConfig->Caps().m_bNeedsATICentroidHack ? "yes" : "no" );
|
|
Warning( "m_bDisableShaderOptimizations: %s\n", g_pHardwareConfig->Caps().m_bDisableShaderOptimizations ? "yes" : "no" );
|
|
Warning( "m_bColorOnSecondStream: %s\n", g_pHardwareConfig->Caps().m_bColorOnSecondStream ? "yes" : "no" );
|
|
Warning( "m_MaxSimultaneousRenderTargets: %d\n", g_pHardwareConfig->Caps().m_MaxSimultaneousRenderTargets );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Back buffer information
|
|
//-----------------------------------------------------------------------------
|
|
ImageFormat CShaderDeviceDx8::GetBackBufferFormat() const
|
|
{
|
|
return ImageLoader::D3DFormatToImageFormat( m_PresentParameters.BackBufferFormat );
|
|
}
|
|
|
|
void CShaderDeviceDx8::GetBackBufferDimensions( int& width, int& height ) const
|
|
{
|
|
width = m_PresentParameters.BackBufferWidth;
|
|
height = m_PresentParameters.BackBufferHeight;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Detects support for CreateQuery
|
|
//-----------------------------------------------------------------------------
|
|
void CShaderDeviceDx8::DetectQuerySupport( IDirect3DDevice9 *pD3DDevice )
|
|
{
|
|
// Do I need to detect whether this device supports CreateQuery before creating it?
|
|
if ( m_DeviceSupportsCreateQuery != -1 )
|
|
return;
|
|
|
|
IDirect3DQuery9 *pQueryObject = NULL;
|
|
|
|
// Detect whether query is supported by creating and releasing:
|
|
HRESULT hr = pD3DDevice->CreateQuery( D3DQUERYTYPE_EVENT, &pQueryObject );
|
|
if ( !FAILED(hr) && pQueryObject )
|
|
{
|
|
pQueryObject->Release();
|
|
m_DeviceSupportsCreateQuery = 1;
|
|
}
|
|
else
|
|
{
|
|
m_DeviceSupportsCreateQuery = 0;
|
|
}
|
|
}
|
|
|
|
|
|
const char *GetD3DErrorText( HRESULT hr )
|
|
{
|
|
const char *pszMoreInfo = NULL;
|
|
|
|
#if defined( _WIN32 ) && !defined(DX_TO_GL_ABSTRACTION)
|
|
switch ( hr )
|
|
{
|
|
case D3DERR_WRONGTEXTUREFORMAT:
|
|
pszMoreInfo = "D3DERR_WRONGTEXTUREFORMAT: The pixel format of the texture surface is not valid.";
|
|
break;
|
|
case D3DERR_UNSUPPORTEDCOLOROPERATION:
|
|
pszMoreInfo = "D3DERR_UNSUPPORTEDCOLOROPERATION: The device does not support a specified texture-blending operation for color values.";
|
|
break;
|
|
case D3DERR_UNSUPPORTEDCOLORARG:
|
|
pszMoreInfo = "D3DERR_UNSUPPORTEDCOLORARG: The device does not support a specified texture-blending argument for color values.";
|
|
break;
|
|
case D3DERR_UNSUPPORTEDALPHAOPERATION:
|
|
pszMoreInfo = "D3DERR_UNSUPPORTEDALPHAOPERATION: The device does not support a specified texture-blending operation for the alpha channel.";
|
|
break;
|
|
case D3DERR_UNSUPPORTEDALPHAARG:
|
|
pszMoreInfo = "D3DERR_UNSUPPORTEDALPHAARG: The device does not support a specified texture-blending argument for the alpha channel.";
|
|
break;
|
|
case D3DERR_TOOMANYOPERATIONS:
|
|
pszMoreInfo = "D3DERR_TOOMANYOPERATIONS: The application is requesting more texture-filtering operations than the device supports.";
|
|
break;
|
|
case D3DERR_CONFLICTINGTEXTUREFILTER:
|
|
pszMoreInfo = "D3DERR_CONFLICTINGTEXTUREFILTER: The current texture filters cannot be used together.";
|
|
break;
|
|
case D3DERR_UNSUPPORTEDFACTORVALUE:
|
|
pszMoreInfo = "D3DERR_UNSUPPORTEDFACTORVALUE: The device does not support the specified texture factor value.";
|
|
break;
|
|
case D3DERR_CONFLICTINGRENDERSTATE:
|
|
pszMoreInfo = "D3DERR_CONFLICTINGRENDERSTATE: The currently set render states cannot be used together.";
|
|
break;
|
|
case D3DERR_UNSUPPORTEDTEXTUREFILTER:
|
|
pszMoreInfo = "D3DERR_UNSUPPORTEDTEXTUREFILTER: The device does not support the specified texture filter.";
|
|
break;
|
|
case D3DERR_CONFLICTINGTEXTUREPALETTE:
|
|
pszMoreInfo = "D3DERR_CONFLICTINGTEXTUREPALETTE: The current textures cannot be used simultaneously.";
|
|
break;
|
|
case D3DERR_DRIVERINTERNALERROR:
|
|
pszMoreInfo = "D3DERR_DRIVERINTERNALERROR: Internal driver error.";
|
|
break;
|
|
case D3DERR_NOTFOUND:
|
|
pszMoreInfo = "D3DERR_NOTFOUND: The requested item was not found.";
|
|
break;
|
|
case D3DERR_DEVICELOST:
|
|
pszMoreInfo = "D3DERR_DEVICELOST: The device has been lost but cannot be reset at this time. Therefore, rendering is not possible.";
|
|
break;
|
|
case D3DERR_DEVICENOTRESET:
|
|
pszMoreInfo = "D3DERR_DEVICENOTRESET: The device has been lost.";
|
|
break;
|
|
case D3DERR_NOTAVAILABLE:
|
|
pszMoreInfo = "D3DERR_NOTAVAILABLE: This device does not support the queried technique.";
|
|
break;
|
|
case D3DERR_OUTOFVIDEOMEMORY:
|
|
pszMoreInfo = "D3DERR_OUTOFVIDEOMEMORY: Direct3D does not have enough display memory to perform the operation. The device is using more resources in a single scene than can fit simultaneously into video memory.";
|
|
break;
|
|
case D3DERR_INVALIDDEVICE:
|
|
pszMoreInfo = "D3DERR_INVALIDDEVICE: The requested device type is not valid.";
|
|
break;
|
|
case D3DERR_INVALIDCALL:
|
|
pszMoreInfo = "D3DERR_INVALIDCALL: The method call is invalid.";
|
|
break;
|
|
case D3DERR_DRIVERINVALIDCALL:
|
|
pszMoreInfo = "D3DERR_DRIVERINVALIDCALL";
|
|
break;
|
|
case D3DERR_WASSTILLDRAWING:
|
|
pszMoreInfo = "D3DERR_WASSTILLDRAWING: The previous blit operation that is transferring information to or from this surface is incomplete.";
|
|
break;
|
|
}
|
|
#endif // _WIN32
|
|
|
|
return pszMoreInfo;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Actually creates the D3D Device once the present parameters are set up
|
|
//-----------------------------------------------------------------------------
|
|
IDirect3DDevice9* CShaderDeviceDx8::InvokeCreateDevice( void* hWnd, int nAdapter, DWORD deviceCreationFlags )
|
|
{
|
|
IDirect3DDevice9 *pD3DDevice = NULL;
|
|
D3DDEVTYPE devType = DX8_DEVTYPE;
|
|
|
|
#if NVPERFHUD
|
|
nAdapter = D3D()->GetAdapterCount()-1;
|
|
devType = D3DDEVTYPE_REF;
|
|
deviceCreationFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_HARDWARE_VERTEXPROCESSING;
|
|
#endif
|
|
|
|
#if 1 // with the changes for opengl to enable threading, we no longer need the d3d device to have threading guards
|
|
#ifndef _X360
|
|
// Create the device with multi-threaded safeguards if we're using mat_queue_mode 2.
|
|
// The logic to enable multithreaded rendering happens well after the device has been created,
|
|
// so we replicate some of that logic here.
|
|
ConVarRef mat_queue_mode( "mat_queue_mode" );
|
|
if ( mat_queue_mode.GetInt() == 2 ||
|
|
( mat_queue_mode.GetInt() == -2 && GetCPUInformation()->m_nPhysicalProcessors >= 2 ) ||
|
|
( mat_queue_mode.GetInt() == -1 && GetCPUInformation()->m_nPhysicalProcessors >= 2 ) )
|
|
{
|
|
deviceCreationFlags |= D3DCREATE_MULTITHREADED;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef ENABLE_NULLREF_DEVICE_SUPPORT
|
|
devType = CommandLine()->FindParm( "-nulldevice" ) ? D3DDEVTYPE_NULLREF: devType;
|
|
#endif
|
|
|
|
HRESULT hr = D3D()->CreateDevice( nAdapter, devType,
|
|
(VD3DHWND)hWnd, deviceCreationFlags, &m_PresentParameters, &pD3DDevice );
|
|
|
|
if ( !FAILED( hr ) && pD3DDevice )
|
|
return pD3DDevice;
|
|
|
|
if ( !IsPC() )
|
|
return NULL;
|
|
|
|
// try again, other applications may be taking their time
|
|
Sleep( 1000 );
|
|
hr = D3D()->CreateDevice( nAdapter, devType,
|
|
(VD3DHWND)hWnd, deviceCreationFlags, &m_PresentParameters, &pD3DDevice );
|
|
if ( !FAILED( hr ) && pD3DDevice )
|
|
return pD3DDevice;
|
|
|
|
// in this case, we actually are allocating too much memory....
|
|
// This will cause us to use less buffers...
|
|
if ( m_PresentParameters.Windowed )
|
|
{
|
|
m_PresentParameters.SwapEffect = D3DSWAPEFFECT_COPY;
|
|
m_PresentParameters.BackBufferCount = 0;
|
|
hr = D3D()->CreateDevice( nAdapter, devType,
|
|
(VD3DHWND)hWnd, deviceCreationFlags, &m_PresentParameters, &pD3DDevice );
|
|
}
|
|
if ( !FAILED( hr ) && pD3DDevice )
|
|
return pD3DDevice;
|
|
|
|
const char *pszMoreInfo = NULL;
|
|
switch ( hr )
|
|
{
|
|
#ifdef _WIN32
|
|
case D3DERR_INVALIDCALL:
|
|
// Override the error text for this error since it has a known meaning for CreateDevice failures.
|
|
pszMoreInfo = "D3DERR_INVALIDCALL: The device or the device driver may not support Direct3D or may not support the resolution or color depth specified.";
|
|
break;
|
|
#endif // _WIN32
|
|
default:
|
|
pszMoreInfo = GetD3DErrorText( hr );
|
|
break;
|
|
}
|
|
|
|
// Otherwise we failed, show a message and shutdown
|
|
if ( pszMoreInfo )
|
|
{
|
|
DWarning( "init", 0, "Failed to create %s device!\nError 0x%lX: %s\n\nPlease see the following for more info.\n"
|
|
"http://support.steampowered.com/cgi-bin/steampowered.cfg/php/enduser/std_adp.php?p_faqid=772\n", IsOpenGL() ? "OpenGL" : "D3D", hr, pszMoreInfo );
|
|
}
|
|
else
|
|
{
|
|
DWarning( "init", 0, "Failed to create %s device!\nError 0x%lX.\n\nPlease see the following for more info.\n"
|
|
"http://support.steampowered.com/cgi-bin/steampowered.cfg/php/enduser/std_adp.php?p_faqid=772\n", IsOpenGL() ? "OpenGL" : "D3D", hr );
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Creates the D3D Device
|
|
//-----------------------------------------------------------------------------
|
|
bool CShaderDeviceDx8::CreateD3DDevice( void* pHWnd, int nAdapter, const ShaderDeviceInfo_t &info )
|
|
{
|
|
Assert( info.m_nVersion == SHADER_DEVICE_INFO_VERSION );
|
|
|
|
MEM_ALLOC_CREDIT_( __FILE__ ": D3D Device" );
|
|
|
|
VD3DHWND hWnd = (VD3DHWND)pHWnd;
|
|
|
|
#if ( !defined( PIX_INSTRUMENTATION ) && !defined( _X360 ) && !defined( NVPERFHUD ) )
|
|
D3DPERF_SetOptions(1); // Explicitly disallow PIX instrumented profiling in external builds
|
|
#endif
|
|
|
|
// Get some caps....
|
|
D3DCAPS caps;
|
|
HRESULT hr = D3D()->GetDeviceCaps( nAdapter, DX8_DEVTYPE, &caps );
|
|
if ( FAILED( hr ) )
|
|
return false;
|
|
|
|
// Determine the adapter format
|
|
ShaderDisplayMode_t mode;
|
|
g_pShaderDeviceMgrDx8->GetCurrentModeInfo( &mode, nAdapter );
|
|
m_AdapterFormat = mode.m_Format;
|
|
|
|
// FIXME: Need to do this prior to SetPresentParameters. Fix.
|
|
// Make it part of HardwareCaps_t
|
|
InitializeColorInformation( nAdapter, DX8_DEVTYPE, m_AdapterFormat );
|
|
|
|
const HardwareCaps_t &adapterCaps = g_ShaderDeviceMgrDx8.GetHardwareCaps( nAdapter );
|
|
DWORD deviceCreationFlags = ComputeDeviceCreationFlags( caps, adapterCaps.m_bSoftwareVertexProcessing );
|
|
SetPresentParameters( hWnd, nAdapter, info );
|
|
|
|
// Tell all other instances of the material system to let go of memory
|
|
SendIPCMessage( RELEASE_MESSAGE );
|
|
|
|
// Creates the device
|
|
IDirect3DDevice9 *pD3DDevice = InvokeCreateDevice( pHWnd, nAdapter, deviceCreationFlags );
|
|
|
|
if ( !pD3DDevice )
|
|
return false;
|
|
|
|
// Check to see if query is supported
|
|
DetectQuerySupport( pD3DDevice );
|
|
|
|
#ifdef STUBD3D
|
|
Dx9Device() = new CStubD3DDevice( pD3DDevice, g_pFullFileSystem );
|
|
#else
|
|
g_pD3DDevice = pD3DDevice;
|
|
#endif
|
|
|
|
#if defined( _X360 )
|
|
// Create the depth buffer, created manually to enable hierarchical z
|
|
{
|
|
D3DSURFACE_PARAMETERS DepthStencilParams;
|
|
|
|
// Depth is immediately after the back buffer in EDRAM
|
|
// allocate the hierarchical z tiles at the end of the area so all other allocations can trivially allocate at 0
|
|
DepthStencilParams.Base = XGSurfaceSize(
|
|
m_PresentParameters.BackBufferWidth,
|
|
m_PresentParameters.BackBufferHeight,
|
|
m_PresentParameters.BackBufferFormat,
|
|
m_PresentParameters.MultiSampleType );
|
|
DepthStencilParams.ColorExpBias = 0;
|
|
DepthStencilParams.HierarchicalZBase = GPU_HIERARCHICAL_Z_TILES - XGHierarchicalZSize( m_PresentParameters.BackBufferWidth, m_PresentParameters.BackBufferHeight, m_PresentParameters.MultiSampleType );
|
|
|
|
IDirect3DSurface *pDepthStencilSurface = NULL;
|
|
hr = Dx9Device()->CreateDepthStencilSurface(
|
|
m_PresentParameters.BackBufferWidth,
|
|
m_PresentParameters.BackBufferHeight,
|
|
m_PresentParameters.AutoDepthStencilFormat,
|
|
m_PresentParameters.MultiSampleType,
|
|
m_PresentParameters.MultiSampleQuality,
|
|
TRUE,
|
|
&pDepthStencilSurface,
|
|
&DepthStencilParams );
|
|
Assert( SUCCEEDED( hr ) );
|
|
if ( FAILED( hr ) )
|
|
return false;
|
|
|
|
hr = Dx9Device()->SetDepthStencilSurface( pDepthStencilSurface );
|
|
Assert( SUCCEEDED( hr ) );
|
|
if ( FAILED( hr ) )
|
|
return false;
|
|
}
|
|
|
|
// Initialize XUI, needed for TTF font rasterization
|
|
// xui requires and shares our d3d device
|
|
{
|
|
hr = XuiRenderInitShared( pD3DDevice, &m_PresentParameters, XuiD3DXTextureLoader );
|
|
if ( FAILED( hr ) )
|
|
return false;
|
|
|
|
XUIInitParams xuiInit;
|
|
XUI_INIT_PARAMS( xuiInit );
|
|
xuiInit.dwFlags = XUI_INIT_PARAMS_FLAGS_NONE;
|
|
xuiInit.pHooks = NULL;
|
|
hr = XuiInit( &xuiInit );
|
|
if ( FAILED( hr ) )
|
|
return false;
|
|
|
|
hr = XuiRenderCreateDC( &m_hDC );
|
|
if ( FAILED( hr ) )
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
// CheckDeviceLost();
|
|
|
|
// Tell all other instances of the material system it's ok to grab memory
|
|
SendIPCMessage( REACQUIRE_MESSAGE );
|
|
|
|
m_hWnd = pHWnd;
|
|
m_nAdapter = m_DisplayAdapter = nAdapter;
|
|
m_DeviceState = DEVICE_STATE_OK;
|
|
m_bIsMinimized = false;
|
|
m_bQueuedDeviceLost = false;
|
|
|
|
m_IsResizing = info.m_bWindowed && info.m_bResizing;
|
|
|
|
// This is our current view.
|
|
m_ViewHWnd = hWnd;
|
|
GetWindowSize( m_nWindowWidth, m_nWindowHeight );
|
|
|
|
g_pHardwareConfig->SetupHardwareCaps( info, g_ShaderDeviceMgrDx8.GetHardwareCaps( nAdapter ) );
|
|
|
|
// FIXME: Bake this into hardware config
|
|
// What texture formats do we support?
|
|
if ( D3DSupportsCompressedTextures() )
|
|
{
|
|
g_pHardwareConfig->ActualCapsForEdit().m_SupportsCompressedTextures = COMPRESSED_TEXTURES_ON;
|
|
g_pHardwareConfig->CapsForEdit().m_SupportsCompressedTextures = COMPRESSED_TEXTURES_ON;
|
|
}
|
|
else
|
|
{
|
|
g_pHardwareConfig->ActualCapsForEdit().m_SupportsCompressedTextures = COMPRESSED_TEXTURES_OFF;
|
|
g_pHardwareConfig->CapsForEdit().m_SupportsCompressedTextures = COMPRESSED_TEXTURES_OFF;
|
|
}
|
|
|
|
return ( !FAILED( hr ) );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Frame sync
|
|
//-----------------------------------------------------------------------------
|
|
void CShaderDeviceDx8::AllocFrameSyncTextureObject()
|
|
{
|
|
if ( IsX360() )
|
|
return;
|
|
|
|
FreeFrameSyncTextureObject();
|
|
|
|
// Create a tiny managed texture.
|
|
HRESULT hr = Dx9Device()->CreateTexture(
|
|
1, 1, // width, height
|
|
0, // levels
|
|
D3DUSAGE_DYNAMIC, // usage
|
|
D3DFMT_A8R8G8B8, // format
|
|
D3DPOOL_DEFAULT,
|
|
&m_pFrameSyncTexture,
|
|
NULL );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
m_pFrameSyncTexture = NULL;
|
|
}
|
|
}
|
|
|
|
void CShaderDeviceDx8::FreeFrameSyncTextureObject()
|
|
{
|
|
if ( IsX360() )
|
|
return;
|
|
|
|
if ( m_pFrameSyncTexture )
|
|
{
|
|
m_pFrameSyncTexture->Release();
|
|
m_pFrameSyncTexture = NULL;
|
|
}
|
|
}
|
|
|
|
void CShaderDeviceDx8::AllocFrameSyncObjects( void )
|
|
{
|
|
if ( IsX360() )
|
|
return;
|
|
|
|
if ( mat_debugalttab.GetBool() )
|
|
{
|
|
Warning( "mat_debugalttab: CShaderAPIDX8::AllocFrameSyncObjects\n" );
|
|
}
|
|
|
|
// Allocate the texture for frame syncing in case we force that to be on.
|
|
AllocFrameSyncTextureObject();
|
|
|
|
if ( m_DeviceSupportsCreateQuery == 0 )
|
|
{
|
|
for ( int i = 0; i < ARRAYSIZE(m_pFrameSyncQueryObject); i++ )
|
|
{
|
|
m_pFrameSyncQueryObject[i] = NULL;
|
|
m_bQueryIssued[i] = false;
|
|
}
|
|
return;
|
|
}
|
|
|
|
// FIXME FIXME FIXME!!!!! Need to record this.
|
|
for ( int i = 0; i < ARRAYSIZE(m_pFrameSyncQueryObject); i++ )
|
|
{
|
|
HRESULT hr = Dx9Device()->CreateQuery( D3DQUERYTYPE_EVENT, &m_pFrameSyncQueryObject[i] );
|
|
if( hr == D3DERR_NOTAVAILABLE )
|
|
{
|
|
Warning( "D3DQUERYTYPE_EVENT not available on this driver\n" );
|
|
Assert( m_pFrameSyncQueryObject[i] == NULL );
|
|
}
|
|
else
|
|
{
|
|
Assert( hr == D3D_OK );
|
|
Assert( m_pFrameSyncQueryObject[i] );
|
|
m_pFrameSyncQueryObject[i]->Issue( D3DISSUE_END );
|
|
m_bQueryIssued[i] = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CShaderDeviceDx8::FreeFrameSyncObjects( void )
|
|
{
|
|
if ( IsX360() )
|
|
return;
|
|
|
|
if ( mat_debugalttab.GetBool() )
|
|
{
|
|
Warning( "mat_debugalttab: CShaderAPIDX8::FreeFrameSyncObjects\n" );
|
|
}
|
|
|
|
FreeFrameSyncTextureObject();
|
|
|
|
// FIXME FIXME FIXME!!!!! Need to record this.
|
|
for ( int i = 0; i < ARRAYSIZE(m_pFrameSyncQueryObject); i++ )
|
|
{
|
|
if ( m_pFrameSyncQueryObject[i] )
|
|
{
|
|
if ( m_bQueryIssued[i] )
|
|
{
|
|
tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "D3DQueryGetData %t", tmSendCallStack( TELEMETRY_LEVEL0, 0 ) );
|
|
|
|
double flStartTime = Plat_FloatTime();
|
|
BOOL dummyData = 0;
|
|
HRESULT hr = S_OK;
|
|
|
|
// Make every attempt (within 2 seconds) to get the result from the query. Doing so may prevent
|
|
// crashes in the driver if we try to release outstanding queries.
|
|
do
|
|
{
|
|
hr = m_pFrameSyncQueryObject[i]->GetData( &dummyData, sizeof( dummyData ), D3DGETDATA_FLUSH );
|
|
double flCurrTime = Plat_FloatTime();
|
|
|
|
// don't wait more than 2 seconds for these
|
|
if ( flCurrTime - flStartTime > 2.00 )
|
|
break;
|
|
} while ( hr == S_FALSE );
|
|
}
|
|
#ifdef DBGFLAG_ASSERT
|
|
int nRetVal =
|
|
#endif
|
|
m_pFrameSyncQueryObject[i]->Release();
|
|
Assert( nRetVal == 0 );
|
|
m_pFrameSyncQueryObject[i] = NULL;
|
|
m_bQueryIssued[i] = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Occurs when another application is initializing
|
|
//-----------------------------------------------------------------------------
|
|
void CShaderDeviceDx8::OtherAppInitializing( bool initializing )
|
|
{
|
|
if ( !ThreadOwnsDevice() || !ThreadInMainThread() )
|
|
{
|
|
if ( initializing )
|
|
{
|
|
ShaderUtil()->OnThreadEvent( SHADER_THREAD_OTHER_APP_START );
|
|
}
|
|
else
|
|
{
|
|
ShaderUtil()->OnThreadEvent( SHADER_THREAD_OTHER_APP_END );
|
|
}
|
|
return;
|
|
}
|
|
Assert( m_bOtherAppInitializing != initializing );
|
|
|
|
if ( !IsDeactivated() )
|
|
{
|
|
Dx9Device()->EndScene();
|
|
}
|
|
|
|
// NOTE: OtherApp is set in this way because we need to know we're
|
|
// active as we release and restore everything
|
|
CheckDeviceLost( initializing );
|
|
|
|
if ( !IsDeactivated() )
|
|
{
|
|
Dx9Device()->BeginScene();
|
|
}
|
|
}
|
|
|
|
|
|
void CShaderDeviceDx8::HandleThreadEvent( uint32 threadEvent )
|
|
{
|
|
Assert(ThreadOwnsDevice());
|
|
switch ( threadEvent )
|
|
{
|
|
case SHADER_THREAD_OTHER_APP_START:
|
|
OtherAppInitializing(true);
|
|
break;
|
|
case SHADER_THREAD_RELEASE_RESOURCES:
|
|
ReleaseResources();
|
|
break;
|
|
case SHADER_THREAD_EVICT_RESOURCES:
|
|
EvictManagedResourcesInternal();
|
|
break;
|
|
case SHADER_THREAD_RESET_RENDER_STATE:
|
|
ResetRenderState();
|
|
break;
|
|
case SHADER_THREAD_ACQUIRE_RESOURCES:
|
|
ReacquireResources();
|
|
break;
|
|
case SHADER_THREAD_OTHER_APP_END:
|
|
OtherAppInitializing(false);
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// We lost the device, but we have a chance to recover
|
|
//-----------------------------------------------------------------------------
|
|
bool CShaderDeviceDx8::TryDeviceReset()
|
|
{
|
|
if ( IsX360() )
|
|
return true;
|
|
|
|
// Don't try to reset the device until we're sure our resources have been released
|
|
if ( !m_bResourcesReleased )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// FIXME: Make this rebuild the Dx9Device from scratch!
|
|
// Helps with compatibility
|
|
HRESULT hr = Dx9Device()->Reset( &m_PresentParameters );
|
|
bool bResetSuccess = !FAILED(hr);
|
|
|
|
#if defined(IS_WINDOWS_PC) && defined(SHADERAPIDX9)
|
|
if ( bResetSuccess && g_ShaderDeviceUsingD3D9Ex )
|
|
{
|
|
bResetSuccess = SUCCEEDED( Dx9Device()->TestCooperativeLevel() );
|
|
if ( bResetSuccess )
|
|
{
|
|
Warning("video driver has crashed and been reset, re-uploading resources now");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if ( bResetSuccess )
|
|
m_bResourcesReleased = false;
|
|
return bResetSuccess;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Release, reacquire resources
|
|
//-----------------------------------------------------------------------------
|
|
void CShaderDeviceDx8::ReleaseResources()
|
|
{
|
|
if ( !ThreadOwnsDevice() || !ThreadInMainThread() )
|
|
{
|
|
// Set our resources as not being released yet.
|
|
// We reset this in two places since release resources can be called without a call to TryDeviceReset.
|
|
m_bResourcesReleased = false;
|
|
ShaderUtil()->OnThreadEvent( SHADER_THREAD_RELEASE_RESOURCES );
|
|
return;
|
|
}
|
|
|
|
// Only the initial "ReleaseResources" actually has effect
|
|
if ( m_numReleaseResourcesRefCount ++ != 0 )
|
|
{
|
|
Warning( "ReleaseResources has no effect, now at level %d.\n", m_numReleaseResourcesRefCount );
|
|
DevWarning( "ReleaseResources called twice is a bug: use IsDeactivated to check for a valid device.\n" );
|
|
Assert( 0 );
|
|
return;
|
|
}
|
|
|
|
LOCK_SHADERAPI();
|
|
CPixEvent( PIX_VALVE_ORANGE, "ReleaseResources" );
|
|
|
|
FreeFrameSyncObjects();
|
|
FreeNonInteractiveRefreshObjects();
|
|
ShaderUtil()->ReleaseShaderObjects();
|
|
MeshMgr()->ReleaseBuffers();
|
|
g_pShaderAPI->ReleaseShaderObjects();
|
|
|
|
#ifdef _DEBUG
|
|
if ( MeshMgr()->BufferCount() != 0 )
|
|
{
|
|
for( int i = 0; i < MeshMgr()->BufferCount(); i++ )
|
|
{
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// All meshes cleaned up?
|
|
Assert( MeshMgr()->BufferCount() == 0 );
|
|
|
|
// Signal that our resources have been released so that we can try to reset the device
|
|
m_bResourcesReleased = true;
|
|
}
|
|
|
|
|
|
void CShaderDeviceDx8::ReacquireResources()
|
|
{
|
|
ReacquireResourcesInternal();
|
|
}
|
|
|
|
void CShaderDeviceDx8::ReacquireResourcesInternal( bool bResetState, bool bForceReacquire, char const *pszForceReason )
|
|
{
|
|
if ( !ThreadOwnsDevice() || !ThreadInMainThread() )
|
|
{
|
|
if ( bResetState )
|
|
{
|
|
ShaderUtil()->OnThreadEvent( SHADER_THREAD_RESET_RENDER_STATE );
|
|
}
|
|
ShaderUtil()->OnThreadEvent( SHADER_THREAD_ACQUIRE_RESOURCES );
|
|
return;
|
|
}
|
|
if ( bForceReacquire )
|
|
{
|
|
// If we are forcing reacquire then warn if release calls are remaining unpaired
|
|
if ( m_numReleaseResourcesRefCount > 1 )
|
|
{
|
|
Warning( "Forcefully resetting device (%s), resources release level was %d.\n", pszForceReason ? pszForceReason : "unspecified", m_numReleaseResourcesRefCount );
|
|
Assert( 0 );
|
|
}
|
|
m_numReleaseResourcesRefCount = 0;
|
|
}
|
|
else
|
|
{
|
|
// Only the final "ReacquireResources" actually has effect
|
|
if ( -- m_numReleaseResourcesRefCount != 0 )
|
|
{
|
|
Warning( "ReacquireResources has no effect, now at level %d.\n", m_numReleaseResourcesRefCount );
|
|
DevWarning( "ReacquireResources being discarded is a bug: use IsDeactivated to check for a valid device.\n" );
|
|
Assert( 0 );
|
|
|
|
if ( m_numReleaseResourcesRefCount < 0 )
|
|
{
|
|
m_numReleaseResourcesRefCount = 0;
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ( bResetState )
|
|
{
|
|
ResetRenderState();
|
|
}
|
|
|
|
LOCK_SHADERAPI();
|
|
CPixEvent event( PIX_VALVE_ORANGE, "ReacquireResources" );
|
|
|
|
g_pShaderAPI->RestoreShaderObjects();
|
|
AllocFrameSyncObjects();
|
|
AllocNonInteractiveRefreshObjects();
|
|
MeshMgr()->RestoreBuffers();
|
|
ShaderUtil()->RestoreShaderObjects( CShaderDeviceMgrBase::ShaderInterfaceFactory );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Changes the window size
|
|
//-----------------------------------------------------------------------------
|
|
bool CShaderDeviceDx8::ResizeWindow( const ShaderDeviceInfo_t &info )
|
|
{
|
|
if ( IsX360() )
|
|
return false;
|
|
|
|
m_bPendingVideoModeChange = false;
|
|
|
|
// We don't need to do crap if the window was set up to set up
|
|
// to be resizing...
|
|
if ( info.m_bResizing )
|
|
return false;
|
|
|
|
g_pShaderDeviceMgr->InvokeModeChangeCallbacks();
|
|
|
|
ReleaseResources();
|
|
|
|
SetPresentParameters( (VD3DHWND)m_hWnd, m_DisplayAdapter, info );
|
|
HRESULT hr = Dx9Device()->Reset( &m_PresentParameters );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
Warning( "ResizeWindow: Reset failed, hr = 0x%08lX.\n", hr );
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
ReacquireResourcesInternal( true, true, "ResizeWindow" );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Queue up the fact that the device was lost
|
|
//-----------------------------------------------------------------------------
|
|
void CShaderDeviceDx8::MarkDeviceLost( )
|
|
{
|
|
if ( IsX360() )
|
|
return;
|
|
|
|
m_bQueuedDeviceLost = true;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Checks if the device was lost
|
|
//-----------------------------------------------------------------------------
|
|
#if defined( _DEBUG ) && !defined( _X360 )
|
|
ConVar mat_forcelostdevice( "mat_forcelostdevice", "0" );
|
|
#endif
|
|
|
|
void CShaderDeviceDx8::CheckDeviceLost( bool bOtherAppInitializing )
|
|
{
|
|
#if !defined( _X360 )
|
|
// FIXME: We could also queue up if WM_SIZE changes and look at that
|
|
// but that seems to only make sense if we have resizable windows where
|
|
// we do *not* allocate buffers as large as the entire current video mode
|
|
// which we're not doing
|
|
#ifdef _WIN32
|
|
m_bIsMinimized = ( static_cast<BOOL>(IsIconic( ( HWND )m_hWnd )) == (BOOL)TRUE );
|
|
#else
|
|
m_bIsMinimized = ( IsIconic( (VD3DHWND)m_hWnd ) == TRUE );
|
|
#endif
|
|
m_bOtherAppInitializing = bOtherAppInitializing;
|
|
|
|
#ifdef _DEBUG
|
|
if ( mat_forcelostdevice.GetBool() )
|
|
{
|
|
mat_forcelostdevice.SetValue( 0 );
|
|
MarkDeviceLost();
|
|
}
|
|
#endif
|
|
|
|
HRESULT hr = D3D_OK;
|
|
#if defined(IS_WINDOWS_PC) && defined(SHADERAPIDX9)
|
|
if ( g_ShaderDeviceUsingD3D9Ex && m_DeviceState == DEVICE_STATE_OK )
|
|
{
|
|
// Steady state - PresentEx return value will mark us lost if necessary.
|
|
// We do not care if we are minimized in this state.
|
|
m_bIsMinimized = false;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
RECORD_COMMAND( DX8_TEST_COOPERATIVE_LEVEL, 0 );
|
|
hr = Dx9Device()->TestCooperativeLevel();
|
|
}
|
|
|
|
// If some other call returned device lost previously in the frame, spoof the return value from TCL
|
|
if ( m_bQueuedDeviceLost )
|
|
{
|
|
hr = (hr != D3D_OK) ? hr : D3DERR_DEVICENOTRESET;
|
|
m_bQueuedDeviceLost = false;
|
|
}
|
|
|
|
if ( m_DeviceState == DEVICE_STATE_OK )
|
|
{
|
|
// We can transition out of ok if bOtherAppInitializing is set
|
|
// or if we become minimized, or if TCL returns anything other than D3D_OK.
|
|
if ( ( hr != D3D_OK ) || m_bIsMinimized )
|
|
{
|
|
// purge unreferenced materials
|
|
g_pShaderUtil->UncacheUnusedMaterials( true );
|
|
|
|
// We were ok, now we're not. Release resources
|
|
ReleaseResources();
|
|
m_DeviceState = DEVICE_STATE_LOST_DEVICE;
|
|
}
|
|
else if ( bOtherAppInitializing )
|
|
{
|
|
// purge unreferenced materials
|
|
g_pShaderUtil->UncacheUnusedMaterials( true );
|
|
|
|
// We were ok, now we're not. Release resources
|
|
ReleaseResources();
|
|
m_DeviceState = DEVICE_STATE_OTHER_APP_INIT;
|
|
}
|
|
}
|
|
|
|
// Immediately checking devicelost after ok helps in the case where we got D3DERR_DEVICENOTRESET
|
|
// in which case we want to immdiately try to switch out of DEVICE_STATE_LOST and into DEVICE_STATE_NEEDS_RESET
|
|
if ( m_DeviceState == DEVICE_STATE_LOST_DEVICE )
|
|
{
|
|
// We can only try to reset if we're not minimized and not lost
|
|
if ( !m_bIsMinimized && (hr != D3DERR_DEVICELOST) )
|
|
{
|
|
m_DeviceState = DEVICE_STATE_NEEDS_RESET;
|
|
}
|
|
}
|
|
|
|
// Immediately checking needs reset also helps for the case where we got D3DERR_DEVICENOTRESET
|
|
if ( m_DeviceState == DEVICE_STATE_NEEDS_RESET )
|
|
{
|
|
if ( ( hr == D3DERR_DEVICELOST ) || m_bIsMinimized )
|
|
{
|
|
m_DeviceState = DEVICE_STATE_LOST_DEVICE;
|
|
}
|
|
else
|
|
{
|
|
bool bResetSucceeded = TryDeviceReset();
|
|
if ( bResetSucceeded )
|
|
{
|
|
if ( !bOtherAppInitializing )
|
|
{
|
|
m_DeviceState = DEVICE_STATE_OK;
|
|
|
|
// We were bad, now we're ok. Restore resources and reset render state.
|
|
ReacquireResourcesInternal( true, true, "NeedsReset" );
|
|
}
|
|
else
|
|
{
|
|
m_DeviceState = DEVICE_STATE_OTHER_APP_INIT;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( m_DeviceState == DEVICE_STATE_OTHER_APP_INIT )
|
|
{
|
|
if ( ( hr != D3D_OK ) || m_bIsMinimized )
|
|
{
|
|
m_DeviceState = DEVICE_STATE_LOST_DEVICE;
|
|
}
|
|
else if ( !bOtherAppInitializing )
|
|
{
|
|
m_DeviceState = DEVICE_STATE_OK;
|
|
|
|
// We were bad, now we're ok. Restore resources and reset render state.
|
|
ReacquireResourcesInternal( true, true, "OtherAppInit" );
|
|
}
|
|
}
|
|
|
|
// Do mode change if we have a video mode change.
|
|
if ( m_bPendingVideoModeChange && !IsDeactivated() )
|
|
{
|
|
#ifdef _DEBUG
|
|
Warning( "mode change!\n" );
|
|
#endif
|
|
// now purge unreferenced materials
|
|
g_pShaderUtil->UncacheUnusedMaterials( true );
|
|
|
|
ResizeWindow( m_PendingVideoModeChangeConfig );
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Special method to refresh the screen on the XBox360
|
|
//-----------------------------------------------------------------------------
|
|
bool CShaderDeviceDx8::AllocNonInteractiveRefreshObjects()
|
|
{
|
|
#if defined( _X360 )
|
|
|
|
const char *strVertexShaderProgram =
|
|
" float4x4 matWVP : register(c0);"
|
|
" struct VS_IN"
|
|
" {"
|
|
" float4 ObjPos : POSITION;"
|
|
" float2 TexCoord : TEXCOORD;"
|
|
" };"
|
|
" struct VS_OUT"
|
|
" {"
|
|
" float4 ProjPos : POSITION;"
|
|
" float2 TexCoord : TEXCOORD;"
|
|
" };"
|
|
" VS_OUT main( VS_IN In )"
|
|
" {"
|
|
" VS_OUT Out; "
|
|
" Out.ProjPos = mul( matWVP, In.ObjPos );"
|
|
" Out.TexCoord = In.TexCoord;"
|
|
" return Out;"
|
|
" }";
|
|
|
|
const char *strPixelShaderProgram =
|
|
" struct PS_IN"
|
|
" {"
|
|
" float2 TexCoord : TEXCOORD;"
|
|
" };"
|
|
" sampler detail : register( s0 );"
|
|
" float4 main( PS_IN In ) : COLOR"
|
|
" {"
|
|
" return tex2D( detail, In.TexCoord );"
|
|
" }";
|
|
|
|
const char *strPixelShaderProgram2 =
|
|
" struct PS_IN"
|
|
" {"
|
|
" float2 TexCoord : TEXCOORD;"
|
|
" };"
|
|
" sampler detail : register( s0 );"
|
|
" float4 main( PS_IN In ) : COLOR"
|
|
" {"
|
|
" return tex2D( detail, In.TexCoord );"
|
|
" }";
|
|
|
|
const char *strPixelShaderProgram3 =
|
|
" struct PS_IN"
|
|
" {"
|
|
" float2 TexCoord : TEXCOORD;"
|
|
" };"
|
|
" float SrgbGammaToLinear( float flSrgbGammaValue )"
|
|
" {"
|
|
" float x = saturate( flSrgbGammaValue );"
|
|
" return ( x <= 0.04045f ) ? ( x / 12.92f ) : ( pow( ( x + 0.055f ) / 1.055f, 2.4f ) );"
|
|
" }"
|
|
"float X360LinearToGamma( float flLinearValue )"
|
|
"{"
|
|
" float fl360GammaValue;"
|
|
""
|
|
" flLinearValue = saturate( flLinearValue );"
|
|
" if ( flLinearValue < ( 128.0f / 1023.0f ) )"
|
|
" {"
|
|
" if ( flLinearValue < ( 64.0f / 1023.0f ) )"
|
|
" {"
|
|
" fl360GammaValue = flLinearValue * ( 1023.0f * ( 1.0f / 255.0f ) );"
|
|
" }"
|
|
" else"
|
|
" {"
|
|
" fl360GammaValue = flLinearValue * ( ( 1023.0f / 2.0f ) * ( 1.0f / 255.0f ) ) + ( 32.0f / 255.0f );"
|
|
" }"
|
|
" }"
|
|
" else"
|
|
" {"
|
|
" if ( flLinearValue < ( 512.0f / 1023.0f ) )"
|
|
" {"
|
|
" fl360GammaValue = flLinearValue * ( ( 1023.0f / 4.0f ) * ( 1.0f / 255.0f ) ) + ( 64.0f / 255.0f );"
|
|
" }"
|
|
" else"
|
|
" {"
|
|
" fl360GammaValue = flLinearValue * ( ( 1023.0f /8.0f ) * ( 1.0f / 255.0f ) ) + ( 128.0f /255.0f );"
|
|
" if ( fl360GammaValue > 1.0f )"
|
|
" {"
|
|
" fl360GammaValue = 1.0f;"
|
|
" }"
|
|
" }"
|
|
" }"
|
|
""
|
|
" fl360GammaValue = saturate( fl360GammaValue );"
|
|
" return fl360GammaValue;"
|
|
"}"
|
|
" sampler detail : register( s0 );"
|
|
" float4 main( PS_IN In ) : COLOR"
|
|
" {"
|
|
" float4 vTextureColor = tex2D( detail, In.TexCoord );"
|
|
" vTextureColor.r = X360LinearToGamma( SrgbGammaToLinear( vTextureColor.r ) );"
|
|
" vTextureColor.g = X360LinearToGamma( SrgbGammaToLinear( vTextureColor.g ) );"
|
|
" vTextureColor.b = X360LinearToGamma( SrgbGammaToLinear( vTextureColor.b ) );"
|
|
" return vTextureColor;"
|
|
" }";
|
|
|
|
D3DVERTEXELEMENT9 VertexElements[4] =
|
|
{
|
|
{ 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
|
|
{ 0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
|
|
D3DDECL_END()
|
|
};
|
|
|
|
ID3DXBuffer *pErrorMsg = NULL;
|
|
ID3DXBuffer *pShaderCode = NULL;
|
|
|
|
HRESULT hr = D3DXCompileShader( strVertexShaderProgram, (UINT)strlen( strVertexShaderProgram ), NULL, NULL, "main", "vs_2_0", 0, &pShaderCode, &pErrorMsg, NULL );
|
|
if ( FAILED( hr ) )
|
|
return false;
|
|
|
|
Dx9Device()->CreateVertexShader( (DWORD*)pShaderCode->GetBufferPointer(), &m_NonInteractiveRefresh.m_pVertexShader );
|
|
pShaderCode->Release();
|
|
pShaderCode = NULL;
|
|
if ( pErrorMsg )
|
|
{
|
|
pErrorMsg->Release();
|
|
pErrorMsg = NULL;
|
|
}
|
|
|
|
hr = D3DXCompileShader( strPixelShaderProgram, (UINT)strlen( strPixelShaderProgram ), NULL, NULL, "main", "ps_2_0", 0, &pShaderCode, &pErrorMsg, NULL );
|
|
if ( FAILED(hr) )
|
|
return false;
|
|
|
|
Dx9Device()->CreatePixelShader( (DWORD*)pShaderCode->GetBufferPointer(), &m_NonInteractiveRefresh.m_pPixelShader );
|
|
pShaderCode->Release();
|
|
if ( pErrorMsg )
|
|
{
|
|
pErrorMsg->Release();
|
|
pErrorMsg = NULL;
|
|
}
|
|
|
|
hr = D3DXCompileShader( strPixelShaderProgram3, (UINT)strlen( strPixelShaderProgram3 ), NULL, NULL, "main", "ps_2_0", 0, &pShaderCode, &pErrorMsg, NULL );
|
|
if ( FAILED(hr) )
|
|
return false;
|
|
|
|
Dx9Device()->CreatePixelShader( (DWORD*)pShaderCode->GetBufferPointer(), &m_NonInteractiveRefresh.m_pPixelShaderStartup );
|
|
pShaderCode->Release();
|
|
if ( pErrorMsg )
|
|
{
|
|
pErrorMsg->Release();
|
|
pErrorMsg = NULL;
|
|
}
|
|
|
|
hr = D3DXCompileShader( strPixelShaderProgram2, (UINT)strlen( strPixelShaderProgram2 ), NULL, NULL, "main", "ps_2_0", 0, &pShaderCode, &pErrorMsg, NULL );
|
|
if ( FAILED(hr) )
|
|
return false;
|
|
|
|
Dx9Device()->CreatePixelShader( (DWORD*)pShaderCode->GetBufferPointer(), &m_NonInteractiveRefresh.m_pPixelShaderStartupPass2 );
|
|
pShaderCode->Release();
|
|
if ( pErrorMsg )
|
|
{
|
|
pErrorMsg->Release();
|
|
pErrorMsg = NULL;
|
|
}
|
|
|
|
// Create a vertex declaration from the element descriptions.
|
|
Dx9Device()->CreateVertexDeclaration( VertexElements, &m_NonInteractiveRefresh.m_pVertexDecl );
|
|
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
void CShaderDeviceDx8::FreeNonInteractiveRefreshObjects()
|
|
{
|
|
if ( m_NonInteractiveRefresh.m_pVertexShader )
|
|
{
|
|
m_NonInteractiveRefresh.m_pVertexShader->Release();
|
|
m_NonInteractiveRefresh.m_pVertexShader = NULL;
|
|
}
|
|
|
|
if ( m_NonInteractiveRefresh.m_pPixelShader )
|
|
{
|
|
m_NonInteractiveRefresh.m_pPixelShader->Release();
|
|
m_NonInteractiveRefresh.m_pPixelShader = NULL;
|
|
}
|
|
|
|
if ( m_NonInteractiveRefresh.m_pPixelShaderStartup )
|
|
{
|
|
m_NonInteractiveRefresh.m_pPixelShaderStartup->Release();
|
|
m_NonInteractiveRefresh.m_pPixelShaderStartup = NULL;
|
|
}
|
|
|
|
if ( m_NonInteractiveRefresh.m_pPixelShaderStartupPass2 )
|
|
{
|
|
m_NonInteractiveRefresh.m_pPixelShaderStartupPass2->Release();
|
|
m_NonInteractiveRefresh.m_pPixelShaderStartupPass2 = NULL;
|
|
}
|
|
|
|
if ( m_NonInteractiveRefresh.m_pVertexDecl )
|
|
{
|
|
m_NonInteractiveRefresh.m_pVertexDecl->Release();
|
|
m_NonInteractiveRefresh.m_pVertexDecl = NULL;
|
|
}
|
|
}
|
|
|
|
bool CShaderDeviceDx8::InNonInteractiveMode() const
|
|
{
|
|
return m_NonInteractiveRefresh.m_Mode != MATERIAL_NON_INTERACTIVE_MODE_NONE;
|
|
}
|
|
|
|
void CShaderDeviceDx8::EnableNonInteractiveMode( MaterialNonInteractiveMode_t mode, ShaderNonInteractiveInfo_t *pInfo )
|
|
{
|
|
if ( !IsX360() )
|
|
return;
|
|
if ( pInfo && ( pInfo->m_hTempFullscreenTexture == INVALID_SHADERAPI_TEXTURE_HANDLE ) )
|
|
{
|
|
mode = MATERIAL_NON_INTERACTIVE_MODE_NONE;
|
|
}
|
|
m_NonInteractiveRefresh.m_Mode = mode;
|
|
if ( pInfo )
|
|
{
|
|
m_NonInteractiveRefresh.m_Info = *pInfo;
|
|
}
|
|
m_NonInteractiveRefresh.m_nPacifierFrame = 0;
|
|
|
|
if ( mode != MATERIAL_NON_INTERACTIVE_MODE_NONE )
|
|
{
|
|
ConVarRef mat_monitorgamma( "mat_monitorgamma" );
|
|
ConVarRef mat_monitorgamma_tv_range_min( "mat_monitorgamma_tv_range_min" );
|
|
ConVarRef mat_monitorgamma_tv_range_max( "mat_monitorgamma_tv_range_max" );
|
|
ConVarRef mat_monitorgamma_tv_exp( "mat_monitorgamma_tv_exp" );
|
|
ConVarRef mat_monitorgamma_tv_enabled( "mat_monitorgamma_tv_enabled" );
|
|
SetHardwareGammaRamp( mat_monitorgamma.GetFloat(), mat_monitorgamma_tv_range_min.GetFloat(), mat_monitorgamma_tv_range_max.GetFloat(),
|
|
mat_monitorgamma_tv_exp.GetFloat(), mat_monitorgamma_tv_enabled.GetBool() );
|
|
}
|
|
|
|
#ifdef _X360
|
|
if ( mode != MATERIAL_NON_INTERACTIVE_MODE_NONE )
|
|
{
|
|
// HACK: VSync off (prevents us wasting time blocking on VSync due to our irregular present intervals)
|
|
Dx9Device()->SetRenderState( D3DRS_PRESENTINTERVAL, D3DPRESENT_INTERVAL_IMMEDIATE );
|
|
}
|
|
else
|
|
{
|
|
// HACK: VSync on (defaulting to on on 360 is fine, but really should save+restore this state)
|
|
Dx9Device()->SetRenderState( D3DRS_PRESENTINTERVAL, D3DPRESENT_INTERVAL_ONE );
|
|
}
|
|
#endif
|
|
|
|
// Msg( "Time elapsed: %.3f Peak %.3f Ave %.5f Count %d Count Above %d\n", Plat_FloatTime() - m_NonInteractiveRefresh.m_flStartTime,
|
|
// m_NonInteractiveRefresh.m_flPeakDt, m_NonInteractiveRefresh.m_flTotalDt / m_NonInteractiveRefresh.m_nSamples, m_NonInteractiveRefresh.m_nSamples, m_NonInteractiveRefresh.m_nCountAbove66 );
|
|
|
|
m_NonInteractiveRefresh.m_flStartTime = m_NonInteractiveRefresh.m_flLastPresentTime =
|
|
m_NonInteractiveRefresh.m_flLastPacifierTime = Plat_FloatTime();
|
|
m_NonInteractiveRefresh.m_flPeakDt = 0.0f;
|
|
m_NonInteractiveRefresh.m_flTotalDt = 0.0f;
|
|
m_NonInteractiveRefresh.m_nSamples = 0;
|
|
m_NonInteractiveRefresh.m_nCountAbove66 = 0;
|
|
}
|
|
|
|
void CShaderDeviceDx8::UpdatePresentStats()
|
|
{
|
|
float t = Plat_FloatTime();
|
|
float flActualDt = t - m_NonInteractiveRefresh.m_flLastPresentTime;
|
|
if ( flActualDt > m_NonInteractiveRefresh.m_flPeakDt )
|
|
{
|
|
m_NonInteractiveRefresh.m_flPeakDt = flActualDt;
|
|
}
|
|
if ( flActualDt > 0.066 )
|
|
{
|
|
++m_NonInteractiveRefresh.m_nCountAbove66;
|
|
}
|
|
|
|
m_NonInteractiveRefresh.m_flTotalDt += flActualDt;
|
|
++m_NonInteractiveRefresh.m_nSamples;
|
|
|
|
t = Plat_FloatTime();
|
|
m_NonInteractiveRefresh.m_flLastPresentTime = t;
|
|
}
|
|
|
|
void CShaderDeviceDx8::RefreshFrontBufferNonInteractive()
|
|
{
|
|
if ( !IsX360() || !InNonInteractiveMode() )
|
|
return;
|
|
|
|
// Other code should not be talking to D3D at the same time as this
|
|
AUTO_LOCK( m_nonInteractiveModeMutex );
|
|
|
|
#ifdef _X360
|
|
g_pShaderAPI->OwnGPUResources( false );
|
|
IDirect3DBaseTexture *pTexture = g_pShaderAPI->GetD3DTexture( m_NonInteractiveRefresh.m_Info.m_hTempFullscreenTexture );
|
|
|
|
int w, h;
|
|
g_pShaderAPI->GetBackBufferDimensions( w, h );
|
|
XMMATRIX matWVP = XMMatrixOrthographicOffCenterLH( 0, (FLOAT)w, (FLOAT)h, 0, 0, 1 );
|
|
|
|
// Structure to hold vertex data.
|
|
struct TEXVERTEX
|
|
{
|
|
FLOAT Position[3];
|
|
FLOAT TexCoord[2];
|
|
};
|
|
TEXVERTEX Vertices[4];
|
|
|
|
Vertices[0].Position[0] = -0.5f;
|
|
Vertices[0].Position[1] = -0.5f;
|
|
Vertices[0].Position[2] = 0;
|
|
Vertices[0].TexCoord[0] = 0;
|
|
Vertices[0].TexCoord[1] = 0;
|
|
|
|
Vertices[1].Position[0] = w-0.5f;
|
|
Vertices[1].Position[1] = -0.5f;
|
|
Vertices[1].Position[2] = 0;
|
|
Vertices[1].TexCoord[0] = 1;
|
|
Vertices[1].TexCoord[1] = 0;
|
|
|
|
Vertices[2].Position[0] = w-0.5f;
|
|
Vertices[2].Position[1] = h-0.5f;
|
|
Vertices[2].Position[2] = 0;
|
|
Vertices[2].TexCoord[0] = 1;
|
|
Vertices[2].TexCoord[1] = 1;
|
|
|
|
Vertices[3].Position[0] = -0.5f;
|
|
Vertices[3].Position[1] = h-0.5f;
|
|
Vertices[3].Position[2] = 0;
|
|
Vertices[3].TexCoord[0] = 0;
|
|
Vertices[3].TexCoord[1] = 1;
|
|
|
|
D3DVIEWPORT9 viewport;
|
|
viewport.X = viewport.Y = 0;
|
|
viewport.Width = w; viewport.Height = h;
|
|
viewport.MinZ = ReverseDepthOnX360() ? 1.0f : 0.0f;
|
|
viewport.MaxZ = 1.0f - viewport.MinZ;
|
|
|
|
bool bInStartupMode = ( m_NonInteractiveRefresh.m_Mode == MATERIAL_NON_INTERACTIVE_MODE_STARTUP );
|
|
|
|
float flDepth = (ShaderUtil()->GetConfig().bReverseDepth ^ ReverseDepthOnX360()) ? 0.0f : 1.0f;
|
|
Dx9Device()->Clear( 0, NULL, D3DCLEAR_ZBUFFER, 0, flDepth, 0L );
|
|
|
|
Dx9Device()->SetViewport( &viewport );
|
|
Dx9Device()->SetTexture( 0, pTexture );
|
|
Dx9Device()->SetVertexShader( m_NonInteractiveRefresh.m_pVertexShader );
|
|
Dx9Device()->SetPixelShader( bInStartupMode ? m_NonInteractiveRefresh.m_pPixelShaderStartup : m_NonInteractiveRefresh.m_pPixelShader );
|
|
Dx9Device()->SetVertexShaderConstantF( 0, (FLOAT*)&matWVP, 4 );
|
|
Dx9Device()->SetVertexDeclaration( m_NonInteractiveRefresh.m_pVertexDecl );
|
|
Dx9Device()->SetSamplerState( 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP );
|
|
Dx9Device()->SetSamplerState( 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP );
|
|
Dx9Device()->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
|
|
Dx9Device()->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
|
|
|
|
tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "%s", __FUNCTION__ );
|
|
|
|
Dx9Device()->DrawPrimitiveUP( D3DPT_QUADLIST, 1, Vertices, sizeof( TEXVERTEX ) );
|
|
|
|
if ( bInStartupMode )
|
|
{
|
|
float flXPos = m_NonInteractiveRefresh.m_Info.m_flNormalizedX;
|
|
float flYPos = m_NonInteractiveRefresh.m_Info.m_flNormalizedY;
|
|
float flHeight = m_NonInteractiveRefresh.m_Info.m_flNormalizedSize;
|
|
int nSize = h * flHeight;
|
|
int x = w * flXPos - nSize * 0.5f;
|
|
int y = h * flYPos - nSize * 0.5f;
|
|
w = h = nSize;
|
|
|
|
Vertices[0].Position[0] = x - 0.5f;
|
|
Vertices[0].Position[1] = y - 0.5f;
|
|
Vertices[1].Position[0] = x+w-0.5f;
|
|
Vertices[1].Position[1] = y - 0.5f;
|
|
Vertices[2].Position[0] = x+w-0.5f;
|
|
Vertices[2].Position[1] = y+h-0.5f;
|
|
Vertices[3].Position[0] = x - 0.5f;
|
|
Vertices[3].Position[1] = y+h-0.5f;
|
|
|
|
float t = Plat_FloatTime();
|
|
float flDt = t - m_NonInteractiveRefresh.m_flLastPacifierTime;
|
|
if ( flDt > 0.030f )
|
|
{
|
|
if ( ++m_NonInteractiveRefresh.m_nPacifierFrame >= m_NonInteractiveRefresh.m_Info.m_nPacifierCount )
|
|
{
|
|
m_NonInteractiveRefresh.m_nPacifierFrame = 0;
|
|
}
|
|
m_NonInteractiveRefresh.m_flLastPacifierTime = t;
|
|
}
|
|
|
|
pTexture = g_pShaderAPI->GetD3DTexture( m_NonInteractiveRefresh.m_Info.m_pPacifierTextures[ m_NonInteractiveRefresh.m_nPacifierFrame ] );
|
|
Dx9Device()->SetRenderState( D3DRS_ALPHABLENDENABLE, 1 );
|
|
Dx9Device()->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
|
|
Dx9Device()->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
|
|
Dx9Device()->SetTexture( 0, pTexture );
|
|
Dx9Device()->SetPixelShader( m_NonInteractiveRefresh.m_pPixelShaderStartupPass2 );
|
|
Dx9Device()->DrawPrimitiveUP( D3DPT_QUADLIST, 1, Vertices, sizeof( TEXVERTEX ) );
|
|
}
|
|
|
|
Dx9Device()->SetVertexShader( NULL );
|
|
Dx9Device()->SetPixelShader( NULL );
|
|
Dx9Device()->SetTexture( 0, NULL );
|
|
Dx9Device()->SetVertexDeclaration( NULL );
|
|
|
|
tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "D3DPresent" );
|
|
|
|
Dx9Device()->Present( 0, 0, 0, 0 );
|
|
g_pShaderAPI->QueueResetRenderState();
|
|
g_pShaderAPI->OwnGPUResources( true );
|
|
|
|
UpdatePresentStats();
|
|
#endif
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Page flip
|
|
//-----------------------------------------------------------------------------
|
|
void CShaderDeviceDx8::Present()
|
|
{
|
|
LOCK_SHADERAPI();
|
|
|
|
// need to flush the dynamic buffer
|
|
g_pShaderAPI->FlushBufferedPrimitives();
|
|
|
|
if ( !IsDeactivated() )
|
|
{
|
|
Dx9Device()->EndScene();
|
|
}
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
// if we're in queued mode, don't present if the device is already lost
|
|
bool bValidPresent = true;
|
|
bool bInMainThread = ThreadInMainThread();
|
|
if ( !bInMainThread )
|
|
{
|
|
// don't present if the device is in an invalid state and in queued mode
|
|
if ( m_DeviceState != DEVICE_STATE_OK )
|
|
{
|
|
bValidPresent = false;
|
|
}
|
|
// check for lost device early in threaded mode
|
|
CheckDeviceLost( m_bOtherAppInitializing );
|
|
if ( m_DeviceState != DEVICE_STATE_OK )
|
|
{
|
|
bValidPresent = false;
|
|
}
|
|
}
|
|
// Copy the back buffer into the non-interactive temp buffer
|
|
if ( m_NonInteractiveRefresh.m_Mode == MATERIAL_NON_INTERACTIVE_MODE_LEVEL_LOAD )
|
|
{
|
|
g_pShaderAPI->CopyRenderTargetToTextureEx( m_NonInteractiveRefresh.m_Info.m_hTempFullscreenTexture, 0, NULL, NULL );
|
|
}
|
|
|
|
// If we're not iconified, try to present (without this check, we can flicker when Alt-Tabbed away)
|
|
#ifdef _WIN32
|
|
if ( IsX360() || (IsIconic( ( HWND )m_hWnd ) == 0 && bValidPresent) )
|
|
#else
|
|
if ( IsX360() || (IsIconic( (VD3DHWND)m_hWnd ) == 0 && bValidPresent) )
|
|
#endif
|
|
{
|
|
if ( IsPC() && ( m_IsResizing || ( m_ViewHWnd != (VD3DHWND)m_hWnd ) ) )
|
|
{
|
|
RECT destRect;
|
|
#ifndef DX_TO_GL_ABSTRACTION
|
|
GetClientRect( ( HWND )m_ViewHWnd, &destRect );
|
|
#else
|
|
toglGetClientRect( (VD3DHWND)m_ViewHWnd, &destRect );
|
|
#endif
|
|
|
|
ShaderViewport_t viewport;
|
|
g_pShaderAPI->GetViewports( &viewport, 1 );
|
|
|
|
RECT srcRect;
|
|
srcRect.left = viewport.m_nTopLeftX;
|
|
srcRect.right = viewport.m_nTopLeftX + viewport.m_nWidth;
|
|
srcRect.top = viewport.m_nTopLeftY;
|
|
srcRect.bottom = viewport.m_nTopLeftY + viewport.m_nHeight;
|
|
|
|
hr = Dx9Device()->Present( &srcRect, &destRect, (VD3DHWND)m_ViewHWnd, 0 );
|
|
}
|
|
else
|
|
{
|
|
g_pShaderAPI->OwnGPUResources( false );
|
|
hr = Dx9Device()->Present( 0, 0, 0, 0 );
|
|
}
|
|
}
|
|
|
|
UpdatePresentStats();
|
|
|
|
if ( IsWindows() )
|
|
{
|
|
if ( hr == D3DERR_DRIVERINTERNALERROR )
|
|
{
|
|
/* Usually this bug means that the driver has run out of internal video
|
|
memory, due to leaking it slowly over several application restarts.
|
|
As of summer 2007, IE in particular seemed to leak a lot of driver
|
|
memory for every image context it created in the browser window. A
|
|
reboot clears out the leaked memory and will generally allow the game
|
|
to be run again; occasionally (but not frequently) it's necessary to
|
|
reduce video settings in the game as well to run. But, this is too
|
|
fine a distinction to explain in a dialog, so place the guilt on the
|
|
user and ask them to reduce video settings regardless.
|
|
*/
|
|
|
|
Error( "Internal driver error at Present.\n"
|
|
"You're likely out of OS Paged Pool Memory! For more info, see\n"
|
|
"http://support.steampowered.com/cgi-bin/steampowered.cfg/php/enduser/std_adp.php?p_faqid=150\n" );
|
|
}
|
|
if ( hr == D3DERR_DEVICELOST )
|
|
{
|
|
MarkDeviceLost();
|
|
}
|
|
}
|
|
|
|
MeshMgr()->DiscardVertexBuffers();
|
|
|
|
if ( bInMainThread )
|
|
{
|
|
CheckDeviceLost( m_bOtherAppInitializing );
|
|
}
|
|
|
|
if ( IsX360() )
|
|
{
|
|
// according to docs - "Mandatory Reset of GPU Registers"
|
|
// 360 must force the cached state to be dirty after any present()
|
|
g_pShaderAPI->ResetRenderState( false );
|
|
}
|
|
|
|
#ifdef RECORD_KEYFRAMES
|
|
static int frame = 0;
|
|
++frame;
|
|
if (frame == KEYFRAME_INTERVAL)
|
|
{
|
|
RECORD_COMMAND( DX8_KEYFRAME, 0 );
|
|
|
|
g_pShaderAPI->ResetRenderState();
|
|
frame = 0;
|
|
}
|
|
#endif
|
|
|
|
g_pShaderAPI->AdvancePIXFrame();
|
|
|
|
if ( !IsDeactivated() )
|
|
{
|
|
#ifndef DX_TO_GL_ABSTRACTION
|
|
if ( ( ShaderUtil()->GetConfig().bMeasureFillRate || ShaderUtil()->GetConfig().bVisualizeFillRate ) )
|
|
{
|
|
g_pShaderAPI->ClearBuffers( true, true, true, -1, -1 );
|
|
}
|
|
#endif
|
|
|
|
Dx9Device()->BeginScene();
|
|
}
|
|
}
|
|
|
|
|
|
// We need to scale our colors to the range [16, 235] to keep our colors within TV standards. Some colors might
|
|
// still be out of gamut if any of the R, G, or B channels are more than 191 units apart from each other in
|
|
// the 0-255 scale, but it looks like the 360 deals with this for us by lowering the bright saturated color components.
|
|
// NOTE: I'm leaving the max at 255 to retain whiter than whites. On most TV's, we seems a little dark in the bright colors
|
|
// compared to TV and movies when played in the same conditions. This keeps out brights on par with what customers are
|
|
// used to seeing.
|
|
// TV's generally have a 2.5 gamma, so we need to convert our 2.2 frame buffer into a 2.5 frame buffer for display on a TV
|
|
|
|
void CShaderDeviceDx8::SetHardwareGammaRamp( float fGamma, float fGammaTVRangeMin, float fGammaTVRangeMax, float fGammaTVExponent, bool bTVEnabled )
|
|
{
|
|
DevMsg( 2, "SetHardwareGammaRamp( %f )\n", fGamma );
|
|
|
|
Assert( Dx9Device() );
|
|
if( !Dx9Device() )
|
|
return;
|
|
|
|
D3DGAMMARAMP gammaRamp;
|
|
for ( int i = 0; i < 256; i++ )
|
|
{
|
|
float flInputValue = float( i ) / 255.0f;
|
|
|
|
// Since the 360's sRGB read/write is a piecewise linear approximation, we need to correct for the difference in gamma space here
|
|
float flSrgbGammaValue;
|
|
if ( IsX360() ) // Should we also do this for the PS3?
|
|
{
|
|
// First undo the 360 broken sRGB curve by bringing the value back into linear space
|
|
float flLinearValue = X360GammaToLinear( flInputValue );
|
|
flLinearValue = clamp( flLinearValue, 0.0f, 1.0f );
|
|
|
|
// Now apply a true sRGB curve to mimic PC hardware
|
|
flSrgbGammaValue = SrgbLinearToGamma( flLinearValue ); // ( flLinearValue <= 0.0031308f ) ? ( flLinearValue * 12.92f ) : ( 1.055f * powf( flLinearValue, ( 1.0f / 2.4f ) ) ) - 0.055f;
|
|
flSrgbGammaValue = clamp( flSrgbGammaValue, 0.0f, 1.0f );
|
|
}
|
|
else
|
|
{
|
|
flSrgbGammaValue = flInputValue;
|
|
}
|
|
|
|
// Apply the user controlled exponent curve
|
|
float flCorrection = pow( flSrgbGammaValue, ( fGamma / 2.2f ) );
|
|
flCorrection = clamp( flCorrection, 0.0f, 1.0f );
|
|
|
|
// TV adjustment - Apply an exp and a scale and bias
|
|
if ( bTVEnabled )
|
|
{
|
|
// Adjust for TV gamma of 2.5 by applying an exponent of 2.2 / 2.5 = 0.88
|
|
flCorrection = pow( flCorrection, 2.2f / fGammaTVExponent );
|
|
flCorrection = clamp( flCorrection, 0.0f, 1.0f );
|
|
|
|
// Scale and bias to fit into the 16-235 range for TV's
|
|
flCorrection = ( flCorrection * ( fGammaTVRangeMax - fGammaTVRangeMin ) / 255.0f ) + ( fGammaTVRangeMin / 255.0f );
|
|
flCorrection = clamp( flCorrection, 0.0f, 1.0f );
|
|
}
|
|
|
|
// Generate final int value
|
|
unsigned int val = ( int )( flCorrection * 65535.0f );
|
|
gammaRamp.red[i] = val;
|
|
gammaRamp.green[i] = val;
|
|
gammaRamp.blue[i] = val;
|
|
}
|
|
|
|
Dx9Device()->SetGammaRamp( 0, D3DSGR_NO_CALIBRATION, &gammaRamp );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Shader compilation
|
|
//-----------------------------------------------------------------------------
|
|
IShaderBuffer* CShaderDeviceDx8::CompileShader( const char *pProgram, size_t nBufLen, const char *pShaderVersion )
|
|
{
|
|
return ShaderManager()->CompileShader( pProgram, nBufLen, pShaderVersion );
|
|
}
|
|
|
|
VertexShaderHandle_t CShaderDeviceDx8::CreateVertexShader( IShaderBuffer *pBuffer )
|
|
{
|
|
return ShaderManager()->CreateVertexShader( pBuffer );
|
|
}
|
|
|
|
void CShaderDeviceDx8::DestroyVertexShader( VertexShaderHandle_t hShader )
|
|
{
|
|
ShaderManager()->DestroyVertexShader( hShader );
|
|
}
|
|
|
|
GeometryShaderHandle_t CShaderDeviceDx8::CreateGeometryShader( IShaderBuffer* pShaderBuffer )
|
|
{
|
|
Assert( 0 );
|
|
return GEOMETRY_SHADER_HANDLE_INVALID;
|
|
}
|
|
|
|
void CShaderDeviceDx8::DestroyGeometryShader( GeometryShaderHandle_t hShader )
|
|
{
|
|
Assert( hShader == GEOMETRY_SHADER_HANDLE_INVALID );
|
|
}
|
|
|
|
PixelShaderHandle_t CShaderDeviceDx8::CreatePixelShader( IShaderBuffer *pBuffer )
|
|
{
|
|
return ShaderManager()->CreatePixelShader( pBuffer );
|
|
}
|
|
|
|
void CShaderDeviceDx8::DestroyPixelShader( PixelShaderHandle_t hShader )
|
|
{
|
|
ShaderManager()->DestroyPixelShader( hShader );
|
|
}
|
|
|
|
#ifdef DX_TO_GL_ABSTRACTION
|
|
void CShaderDeviceDx8::DoStartupShaderPreloading( void )
|
|
{
|
|
ShaderManager()->DoStartupShaderPreloading();
|
|
}
|
|
#endif
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Creates/destroys Mesh
|
|
// NOTE: Will be deprecated soon!
|
|
//-----------------------------------------------------------------------------
|
|
IMesh* CShaderDeviceDx8::CreateStaticMesh( VertexFormat_t vertexFormat, const char *pTextureBudgetGroup, IMaterial * pMaterial )
|
|
{
|
|
LOCK_SHADERAPI();
|
|
return MeshMgr()->CreateStaticMesh( vertexFormat, pTextureBudgetGroup, pMaterial );
|
|
}
|
|
|
|
void CShaderDeviceDx8::DestroyStaticMesh( IMesh* pMesh )
|
|
{
|
|
LOCK_SHADERAPI();
|
|
MeshMgr()->DestroyStaticMesh( pMesh );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Creates/destroys vertex buffers + index buffers
|
|
//-----------------------------------------------------------------------------
|
|
IVertexBuffer *CShaderDeviceDx8::CreateVertexBuffer( ShaderBufferType_t type, VertexFormat_t fmt, int nVertexCount, const char *pBudgetGroup )
|
|
{
|
|
LOCK_SHADERAPI();
|
|
return MeshMgr()->CreateVertexBuffer( type, fmt, nVertexCount, pBudgetGroup );
|
|
}
|
|
|
|
void CShaderDeviceDx8::DestroyVertexBuffer( IVertexBuffer *pVertexBuffer )
|
|
{
|
|
LOCK_SHADERAPI();
|
|
MeshMgr()->DestroyVertexBuffer( pVertexBuffer );
|
|
}
|
|
|
|
IIndexBuffer *CShaderDeviceDx8::CreateIndexBuffer( ShaderBufferType_t bufferType, MaterialIndexFormat_t fmt, int nIndexCount, const char *pBudgetGroup )
|
|
{
|
|
LOCK_SHADERAPI();
|
|
return MeshMgr()->CreateIndexBuffer( bufferType, fmt, nIndexCount, pBudgetGroup );
|
|
}
|
|
|
|
void CShaderDeviceDx8::DestroyIndexBuffer( IIndexBuffer *pIndexBuffer )
|
|
{
|
|
LOCK_SHADERAPI();
|
|
MeshMgr()->DestroyIndexBuffer( pIndexBuffer );
|
|
}
|
|
|
|
IVertexBuffer *CShaderDeviceDx8::GetDynamicVertexBuffer( int streamID, VertexFormat_t vertexFormat, bool bBuffered )
|
|
{
|
|
LOCK_SHADERAPI();
|
|
return MeshMgr()->GetDynamicVertexBuffer( streamID, vertexFormat, bBuffered );
|
|
}
|
|
|
|
IIndexBuffer *CShaderDeviceDx8::GetDynamicIndexBuffer( MaterialIndexFormat_t fmt, bool bBuffered )
|
|
{
|
|
LOCK_SHADERAPI();
|
|
return MeshMgr()->GetDynamicIndexBuffer( fmt, bBuffered );
|
|
}
|
|
|
|
#ifdef _X360
|
|
void CShaderDeviceDx8::SpewVideoInfo360( const CCommand &args )
|
|
{
|
|
XVIDEO_MODE videoMode;
|
|
XGetVideoMode( &videoMode );
|
|
|
|
Warning( "back buffer size: %dx%d\n", m_PresentParameters.BackBufferWidth, m_PresentParameters.BackBufferHeight );
|
|
Warning( "display resolution: %dx%d %s\n", videoMode.dwDisplayWidth, videoMode.dwDisplayHeight, videoMode.fIsInterlaced ? "interlaced" : "progressive" );
|
|
Warning( "refresh rate: %f\n", videoMode.RefreshRate );
|
|
Warning( "aspect: %s\n", videoMode.fIsWideScreen ? "16x9 (widescreen)" : "4x3 (normal)" );
|
|
Warning( "%s\n", videoMode.fIsHiDef ? "hidef" : "lodef" );
|
|
switch( videoMode.VideoStandard )
|
|
{
|
|
case XC_VIDEO_STANDARD_NTSC_M:
|
|
Warning( "video standard: NTSC_M\n" );
|
|
break;
|
|
case XC_VIDEO_STANDARD_NTSC_J:
|
|
Warning( "video standard: NTSC_J\n" );
|
|
break;
|
|
case XC_VIDEO_STANDARD_PAL_I:
|
|
Warning( "video standard: PAL_I\n" );
|
|
break;
|
|
default:
|
|
Warning( "error: UNKNOWN VIDEO STANDARD!\n" );
|
|
Assert( 0 );
|
|
break;
|
|
}
|
|
ConVarRef fps_max( "fps_max" );
|
|
Warning( "fps_max: %f\n", fps_max.GetFloat() );
|
|
switch( m_PresentParameters.MultiSampleType )
|
|
{
|
|
case D3DMULTISAMPLE_NONE:
|
|
Warning( "multisample type: D3DMULTISAMPLE_NONE\n" );
|
|
break;
|
|
case D3DMULTISAMPLE_2_SAMPLES:
|
|
Warning( "multisample type: D3DMULTISAMPLE_2_SAMPLES\n" );
|
|
break;
|
|
case D3DMULTISAMPLE_4_SAMPLES:
|
|
Warning( "multisample type: D3DMULTISAMPLE_4_SAMPLES\n" );
|
|
break;
|
|
}
|
|
}
|
|
#endif
|