D3D: Uber shader support
This commit is contained in:
parent
cd502990fa
commit
4bf5625895
|
@ -185,10 +185,9 @@ std::vector<DXGI_SAMPLE_DESC> EnumAAModes(IDXGIAdapter* adapter)
|
|||
ID3D11Device* _device;
|
||||
ID3D11DeviceContext* _context;
|
||||
D3D_FEATURE_LEVEL feat_level;
|
||||
HRESULT hr = PD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr,
|
||||
D3D11_CREATE_DEVICE_SINGLETHREADED, supported_feature_levels,
|
||||
NUM_SUPPORTED_FEATURE_LEVELS, D3D11_SDK_VERSION, &_device,
|
||||
&feat_level, &_context);
|
||||
HRESULT hr = PD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0,
|
||||
supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS,
|
||||
D3D11_SDK_VERSION, &_device, &feat_level, &_context);
|
||||
if (FAILED(hr) || feat_level == D3D_FEATURE_LEVEL_10_0)
|
||||
{
|
||||
DXGI_SAMPLE_DESC desc;
|
||||
|
@ -221,9 +220,9 @@ std::vector<DXGI_SAMPLE_DESC> EnumAAModes(IDXGIAdapter* adapter)
|
|||
D3D_FEATURE_LEVEL GetFeatureLevel(IDXGIAdapter* adapter)
|
||||
{
|
||||
D3D_FEATURE_LEVEL feat_level = D3D_FEATURE_LEVEL_9_1;
|
||||
PD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, D3D11_CREATE_DEVICE_SINGLETHREADED,
|
||||
supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS, D3D11_SDK_VERSION,
|
||||
nullptr, &feat_level, nullptr);
|
||||
PD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, supported_feature_levels,
|
||||
NUM_SUPPORTED_FEATURE_LEVELS, D3D11_SDK_VERSION, nullptr, &feat_level,
|
||||
nullptr);
|
||||
return feat_level;
|
||||
}
|
||||
|
||||
|
@ -311,8 +310,7 @@ HRESULT Create(HWND wnd)
|
|||
// Creating debug devices can sometimes fail if the user doesn't have the correct
|
||||
// version of the DirectX SDK. If it does, simply fallback to a non-debug device.
|
||||
{
|
||||
hr = PD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr,
|
||||
D3D11_CREATE_DEVICE_SINGLETHREADED | D3D11_CREATE_DEVICE_DEBUG,
|
||||
hr = PD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, D3D11_CREATE_DEVICE_DEBUG,
|
||||
supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS,
|
||||
D3D11_SDK_VERSION, &device, &featlevel, &context);
|
||||
|
||||
|
@ -339,8 +337,7 @@ HRESULT Create(HWND wnd)
|
|||
if (FAILED(hr))
|
||||
#endif
|
||||
{
|
||||
hr = PD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr,
|
||||
D3D11_CREATE_DEVICE_SINGLETHREADED, supported_feature_levels,
|
||||
hr = PD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, supported_feature_levels,
|
||||
NUM_SUPPORTED_FEATURE_LEVELS, D3D11_SDK_VERSION, &device, &featlevel,
|
||||
&context);
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ namespace DX11
|
|||
namespace D3D
|
||||
{
|
||||
// bytecode->shader
|
||||
ID3D11VertexShader* CreateVertexShaderFromByteCode(const void* bytecode, unsigned int len)
|
||||
ID3D11VertexShader* CreateVertexShaderFromByteCode(const void* bytecode, size_t len)
|
||||
{
|
||||
ID3D11VertexShader* v_shader;
|
||||
HRESULT hr = D3D::device->CreateVertexShader(bytecode, len, nullptr, &v_shader);
|
||||
|
@ -73,7 +73,7 @@ bool CompileVertexShader(const std::string& code, D3DBlob** blob)
|
|||
}
|
||||
|
||||
// bytecode->shader
|
||||
ID3D11GeometryShader* CreateGeometryShaderFromByteCode(const void* bytecode, unsigned int len)
|
||||
ID3D11GeometryShader* CreateGeometryShaderFromByteCode(const void* bytecode, size_t len)
|
||||
{
|
||||
ID3D11GeometryShader* g_shader;
|
||||
HRESULT hr = D3D::device->CreateGeometryShader(bytecode, len, nullptr, &g_shader);
|
||||
|
@ -131,7 +131,7 @@ bool CompileGeometryShader(const std::string& code, D3DBlob** blob,
|
|||
}
|
||||
|
||||
// bytecode->shader
|
||||
ID3D11PixelShader* CreatePixelShaderFromByteCode(const void* bytecode, unsigned int len)
|
||||
ID3D11PixelShader* CreatePixelShaderFromByteCode(const void* bytecode, size_t len)
|
||||
{
|
||||
ID3D11PixelShader* p_shader;
|
||||
HRESULT hr = D3D::device->CreatePixelShader(bytecode, len, nullptr, &p_shader);
|
||||
|
|
|
@ -16,9 +16,9 @@ namespace DX11
|
|||
{
|
||||
namespace D3D
|
||||
{
|
||||
ID3D11VertexShader* CreateVertexShaderFromByteCode(const void* bytecode, unsigned int len);
|
||||
ID3D11GeometryShader* CreateGeometryShaderFromByteCode(const void* bytecode, unsigned int len);
|
||||
ID3D11PixelShader* CreatePixelShaderFromByteCode(const void* bytecode, unsigned int len);
|
||||
ID3D11VertexShader* CreateVertexShaderFromByteCode(const void* bytecode, size_t len);
|
||||
ID3D11GeometryShader* CreateGeometryShaderFromByteCode(const void* bytecode, size_t len);
|
||||
ID3D11PixelShader* CreatePixelShaderFromByteCode(const void* bytecode, size_t len);
|
||||
|
||||
// The returned bytecode buffers should be Release()d.
|
||||
bool CompileVertexShader(const std::string& code, D3DBlob** blob);
|
||||
|
|
|
@ -136,7 +136,7 @@ void StateManager::Apply()
|
|||
m_current.pixelConstants[1] != m_pending.pixelConstants[1])
|
||||
{
|
||||
D3D::context->PSSetConstantBuffers(0, m_pending.pixelConstants[1] ? 2 : 1,
|
||||
m_pending.pixelConstants);
|
||||
m_pending.pixelConstants.data());
|
||||
m_current.pixelConstants[0] = m_pending.pixelConstants[0];
|
||||
m_current.pixelConstants[1] = m_pending.pixelConstants[1];
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <stack>
|
||||
#include <unordered_map>
|
||||
|
@ -269,9 +270,9 @@ private:
|
|||
|
||||
struct Resources
|
||||
{
|
||||
ID3D11ShaderResourceView* textures[8];
|
||||
ID3D11SamplerState* samplers[8];
|
||||
ID3D11Buffer* pixelConstants[2];
|
||||
std::array<ID3D11ShaderResourceView*, 8> textures;
|
||||
std::array<ID3D11SamplerState*, 8> samplers;
|
||||
std::array<ID3D11Buffer*, 2> pixelConstants;
|
||||
ID3D11Buffer* vertexConstants;
|
||||
ID3D11Buffer* geometryConstants;
|
||||
ID3D11Buffer* vertexBuffer;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include "VideoBackends/D3D/D3DBase.h"
|
||||
#include "VideoBackends/D3D/D3DShader.h"
|
||||
#include "VideoBackends/D3D/D3DState.h"
|
||||
#include "VideoBackends/D3D/FramebufferManager.h"
|
||||
#include "VideoBackends/D3D/GeometryShaderCache.h"
|
||||
|
||||
|
@ -159,6 +160,9 @@ void GeometryShaderCache::Init()
|
|||
|
||||
if (g_ActiveConfig.bShaderCache)
|
||||
LoadShaderCache();
|
||||
|
||||
if (g_ActiveConfig.CanPrecompileUberShaders())
|
||||
PrecompileShaders();
|
||||
}
|
||||
|
||||
void GeometryShaderCache::LoadShaderCache()
|
||||
|
@ -175,6 +179,9 @@ void GeometryShaderCache::Reload()
|
|||
|
||||
if (g_ActiveConfig.bShaderCache)
|
||||
LoadShaderCache();
|
||||
|
||||
if (g_ActiveConfig.CanPrecompileUberShaders())
|
||||
PrecompileShaders();
|
||||
}
|
||||
|
||||
// ONLY to be used during shutdown.
|
||||
|
@ -203,78 +210,74 @@ void GeometryShaderCache::Shutdown()
|
|||
bool GeometryShaderCache::SetShader(u32 primitive_type)
|
||||
{
|
||||
GeometryShaderUid uid = GetGeometryShaderUid(primitive_type);
|
||||
|
||||
// Check if the shader is already set
|
||||
if (last_entry)
|
||||
{
|
||||
if (uid == last_uid)
|
||||
if (last_entry && uid == last_uid)
|
||||
{
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true);
|
||||
D3D::stateman->SetGeometryShader(last_entry->shader);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
last_uid = uid;
|
||||
|
||||
// Check if the shader is a pass-through shader
|
||||
if (uid.GetUidData()->IsPassthrough())
|
||||
{
|
||||
// Return the default pass-through shader
|
||||
last_uid = uid;
|
||||
last_entry = &pass_entry;
|
||||
D3D::stateman->SetGeometryShader(last_entry->shader);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if the shader is already in the cache
|
||||
GSCache::iterator iter;
|
||||
iter = GeometryShaders.find(uid);
|
||||
auto iter = GeometryShaders.find(uid);
|
||||
if (iter != GeometryShaders.end())
|
||||
{
|
||||
const GSCacheEntry& entry = iter->second;
|
||||
last_uid = uid;
|
||||
last_entry = &entry;
|
||||
|
||||
D3D::stateman->SetGeometryShader(last_entry->shader);
|
||||
return (entry.shader != nullptr);
|
||||
}
|
||||
|
||||
// Need to compile a new shader
|
||||
if (CompileShader(uid))
|
||||
return SetShader(primitive_type);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GeometryShaderCache::CompileShader(const GeometryShaderUid& uid)
|
||||
{
|
||||
D3DBlob* bytecode;
|
||||
ShaderCode code =
|
||||
GenerateGeometryShaderCode(APIType::D3D, ShaderHostConfig::GetCurrent(), uid.GetUidData());
|
||||
|
||||
D3DBlob* pbytecode;
|
||||
if (!D3D::CompileGeometryShader(code.GetBuffer(), &pbytecode))
|
||||
if (!D3D::CompileGeometryShader(code.GetBuffer(), &bytecode) ||
|
||||
!InsertByteCode(uid, bytecode->Data(), bytecode->Size()))
|
||||
{
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true);
|
||||
SAFE_RELEASE(bytecode);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Insert the bytecode into the caches
|
||||
g_gs_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size());
|
||||
|
||||
bool success = InsertByteCode(uid, pbytecode->Data(), pbytecode->Size());
|
||||
pbytecode->Release();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool GeometryShaderCache::InsertByteCode(const GeometryShaderUid& uid, const void* bytecode,
|
||||
unsigned int bytecodelen)
|
||||
{
|
||||
ID3D11GeometryShader* shader = D3D::CreateGeometryShaderFromByteCode(bytecode, bytecodelen);
|
||||
if (shader == nullptr)
|
||||
return false;
|
||||
|
||||
// TODO: Somehow make the debug name a bit more specific
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)shader, "a pixel shader of GeometryShaderCache");
|
||||
|
||||
// Make an entry in the table
|
||||
GSCacheEntry newentry;
|
||||
newentry.shader = shader;
|
||||
GeometryShaders[uid] = newentry;
|
||||
last_entry = &GeometryShaders[uid];
|
||||
|
||||
if (!shader)
|
||||
return false;
|
||||
|
||||
g_gs_disk_cache.Append(uid, bytecode->Data(), bytecode->Size());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GeometryShaderCache::InsertByteCode(const GeometryShaderUid& uid, const u8* bytecode,
|
||||
size_t len)
|
||||
{
|
||||
GSCacheEntry& newentry = GeometryShaders[uid];
|
||||
newentry.shader = bytecode ? D3D::CreateGeometryShaderFromByteCode(bytecode, len) : nullptr;
|
||||
return newentry.shader != nullptr;
|
||||
}
|
||||
|
||||
void GeometryShaderCache::PrecompileShaders()
|
||||
{
|
||||
EnumerateGeometryShaderUids([](const GeometryShaderUid& uid) {
|
||||
if (GeometryShaders.find(uid) != GeometryShaders.end())
|
||||
return;
|
||||
|
||||
CompileShader(uid);
|
||||
});
|
||||
}
|
||||
|
||||
} // DX11
|
||||
|
|
|
@ -18,14 +18,14 @@ public:
|
|||
static void Reload();
|
||||
static void Clear();
|
||||
static void Shutdown();
|
||||
static bool SetShader(u32 primitive_type); // TODO: Should be renamed to LoadShader
|
||||
static bool InsertByteCode(const GeometryShaderUid& uid, const void* bytecode,
|
||||
unsigned int bytecodelen);
|
||||
static bool SetShader(u32 primitive_type);
|
||||
static bool CompileShader(const GeometryShaderUid& uid);
|
||||
static bool InsertByteCode(const GeometryShaderUid& uid, const u8* bytecode, size_t len);
|
||||
static void PrecompileShaders();
|
||||
|
||||
static ID3D11GeometryShader* GetClearGeometryShader();
|
||||
static ID3D11GeometryShader* GetCopyGeometryShader();
|
||||
|
||||
static ID3D11GeometryShader* GetActiveShader() { return last_entry->shader; }
|
||||
static ID3D11Buffer*& GetConstantBuffer();
|
||||
|
||||
private:
|
||||
|
|
|
@ -13,20 +13,6 @@
|
|||
|
||||
namespace DX11
|
||||
{
|
||||
class D3DVertexFormat : public NativeVertexFormat
|
||||
{
|
||||
public:
|
||||
D3DVertexFormat(const PortableVertexDeclaration& vtx_decl);
|
||||
~D3DVertexFormat() { SAFE_RELEASE(m_layout); }
|
||||
void SetupVertexPointers() override;
|
||||
|
||||
private:
|
||||
std::array<D3D11_INPUT_ELEMENT_DESC, 32> m_elems{};
|
||||
UINT m_num_elems = 0;
|
||||
|
||||
ID3D11InputLayout* m_layout = nullptr;
|
||||
};
|
||||
|
||||
std::unique_ptr<NativeVertexFormat>
|
||||
VertexManager::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
|
||||
{
|
||||
|
@ -66,7 +52,6 @@ D3DVertexFormat::D3DVertexFormat(const PortableVertexDeclaration& _vtx_decl)
|
|||
this->vtx_decl = _vtx_decl;
|
||||
|
||||
const AttributeFormat* format = &_vtx_decl.position;
|
||||
|
||||
if (format->enable)
|
||||
{
|
||||
m_elems[m_num_elems].SemanticName = "POSITION";
|
||||
|
@ -129,15 +114,22 @@ D3DVertexFormat::D3DVertexFormat(const PortableVertexDeclaration& _vtx_decl)
|
|||
}
|
||||
}
|
||||
|
||||
D3DVertexFormat::~D3DVertexFormat()
|
||||
{
|
||||
SAFE_RELEASE(m_layout);
|
||||
}
|
||||
|
||||
void D3DVertexFormat::SetupVertexPointers()
|
||||
{
|
||||
}
|
||||
|
||||
void D3DVertexFormat::SetInputLayout(D3DBlob* vs_bytecode)
|
||||
{
|
||||
if (!m_layout)
|
||||
{
|
||||
// CreateInputLayout requires a shader input, but it only looks at the
|
||||
// signature of the shader, so we don't need to recompute it if the shader
|
||||
// changes.
|
||||
D3DBlob* vs_bytecode = DX11::VertexShaderCache::GetActiveShaderBytecode();
|
||||
|
||||
HRESULT hr = DX11::D3D::device->CreateInputLayout(
|
||||
m_elems.data(), m_num_elems, vs_bytecode->Data(), vs_bytecode->Size(), &m_layout);
|
||||
if (FAILED(hr))
|
||||
|
|
|
@ -8,12 +8,15 @@
|
|||
#include "Common/CommonTypes.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/LinearDiskCache.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "Common/StringUtil.h"
|
||||
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Host.h"
|
||||
|
||||
#include "VideoBackends/D3D/D3DBase.h"
|
||||
#include "VideoBackends/D3D/D3DShader.h"
|
||||
#include "VideoBackends/D3D/D3DState.h"
|
||||
#include "VideoBackends/D3D/PixelShaderCache.h"
|
||||
|
||||
#include "VideoCommon/Debugger.h"
|
||||
|
@ -25,10 +28,15 @@
|
|||
namespace DX11
|
||||
{
|
||||
PixelShaderCache::PSCache PixelShaderCache::PixelShaders;
|
||||
PixelShaderCache::UberPSCache PixelShaderCache::UberPixelShaders;
|
||||
const PixelShaderCache::PSCacheEntry* PixelShaderCache::last_entry;
|
||||
const PixelShaderCache::PSCacheEntry* PixelShaderCache::last_uber_entry;
|
||||
PixelShaderUid PixelShaderCache::last_uid;
|
||||
UberShader::PixelShaderUid PixelShaderCache::last_uber_uid;
|
||||
|
||||
LinearDiskCache<PixelShaderUid, u8> g_ps_disk_cache;
|
||||
LinearDiskCache<UberShader::PixelShaderUid, u8> g_uber_ps_disk_cache;
|
||||
extern std::unique_ptr<VideoCommon::AsyncShaderCompiler> g_async_compiler;
|
||||
|
||||
ID3D11PixelShader* s_ColorMatrixProgram[2] = {nullptr};
|
||||
ID3D11PixelShader* s_ColorCopyProgram[2] = {nullptr};
|
||||
|
@ -429,10 +437,8 @@ ID3D11PixelShader* PixelShaderCache::GetDepthResolveProgram()
|
|||
return s_DepthResolveProgram;
|
||||
}
|
||||
|
||||
ID3D11Buffer*& PixelShaderCache::GetConstantBuffer()
|
||||
static void UpdateConstantBuffers()
|
||||
{
|
||||
// TODO: divide the global variables of the generated shaders into about 5 constant buffers to
|
||||
// speed this up
|
||||
if (PixelShaderManager::dirty)
|
||||
{
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
|
@ -443,14 +449,20 @@ ID3D11Buffer*& PixelShaderCache::GetConstantBuffer()
|
|||
|
||||
ADDSTAT(stats.thisFrame.bytesUniformStreamed, sizeof(PixelShaderConstants));
|
||||
}
|
||||
}
|
||||
|
||||
ID3D11Buffer* PixelShaderCache::GetConstantBuffer()
|
||||
{
|
||||
UpdateConstantBuffers();
|
||||
return pscbuf;
|
||||
}
|
||||
|
||||
// this class will load the precompiled shaders into our cache
|
||||
class PixelShaderCacheInserter : public LinearDiskCacheReader<PixelShaderUid, u8>
|
||||
template <typename UidType>
|
||||
class PixelShaderCacheInserter : public LinearDiskCacheReader<UidType, u8>
|
||||
{
|
||||
public:
|
||||
void Read(const PixelShaderUid& key, const u8* value, u32 value_size)
|
||||
void Read(const UidType& key, const u8* value, u32 value_size)
|
||||
{
|
||||
PixelShaderCache::InsertByteCode(key, value, value_size);
|
||||
}
|
||||
|
@ -499,22 +511,34 @@ void PixelShaderCache::Init()
|
|||
|
||||
if (g_ActiveConfig.bShaderCache)
|
||||
LoadShaderCache();
|
||||
|
||||
if (g_ActiveConfig.CanPrecompileUberShaders())
|
||||
PrecompileUberShaders();
|
||||
}
|
||||
|
||||
void PixelShaderCache::LoadShaderCache()
|
||||
{
|
||||
PixelShaderCacheInserter inserter;
|
||||
PixelShaderCacheInserter<PixelShaderUid> inserter;
|
||||
g_ps_disk_cache.OpenAndRead(GetDiskShaderCacheFileName(APIType::D3D, "PS", true, true), inserter);
|
||||
|
||||
PixelShaderCacheInserter<UberShader::PixelShaderUid> uber_inserter;
|
||||
g_uber_ps_disk_cache.OpenAndRead(GetDiskShaderCacheFileName(APIType::D3D, "UberPS", false, true),
|
||||
uber_inserter);
|
||||
}
|
||||
|
||||
void PixelShaderCache::Reload()
|
||||
{
|
||||
g_ps_disk_cache.Sync();
|
||||
g_ps_disk_cache.Close();
|
||||
g_uber_ps_disk_cache.Sync();
|
||||
g_uber_ps_disk_cache.Close();
|
||||
Clear();
|
||||
|
||||
if (g_ActiveConfig.bShaderCache)
|
||||
LoadShaderCache();
|
||||
|
||||
if (g_ActiveConfig.CanPrecompileUberShaders())
|
||||
PrecompileUberShaders();
|
||||
}
|
||||
|
||||
// ONLY to be used during shutdown.
|
||||
|
@ -522,10 +546,15 @@ void PixelShaderCache::Clear()
|
|||
{
|
||||
for (auto& iter : PixelShaders)
|
||||
iter.second.Destroy();
|
||||
for (auto& iter : UberPixelShaders)
|
||||
iter.second.Destroy();
|
||||
PixelShaders.clear();
|
||||
UberPixelShaders.clear();
|
||||
|
||||
last_entry = nullptr;
|
||||
last_uber_entry = nullptr;
|
||||
last_uid = {};
|
||||
last_uber_uid = {};
|
||||
}
|
||||
|
||||
// Used in Swap() when AA mode has changed
|
||||
|
@ -558,82 +587,252 @@ void PixelShaderCache::Shutdown()
|
|||
Clear();
|
||||
g_ps_disk_cache.Sync();
|
||||
g_ps_disk_cache.Close();
|
||||
g_uber_ps_disk_cache.Sync();
|
||||
g_uber_ps_disk_cache.Close();
|
||||
}
|
||||
|
||||
bool PixelShaderCache::SetShader()
|
||||
{
|
||||
if (g_ActiveConfig.CanUseUberShaders() &&
|
||||
(g_ActiveConfig.bDisableSpecializedShaders || g_ActiveConfig.bForcePixelUberShaders))
|
||||
{
|
||||
return SetUberShader();
|
||||
}
|
||||
|
||||
PixelShaderUid uid = GetPixelShaderUid();
|
||||
|
||||
// Check if the shader is already set
|
||||
if (last_entry)
|
||||
if (last_entry && uid == last_uid)
|
||||
{
|
||||
if (uid == last_uid)
|
||||
{
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true);
|
||||
return (last_entry->shader != nullptr);
|
||||
}
|
||||
}
|
||||
if (last_entry->pending)
|
||||
return SetUberShader();
|
||||
|
||||
last_uid = uid;
|
||||
if (!last_entry->shader)
|
||||
return false;
|
||||
|
||||
D3D::stateman->SetPixelShader(last_entry->shader);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if the shader is already in the cache
|
||||
PSCache::iterator iter;
|
||||
iter = PixelShaders.find(uid);
|
||||
auto iter = PixelShaders.find(uid);
|
||||
if (iter != PixelShaders.end())
|
||||
{
|
||||
const PSCacheEntry& entry = iter->second;
|
||||
if (entry.pending)
|
||||
return SetUberShader();
|
||||
|
||||
last_uid = uid;
|
||||
last_entry = &entry;
|
||||
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true);
|
||||
return (entry.shader != nullptr);
|
||||
if (!last_entry->shader)
|
||||
return false;
|
||||
|
||||
D3D::stateman->SetPixelShader(last_entry->shader);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Background compiling?
|
||||
if (g_ActiveConfig.CanBackgroundCompileShaders())
|
||||
{
|
||||
// Create a pending entry
|
||||
PSCacheEntry entry;
|
||||
entry.pending = true;
|
||||
PixelShaders[uid] = entry;
|
||||
|
||||
// Queue normal shader compiling and use ubershader
|
||||
g_async_compiler->QueueWorkItem(
|
||||
g_async_compiler->CreateWorkItem<PixelShaderCompilerWorkItem>(uid));
|
||||
return SetUberShader();
|
||||
}
|
||||
|
||||
// Need to compile a new shader
|
||||
D3DBlob* bytecode = nullptr;
|
||||
ShaderCode code =
|
||||
GeneratePixelShaderCode(APIType::D3D, ShaderHostConfig::GetCurrent(), uid.GetUidData());
|
||||
|
||||
D3DBlob* pbytecode;
|
||||
if (!D3D::CompilePixelShader(code.GetBuffer(), &pbytecode))
|
||||
D3D::CompilePixelShader(code.GetBuffer(), &bytecode);
|
||||
if (!InsertByteCode(uid, bytecode->Data(), bytecode->Size()))
|
||||
{
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true);
|
||||
SAFE_RELEASE(bytecode);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Insert the bytecode into the caches
|
||||
g_ps_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size());
|
||||
|
||||
bool success = InsertByteCode(uid, pbytecode->Data(), pbytecode->Size());
|
||||
pbytecode->Release();
|
||||
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true);
|
||||
return success;
|
||||
g_ps_disk_cache.Append(uid, bytecode->Data(), bytecode->Size());
|
||||
return SetShader();
|
||||
}
|
||||
|
||||
bool PixelShaderCache::InsertByteCode(const PixelShaderUid& uid, const void* bytecode,
|
||||
unsigned int bytecodelen)
|
||||
bool PixelShaderCache::SetUberShader()
|
||||
{
|
||||
ID3D11PixelShader* shader = D3D::CreatePixelShaderFromByteCode(bytecode, bytecodelen);
|
||||
if (shader == nullptr)
|
||||
UberShader::PixelShaderUid uid = UberShader::GetPixelShaderUid();
|
||||
|
||||
if (last_uber_entry && last_uber_uid == uid)
|
||||
{
|
||||
if (!last_uber_entry->shader)
|
||||
return false;
|
||||
|
||||
// TODO: Somehow make the debug name a bit more specific
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)shader, "a pixel shader of PixelShaderCache");
|
||||
D3D::stateman->SetPixelShader(last_uber_entry->shader);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Make an entry in the table
|
||||
PSCacheEntry newentry;
|
||||
newentry.shader = shader;
|
||||
PixelShaders[uid] = newentry;
|
||||
last_entry = &PixelShaders[uid];
|
||||
|
||||
if (!shader)
|
||||
auto iter = UberPixelShaders.find(uid);
|
||||
if (iter != UberPixelShaders.end())
|
||||
{
|
||||
// INCSTAT(stats.numPixelShadersFailed);
|
||||
const PSCacheEntry& entry = iter->second;
|
||||
last_uber_uid = uid;
|
||||
last_uber_entry = &entry;
|
||||
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true);
|
||||
if (!last_uber_entry->shader)
|
||||
return false;
|
||||
|
||||
D3D::stateman->SetPixelShader(last_uber_entry->shader);
|
||||
return true;
|
||||
}
|
||||
|
||||
D3DBlob* bytecode = nullptr;
|
||||
ShaderCode code =
|
||||
UberShader::GenPixelShader(APIType::D3D, ShaderHostConfig::GetCurrent(), uid.GetUidData());
|
||||
D3D::CompilePixelShader(code.GetBuffer(), &bytecode);
|
||||
if (!InsertByteCode(uid, bytecode->Data(), bytecode->Size()))
|
||||
{
|
||||
SAFE_RELEASE(bytecode);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Lookup map again.
|
||||
g_uber_ps_disk_cache.Append(uid, bytecode->Data(), bytecode->Size());
|
||||
bytecode->Release();
|
||||
return SetUberShader();
|
||||
}
|
||||
|
||||
bool PixelShaderCache::InsertByteCode(const PixelShaderUid& uid, const u8* data, size_t len)
|
||||
{
|
||||
ID3D11PixelShader* shader = data ? D3D::CreatePixelShaderFromByteCode(data, len) : nullptr;
|
||||
if (!InsertShader(uid, shader))
|
||||
{
|
||||
SAFE_RELEASE(shader);
|
||||
return false;
|
||||
}
|
||||
|
||||
INCSTAT(stats.numPixelShadersCreated);
|
||||
SETSTAT(stats.numPixelShadersAlive, PixelShaders.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PixelShaderCache::InsertByteCode(const UberShader::PixelShaderUid& uid, const u8* data,
|
||||
size_t len)
|
||||
{
|
||||
ID3D11PixelShader* shader = data ? D3D::CreatePixelShaderFromByteCode(data, len) : nullptr;
|
||||
if (!InsertShader(uid, shader))
|
||||
{
|
||||
SAFE_RELEASE(shader);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PixelShaderCache::InsertShader(const PixelShaderUid& uid, ID3D11PixelShader* shader)
|
||||
{
|
||||
auto iter = PixelShaders.find(uid);
|
||||
if (iter != PixelShaders.end() && !iter->second.pending)
|
||||
return false;
|
||||
|
||||
PSCacheEntry& newentry = PixelShaders[uid];
|
||||
newentry.pending = false;
|
||||
newentry.shader = shader;
|
||||
|
||||
INCSTAT(stats.numPixelShadersCreated);
|
||||
SETSTAT(stats.numPixelShadersAlive, PixelShaders.size());
|
||||
return (shader != nullptr);
|
||||
}
|
||||
|
||||
bool PixelShaderCache::InsertShader(const UberShader::PixelShaderUid& uid,
|
||||
ID3D11PixelShader* shader)
|
||||
{
|
||||
auto iter = UberPixelShaders.find(uid);
|
||||
if (iter != UberPixelShaders.end() && !iter->second.pending)
|
||||
return false;
|
||||
|
||||
PSCacheEntry& newentry = UberPixelShaders[uid];
|
||||
newentry.pending = false;
|
||||
newentry.shader = shader;
|
||||
return (shader != nullptr);
|
||||
}
|
||||
|
||||
void PixelShaderCache::PrecompileUberShaders()
|
||||
{
|
||||
UberShader::EnumeratePixelShaderUids([&](const UberShader::PixelShaderUid& uid) {
|
||||
if (UberPixelShaders.find(uid) != UberPixelShaders.end())
|
||||
return;
|
||||
|
||||
g_async_compiler->QueueWorkItem(
|
||||
g_async_compiler->CreateWorkItem<UberPixelShaderCompilerWorkItem>(uid));
|
||||
});
|
||||
|
||||
g_async_compiler->WaitUntilCompletion([](size_t completed, size_t total) {
|
||||
Host_UpdateProgressDialog(GetStringT("Compiling shaders...").c_str(),
|
||||
static_cast<int>(completed), static_cast<int>(total));
|
||||
});
|
||||
g_async_compiler->RetrieveWorkItems();
|
||||
Host_UpdateProgressDialog("", -1, -1);
|
||||
}
|
||||
|
||||
PixelShaderCache::PixelShaderCompilerWorkItem::PixelShaderCompilerWorkItem(
|
||||
const PixelShaderUid& uid)
|
||||
{
|
||||
std::memcpy(&m_uid, &uid, sizeof(uid));
|
||||
}
|
||||
|
||||
PixelShaderCache::PixelShaderCompilerWorkItem::~PixelShaderCompilerWorkItem()
|
||||
{
|
||||
SAFE_RELEASE(m_bytecode);
|
||||
}
|
||||
|
||||
bool PixelShaderCache::PixelShaderCompilerWorkItem::Compile()
|
||||
{
|
||||
ShaderCode code =
|
||||
GeneratePixelShaderCode(APIType::D3D, ShaderHostConfig::GetCurrent(), m_uid.GetUidData());
|
||||
|
||||
if (D3D::CompilePixelShader(code.GetBuffer(), &m_bytecode))
|
||||
m_shader = D3D::CreatePixelShaderFromByteCode(m_bytecode);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PixelShaderCache::PixelShaderCompilerWorkItem::Retrieve()
|
||||
{
|
||||
if (InsertShader(m_uid, m_shader))
|
||||
g_ps_disk_cache.Append(m_uid, m_bytecode->Data(), m_bytecode->Size());
|
||||
else
|
||||
SAFE_RELEASE(m_shader);
|
||||
}
|
||||
|
||||
PixelShaderCache::UberPixelShaderCompilerWorkItem::UberPixelShaderCompilerWorkItem(
|
||||
const UberShader::PixelShaderUid& uid)
|
||||
{
|
||||
std::memcpy(&m_uid, &uid, sizeof(uid));
|
||||
}
|
||||
|
||||
PixelShaderCache::UberPixelShaderCompilerWorkItem::~UberPixelShaderCompilerWorkItem()
|
||||
{
|
||||
SAFE_RELEASE(m_bytecode);
|
||||
}
|
||||
|
||||
bool PixelShaderCache::UberPixelShaderCompilerWorkItem::Compile()
|
||||
{
|
||||
ShaderCode code =
|
||||
UberShader::GenPixelShader(APIType::D3D, ShaderHostConfig::GetCurrent(), m_uid.GetUidData());
|
||||
|
||||
if (D3D::CompilePixelShader(code.GetBuffer(), &m_bytecode))
|
||||
m_shader = D3D::CreatePixelShaderFromByteCode(m_bytecode);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PixelShaderCache::UberPixelShaderCompilerWorkItem::Retrieve()
|
||||
{
|
||||
if (InsertShader(m_uid, m_shader))
|
||||
g_uber_ps_disk_cache.Append(m_uid, m_bytecode->Data(), m_bytecode->Size());
|
||||
else
|
||||
SAFE_RELEASE(m_shader);
|
||||
}
|
||||
|
||||
} // DX11
|
||||
|
|
|
@ -7,10 +7,14 @@
|
|||
#include <d3d11.h>
|
||||
#include <map>
|
||||
|
||||
#include "VideoCommon/AsyncShaderCompiler.h"
|
||||
#include "VideoCommon/PixelShaderGen.h"
|
||||
#include "VideoCommon/UberShaderPixel.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
class D3DBlob;
|
||||
|
||||
class PixelShaderCache
|
||||
{
|
||||
public:
|
||||
|
@ -18,12 +22,15 @@ public:
|
|||
static void Reload();
|
||||
static void Clear();
|
||||
static void Shutdown();
|
||||
static bool SetShader(); // TODO: Should be renamed to LoadShader
|
||||
static bool InsertByteCode(const PixelShaderUid& uid, const void* bytecode,
|
||||
unsigned int bytecodelen);
|
||||
static bool SetShader();
|
||||
static bool SetUberShader();
|
||||
static bool InsertByteCode(const PixelShaderUid& uid, const u8* data, size_t len);
|
||||
static bool InsertByteCode(const UberShader::PixelShaderUid& uid, const u8* data, size_t len);
|
||||
static bool InsertShader(const PixelShaderUid& uid, ID3D11PixelShader* shader);
|
||||
static bool InsertShader(const UberShader::PixelShaderUid& uid, ID3D11PixelShader* shader);
|
||||
static void PrecompileUberShaders();
|
||||
|
||||
static ID3D11PixelShader* GetActiveShader() { return last_entry->shader; }
|
||||
static ID3D11Buffer*& GetConstantBuffer();
|
||||
static ID3D11Buffer* GetConstantBuffer();
|
||||
|
||||
static ID3D11PixelShader* GetColorMatrixProgram(bool multisampled);
|
||||
static ID3D11PixelShader* GetColorCopyProgram(bool multisampled);
|
||||
|
@ -40,18 +47,53 @@ private:
|
|||
struct PSCacheEntry
|
||||
{
|
||||
ID3D11PixelShader* shader;
|
||||
bool pending;
|
||||
|
||||
PSCacheEntry() : shader(nullptr) {}
|
||||
PSCacheEntry() : shader(nullptr), pending(false) {}
|
||||
void Destroy() { SAFE_RELEASE(shader); }
|
||||
};
|
||||
|
||||
class PixelShaderCompilerWorkItem : public VideoCommon::AsyncShaderCompiler::WorkItem
|
||||
{
|
||||
public:
|
||||
PixelShaderCompilerWorkItem(const PixelShaderUid& uid);
|
||||
~PixelShaderCompilerWorkItem() override;
|
||||
|
||||
bool Compile() override;
|
||||
void Retrieve() override;
|
||||
|
||||
private:
|
||||
PixelShaderUid m_uid;
|
||||
ID3D11PixelShader* m_shader = nullptr;
|
||||
D3DBlob* m_bytecode = nullptr;
|
||||
};
|
||||
|
||||
class UberPixelShaderCompilerWorkItem : public VideoCommon::AsyncShaderCompiler::WorkItem
|
||||
{
|
||||
public:
|
||||
UberPixelShaderCompilerWorkItem(const UberShader::PixelShaderUid& uid);
|
||||
~UberPixelShaderCompilerWorkItem() override;
|
||||
|
||||
bool Compile() override;
|
||||
void Retrieve() override;
|
||||
|
||||
private:
|
||||
UberShader::PixelShaderUid m_uid;
|
||||
ID3D11PixelShader* m_shader = nullptr;
|
||||
D3DBlob* m_bytecode = nullptr;
|
||||
};
|
||||
|
||||
typedef std::map<PixelShaderUid, PSCacheEntry> PSCache;
|
||||
typedef std::map<UberShader::PixelShaderUid, PSCacheEntry> UberPSCache;
|
||||
|
||||
static void LoadShaderCache();
|
||||
|
||||
static PSCache PixelShaders;
|
||||
static UberPSCache UberPixelShaders;
|
||||
static const PSCacheEntry* last_entry;
|
||||
static const PSCacheEntry* last_uber_entry;
|
||||
static PixelShaderUid last_uid;
|
||||
static UberShader::PixelShaderUid last_uber_uid;
|
||||
};
|
||||
|
||||
} // namespace DX11
|
||||
|
|
|
@ -837,6 +837,7 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight,
|
|||
// Enable configuration changes
|
||||
UpdateActiveConfig();
|
||||
g_texture_cache->OnConfigChanged(g_ActiveConfig);
|
||||
VertexShaderCache::RetreiveAsyncShaders();
|
||||
|
||||
SetWindowSize(fbStride, fbHeight);
|
||||
|
||||
|
@ -958,10 +959,6 @@ void Renderer::ApplyState()
|
|||
g_ActiveConfig.bEnablePixelLighting ? vertexConstants : nullptr);
|
||||
D3D::stateman->SetVertexConstants(vertexConstants);
|
||||
D3D::stateman->SetGeometryConstants(GeometryShaderCache::GetConstantBuffer());
|
||||
|
||||
D3D::stateman->SetPixelShader(PixelShaderCache::GetActiveShader());
|
||||
D3D::stateman->SetVertexShader(VertexShaderCache::GetActiveShader());
|
||||
D3D::stateman->SetGeometryShader(GeometryShaderCache::GetActiveShader());
|
||||
}
|
||||
|
||||
void Renderer::RestoreState()
|
||||
|
|
|
@ -159,7 +159,9 @@ void VertexManager::vFlush()
|
|||
return;
|
||||
}
|
||||
|
||||
if (!VertexShaderCache::SetShader())
|
||||
D3DVertexFormat* vertex_format =
|
||||
static_cast<D3DVertexFormat*>(VertexLoaderManager::GetCurrentVertexFormat());
|
||||
if (!VertexShaderCache::SetShader(vertex_format))
|
||||
{
|
||||
GFX_DEBUGGER_PAUSE_LOG_AT(NEXT_ERROR, true, { printf("Fail to set pixel shader\n"); });
|
||||
return;
|
||||
|
@ -182,7 +184,6 @@ void VertexManager::vFlush()
|
|||
|
||||
PrepareDrawBuffers(stride);
|
||||
|
||||
VertexLoaderManager::GetCurrentVertexFormat()->SetupVertexPointers();
|
||||
g_renderer->ApplyState();
|
||||
|
||||
Draw(stride);
|
||||
|
|
|
@ -4,13 +4,31 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <d3d11.h>
|
||||
#include <memory>
|
||||
#include "VideoCommon/NativeVertexFormat.h"
|
||||
#include "VideoCommon/VertexManagerBase.h"
|
||||
|
||||
struct ID3D11Buffer;
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
class D3DBlob;
|
||||
class D3DVertexFormat : public NativeVertexFormat
|
||||
{
|
||||
public:
|
||||
D3DVertexFormat(const PortableVertexDeclaration& vtx_decl);
|
||||
~D3DVertexFormat();
|
||||
void SetupVertexPointers() override;
|
||||
void SetInputLayout(D3DBlob* vs_bytecode);
|
||||
|
||||
private:
|
||||
std::array<D3D11_INPUT_ELEMENT_DESC, 32> m_elems{};
|
||||
UINT m_num_elems = 0;
|
||||
|
||||
ID3D11InputLayout* m_layout = nullptr;
|
||||
};
|
||||
|
||||
class VertexManager : public VertexManagerBase
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -8,23 +8,32 @@
|
|||
#include "Common/CommonTypes.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/LinearDiskCache.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "Common/StringUtil.h"
|
||||
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Host.h"
|
||||
|
||||
#include "VideoBackends/D3D/D3DShader.h"
|
||||
#include "VideoBackends/D3D/D3DState.h"
|
||||
#include "VideoBackends/D3D/VertexManager.h"
|
||||
#include "VideoBackends/D3D/VertexShaderCache.h"
|
||||
|
||||
#include "VideoCommon/Debugger.h"
|
||||
#include "VideoCommon/Statistics.h"
|
||||
#include "VideoCommon/UberShaderVertex.h"
|
||||
#include "VideoCommon/VertexLoaderManager.h"
|
||||
#include "VideoCommon/VertexShaderGen.h"
|
||||
#include "VideoCommon/VertexShaderManager.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
VertexShaderCache::VSCache VertexShaderCache::vshaders;
|
||||
VertexShaderCache::UberVSCache VertexShaderCache::ubervshaders;
|
||||
const VertexShaderCache::VSCacheEntry* VertexShaderCache::last_entry;
|
||||
const VertexShaderCache::VSCacheEntry* VertexShaderCache::last_uber_entry;
|
||||
VertexShaderUid VertexShaderCache::last_uid;
|
||||
UberShader::VertexShaderUid VertexShaderCache::last_uber_uid;
|
||||
|
||||
static ID3D11VertexShader* SimpleVertexShader = nullptr;
|
||||
static ID3D11VertexShader* ClearVertexShader = nullptr;
|
||||
|
@ -32,6 +41,8 @@ static ID3D11InputLayout* SimpleLayout = nullptr;
|
|||
static ID3D11InputLayout* ClearLayout = nullptr;
|
||||
|
||||
LinearDiskCache<VertexShaderUid, u8> g_vs_disk_cache;
|
||||
LinearDiskCache<UberShader::VertexShaderUid, u8> g_uber_vs_disk_cache;
|
||||
std::unique_ptr<VideoCommon::AsyncShaderCompiler> g_async_compiler;
|
||||
|
||||
ID3D11VertexShader* VertexShaderCache::GetSimpleVertexShader()
|
||||
{
|
||||
|
@ -70,10 +81,11 @@ ID3D11Buffer*& VertexShaderCache::GetConstantBuffer()
|
|||
}
|
||||
|
||||
// this class will load the precompiled shaders into our cache
|
||||
class VertexShaderCacheInserter : public LinearDiskCacheReader<VertexShaderUid, u8>
|
||||
template <typename UidType>
|
||||
class VertexShaderCacheInserter : public LinearDiskCacheReader<UidType, u8>
|
||||
{
|
||||
public:
|
||||
void Read(const VertexShaderUid& key, const u8* value, u32 value_size)
|
||||
void Read(const UidType& key, const u8* value, u32 value_size)
|
||||
{
|
||||
D3DBlob* blob = new D3DBlob(value_size, value);
|
||||
VertexShaderCache::InsertByteCode(key, blob);
|
||||
|
@ -160,36 +172,65 @@ void VertexShaderCache::Init()
|
|||
|
||||
if (g_ActiveConfig.bShaderCache)
|
||||
LoadShaderCache();
|
||||
|
||||
g_async_compiler = std::make_unique<VideoCommon::AsyncShaderCompiler>();
|
||||
if (g_ActiveConfig.GetShaderCompilerThreads() > 0)
|
||||
g_async_compiler->StartWorkerThreads(g_ActiveConfig.GetShaderCompilerThreads());
|
||||
|
||||
if (g_ActiveConfig.CanPrecompileUberShaders())
|
||||
PrecompileUberShaders();
|
||||
}
|
||||
|
||||
void VertexShaderCache::LoadShaderCache()
|
||||
{
|
||||
VertexShaderCacheInserter inserter;
|
||||
VertexShaderCacheInserter<VertexShaderUid> inserter;
|
||||
g_vs_disk_cache.OpenAndRead(GetDiskShaderCacheFileName(APIType::D3D, "VS", true, true), inserter);
|
||||
|
||||
VertexShaderCacheInserter<UberShader::VertexShaderUid> uber_inserter;
|
||||
g_uber_vs_disk_cache.OpenAndRead(GetDiskShaderCacheFileName(APIType::D3D, "UberVS", false, true),
|
||||
uber_inserter);
|
||||
}
|
||||
|
||||
void VertexShaderCache::Reload()
|
||||
{
|
||||
g_async_compiler->WaitUntilCompletion();
|
||||
g_async_compiler->RetrieveWorkItems();
|
||||
|
||||
g_vs_disk_cache.Sync();
|
||||
g_vs_disk_cache.Close();
|
||||
g_uber_vs_disk_cache.Sync();
|
||||
g_uber_vs_disk_cache.Close();
|
||||
Clear();
|
||||
|
||||
if (g_ActiveConfig.bShaderCache)
|
||||
LoadShaderCache();
|
||||
|
||||
if (g_ActiveConfig.CanPrecompileUberShaders())
|
||||
PrecompileUberShaders();
|
||||
}
|
||||
|
||||
void VertexShaderCache::Clear()
|
||||
{
|
||||
for (auto& iter : vshaders)
|
||||
iter.second.Destroy();
|
||||
for (auto& iter : ubervshaders)
|
||||
iter.second.Destroy();
|
||||
vshaders.clear();
|
||||
ubervshaders.clear();
|
||||
|
||||
last_entry = nullptr;
|
||||
last_uid = {};
|
||||
last_uber_uid = {};
|
||||
last_entry = nullptr;
|
||||
last_uber_entry = nullptr;
|
||||
last_uid = {};
|
||||
last_uber_uid = {};
|
||||
}
|
||||
|
||||
void VertexShaderCache::Shutdown()
|
||||
{
|
||||
g_async_compiler->StopWorkerThreads();
|
||||
g_async_compiler->RetrieveWorkItems();
|
||||
|
||||
SAFE_RELEASE(vscbuf);
|
||||
|
||||
SAFE_RELEASE(SimpleVertexShader);
|
||||
|
@ -201,74 +242,264 @@ void VertexShaderCache::Shutdown()
|
|||
Clear();
|
||||
g_vs_disk_cache.Sync();
|
||||
g_vs_disk_cache.Close();
|
||||
g_uber_vs_disk_cache.Sync();
|
||||
g_uber_vs_disk_cache.Close();
|
||||
}
|
||||
|
||||
bool VertexShaderCache::SetShader()
|
||||
bool VertexShaderCache::SetShader(D3DVertexFormat* vertex_format)
|
||||
{
|
||||
if (g_ActiveConfig.CanUseUberShaders() &&
|
||||
(g_ActiveConfig.bDisableSpecializedShaders || g_ActiveConfig.bForceVertexUberShaders))
|
||||
{
|
||||
return SetUberShader(vertex_format);
|
||||
}
|
||||
|
||||
VertexShaderUid uid = GetVertexShaderUid();
|
||||
if (last_entry && uid == last_uid)
|
||||
{
|
||||
if (last_entry->pending)
|
||||
return SetUberShader(vertex_format);
|
||||
|
||||
if (last_entry)
|
||||
{
|
||||
if (uid == last_uid)
|
||||
{
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
|
||||
return (last_entry->shader != nullptr);
|
||||
}
|
||||
if (!last_entry->shader)
|
||||
return false;
|
||||
|
||||
vertex_format->SetInputLayout(last_entry->bytecode);
|
||||
D3D::stateman->SetVertexShader(last_entry->shader);
|
||||
return true;
|
||||
}
|
||||
|
||||
last_uid = uid;
|
||||
|
||||
VSCache::iterator iter = vshaders.find(uid);
|
||||
auto iter = vshaders.find(uid);
|
||||
if (iter != vshaders.end())
|
||||
{
|
||||
const VSCacheEntry& entry = iter->second;
|
||||
if (entry.pending)
|
||||
return SetUberShader(vertex_format);
|
||||
|
||||
last_uid = uid;
|
||||
last_entry = &entry;
|
||||
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
|
||||
return (entry.shader != nullptr);
|
||||
if (!last_entry->shader)
|
||||
return false;
|
||||
|
||||
vertex_format->SetInputLayout(last_entry->bytecode);
|
||||
D3D::stateman->SetVertexShader(last_entry->shader);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Background compiling?
|
||||
if (g_ActiveConfig.CanBackgroundCompileShaders())
|
||||
{
|
||||
// Create a pending entry
|
||||
VSCacheEntry entry;
|
||||
entry.pending = true;
|
||||
vshaders[uid] = entry;
|
||||
|
||||
// Queue normal shader compiling and use ubershader
|
||||
g_async_compiler->QueueWorkItem(
|
||||
g_async_compiler->CreateWorkItem<VertexShaderCompilerWorkItem>(uid));
|
||||
return SetUberShader(vertex_format);
|
||||
}
|
||||
|
||||
// Need to compile a new shader
|
||||
D3DBlob* bytecode = nullptr;
|
||||
ShaderCode code =
|
||||
GenerateVertexShaderCode(APIType::D3D, ShaderHostConfig::GetCurrent(), uid.GetUidData());
|
||||
|
||||
D3DBlob* pbytecode = nullptr;
|
||||
D3D::CompileVertexShader(code.GetBuffer(), &pbytecode);
|
||||
|
||||
if (pbytecode == nullptr)
|
||||
D3D::CompileVertexShader(code.GetBuffer(), &bytecode);
|
||||
if (!InsertByteCode(uid, bytecode))
|
||||
{
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true);
|
||||
SAFE_RELEASE(bytecode);
|
||||
return false;
|
||||
}
|
||||
g_vs_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size());
|
||||
|
||||
bool success = InsertByteCode(uid, pbytecode);
|
||||
pbytecode->Release();
|
||||
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
|
||||
return success;
|
||||
g_vs_disk_cache.Append(uid, bytecode->Data(), bytecode->Size());
|
||||
bytecode->Release();
|
||||
return SetShader(vertex_format);
|
||||
}
|
||||
|
||||
bool VertexShaderCache::InsertByteCode(const VertexShaderUid& uid, D3DBlob* bcodeblob)
|
||||
bool VertexShaderCache::SetUberShader(D3DVertexFormat* vertex_format)
|
||||
{
|
||||
ID3D11VertexShader* shader = D3D::CreateVertexShaderFromByteCode(bcodeblob);
|
||||
if (shader == nullptr)
|
||||
D3DVertexFormat* uber_vertex_format = static_cast<D3DVertexFormat*>(
|
||||
VertexLoaderManager::GetUberVertexFormat(vertex_format->GetVertexDeclaration()));
|
||||
UberShader::VertexShaderUid uid = UberShader::GetVertexShaderUid();
|
||||
if (last_uber_entry && last_uber_uid == uid)
|
||||
{
|
||||
if (!last_uber_entry->shader)
|
||||
return false;
|
||||
|
||||
// TODO: Somehow make the debug name a bit more specific
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)shader, "a vertex shader of VertexShaderCache");
|
||||
uber_vertex_format->SetInputLayout(last_uber_entry->bytecode);
|
||||
D3D::stateman->SetVertexShader(last_uber_entry->shader);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Make an entry in the table
|
||||
VSCacheEntry entry;
|
||||
entry.shader = shader;
|
||||
entry.SetByteCode(bcodeblob);
|
||||
auto iter = ubervshaders.find(uid);
|
||||
if (iter != ubervshaders.end())
|
||||
{
|
||||
const VSCacheEntry& entry = iter->second;
|
||||
last_uber_uid = uid;
|
||||
last_uber_entry = &entry;
|
||||
|
||||
vshaders[uid] = entry;
|
||||
last_entry = &vshaders[uid];
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
|
||||
if (!last_uber_entry->shader)
|
||||
return false;
|
||||
|
||||
INCSTAT(stats.numVertexShadersCreated);
|
||||
SETSTAT(stats.numVertexShadersAlive, (int)vshaders.size());
|
||||
uber_vertex_format->SetInputLayout(last_uber_entry->bytecode);
|
||||
D3D::stateman->SetVertexShader(last_uber_entry->shader);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Need to compile a new shader
|
||||
D3DBlob* bytecode = nullptr;
|
||||
ShaderCode code =
|
||||
UberShader::GenVertexShader(APIType::D3D, ShaderHostConfig::GetCurrent(), uid.GetUidData());
|
||||
D3D::CompileVertexShader(code.GetBuffer(), &bytecode);
|
||||
if (!InsertByteCode(uid, bytecode))
|
||||
{
|
||||
SAFE_RELEASE(bytecode);
|
||||
return false;
|
||||
}
|
||||
|
||||
g_uber_vs_disk_cache.Append(uid, bytecode->Data(), bytecode->Size());
|
||||
bytecode->Release();
|
||||
return SetUberShader(vertex_format);
|
||||
}
|
||||
|
||||
bool VertexShaderCache::InsertByteCode(const VertexShaderUid& uid, D3DBlob* blob)
|
||||
{
|
||||
ID3D11VertexShader* shader =
|
||||
blob ? D3D::CreateVertexShaderFromByteCode(blob->Data(), blob->Size()) : nullptr;
|
||||
bool result = InsertShader(uid, shader, blob);
|
||||
SAFE_RELEASE(shader);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool VertexShaderCache::InsertByteCode(const UberShader::VertexShaderUid& uid, D3DBlob* blob)
|
||||
{
|
||||
ID3D11VertexShader* shader =
|
||||
blob ? D3D::CreateVertexShaderFromByteCode(blob->Data(), blob->Size()) : nullptr;
|
||||
bool result = InsertShader(uid, shader, blob);
|
||||
SAFE_RELEASE(shader);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool VertexShaderCache::InsertShader(const VertexShaderUid& uid, ID3D11VertexShader* shader,
|
||||
D3DBlob* blob)
|
||||
{
|
||||
auto iter = vshaders.find(uid);
|
||||
if (iter != vshaders.end() && !iter->second.pending)
|
||||
return false;
|
||||
|
||||
VSCacheEntry& newentry = vshaders[uid];
|
||||
newentry.pending = false;
|
||||
if (!shader || !blob)
|
||||
return false;
|
||||
|
||||
shader->AddRef();
|
||||
newentry.SetByteCode(blob);
|
||||
newentry.shader = shader;
|
||||
|
||||
INCSTAT(stats.numPixelShadersCreated);
|
||||
SETSTAT(stats.numPixelShadersAlive, static_cast<int>(vshaders.size()));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VertexShaderCache::InsertShader(const UberShader::VertexShaderUid& uid,
|
||||
ID3D11VertexShader* shader, D3DBlob* blob)
|
||||
{
|
||||
auto iter = ubervshaders.find(uid);
|
||||
if (iter != ubervshaders.end() && !iter->second.pending)
|
||||
return false;
|
||||
|
||||
VSCacheEntry& newentry = ubervshaders[uid];
|
||||
newentry.pending = false;
|
||||
if (!shader || !blob)
|
||||
return false;
|
||||
|
||||
shader->AddRef();
|
||||
newentry.SetByteCode(blob);
|
||||
newentry.shader = shader;
|
||||
return true;
|
||||
}
|
||||
|
||||
void VertexShaderCache::RetreiveAsyncShaders()
|
||||
{
|
||||
g_async_compiler->RetrieveWorkItems();
|
||||
}
|
||||
|
||||
void VertexShaderCache::PrecompileUberShaders()
|
||||
{
|
||||
UberShader::EnumerateVertexShaderUids([&](const UberShader::VertexShaderUid& uid) {
|
||||
if (ubervshaders.find(uid) != ubervshaders.end())
|
||||
return;
|
||||
|
||||
g_async_compiler->QueueWorkItem(
|
||||
g_async_compiler->CreateWorkItem<UberVertexShaderCompilerWorkItem>(uid));
|
||||
});
|
||||
|
||||
g_async_compiler->WaitUntilCompletion([](size_t completed, size_t total) {
|
||||
Host_UpdateProgressDialog(GetStringT("Compiling shaders...").c_str(),
|
||||
static_cast<int>(completed), static_cast<int>(total));
|
||||
});
|
||||
g_async_compiler->RetrieveWorkItems();
|
||||
Host_UpdateProgressDialog("", -1, -1);
|
||||
}
|
||||
|
||||
VertexShaderCache::VertexShaderCompilerWorkItem::VertexShaderCompilerWorkItem(
|
||||
const VertexShaderUid& uid)
|
||||
{
|
||||
std::memcpy(&m_uid, &uid, sizeof(uid));
|
||||
}
|
||||
|
||||
VertexShaderCache::VertexShaderCompilerWorkItem::~VertexShaderCompilerWorkItem()
|
||||
{
|
||||
SAFE_RELEASE(m_bytecode);
|
||||
SAFE_RELEASE(m_vs);
|
||||
}
|
||||
|
||||
bool VertexShaderCache::VertexShaderCompilerWorkItem::Compile()
|
||||
{
|
||||
ShaderCode code =
|
||||
GenerateVertexShaderCode(APIType::D3D, ShaderHostConfig::GetCurrent(), m_uid.GetUidData());
|
||||
|
||||
if (D3D::CompileVertexShader(code.GetBuffer(), &m_bytecode))
|
||||
m_vs = D3D::CreateVertexShaderFromByteCode(m_bytecode);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VertexShaderCache::VertexShaderCompilerWorkItem::Retrieve()
|
||||
{
|
||||
if (InsertShader(m_uid, m_vs, m_bytecode))
|
||||
g_vs_disk_cache.Append(m_uid, m_bytecode->Data(), m_bytecode->Size());
|
||||
}
|
||||
|
||||
VertexShaderCache::UberVertexShaderCompilerWorkItem::UberVertexShaderCompilerWorkItem(
|
||||
const UberShader::VertexShaderUid& uid)
|
||||
{
|
||||
std::memcpy(&m_uid, &uid, sizeof(uid));
|
||||
}
|
||||
|
||||
VertexShaderCache::UberVertexShaderCompilerWorkItem::~UberVertexShaderCompilerWorkItem()
|
||||
{
|
||||
SAFE_RELEASE(m_bytecode);
|
||||
SAFE_RELEASE(m_vs);
|
||||
}
|
||||
|
||||
bool VertexShaderCache::UberVertexShaderCompilerWorkItem::Compile()
|
||||
{
|
||||
ShaderCode code =
|
||||
UberShader::GenVertexShader(APIType::D3D, ShaderHostConfig::GetCurrent(), m_uid.GetUidData());
|
||||
|
||||
if (D3D::CompileVertexShader(code.GetBuffer(), &m_bytecode))
|
||||
m_vs = D3D::CreateVertexShaderFromByteCode(m_bytecode);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VertexShaderCache::UberVertexShaderCompilerWorkItem::Retrieve()
|
||||
{
|
||||
if (InsertShader(m_uid, m_vs, m_bytecode))
|
||||
g_uber_vs_disk_cache.Append(m_uid, m_bytecode->Data(), m_bytecode->Size());
|
||||
}
|
||||
|
||||
} // namespace DX11
|
||||
|
|
|
@ -9,10 +9,14 @@
|
|||
#include "VideoBackends/D3D/D3DBase.h"
|
||||
#include "VideoBackends/D3D/D3DBlob.h"
|
||||
|
||||
#include "VideoCommon/AsyncShaderCompiler.h"
|
||||
#include "VideoCommon/UberShaderVertex.h"
|
||||
#include "VideoCommon/VertexShaderGen.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
class D3DVertexFormat;
|
||||
|
||||
class VertexShaderCache
|
||||
{
|
||||
public:
|
||||
|
@ -20,10 +24,11 @@ public:
|
|||
static void Reload();
|
||||
static void Clear();
|
||||
static void Shutdown();
|
||||
static bool SetShader(); // TODO: Should be renamed to LoadShader
|
||||
static bool SetShader(D3DVertexFormat* vertex_format);
|
||||
static bool SetUberShader(D3DVertexFormat* vertex_format);
|
||||
static void RetreiveAsyncShaders();
|
||||
static void PrecompileUberShaders();
|
||||
|
||||
static ID3D11VertexShader* GetActiveShader() { return last_entry->shader; }
|
||||
static D3DBlob* GetActiveShaderBytecode() { return last_entry->bytecode; }
|
||||
static ID3D11Buffer*& GetConstantBuffer();
|
||||
|
||||
static ID3D11VertexShader* GetSimpleVertexShader();
|
||||
|
@ -31,15 +36,20 @@ public:
|
|||
static ID3D11InputLayout* GetSimpleInputLayout();
|
||||
static ID3D11InputLayout* GetClearInputLayout();
|
||||
|
||||
static bool InsertByteCode(const VertexShaderUid& uid, D3DBlob* bcodeblob);
|
||||
static bool InsertByteCode(const VertexShaderUid& uid, D3DBlob* blob);
|
||||
static bool InsertByteCode(const UberShader::VertexShaderUid& uid, D3DBlob* blob);
|
||||
static bool InsertShader(const VertexShaderUid& uid, ID3D11VertexShader* shader, D3DBlob* blob);
|
||||
static bool InsertShader(const UberShader::VertexShaderUid& uid, ID3D11VertexShader* shader,
|
||||
D3DBlob* blob);
|
||||
|
||||
private:
|
||||
struct VSCacheEntry
|
||||
{
|
||||
ID3D11VertexShader* shader;
|
||||
D3DBlob* bytecode; // needed to initialize the input layout
|
||||
bool pending;
|
||||
|
||||
VSCacheEntry() : shader(nullptr), bytecode(nullptr) {}
|
||||
VSCacheEntry() : shader(nullptr), bytecode(nullptr), pending(false) {}
|
||||
void SetByteCode(D3DBlob* blob)
|
||||
{
|
||||
SAFE_RELEASE(bytecode);
|
||||
|
@ -52,13 +62,49 @@ private:
|
|||
SAFE_RELEASE(bytecode);
|
||||
}
|
||||
};
|
||||
|
||||
class VertexShaderCompilerWorkItem : public VideoCommon::AsyncShaderCompiler::WorkItem
|
||||
{
|
||||
public:
|
||||
VertexShaderCompilerWorkItem(const VertexShaderUid& uid);
|
||||
~VertexShaderCompilerWorkItem() override;
|
||||
|
||||
bool Compile() override;
|
||||
void Retrieve() override;
|
||||
|
||||
private:
|
||||
VertexShaderUid m_uid;
|
||||
D3DBlob* m_bytecode = nullptr;
|
||||
ID3D11VertexShader* m_vs = nullptr;
|
||||
};
|
||||
|
||||
class UberVertexShaderCompilerWorkItem : public VideoCommon::AsyncShaderCompiler::WorkItem
|
||||
{
|
||||
public:
|
||||
UberVertexShaderCompilerWorkItem(const UberShader::VertexShaderUid& uid);
|
||||
~UberVertexShaderCompilerWorkItem() override;
|
||||
|
||||
bool Compile() override;
|
||||
void Retrieve() override;
|
||||
|
||||
private:
|
||||
UberShader::VertexShaderUid m_uid;
|
||||
D3DBlob* m_bytecode = nullptr;
|
||||
ID3D11VertexShader* m_vs = nullptr;
|
||||
};
|
||||
|
||||
typedef std::map<VertexShaderUid, VSCacheEntry> VSCache;
|
||||
typedef std::map<UberShader::VertexShaderUid, VSCacheEntry> UberVSCache;
|
||||
|
||||
static void LoadShaderCache();
|
||||
static void SetInputLayout();
|
||||
|
||||
static VSCache vshaders;
|
||||
static UberVSCache ubervshaders;
|
||||
static const VSCacheEntry* last_entry;
|
||||
static const VSCacheEntry* last_uber_entry;
|
||||
static VertexShaderUid last_uid;
|
||||
static UberShader::VertexShaderUid last_uber_uid;
|
||||
};
|
||||
|
||||
} // namespace DX11
|
||||
|
|
Loading…
Reference in New Issue