2013-04-18 03:29:41 +00:00
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
2010-06-13 19:50:06 +00:00
2014-02-17 10:18:15 +00:00
# include "Common/FileUtil.h"
# include "Common/LinearDiskCache.h"
2010-06-13 19:50:06 +00:00
2014-02-17 10:18:15 +00:00
# include "Core/ConfigManager.h"
2011-01-25 16:43:08 +00:00
2014-02-17 10:18:15 +00:00
# include "VideoBackends/D3D/D3DShader.h"
# include "VideoBackends/D3D/Globals.h"
# include "VideoBackends/D3D/VertexShaderCache.h"
2010-06-13 19:50:06 +00:00
2014-02-17 10:18:15 +00:00
# include "VideoCommon/Debugger.h"
# include "VideoCommon/Statistics.h"
# include "VideoCommon/VertexShaderGen.h"
# include "VideoCommon/VertexShaderManager.h"
2011-01-31 01:28:32 +00:00
2011-01-29 20:16:51 +00:00
namespace DX11 {
2010-06-13 19:50:06 +00:00
VertexShaderCache : : VSCache VertexShaderCache : : vshaders ;
2011-06-11 19:37:21 +00:00
const VertexShaderCache : : VSCacheEntry * VertexShaderCache : : last_entry ;
2013-03-26 22:35:14 +00:00
VertexShaderUid VertexShaderCache : : last_uid ;
2013-04-29 19:00:39 +00:00
UidChecker < VertexShaderUid , VertexShaderCode > VertexShaderCache : : vertex_uid_checker ;
2010-06-13 19:50:06 +00:00
2014-03-09 20:14:26 +00:00
static ID3D11VertexShader * SimpleVertexShader = nullptr ;
static ID3D11VertexShader * ClearVertexShader = nullptr ;
static ID3D11InputLayout * SimpleLayout = nullptr ;
static ID3D11InputLayout * ClearLayout = nullptr ;
2010-06-13 19:50:06 +00:00
2013-03-26 22:35:14 +00:00
LinearDiskCache < VertexShaderUid , u8 > g_vs_disk_cache ;
2010-06-13 19:50:06 +00:00
ID3D11VertexShader * VertexShaderCache : : GetSimpleVertexShader ( ) { return SimpleVertexShader ; }
ID3D11VertexShader * VertexShaderCache : : GetClearVertexShader ( ) { return ClearVertexShader ; }
ID3D11InputLayout * VertexShaderCache : : GetSimpleInputLayout ( ) { return SimpleLayout ; }
ID3D11InputLayout * VertexShaderCache : : GetClearInputLayout ( ) { return ClearLayout ; }
2014-03-09 20:14:26 +00:00
ID3D11Buffer * vscbuf = nullptr ;
2011-01-25 15:08:30 +00:00
2011-06-11 19:37:21 +00:00
ID3D11Buffer * & VertexShaderCache : : GetConstantBuffer ( )
2011-01-25 15:08:30 +00:00
{
// TODO: divide the global variables of the generated shaders into about 5 constant buffers to speed this up
2013-10-07 15:52:22 +00:00
if ( VertexShaderManager : : dirty )
2011-01-25 15:08:30 +00:00
{
D3D11_MAPPED_SUBRESOURCE map ;
2011-06-11 19:37:21 +00:00
D3D : : context - > Map ( vscbuf , 0 , D3D11_MAP_WRITE_DISCARD , 0 , & map ) ;
2013-10-07 15:52:22 +00:00
memcpy ( map . pData , & VertexShaderManager : : constants , sizeof ( VertexShaderConstants ) ) ;
2011-06-11 19:37:21 +00:00
D3D : : context - > Unmap ( vscbuf , 0 ) ;
2013-10-07 15:52:22 +00:00
VertexShaderManager : : dirty = false ;
2013-10-29 05:23:17 +00:00
2013-10-07 15:52:22 +00:00
ADDSTAT ( stats . thisFrame . bytesUniformStreamed , sizeof ( VertexShaderConstants ) ) ;
2011-01-25 15:08:30 +00:00
}
return vscbuf ;
2010-06-13 19:50:06 +00:00
}
// this class will load the precompiled shaders into our cache
2013-03-26 22:35:14 +00:00
class VertexShaderCacheInserter : public LinearDiskCacheReader < VertexShaderUid , u8 >
2010-11-15 05:22:03 +00:00
{
2010-06-13 19:50:06 +00:00
public :
2013-03-26 22:35:14 +00:00
void Read ( const VertexShaderUid & key , const u8 * value , u32 value_size )
2010-06-13 19:50:06 +00:00
{
2011-06-11 19:37:21 +00:00
D3DBlob * blob = new D3DBlob ( value_size , value ) ;
VertexShaderCache : : InsertByteCode ( key , blob ) ;
blob - > Release ( ) ;
2010-11-15 05:22:03 +00:00
2010-06-13 19:50:06 +00:00
}
} ;
const char simple_shader_code [ ] = {
" struct VSOUTPUT \n "
" { \n "
" float4 vPosition : POSITION; \n "
" float2 vTexCoord : TEXCOORD0; \n "
2010-12-27 03:18:01 +00:00
" float vTexCoord1 : TEXCOORD1; \n "
2010-06-13 19:50:06 +00:00
" }; \n "
2010-12-27 03:18:01 +00:00
" VSOUTPUT main(float4 inPosition : POSITION,float3 inTEX0 : TEXCOORD0) \n "
2010-06-13 19:50:06 +00:00
" { \n "
" VSOUTPUT OUT; \n "
" OUT.vPosition = inPosition; \n "
2010-12-27 03:18:01 +00:00
" OUT.vTexCoord = inTEX0.xy; \n "
" OUT.vTexCoord1 = inTEX0.z; \n "
2010-06-13 19:50:06 +00:00
" return OUT; \n "
" } \n "
} ;
const char clear_shader_code [ ] = {
" struct VSOUTPUT \n "
" { \n "
" float4 vPosition : POSITION; \n "
2013-10-29 05:23:17 +00:00
" float4 vColor0 : COLOR0; \n "
2010-06-13 19:50:06 +00:00
" }; \n "
" VSOUTPUT main(float4 inPosition : POSITION,float4 inColor0: COLOR0) \n "
" { \n "
" VSOUTPUT OUT; \n "
" OUT.vPosition = inPosition; \n "
" OUT.vColor0 = inColor0; \n "
" return OUT; \n "
" } \n "
} ;
void VertexShaderCache : : Init ( )
{
const D3D11_INPUT_ELEMENT_DESC simpleelems [ 2 ] =
{
{ " POSITION " , 0 , DXGI_FORMAT_R32G32B32_FLOAT , 0 , 0 , D3D11_INPUT_PER_VERTEX_DATA , 0 } ,
2010-12-27 03:18:01 +00:00
{ " TEXCOORD " , 0 , DXGI_FORMAT_R32G32B32_FLOAT , 0 , 12 , D3D11_INPUT_PER_VERTEX_DATA , 0 } ,
2013-10-29 05:23:17 +00:00
2010-06-13 19:50:06 +00:00
} ;
const D3D11_INPUT_ELEMENT_DESC clearelems [ 2 ] =
{
{ " POSITION " , 0 , DXGI_FORMAT_R32G32B32_FLOAT , 0 , 0 , D3D11_INPUT_PER_VERTEX_DATA , 0 } ,
2010-06-19 01:02:43 +00:00
{ " COLOR " , 0 , DXGI_FORMAT_R8G8B8A8_UNORM , 0 , 12 , D3D11_INPUT_PER_VERTEX_DATA , 0 } ,
2010-06-13 19:50:06 +00:00
} ;
2013-10-07 15:52:22 +00:00
unsigned int cbsize = ( ( sizeof ( VertexShaderConstants ) ) & ( ~ 0xf ) ) + 0x10 ; // must be a multiple of 16
2011-01-25 15:08:30 +00:00
D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC ( cbsize , D3D11_BIND_CONSTANT_BUFFER , D3D11_USAGE_DYNAMIC , D3D11_CPU_ACCESS_WRITE ) ;
2014-03-09 20:14:26 +00:00
HRESULT hr = D3D : : device - > CreateBuffer ( & cbdesc , nullptr , & vscbuf ) ;
2011-06-11 19:37:21 +00:00
CHECK ( hr = = S_OK , " Create vertex shader constant buffer (size=%u) " , cbsize ) ;
D3D : : SetDebugObjectName ( ( ID3D11DeviceChild * ) vscbuf , " vertex shader constant buffer used to emulate the GX pipeline " ) ;
2011-01-25 15:08:30 +00:00
2011-06-11 19:37:21 +00:00
D3DBlob * blob ;
D3D : : CompileVertexShader ( simple_shader_code , sizeof ( simple_shader_code ) , & blob ) ;
D3D : : device - > CreateInputLayout ( simpleelems , 2 , blob - > Data ( ) , blob - > Size ( ) , & SimpleLayout ) ;
2010-06-13 19:50:06 +00:00
SimpleVertexShader = D3D : : CreateVertexShaderFromByteCode ( blob ) ;
2014-03-09 20:14:26 +00:00
if ( SimpleLayout = = nullptr | | SimpleVertexShader = = nullptr ) PanicAlert ( " Failed to create simple vertex shader or input layout at %s %d \n " , __FILE__ , __LINE__ ) ;
2011-06-11 19:37:21 +00:00
blob - > Release ( ) ;
D3D : : SetDebugObjectName ( ( ID3D11DeviceChild * ) SimpleVertexShader , " simple vertex shader " ) ;
D3D : : SetDebugObjectName ( ( ID3D11DeviceChild * ) SimpleLayout , " simple input layout " ) ;
2010-06-13 19:50:06 +00:00
2011-06-11 19:37:21 +00:00
D3D : : CompileVertexShader ( clear_shader_code , sizeof ( clear_shader_code ) , & blob ) ;
D3D : : device - > CreateInputLayout ( clearelems , 2 , blob - > Data ( ) , blob - > Size ( ) , & ClearLayout ) ;
2010-06-13 19:50:06 +00:00
ClearVertexShader = D3D : : CreateVertexShaderFromByteCode ( blob ) ;
2014-03-09 20:14:26 +00:00
if ( ClearLayout = = nullptr | | ClearVertexShader = = nullptr ) PanicAlert ( " Failed to create clear vertex shader or input layout at %s %d \n " , __FILE__ , __LINE__ ) ;
2011-06-11 19:37:21 +00:00
blob - > Release ( ) ;
D3D : : SetDebugObjectName ( ( ID3D11DeviceChild * ) ClearVertexShader , " clear vertex shader " ) ;
D3D : : SetDebugObjectName ( ( ID3D11DeviceChild * ) ClearLayout , " clear input layout " ) ;
2010-06-13 19:50:06 +00:00
Clear ( ) ;
2011-03-01 03:06:14 +00:00
if ( ! File : : Exists ( File : : GetUserPath ( D_SHADERCACHE_IDX ) ) )
2014-03-12 19:33:41 +00:00
File : : CreateDir ( File : : GetUserPath ( D_SHADERCACHE_IDX ) ) ;
2010-06-13 19:50:06 +00:00
2010-09-28 02:15:02 +00:00
SETSTAT ( stats . numVertexShadersCreated , 0 ) ;
SETSTAT ( stats . numVertexShadersAlive , 0 ) ;
2010-06-13 19:50:06 +00:00
char cache_filename [ MAX_PATH ] ;
2011-02-28 20:40:15 +00:00
sprintf ( cache_filename , " %sdx11-%s-vs.cache " , File : : GetUserPath ( D_SHADERCACHE_IDX ) . c_str ( ) ,
2011-06-11 19:37:21 +00:00
SConfig : : GetInstance ( ) . m_LocalCoreStartupParameter . m_strUniqueID . c_str ( ) ) ;
VertexShaderCacheInserter inserter ;
g_vs_disk_cache . OpenAndRead ( cache_filename , inserter ) ;
2011-09-10 01:10:28 +00:00
2011-09-29 21:32:05 +00:00
if ( g_Config . bEnableShaderDebugging )
2011-09-10 01:10:28 +00:00
Clear ( ) ;
2011-09-29 20:54:52 +00:00
2014-03-09 20:14:26 +00:00
last_entry = nullptr ;
2010-06-13 19:50:06 +00:00
}
void VertexShaderCache : : Clear ( )
{
2014-02-12 15:00:34 +00:00
for ( auto & iter : vshaders )
iter . second . Destroy ( ) ;
2010-06-13 19:50:06 +00:00
vshaders . clear ( ) ;
2013-04-29 19:00:39 +00:00
vertex_uid_checker . Invalidate ( ) ;
2011-09-29 20:54:52 +00:00
2014-03-09 20:14:26 +00:00
last_entry = nullptr ;
2010-06-13 19:50:06 +00:00
}
void VertexShaderCache : : Shutdown ( )
{
2011-06-11 19:37:21 +00:00
SAFE_RELEASE ( vscbuf ) ;
2011-01-25 15:08:30 +00:00
2011-06-11 19:37:21 +00:00
SAFE_RELEASE ( SimpleVertexShader ) ;
SAFE_RELEASE ( ClearVertexShader ) ;
2010-06-13 19:50:06 +00:00
2011-06-11 19:37:21 +00:00
SAFE_RELEASE ( SimpleLayout ) ;
SAFE_RELEASE ( ClearLayout ) ;
2010-06-13 19:50:06 +00:00
Clear ( ) ;
g_vs_disk_cache . Sync ( ) ;
g_vs_disk_cache . Close ( ) ;
}
2011-06-11 19:37:21 +00:00
bool VertexShaderCache : : SetShader ( u32 components )
2010-06-13 19:50:06 +00:00
{
2013-03-26 22:35:14 +00:00
VertexShaderUid uid ;
2013-09-22 16:07:21 +00:00
GetVertexShaderUid ( uid , components , API_D3D ) ;
2013-04-29 19:00:39 +00:00
if ( g_ActiveConfig . bEnableShaderDebugging )
{
VertexShaderCode code ;
2013-09-22 16:07:21 +00:00
GenerateVertexShaderCode ( code , components , API_D3D ) ;
2013-04-29 19:00:39 +00:00
vertex_uid_checker . AddToIndexAndCheck ( code , uid , " Vertex " , " v " ) ;
}
2011-09-29 20:54:52 +00:00
if ( last_entry )
2010-12-05 14:15:36 +00:00
{
2011-09-29 20:54:52 +00:00
if ( uid = = last_uid )
{
GFX_DEBUGGER_PAUSE_AT ( NEXT_VERTEX_SHADER_CHANGE , true ) ;
2014-03-09 20:14:26 +00:00
return ( last_entry - > shader ! = nullptr ) ;
2011-09-29 20:54:52 +00:00
}
2010-12-05 14:15:36 +00:00
}
2010-06-13 19:50:06 +00:00
2011-09-29 20:54:52 +00:00
last_uid = uid ;
2010-06-13 19:50:06 +00:00
2010-09-28 02:15:02 +00:00
VSCache : : iterator iter = vshaders . find ( uid ) ;
2010-06-13 19:50:06 +00:00
if ( iter ! = vshaders . end ( ) )
{
const VSCacheEntry & entry = iter - > second ;
last_entry = & entry ;
2010-12-05 14:15:36 +00:00
GFX_DEBUGGER_PAUSE_AT ( NEXT_VERTEX_SHADER_CHANGE , true ) ;
2014-03-09 20:14:26 +00:00
return ( entry . shader ! = nullptr ) ;
2010-06-13 19:50:06 +00:00
}
2013-03-26 22:35:14 +00:00
VertexShaderCode code ;
2013-09-22 16:07:21 +00:00
GenerateVertexShaderCode ( code , components , API_D3D ) ;
2010-06-13 19:50:06 +00:00
2014-03-09 20:14:26 +00:00
D3DBlob * pbytecode = nullptr ;
2013-03-26 22:35:14 +00:00
D3D : : CompileVertexShader ( code . GetBuffer ( ) , ( int ) strlen ( code . GetBuffer ( ) ) , & pbytecode ) ;
2011-06-11 19:37:21 +00:00
2014-03-09 20:14:26 +00:00
if ( pbytecode = = nullptr )
2010-06-13 19:50:06 +00:00
{
2010-12-05 14:15:36 +00:00
GFX_DEBUGGER_PAUSE_AT ( NEXT_ERROR , true ) ;
2010-06-13 19:50:06 +00:00
return false ;
}
2011-06-11 19:37:21 +00:00
g_vs_disk_cache . Append ( uid , pbytecode - > Data ( ) , pbytecode - > Size ( ) ) ;
2010-06-13 19:50:06 +00:00
2011-09-08 22:32:04 +00:00
bool success = InsertByteCode ( uid , pbytecode ) ;
2011-06-11 19:37:21 +00:00
pbytecode - > Release ( ) ;
2011-09-08 22:32:04 +00:00
2011-09-09 19:34:46 +00:00
if ( g_ActiveConfig . bEnableShaderDebugging & & success )
2011-09-08 22:32:04 +00:00
{
2013-03-26 22:35:14 +00:00
vshaders [ uid ] . code = code . GetBuffer ( ) ;
2011-09-08 22:32:04 +00:00
}
2010-12-05 14:15:36 +00:00
GFX_DEBUGGER_PAUSE_AT ( NEXT_VERTEX_SHADER_CHANGE , true ) ;
2011-09-08 22:32:04 +00:00
return success ;
2010-06-13 19:50:06 +00:00
}
2013-03-26 22:35:14 +00:00
bool VertexShaderCache : : InsertByteCode ( const VertexShaderUid & uid , D3DBlob * bcodeblob )
2010-06-13 19:50:06 +00:00
{
2011-06-11 19:37:21 +00:00
ID3D11VertexShader * shader = D3D : : CreateVertexShaderFromByteCode ( bcodeblob ) ;
2014-03-09 20:14:26 +00:00
if ( shader = = nullptr )
2010-06-13 19:50:06 +00:00
return false ;
2011-09-08 20:59:34 +00:00
2010-06-17 10:42:57 +00:00
// TODO: Somehow make the debug name a bit more specific
2011-06-11 19:37:21 +00:00
D3D : : SetDebugObjectName ( ( ID3D11DeviceChild * ) shader , " a vertex shader of VertexShaderCache " ) ;
2010-06-13 19:50:06 +00:00
// Make an entry in the table
VSCacheEntry entry ;
entry . shader = shader ;
entry . SetByteCode ( bcodeblob ) ;
vshaders [ uid ] = entry ;
last_entry = & vshaders [ uid ] ;
INCSTAT ( stats . numVertexShadersCreated ) ;
SETSTAT ( stats . numVertexShadersAlive , ( int ) vshaders . size ( ) ) ;
return true ;
}
2011-01-31 01:28:32 +00:00
} // namespace DX11