2013-04-17 23:29:41 -04: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-06-03 01:08:54 -04:00
#include <string>
2014-02-17 05:18:15 -05:00
#include "Common/FileUtil.h"
#include "Common/LinearDiskCache.h"
2014-06-03 01:08:54 -04:00
#include "Common/StringUtil.h"
2010-06-13 19:50:06 +00:00
2014-02-17 05:18:15 -05:00
#include "Core/ConfigManager.h"
2011-01-25 16:43:08 +00:00
2014-02-17 05:18:15 -05: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 05:18:15 -05: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 23:35:14 +01:00
VertexShaderUid VertexShaderCache :: last_uid ;
2013-04-29 21:00:39 +02:00
UidChecker < VertexShaderUid , VertexShaderCode > VertexShaderCache :: vertex_uid_checker ;
2010-06-13 19:50:06 +00:00
2014-03-09 21:14:26 +01: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 23:35:14 +01: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 21:14:26 +01: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 17:52:22 +02: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 17:52:22 +02:00
memcpy ( map . pData , & VertexShaderManager :: constants , sizeof ( VertexShaderConstants ));
2011-06-11 19:37:21 +00:00
D3D :: context -> Unmap ( vscbuf , 0 );
2013-10-07 17:52:22 +02:00
VertexShaderManager :: dirty = false ;
2013-10-29 01:23:17 -04:00
2013-10-07 17:52:22 +02: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 23:35:14 +01: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 23:35:14 +01: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 01:23:17 -04: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 01:23:17 -04: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 17:52:22 +02: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 21:14:26 +01: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 ;
2014-07-07 19:28:12 -04:00
D3D :: CompileVertexShader ( simple_shader_code , & blob );
2011-06-11 19:37:21 +00:00
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 21:14:26 +01: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
2014-07-07 19:28:12 -04:00
D3D :: CompileVertexShader ( clear_shader_code , & blob );
2011-06-11 19:37:21 +00:00
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 21:14:26 +01: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 15:33:41 -04: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 );
2014-06-03 01:08:54 -04:00
std :: string cache_filename = StringFromFormat ( "%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 03:10:28 +02:00
2011-09-29 23:32:05 +02:00
if ( g_Config . bEnableShaderDebugging )
2011-09-10 03:10:28 +02:00
Clear ();
2011-09-29 22:54:52 +02:00
2014-03-09 21:14:26 +01:00
last_entry = nullptr ;
2010-06-13 19:50:06 +00:00
}
void VertexShaderCache :: Clear ()
{
2014-02-12 16:00:34 +01:00
for ( auto & iter : vshaders )
iter . second . Destroy ();
2010-06-13 19:50:06 +00:00
vshaders . clear ();
2013-04-29 21:00:39 +02:00
vertex_uid_checker . Invalidate ();
2011-09-29 22:54:52 +02:00
2014-03-09 21:14:26 +01: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 23:35:14 +01:00
VertexShaderUid uid ;
2013-09-22 18:07:21 +02:00
GetVertexShaderUid ( uid , components , API_D3D );
2013-04-29 21:00:39 +02:00
if ( g_ActiveConfig . bEnableShaderDebugging )
{
VertexShaderCode code ;
2013-09-22 18:07:21 +02:00
GenerateVertexShaderCode ( code , components , API_D3D );
2013-04-29 21:00:39 +02:00
vertex_uid_checker . AddToIndexAndCheck ( code , uid , "Vertex" , "v" );
}
2011-09-29 22:54:52 +02:00
if ( last_entry )
2010-12-05 14:15:36 +00:00
{
2011-09-29 22:54:52 +02:00
if ( uid == last_uid )
{
GFX_DEBUGGER_PAUSE_AT ( NEXT_VERTEX_SHADER_CHANGE , true );
2014-03-09 21:14:26 +01:00
return ( last_entry -> shader != nullptr );
2011-09-29 22:54:52 +02:00
}
2010-12-05 14:15:36 +00:00
}
2010-06-13 19:50:06 +00:00
2011-09-29 22:54:52 +02: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 21:14:26 +01:00
return ( entry . shader != nullptr );
2010-06-13 19:50:06 +00:00
}
2013-03-26 23:35:14 +01:00
VertexShaderCode code ;
2013-09-22 18:07:21 +02:00
GenerateVertexShaderCode ( code , components , API_D3D );
2010-06-13 19:50:06 +00:00
2014-03-09 21:14:26 +01:00
D3DBlob * pbytecode = nullptr ;
2014-07-07 19:28:12 -04:00
D3D :: CompileVertexShader ( code . GetBuffer (), & pbytecode );
2011-06-11 19:37:21 +00:00
2014-03-09 21:14:26 +01: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-09 00:32:04 +02:00
bool success = InsertByteCode ( uid , pbytecode );
2011-06-11 19:37:21 +00:00
pbytecode -> Release ();
2011-09-09 00:32:04 +02:00
2011-09-09 21:34:46 +02:00
if ( g_ActiveConfig . bEnableShaderDebugging && success )
2011-09-09 00:32:04 +02:00
{
2013-03-26 23:35:14 +01:00
vshaders [ uid ]. code = code . GetBuffer ();
2011-09-09 00:32:04 +02:00
}
2010-12-05 14:15:36 +00:00
GFX_DEBUGGER_PAUSE_AT ( NEXT_VERTEX_SHADER_CHANGE , true );
2011-09-09 00:32:04 +02:00
return success ;
2010-06-13 19:50:06 +00:00
}
2013-03-26 23:35:14 +01: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 21:14:26 +01:00
if ( shader == nullptr )
2010-06-13 19:50:06 +00:00
return false ;
2011-09-08 22:59:34 +02: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