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