mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-12-16 04:09:39 +00:00
Merge pull request #13975 from iwubcode/shader_includes
VideoBackends / VideoCommon: add support for specifying include files in shader code
This commit is contained in:
commit
1d9c743ef7
@ -749,6 +749,7 @@
|
|||||||
<ClInclude Include="VideoCommon\Present.h" />
|
<ClInclude Include="VideoCommon\Present.h" />
|
||||||
<ClInclude Include="VideoCommon\RenderState.h" />
|
<ClInclude Include="VideoCommon\RenderState.h" />
|
||||||
<ClInclude Include="VideoCommon\ShaderCache.h" />
|
<ClInclude Include="VideoCommon\ShaderCache.h" />
|
||||||
|
<ClInclude Include="VideoCommon\ShaderCompileUtils.h" />
|
||||||
<ClInclude Include="VideoCommon\ShaderGenCommon.h" />
|
<ClInclude Include="VideoCommon\ShaderGenCommon.h" />
|
||||||
<ClInclude Include="VideoCommon\Spirv.h" />
|
<ClInclude Include="VideoCommon\Spirv.h" />
|
||||||
<ClInclude Include="VideoCommon\Statistics.h" />
|
<ClInclude Include="VideoCommon\Statistics.h" />
|
||||||
@ -1396,6 +1397,7 @@
|
|||||||
<ClCompile Include="VideoCommon\Present.cpp" />
|
<ClCompile Include="VideoCommon\Present.cpp" />
|
||||||
<ClCompile Include="VideoCommon\RenderState.cpp" />
|
<ClCompile Include="VideoCommon\RenderState.cpp" />
|
||||||
<ClCompile Include="VideoCommon\ShaderCache.cpp" />
|
<ClCompile Include="VideoCommon\ShaderCache.cpp" />
|
||||||
|
<ClCompile Include="VideoCommon\ShaderCompileUtils.cpp" />
|
||||||
<ClCompile Include="VideoCommon\ShaderGenCommon.cpp" />
|
<ClCompile Include="VideoCommon\ShaderGenCommon.cpp" />
|
||||||
<ClCompile Include="VideoCommon\Spirv.cpp" />
|
<ClCompile Include="VideoCommon\Spirv.cpp" />
|
||||||
<ClCompile Include="VideoCommon\Statistics.cpp" />
|
<ClCompile Include="VideoCommon\Statistics.cpp" />
|
||||||
|
|||||||
@ -71,9 +71,10 @@ Gfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader>
|
std::unique_ptr<AbstractShader>
|
||||||
Gfx::CreateShaderFromSource(ShaderStage stage, std::string_view source, std::string_view name)
|
Gfx::CreateShaderFromSource(ShaderStage stage, std::string_view source,
|
||||||
|
VideoCommon::ShaderIncluder* shader_includer, std::string_view name)
|
||||||
{
|
{
|
||||||
auto bytecode = DXShader::CompileShader(D3D::feature_level, stage, source);
|
auto bytecode = DXShader::CompileShader(D3D::feature_level, stage, source, shader_includer);
|
||||||
if (!bytecode)
|
if (!bytecode)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
|||||||
@ -31,8 +31,10 @@ public:
|
|||||||
std::string_view name) override;
|
std::string_view name) override;
|
||||||
std::unique_ptr<AbstractStagingTexture>
|
std::unique_ptr<AbstractStagingTexture>
|
||||||
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
|
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
|
||||||
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, std::string_view source,
|
std::unique_ptr<AbstractShader>
|
||||||
std::string_view name) override;
|
CreateShaderFromSource(ShaderStage stage, std::string_view source,
|
||||||
|
VideoCommon::ShaderIncluder* shader_includer,
|
||||||
|
std::string_view name) override;
|
||||||
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
||||||
size_t length,
|
size_t length,
|
||||||
std::string_view name) override;
|
std::string_view name) override;
|
||||||
|
|||||||
@ -68,9 +68,10 @@ Gfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader>
|
std::unique_ptr<AbstractShader>
|
||||||
Gfx::CreateShaderFromSource(ShaderStage stage, std::string_view source, std::string_view name)
|
Gfx::CreateShaderFromSource(ShaderStage stage, std::string_view source,
|
||||||
|
VideoCommon::ShaderIncluder* shader_includer, std::string_view name)
|
||||||
{
|
{
|
||||||
return DXShader::CreateFromSource(stage, source, name);
|
return DXShader::CreateFromSource(stage, source, shader_includer, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader> Gfx::CreateShaderFromBinary(ShaderStage stage, const void* data,
|
std::unique_ptr<AbstractShader> Gfx::CreateShaderFromBinary(ShaderStage stage, const void* data,
|
||||||
|
|||||||
@ -36,8 +36,10 @@ public:
|
|||||||
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
|
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
|
||||||
std::vector<AbstractTexture*> additional_color_attachments) override;
|
std::vector<AbstractTexture*> additional_color_attachments) override;
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, std::string_view source,
|
std::unique_ptr<AbstractShader>
|
||||||
std::string_view name) override;
|
CreateShaderFromSource(ShaderStage stage, std::string_view source,
|
||||||
|
VideoCommon::ShaderIncluder* shader_includer,
|
||||||
|
std::string_view name) override;
|
||||||
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
||||||
size_t length,
|
size_t length,
|
||||||
std::string_view name) override;
|
std::string_view name) override;
|
||||||
|
|||||||
@ -29,9 +29,10 @@ std::unique_ptr<DXShader> DXShader::CreateFromBytecode(ShaderStage stage, Binary
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<DXShader> DXShader::CreateFromSource(ShaderStage stage, std::string_view source,
|
std::unique_ptr<DXShader> DXShader::CreateFromSource(ShaderStage stage, std::string_view source,
|
||||||
|
VideoCommon::ShaderIncluder* shader_includer,
|
||||||
std::string_view name)
|
std::string_view name)
|
||||||
{
|
{
|
||||||
auto bytecode = CompileShader(g_dx_context->GetFeatureLevel(), stage, source);
|
auto bytecode = CompileShader(g_dx_context->GetFeatureLevel(), stage, source, shader_includer);
|
||||||
if (!bytecode)
|
if (!bytecode)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
|||||||
@ -23,6 +23,7 @@ public:
|
|||||||
static std::unique_ptr<DXShader> CreateFromBytecode(ShaderStage stage, BinaryData bytecode,
|
static std::unique_ptr<DXShader> CreateFromBytecode(ShaderStage stage, BinaryData bytecode,
|
||||||
std::string_view name);
|
std::string_view name);
|
||||||
static std::unique_ptr<DXShader> CreateFromSource(ShaderStage stage, std::string_view source,
|
static std::unique_ptr<DXShader> CreateFromSource(ShaderStage stage, std::string_view source,
|
||||||
|
VideoCommon::ShaderIncluder* shader_includer,
|
||||||
std::string_view name);
|
std::string_view name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@ -20,6 +20,7 @@
|
|||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
#include "Common/Version.h"
|
#include "Common/Version.h"
|
||||||
|
|
||||||
|
#include "VideoCommon/ShaderCompileUtils.h"
|
||||||
#include "VideoCommon/Spirv.h"
|
#include "VideoCommon/Spirv.h"
|
||||||
#include "VideoCommon/VideoBackendBase.h"
|
#include "VideoCommon/VideoBackendBase.h"
|
||||||
#include "VideoCommon/VideoConfig.h"
|
#include "VideoCommon/VideoConfig.h"
|
||||||
@ -35,6 +36,9 @@ namespace
|
|||||||
constexpr std::string_view SHADER_HEADER = R"(
|
constexpr std::string_view SHADER_HEADER = R"(
|
||||||
// Target GLSL 4.5.
|
// Target GLSL 4.5.
|
||||||
#version 450 core
|
#version 450 core
|
||||||
|
|
||||||
|
#extension GL_ARB_shading_language_include : enable
|
||||||
|
|
||||||
#define ATTRIBUTE_LOCATION(x) layout(location = x)
|
#define ATTRIBUTE_LOCATION(x) layout(location = x)
|
||||||
#define FRAGMENT_OUTPUT_LOCATION(x) layout(location = x)
|
#define FRAGMENT_OUTPUT_LOCATION(x) layout(location = x)
|
||||||
#define FRAGMENT_OUTPUT_LOCATION_INDEXED(x, y) layout(location = x, index = y)
|
#define FRAGMENT_OUTPUT_LOCATION_INDEXED(x, y) layout(location = x, index = y)
|
||||||
@ -107,14 +111,16 @@ std::optional<std::string> GetHLSLFromSPIRV(SPIRV::CodeVector spv, D3D_FEATURE_L
|
|||||||
return compiler.compile();
|
return compiler.compile();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<SPIRV::CodeVector> GetSpirv(ShaderStage stage, std::string_view source)
|
std::optional<SPIRV::CodeVector> GetSpirv(ShaderStage stage, std::string_view source,
|
||||||
|
glslang::TShader::Includer* shader_includer)
|
||||||
{
|
{
|
||||||
switch (stage)
|
switch (stage)
|
||||||
{
|
{
|
||||||
case ShaderStage::Vertex:
|
case ShaderStage::Vertex:
|
||||||
{
|
{
|
||||||
const auto full_source = fmt::format("{}{}", SHADER_HEADER, source);
|
const auto full_source = fmt::format("{}{}", SHADER_HEADER, source);
|
||||||
return SPIRV::CompileVertexShader(full_source, APIType::D3D, glslang::EShTargetSpv_1_0);
|
return SPIRV::CompileVertexShader(full_source, APIType::D3D, glslang::EShTargetSpv_1_0,
|
||||||
|
shader_includer);
|
||||||
}
|
}
|
||||||
|
|
||||||
case ShaderStage::Geometry:
|
case ShaderStage::Geometry:
|
||||||
@ -126,13 +132,15 @@ std::optional<SPIRV::CodeVector> GetSpirv(ShaderStage stage, std::string_view so
|
|||||||
case ShaderStage::Pixel:
|
case ShaderStage::Pixel:
|
||||||
{
|
{
|
||||||
const auto full_source = fmt::format("{}{}", SHADER_HEADER, source);
|
const auto full_source = fmt::format("{}{}", SHADER_HEADER, source);
|
||||||
return SPIRV::CompileFragmentShader(full_source, APIType::D3D, glslang::EShTargetSpv_1_0);
|
return SPIRV::CompileFragmentShader(full_source, APIType::D3D, glslang::EShTargetSpv_1_0,
|
||||||
|
shader_includer);
|
||||||
}
|
}
|
||||||
|
|
||||||
case ShaderStage::Compute:
|
case ShaderStage::Compute:
|
||||||
{
|
{
|
||||||
const auto full_source = fmt::format("{}{}", COMPUTE_SHADER_HEADER, source);
|
const auto full_source = fmt::format("{}{}", COMPUTE_SHADER_HEADER, source);
|
||||||
return SPIRV::CompileComputeShader(full_source, APIType::D3D, glslang::EShTargetSpv_1_0);
|
return SPIRV::CompileComputeShader(full_source, APIType::D3D, glslang::EShTargetSpv_1_0,
|
||||||
|
shader_includer);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -140,13 +148,14 @@ std::optional<SPIRV::CodeVector> GetSpirv(ShaderStage stage, std::string_view so
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::string> GetHLSL(D3D_FEATURE_LEVEL feature_level, ShaderStage stage,
|
std::optional<std::string> GetHLSL(D3D_FEATURE_LEVEL feature_level, ShaderStage stage,
|
||||||
std::string_view source)
|
std::string_view source,
|
||||||
|
VideoCommon::ShaderIncluder* shader_includer)
|
||||||
{
|
{
|
||||||
if (stage == ShaderStage::Geometry)
|
if (stage == ShaderStage::Geometry)
|
||||||
{
|
{
|
||||||
return std::string{source};
|
return std::string{source};
|
||||||
}
|
}
|
||||||
else if (const auto spirv = GetSpirv(stage, source))
|
else if (const auto spirv = GetSpirv(stage, source, shader_includer))
|
||||||
{
|
{
|
||||||
return GetHLSLFromSPIRV(std::move(*spirv), feature_level);
|
return GetHLSLFromSPIRV(std::move(*spirv), feature_level);
|
||||||
}
|
}
|
||||||
@ -230,10 +239,11 @@ static const char* GetCompileTarget(D3D_FEATURE_LEVEL feature_level, ShaderStage
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Shader::BinaryData> Shader::CompileShader(D3D_FEATURE_LEVEL feature_level,
|
std::optional<Shader::BinaryData>
|
||||||
ShaderStage stage, std::string_view source)
|
Shader::CompileShader(D3D_FEATURE_LEVEL feature_level, ShaderStage stage, std::string_view source,
|
||||||
|
VideoCommon::ShaderIncluder* shader_includer)
|
||||||
{
|
{
|
||||||
const auto hlsl = GetHLSL(feature_level, stage, source);
|
const auto hlsl = GetHLSL(feature_level, stage, source, shader_includer);
|
||||||
if (!hlsl)
|
if (!hlsl)
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
|
||||||
@ -260,7 +270,7 @@ std::optional<Shader::BinaryData> Shader::CompileShader(D3D_FEATURE_LEVEL featur
|
|||||||
file << "Dolphin Version: " + Common::GetScmRevStr() + "\n";
|
file << "Dolphin Version: " + Common::GetScmRevStr() + "\n";
|
||||||
file << "Video Backend: " + g_video_backend->GetDisplayName();
|
file << "Video Backend: " + g_video_backend->GetDisplayName();
|
||||||
|
|
||||||
if (const auto spirv = GetSpirv(stage, source))
|
if (const auto spirv = GetSpirv(stage, source, shader_includer))
|
||||||
{
|
{
|
||||||
file << "\nOriginal Source: \n";
|
file << "\nOriginal Source: \n";
|
||||||
file << source << std::endl;
|
file << source << std::endl;
|
||||||
|
|||||||
@ -20,7 +20,8 @@ public:
|
|||||||
BinaryData GetBinary() const override;
|
BinaryData GetBinary() const override;
|
||||||
|
|
||||||
static std::optional<BinaryData> CompileShader(D3D_FEATURE_LEVEL feature_level, ShaderStage stage,
|
static std::optional<BinaryData> CompileShader(D3D_FEATURE_LEVEL feature_level, ShaderStage stage,
|
||||||
std::string_view source);
|
std::string_view source,
|
||||||
|
VideoCommon::ShaderIncluder* shader_includer);
|
||||||
|
|
||||||
static BinaryData CreateByteCode(const void* data, size_t length);
|
static BinaryData CreateByteCode(const void* data, size_t length);
|
||||||
|
|
||||||
|
|||||||
@ -31,8 +31,10 @@ public:
|
|||||||
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
|
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
|
||||||
std::vector<AbstractTexture*> additional_color_attachments) override;
|
std::vector<AbstractTexture*> additional_color_attachments) override;
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, std::string_view source,
|
std::unique_ptr<AbstractShader>
|
||||||
std::string_view name) override;
|
CreateShaderFromSource(ShaderStage stage, std::string_view source,
|
||||||
|
VideoCommon::ShaderIncluder* shader_includer,
|
||||||
|
std::string_view name) override;
|
||||||
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
||||||
size_t length,
|
size_t length,
|
||||||
std::string_view name) override;
|
std::string_view name) override;
|
||||||
|
|||||||
@ -120,11 +120,12 @@ Metal::Gfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture
|
|||||||
|
|
||||||
// MARK: Pipeline Creation
|
// MARK: Pipeline Creation
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader> Metal::Gfx::CreateShaderFromSource(ShaderStage stage,
|
std::unique_ptr<AbstractShader>
|
||||||
std::string_view source,
|
Metal::Gfx::CreateShaderFromSource(ShaderStage stage, std::string_view source,
|
||||||
std::string_view name)
|
VideoCommon::ShaderIncluder* shader_includer,
|
||||||
|
std::string_view name)
|
||||||
{
|
{
|
||||||
std::optional<std::string> msl = Util::TranslateShaderToMSL(stage, source);
|
std::optional<std::string> msl = Util::TranslateShaderToMSL(stage, source, shader_includer);
|
||||||
if (!msl.has_value())
|
if (!msl.has_value())
|
||||||
{
|
{
|
||||||
PanicAlertFmt("Failed to convert shader {} to MSL", name);
|
PanicAlertFmt("Failed to convert shader {} to MSL", name);
|
||||||
|
|||||||
@ -54,7 +54,8 @@ static inline bool HasStencil(AbstractTextureFormat format)
|
|||||||
return format == AbstractTextureFormat::D24_S8 || format == AbstractTextureFormat::D32F_S8;
|
return format == AbstractTextureFormat::D24_S8 || format == AbstractTextureFormat::D32F_S8;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::string> TranslateShaderToMSL(ShaderStage stage, std::string_view source);
|
std::optional<std::string> TranslateShaderToMSL(ShaderStage stage, std::string_view source,
|
||||||
|
VideoCommon::ShaderIncluder* shader_includer);
|
||||||
|
|
||||||
} // namespace Util
|
} // namespace Util
|
||||||
} // namespace Metal
|
} // namespace Metal
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include "VideoCommon/Constants.h"
|
#include "VideoCommon/Constants.h"
|
||||||
#include "VideoCommon/DriverDetails.h"
|
#include "VideoCommon/DriverDetails.h"
|
||||||
|
#include "VideoCommon/ShaderCompileUtils.h"
|
||||||
#include "VideoCommon/Spirv.h"
|
#include "VideoCommon/Spirv.h"
|
||||||
|
|
||||||
Metal::DeviceFeatures Metal::g_features;
|
Metal::DeviceFeatures Metal::g_features;
|
||||||
@ -490,8 +491,9 @@ MakeResourceBinding(spv::ExecutionModel stage, u32 set, u32 binding, //
|
|||||||
return resource;
|
return resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::string> Metal::Util::TranslateShaderToMSL(ShaderStage stage,
|
std::optional<std::string>
|
||||||
std::string_view source)
|
Metal::Util::TranslateShaderToMSL(ShaderStage stage, std::string_view source,
|
||||||
|
VideoCommon::ShaderIncluder* shader_includer)
|
||||||
{
|
{
|
||||||
std::string full_source;
|
std::string full_source;
|
||||||
|
|
||||||
@ -514,16 +516,19 @@ std::optional<std::string> Metal::Util::TranslateShaderToMSL(ShaderStage stage,
|
|||||||
switch (stage)
|
switch (stage)
|
||||||
{
|
{
|
||||||
case ShaderStage::Vertex:
|
case ShaderStage::Vertex:
|
||||||
code = SPIRV::CompileVertexShader(full_source, APIType::Metal, glslang::EShTargetSpv_1_5);
|
code = SPIRV::CompileVertexShader(full_source, APIType::Metal, glslang::EShTargetSpv_1_5,
|
||||||
|
shader_includer);
|
||||||
break;
|
break;
|
||||||
case ShaderStage::Geometry:
|
case ShaderStage::Geometry:
|
||||||
PanicAlertFmt("Tried to compile geometry shader for Metal, but Metal doesn't support them!");
|
PanicAlertFmt("Tried to compile geometry shader for Metal, but Metal doesn't support them!");
|
||||||
break;
|
break;
|
||||||
case ShaderStage::Pixel:
|
case ShaderStage::Pixel:
|
||||||
code = SPIRV::CompileFragmentShader(full_source, APIType::Metal, glslang::EShTargetSpv_1_5);
|
code = SPIRV::CompileFragmentShader(full_source, APIType::Metal, glslang::EShTargetSpv_1_5,
|
||||||
|
shader_includer);
|
||||||
break;
|
break;
|
||||||
case ShaderStage::Compute:
|
case ShaderStage::Compute:
|
||||||
code = SPIRV::CompileComputeShader(full_source, APIType::Metal, glslang::EShTargetSpv_1_5);
|
code = SPIRV::CompileComputeShader(full_source, APIType::Metal, glslang::EShTargetSpv_1_5,
|
||||||
|
shader_includer);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!code.has_value())
|
if (!code.has_value())
|
||||||
|
|||||||
@ -53,6 +53,7 @@ public:
|
|||||||
|
|
||||||
std::unique_ptr<AbstractShader>
|
std::unique_ptr<AbstractShader>
|
||||||
NullGfx::CreateShaderFromSource(ShaderStage stage, [[maybe_unused]] std::string_view source,
|
NullGfx::CreateShaderFromSource(ShaderStage stage, [[maybe_unused]] std::string_view source,
|
||||||
|
[[maybe_unused]] VideoCommon::ShaderIncluder* shader_includer,
|
||||||
[[maybe_unused]] std::string_view name)
|
[[maybe_unused]] std::string_view name)
|
||||||
{
|
{
|
||||||
return std::make_unique<NullShader>(stage);
|
return std::make_unique<NullShader>(stage);
|
||||||
|
|||||||
@ -25,8 +25,10 @@ public:
|
|||||||
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
|
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
|
||||||
std::vector<AbstractTexture*> additional_color_attachments) override;
|
std::vector<AbstractTexture*> additional_color_attachments) override;
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, std::string_view source,
|
std::unique_ptr<AbstractShader>
|
||||||
std::string_view name) override;
|
CreateShaderFromSource(ShaderStage stage, std::string_view source,
|
||||||
|
VideoCommon::ShaderIncluder* shader_includer,
|
||||||
|
std::string_view name) override;
|
||||||
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
||||||
size_t length,
|
size_t length,
|
||||||
std::string_view name) override;
|
std::string_view name) override;
|
||||||
|
|||||||
@ -231,9 +231,10 @@ OGLGfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* de
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader>
|
std::unique_ptr<AbstractShader>
|
||||||
OGLGfx::CreateShaderFromSource(ShaderStage stage, std::string_view source, std::string_view name)
|
OGLGfx::CreateShaderFromSource(ShaderStage stage, std::string_view source,
|
||||||
|
VideoCommon::ShaderIncluder* shader_includer, std::string_view name)
|
||||||
{
|
{
|
||||||
return OGLShader::CreateFromSource(stage, source, name);
|
return OGLShader::CreateFromSource(stage, source, shader_includer, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader>
|
std::unique_ptr<AbstractShader>
|
||||||
|
|||||||
@ -25,8 +25,10 @@ public:
|
|||||||
std::string_view name) override;
|
std::string_view name) override;
|
||||||
std::unique_ptr<AbstractStagingTexture>
|
std::unique_ptr<AbstractStagingTexture>
|
||||||
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
|
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
|
||||||
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, std::string_view source,
|
std::unique_ptr<AbstractShader>
|
||||||
std::string_view name) override;
|
CreateShaderFromSource(ShaderStage stage, std::string_view source,
|
||||||
|
VideoCommon::ShaderIncluder* shader_includer,
|
||||||
|
std::string_view name) override;
|
||||||
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
||||||
size_t length,
|
size_t length,
|
||||||
std::string_view name) override;
|
std::string_view name) override;
|
||||||
|
|||||||
@ -3,12 +3,110 @@
|
|||||||
|
|
||||||
#include "VideoBackends/OGL/OGLShader.h"
|
#include "VideoBackends/OGL/OGLShader.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cctype>
|
||||||
|
|
||||||
#include "VideoBackends/OGL/ProgramShaderCache.h"
|
#include "VideoBackends/OGL/ProgramShaderCache.h"
|
||||||
|
|
||||||
|
#include "VideoCommon/ShaderCompileUtils.h"
|
||||||
|
#include "VideoCommon/ShaderGenCommon.h"
|
||||||
#include "VideoCommon/VideoConfig.h"
|
#include "VideoCommon/VideoConfig.h"
|
||||||
|
|
||||||
namespace OGL
|
namespace OGL
|
||||||
{
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
std::string ResolveIncludeStatements(glslang::TShader::Includer* shader_includer,
|
||||||
|
std::string_view source, const char* includer_name = "",
|
||||||
|
std::size_t depth = 1)
|
||||||
|
{
|
||||||
|
if (!shader_includer)
|
||||||
|
{
|
||||||
|
return std::string{source};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string source_str(source);
|
||||||
|
std::istringstream iss(source_str);
|
||||||
|
|
||||||
|
ShaderCode output;
|
||||||
|
std::string line;
|
||||||
|
while (std::getline(iss, line))
|
||||||
|
{
|
||||||
|
if (line.empty())
|
||||||
|
{
|
||||||
|
output.Write("{}\n", line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string_view include_preprocessor = "#include";
|
||||||
|
if (!line.starts_with(include_preprocessor))
|
||||||
|
{
|
||||||
|
output.Write("{}\n", line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string after_include = line.substr(include_preprocessor.size());
|
||||||
|
|
||||||
|
bool local_include = true;
|
||||||
|
std::string_view filename;
|
||||||
|
// First non-whitespace character after include
|
||||||
|
const std::string::const_iterator non_whitespace_iter = std::find_if_not(
|
||||||
|
after_include.begin(), after_include.end(), [](char ch) { return std::isspace(ch); });
|
||||||
|
if (*non_whitespace_iter == '<')
|
||||||
|
{
|
||||||
|
const auto after_less = std::next(non_whitespace_iter);
|
||||||
|
if (after_less == after_include.end())
|
||||||
|
{
|
||||||
|
// Found less-than at the end, malformed
|
||||||
|
output.Write("{}\n", line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto end_iter = std::find(after_less, after_include.end(), '>');
|
||||||
|
if (end_iter == after_include.end())
|
||||||
|
{
|
||||||
|
// Include spans multiple lines or is malformed, just pass it along
|
||||||
|
output.Write("{}\n", line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
filename = std::string_view(after_less, end_iter);
|
||||||
|
local_include = false;
|
||||||
|
}
|
||||||
|
else if (*non_whitespace_iter == '"')
|
||||||
|
{
|
||||||
|
const auto after_quote = std::next(non_whitespace_iter);
|
||||||
|
if (after_quote == after_include.end())
|
||||||
|
{
|
||||||
|
// Found quote at the end, malformed
|
||||||
|
output.Write("{}\n", line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto end_iter = std::find(after_quote, after_include.end(), '"');
|
||||||
|
if (end_iter == after_include.end())
|
||||||
|
{
|
||||||
|
// Include spans multiple lines or is malformed, just pass it along
|
||||||
|
output.Write("{}\n", line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
filename = std::string_view(after_quote, end_iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string header_path = std::string{filename};
|
||||||
|
auto include_result =
|
||||||
|
local_include ? shader_includer->includeLocal(header_path.c_str(), includer_name, depth) :
|
||||||
|
shader_includer->includeSystem(header_path.c_str(), includer_name, depth);
|
||||||
|
if (!include_result)
|
||||||
|
{
|
||||||
|
output.Write("{}\n", line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
output.Write("{}", ResolveIncludeStatements(shader_includer, include_result->headerData,
|
||||||
|
header_path.c_str(), ++depth));
|
||||||
|
}
|
||||||
|
|
||||||
|
return output.GetBuffer();
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
static GLenum GetGLShaderTypeForStage(ShaderStage stage)
|
static GLenum GetGLShaderTypeForStage(ShaderStage stage)
|
||||||
{
|
{
|
||||||
switch (stage)
|
switch (stage)
|
||||||
@ -57,9 +155,12 @@ OGLShader::~OGLShader()
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<OGLShader> OGLShader::CreateFromSource(ShaderStage stage, std::string_view source,
|
std::unique_ptr<OGLShader> OGLShader::CreateFromSource(ShaderStage stage, std::string_view source,
|
||||||
|
VideoCommon::ShaderIncluder* shader_includer,
|
||||||
std::string_view name)
|
std::string_view name)
|
||||||
{
|
{
|
||||||
std::string source_str(source);
|
// Note: while the source will all be available, any errors will not
|
||||||
|
// reference the correct paths
|
||||||
|
std::string source_str = ResolveIncludeStatements(shader_includer, source);
|
||||||
std::string name_str(name);
|
std::string name_str(name);
|
||||||
if (stage != ShaderStage::Compute)
|
if (stage != ShaderStage::Compute)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -29,6 +29,7 @@ public:
|
|||||||
const std::string& GetSource() const { return m_source; }
|
const std::string& GetSource() const { return m_source; }
|
||||||
|
|
||||||
static std::unique_ptr<OGLShader> CreateFromSource(ShaderStage stage, std::string_view source,
|
static std::unique_ptr<OGLShader> CreateFromSource(ShaderStage stage, std::string_view source,
|
||||||
|
VideoCommon::ShaderIncluder* shader_includer,
|
||||||
std::string_view name);
|
std::string_view name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@ -78,6 +78,7 @@ public:
|
|||||||
|
|
||||||
std::unique_ptr<AbstractShader>
|
std::unique_ptr<AbstractShader>
|
||||||
SWGfx::CreateShaderFromSource(ShaderStage stage, [[maybe_unused]] std::string_view source,
|
SWGfx::CreateShaderFromSource(ShaderStage stage, [[maybe_unused]] std::string_view source,
|
||||||
|
[[maybe_unused]] VideoCommon::ShaderIncluder* shader_includer,
|
||||||
[[maybe_unused]] std::string_view name)
|
[[maybe_unused]] std::string_view name)
|
||||||
{
|
{
|
||||||
return std::make_unique<SWShader>(stage);
|
return std::make_unique<SWShader>(stage);
|
||||||
|
|||||||
@ -28,8 +28,10 @@ public:
|
|||||||
|
|
||||||
bool BindBackbuffer(const ClearColor& clear_color = {}) override;
|
bool BindBackbuffer(const ClearColor& clear_color = {}) override;
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, std::string_view source,
|
std::unique_ptr<AbstractShader>
|
||||||
std::string_view name) override;
|
CreateShaderFromSource(ShaderStage stage, std::string_view source,
|
||||||
|
VideoCommon::ShaderIncluder* shader_includer,
|
||||||
|
std::string_view name) override;
|
||||||
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
||||||
size_t length,
|
size_t length,
|
||||||
std::string_view name) override;
|
std::string_view name) override;
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include "VideoBackends/Vulkan/VulkanContext.h"
|
#include "VideoBackends/Vulkan/VulkanContext.h"
|
||||||
#include "VideoCommon/DriverDetails.h"
|
#include "VideoCommon/DriverDetails.h"
|
||||||
|
#include "VideoCommon/ShaderCompileUtils.h"
|
||||||
#include "VideoCommon/Spirv.h"
|
#include "VideoCommon/Spirv.h"
|
||||||
|
|
||||||
namespace Vulkan::ShaderCompiler
|
namespace Vulkan::ShaderCompiler
|
||||||
@ -21,6 +22,9 @@ namespace Vulkan::ShaderCompiler
|
|||||||
static const char SHADER_HEADER[] = R"(
|
static const char SHADER_HEADER[] = R"(
|
||||||
// Target GLSL 4.5.
|
// Target GLSL 4.5.
|
||||||
#version 450 core
|
#version 450 core
|
||||||
|
|
||||||
|
#extension GL_ARB_shading_language_include : enable
|
||||||
|
|
||||||
#define ATTRIBUTE_LOCATION(x) layout(location = x)
|
#define ATTRIBUTE_LOCATION(x) layout(location = x)
|
||||||
#define FRAGMENT_OUTPUT_LOCATION(x) layout(location = x)
|
#define FRAGMENT_OUTPUT_LOCATION(x) layout(location = x)
|
||||||
#define FRAGMENT_OUTPUT_LOCATION_INDEXED(x, y) layout(location = x, index = y)
|
#define FRAGMENT_OUTPUT_LOCATION_INDEXED(x, y) layout(location = x, index = y)
|
||||||
@ -121,27 +125,31 @@ static glslang::EShTargetLanguageVersion GetLanguageVersion()
|
|||||||
return glslang::EShTargetSpv_1_0;
|
return glslang::EShTargetSpv_1_0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<SPIRVCodeVector> CompileVertexShader(std::string_view source_code)
|
std::optional<SPIRVCodeVector> CompileVertexShader(std::string_view source_code,
|
||||||
|
VideoCommon::ShaderIncluder* shader_includer)
|
||||||
{
|
{
|
||||||
return SPIRV::CompileVertexShader(GetShaderCode(source_code, SHADER_HEADER), APIType::Vulkan,
|
return SPIRV::CompileVertexShader(GetShaderCode(source_code, SHADER_HEADER), APIType::Vulkan,
|
||||||
GetLanguageVersion());
|
GetLanguageVersion(), shader_includer);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<SPIRVCodeVector> CompileGeometryShader(std::string_view source_code)
|
std::optional<SPIRVCodeVector> CompileGeometryShader(std::string_view source_code,
|
||||||
|
VideoCommon::ShaderIncluder* shader_includer)
|
||||||
{
|
{
|
||||||
return SPIRV::CompileGeometryShader(GetShaderCode(source_code, SHADER_HEADER), APIType::Vulkan,
|
return SPIRV::CompileGeometryShader(GetShaderCode(source_code, SHADER_HEADER), APIType::Vulkan,
|
||||||
GetLanguageVersion());
|
GetLanguageVersion(), shader_includer);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<SPIRVCodeVector> CompileFragmentShader(std::string_view source_code)
|
std::optional<SPIRVCodeVector> CompileFragmentShader(std::string_view source_code,
|
||||||
|
VideoCommon::ShaderIncluder* shader_includer)
|
||||||
{
|
{
|
||||||
return SPIRV::CompileFragmentShader(GetShaderCode(source_code, SHADER_HEADER), APIType::Vulkan,
|
return SPIRV::CompileFragmentShader(GetShaderCode(source_code, SHADER_HEADER), APIType::Vulkan,
|
||||||
GetLanguageVersion());
|
GetLanguageVersion(), shader_includer);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<SPIRVCodeVector> CompileComputeShader(std::string_view source_code)
|
std::optional<SPIRVCodeVector> CompileComputeShader(std::string_view source_code,
|
||||||
|
VideoCommon::ShaderIncluder* shader_includer)
|
||||||
{
|
{
|
||||||
return SPIRV::CompileComputeShader(GetShaderCode(source_code, COMPUTE_SHADER_HEADER),
|
return SPIRV::CompileComputeShader(GetShaderCode(source_code, COMPUTE_SHADER_HEADER),
|
||||||
APIType::Vulkan, GetLanguageVersion());
|
APIType::Vulkan, GetLanguageVersion(), shader_includer);
|
||||||
}
|
}
|
||||||
} // namespace Vulkan::ShaderCompiler
|
} // namespace Vulkan::ShaderCompiler
|
||||||
|
|||||||
@ -10,6 +10,11 @@
|
|||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
|
namespace VideoCommon
|
||||||
|
{
|
||||||
|
class ShaderIncluder;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Vulkan::ShaderCompiler
|
namespace Vulkan::ShaderCompiler
|
||||||
{
|
{
|
||||||
// SPIR-V compiled code type
|
// SPIR-V compiled code type
|
||||||
@ -17,14 +22,18 @@ using SPIRVCodeType = u32;
|
|||||||
using SPIRVCodeVector = std::vector<SPIRVCodeType>;
|
using SPIRVCodeVector = std::vector<SPIRVCodeType>;
|
||||||
|
|
||||||
// Compile a vertex shader to SPIR-V.
|
// Compile a vertex shader to SPIR-V.
|
||||||
std::optional<SPIRVCodeVector> CompileVertexShader(std::string_view source_code);
|
std::optional<SPIRVCodeVector> CompileVertexShader(std::string_view source_code,
|
||||||
|
VideoCommon::ShaderIncluder* shader_includer);
|
||||||
|
|
||||||
// Compile a geometry shader to SPIR-V.
|
// Compile a geometry shader to SPIR-V.
|
||||||
std::optional<SPIRVCodeVector> CompileGeometryShader(std::string_view source_code);
|
std::optional<SPIRVCodeVector> CompileGeometryShader(std::string_view source_code,
|
||||||
|
VideoCommon::ShaderIncluder* shader_includer);
|
||||||
|
|
||||||
// Compile a fragment shader to SPIR-V.
|
// Compile a fragment shader to SPIR-V.
|
||||||
std::optional<SPIRVCodeVector> CompileFragmentShader(std::string_view source_code);
|
std::optional<SPIRVCodeVector> CompileFragmentShader(std::string_view source_code,
|
||||||
|
VideoCommon::ShaderIncluder* shader_includer);
|
||||||
|
|
||||||
// Compile a compute shader to SPIR-V.
|
// Compile a compute shader to SPIR-V.
|
||||||
std::optional<SPIRVCodeVector> CompileComputeShader(std::string_view source_code);
|
std::optional<SPIRVCodeVector> CompileComputeShader(std::string_view source_code,
|
||||||
|
VideoCommon::ShaderIncluder* shader_includer);
|
||||||
} // namespace Vulkan::ShaderCompiler
|
} // namespace Vulkan::ShaderCompiler
|
||||||
|
|||||||
@ -60,9 +60,10 @@ std::unique_ptr<AbstractStagingTexture> VKGfx::CreateStagingTexture(StagingTextu
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader>
|
std::unique_ptr<AbstractShader>
|
||||||
VKGfx::CreateShaderFromSource(ShaderStage stage, std::string_view source, std::string_view name)
|
VKGfx::CreateShaderFromSource(ShaderStage stage, std::string_view source,
|
||||||
|
VideoCommon::ShaderIncluder* shader_includer, std::string_view name)
|
||||||
{
|
{
|
||||||
return VKShader::CreateFromSource(stage, source, name);
|
return VKShader::CreateFromSource(stage, source, shader_includer, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader> VKGfx::CreateShaderFromBinary(ShaderStage stage, const void* data,
|
std::unique_ptr<AbstractShader> VKGfx::CreateShaderFromBinary(ShaderStage stage, const void* data,
|
||||||
|
|||||||
@ -38,8 +38,10 @@ public:
|
|||||||
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
|
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
|
||||||
std::vector<AbstractTexture*> additional_color_attachments) override;
|
std::vector<AbstractTexture*> additional_color_attachments) override;
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, std::string_view source,
|
std::unique_ptr<AbstractShader>
|
||||||
std::string_view name) override;
|
CreateShaderFromSource(ShaderStage stage, std::string_view source,
|
||||||
|
VideoCommon::ShaderIncluder* shader_includer,
|
||||||
|
std::string_view name) override;
|
||||||
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
||||||
size_t length,
|
size_t length,
|
||||||
std::string_view name) override;
|
std::string_view name) override;
|
||||||
|
|||||||
@ -108,22 +108,23 @@ CreateShaderObject(ShaderStage stage, ShaderCompiler::SPIRVCodeVector spv, std::
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<VKShader> VKShader::CreateFromSource(ShaderStage stage, std::string_view source,
|
std::unique_ptr<VKShader> VKShader::CreateFromSource(ShaderStage stage, std::string_view source,
|
||||||
|
VideoCommon::ShaderIncluder* shader_includer,
|
||||||
std::string_view name)
|
std::string_view name)
|
||||||
{
|
{
|
||||||
std::optional<ShaderCompiler::SPIRVCodeVector> spv;
|
std::optional<ShaderCompiler::SPIRVCodeVector> spv;
|
||||||
switch (stage)
|
switch (stage)
|
||||||
{
|
{
|
||||||
case ShaderStage::Vertex:
|
case ShaderStage::Vertex:
|
||||||
spv = ShaderCompiler::CompileVertexShader(source);
|
spv = ShaderCompiler::CompileVertexShader(source, shader_includer);
|
||||||
break;
|
break;
|
||||||
case ShaderStage::Geometry:
|
case ShaderStage::Geometry:
|
||||||
spv = ShaderCompiler::CompileGeometryShader(source);
|
spv = ShaderCompiler::CompileGeometryShader(source, shader_includer);
|
||||||
break;
|
break;
|
||||||
case ShaderStage::Pixel:
|
case ShaderStage::Pixel:
|
||||||
spv = ShaderCompiler::CompileFragmentShader(source);
|
spv = ShaderCompiler::CompileFragmentShader(source, shader_includer);
|
||||||
break;
|
break;
|
||||||
case ShaderStage::Compute:
|
case ShaderStage::Compute:
|
||||||
spv = ShaderCompiler::CompileComputeShader(source);
|
spv = ShaderCompiler::CompileComputeShader(source, shader_includer);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -27,6 +27,7 @@ public:
|
|||||||
BinaryData GetBinary() const override;
|
BinaryData GetBinary() const override;
|
||||||
|
|
||||||
static std::unique_ptr<VKShader> CreateFromSource(ShaderStage stage, std::string_view source,
|
static std::unique_ptr<VKShader> CreateFromSource(ShaderStage stage, std::string_view source,
|
||||||
|
VideoCommon::ShaderIncluder* shader_includer,
|
||||||
std::string_view name);
|
std::string_view name);
|
||||||
static std::unique_ptr<VKShader> CreateFromBinary(ShaderStage stage, const void* data,
|
static std::unique_ptr<VKShader> CreateFromBinary(ShaderStage stage, const void* data,
|
||||||
size_t length, std::string_view name);
|
size_t length, std::string_view name);
|
||||||
|
|||||||
@ -37,7 +37,8 @@ struct SurfaceInfo
|
|||||||
namespace VideoCommon
|
namespace VideoCommon
|
||||||
{
|
{
|
||||||
class AsyncShaderCompiler;
|
class AsyncShaderCompiler;
|
||||||
}
|
class ShaderIncluder;
|
||||||
|
} // namespace VideoCommon
|
||||||
|
|
||||||
using ClearColor = std::array<float, 4>;
|
using ClearColor = std::array<float, 4>;
|
||||||
|
|
||||||
@ -110,9 +111,10 @@ public:
|
|||||||
virtual void PresentBackbuffer() {}
|
virtual void PresentBackbuffer() {}
|
||||||
|
|
||||||
// Shader modules/objects.
|
// Shader modules/objects.
|
||||||
virtual std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage,
|
virtual std::unique_ptr<AbstractShader>
|
||||||
std::string_view source,
|
CreateShaderFromSource(ShaderStage stage, std::string_view source,
|
||||||
std::string_view name = "") = 0;
|
VideoCommon::ShaderIncluder* shader_includer = nullptr,
|
||||||
|
std::string_view name = "") = 0;
|
||||||
virtual std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage,
|
virtual std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage,
|
||||||
const void* data, size_t length,
|
const void* data, size_t length,
|
||||||
std::string_view name = "") = 0;
|
std::string_view name = "") = 0;
|
||||||
|
|||||||
@ -9,6 +9,14 @@
|
|||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
|
// Note: not directly used in this file
|
||||||
|
// but done here to avoid specifying in
|
||||||
|
// every derived class that needs it
|
||||||
|
namespace VideoCommon
|
||||||
|
{
|
||||||
|
class ShaderIncluder;
|
||||||
|
}
|
||||||
|
|
||||||
enum class ShaderStage
|
enum class ShaderStage
|
||||||
{
|
{
|
||||||
Vertex,
|
Vertex,
|
||||||
|
|||||||
@ -147,6 +147,8 @@ add_library(videocommon
|
|||||||
RenderState.h
|
RenderState.h
|
||||||
ShaderCache.cpp
|
ShaderCache.cpp
|
||||||
ShaderCache.h
|
ShaderCache.h
|
||||||
|
ShaderCompileUtils.cpp
|
||||||
|
ShaderCompileUtils.h
|
||||||
ShaderGenCommon.cpp
|
ShaderGenCommon.cpp
|
||||||
ShaderGenCommon.h
|
ShaderGenCommon.h
|
||||||
Spirv.cpp
|
Spirv.cpp
|
||||||
|
|||||||
@ -412,7 +412,7 @@ bool FramebufferManager::CompileConversionPipelines()
|
|||||||
EFBReinterpretType convtype = static_cast<EFBReinterpretType>(i);
|
EFBReinterpretType convtype = static_cast<EFBReinterpretType>(i);
|
||||||
std::unique_ptr<AbstractShader> pixel_shader = g_gfx->CreateShaderFromSource(
|
std::unique_ptr<AbstractShader> pixel_shader = g_gfx->CreateShaderFromSource(
|
||||||
ShaderStage::Pixel,
|
ShaderStage::Pixel,
|
||||||
FramebufferShaderGen::GenerateFormatConversionShader(convtype, GetEFBSamples()),
|
FramebufferShaderGen::GenerateFormatConversionShader(convtype, GetEFBSamples()), nullptr,
|
||||||
fmt::format("Framebuffer conversion pixel shader {}", convtype));
|
fmt::format("Framebuffer conversion pixel shader {}", convtype));
|
||||||
if (!pixel_shader)
|
if (!pixel_shader)
|
||||||
return false;
|
return false;
|
||||||
@ -644,7 +644,7 @@ bool FramebufferManager::CompileReadbackPipelines()
|
|||||||
{
|
{
|
||||||
auto depth_resolve_shader = g_gfx->CreateShaderFromSource(
|
auto depth_resolve_shader = g_gfx->CreateShaderFromSource(
|
||||||
ShaderStage::Pixel, FramebufferShaderGen::GenerateResolveDepthPixelShader(GetEFBSamples()),
|
ShaderStage::Pixel, FramebufferShaderGen::GenerateResolveDepthPixelShader(GetEFBSamples()),
|
||||||
"Depth resolve pixel shader");
|
nullptr, "Depth resolve pixel shader");
|
||||||
if (!depth_resolve_shader)
|
if (!depth_resolve_shader)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -658,7 +658,7 @@ bool FramebufferManager::CompileReadbackPipelines()
|
|||||||
config.framebuffer_state.color_texture_format = GetEFBColorFormat();
|
config.framebuffer_state.color_texture_format = GetEFBColorFormat();
|
||||||
auto color_resolve_shader = g_gfx->CreateShaderFromSource(
|
auto color_resolve_shader = g_gfx->CreateShaderFromSource(
|
||||||
ShaderStage::Pixel,
|
ShaderStage::Pixel,
|
||||||
FramebufferShaderGen::GenerateResolveColorPixelShader(GetEFBSamples()),
|
FramebufferShaderGen::GenerateResolveColorPixelShader(GetEFBSamples()), nullptr,
|
||||||
"Color resolve pixel shader");
|
"Color resolve pixel shader");
|
||||||
if (!color_resolve_shader)
|
if (!color_resolve_shader)
|
||||||
return false;
|
return false;
|
||||||
@ -672,7 +672,7 @@ bool FramebufferManager::CompileReadbackPipelines()
|
|||||||
|
|
||||||
// EFB restore pipeline
|
// EFB restore pipeline
|
||||||
auto restore_shader = g_gfx->CreateShaderFromSource(
|
auto restore_shader = g_gfx->CreateShaderFromSource(
|
||||||
ShaderStage::Pixel, FramebufferShaderGen::GenerateEFBRestorePixelShader(),
|
ShaderStage::Pixel, FramebufferShaderGen::GenerateEFBRestorePixelShader(), nullptr,
|
||||||
"EFB restore pixel shader");
|
"EFB restore pixel shader");
|
||||||
if (!restore_shader)
|
if (!restore_shader)
|
||||||
return false;
|
return false;
|
||||||
@ -888,7 +888,7 @@ void FramebufferManager::ClearEFB(const MathUtil::Rectangle<int>& rc, bool color
|
|||||||
bool FramebufferManager::CompileClearPipelines()
|
bool FramebufferManager::CompileClearPipelines()
|
||||||
{
|
{
|
||||||
auto vertex_shader = g_gfx->CreateShaderFromSource(
|
auto vertex_shader = g_gfx->CreateShaderFromSource(
|
||||||
ShaderStage::Vertex, FramebufferShaderGen::GenerateClearVertexShader(),
|
ShaderStage::Vertex, FramebufferShaderGen::GenerateClearVertexShader(), nullptr,
|
||||||
"Clear vertex shader");
|
"Clear vertex shader");
|
||||||
if (!vertex_shader)
|
if (!vertex_shader)
|
||||||
return false;
|
return false;
|
||||||
@ -1063,7 +1063,7 @@ bool FramebufferManager::CompilePokePipelines()
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
auto poke_vertex_shader = g_gfx->CreateShaderFromSource(
|
auto poke_vertex_shader = g_gfx->CreateShaderFromSource(
|
||||||
ShaderStage::Vertex, FramebufferShaderGen::GenerateEFBPokeVertexShader(),
|
ShaderStage::Vertex, FramebufferShaderGen::GenerateEFBPokeVertexShader(), nullptr,
|
||||||
"EFB poke vertex shader");
|
"EFB poke vertex shader");
|
||||||
if (!poke_vertex_shader)
|
if (!poke_vertex_shader)
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -348,7 +348,7 @@ CustomShaderCache::CompilePixelShader(const PixelShaderUid& uid,
|
|||||||
{
|
{
|
||||||
const ShaderCode source_code =
|
const ShaderCode source_code =
|
||||||
GeneratePixelShaderCode(m_api_type, m_host_config, uid.GetUidData(), {});
|
GeneratePixelShaderCode(m_api_type, m_host_config, uid.GetUidData(), {});
|
||||||
return g_gfx->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer(),
|
return g_gfx->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer(), nullptr,
|
||||||
"Custom Pixel Shader");
|
"Custom Pixel Shader");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,7 +357,7 @@ CustomShaderCache::CompilePixelShader(const UberShader::PixelShaderUid& uid,
|
|||||||
const CustomShaderInstance& custom_shaders) const
|
const CustomShaderInstance& custom_shaders) const
|
||||||
{
|
{
|
||||||
const ShaderCode source_code = GenPixelShader(m_api_type, m_host_config, uid.GetUidData());
|
const ShaderCode source_code = GenPixelShader(m_api_type, m_host_config, uid.GetUidData());
|
||||||
return g_gfx->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer(),
|
return g_gfx->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer(), nullptr,
|
||||||
"Custom Uber Pixel Shader");
|
"Custom Uber Pixel Shader");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -113,11 +113,11 @@ bool OnScreenUI::RecompileImGuiPipeline()
|
|||||||
g_presenter->GetBackbufferFormat() == AbstractTextureFormat::RGBA16F;
|
g_presenter->GetBackbufferFormat() == AbstractTextureFormat::RGBA16F;
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader> vertex_shader = g_gfx->CreateShaderFromSource(
|
std::unique_ptr<AbstractShader> vertex_shader = g_gfx->CreateShaderFromSource(
|
||||||
ShaderStage::Vertex, FramebufferShaderGen::GenerateImGuiVertexShader(),
|
ShaderStage::Vertex, FramebufferShaderGen::GenerateImGuiVertexShader(), nullptr,
|
||||||
"ImGui vertex shader");
|
"ImGui vertex shader");
|
||||||
std::unique_ptr<AbstractShader> pixel_shader = g_gfx->CreateShaderFromSource(
|
std::unique_ptr<AbstractShader> pixel_shader = g_gfx->CreateShaderFromSource(
|
||||||
ShaderStage::Pixel, FramebufferShaderGen::GenerateImGuiPixelShader(linear_space_output),
|
ShaderStage::Pixel, FramebufferShaderGen::GenerateImGuiPixelShader(linear_space_output),
|
||||||
"ImGui pixel shader");
|
nullptr, "ImGui pixel shader");
|
||||||
if (!vertex_shader || !pixel_shader)
|
if (!vertex_shader || !pixel_shader)
|
||||||
{
|
{
|
||||||
PanicAlertFmt("Failed to compile ImGui shaders");
|
PanicAlertFmt("Failed to compile ImGui shaders");
|
||||||
@ -130,7 +130,7 @@ bool OnScreenUI::RecompileImGuiPipeline()
|
|||||||
{
|
{
|
||||||
geometry_shader = g_gfx->CreateShaderFromSource(
|
geometry_shader = g_gfx->CreateShaderFromSource(
|
||||||
ShaderStage::Geometry, FramebufferShaderGen::GeneratePassthroughGeometryShader(1, 1),
|
ShaderStage::Geometry, FramebufferShaderGen::GeneratePassthroughGeometryShader(1, 1),
|
||||||
"ImGui passthrough geometry shader");
|
nullptr, "ImGui passthrough geometry shader");
|
||||||
if (!geometry_shader)
|
if (!geometry_shader)
|
||||||
{
|
{
|
||||||
PanicAlertFmt("Failed to compile ImGui geometry shader");
|
PanicAlertFmt("Failed to compile ImGui geometry shader");
|
||||||
|
|||||||
@ -27,6 +27,7 @@
|
|||||||
#include "VideoCommon/FramebufferManager.h"
|
#include "VideoCommon/FramebufferManager.h"
|
||||||
#include "VideoCommon/Present.h"
|
#include "VideoCommon/Present.h"
|
||||||
#include "VideoCommon/ShaderCache.h"
|
#include "VideoCommon/ShaderCache.h"
|
||||||
|
#include "VideoCommon/ShaderCompileUtils.h"
|
||||||
#include "VideoCommon/VertexManagerBase.h"
|
#include "VideoCommon/VertexManagerBase.h"
|
||||||
#include "VideoCommon/VideoCommon.h"
|
#include "VideoCommon/VideoCommon.h"
|
||||||
#include "VideoCommon/VideoConfig.h"
|
#include "VideoCommon/VideoConfig.h"
|
||||||
@ -97,6 +98,9 @@ void PostProcessingConfiguration::LoadShader(const std::string& shader)
|
|||||||
// might have set in the settings
|
// might have set in the settings
|
||||||
LoadOptionsConfiguration();
|
LoadOptionsConfiguration();
|
||||||
m_current_shader_code = code;
|
m_current_shader_code = code;
|
||||||
|
m_shader_includer =
|
||||||
|
std::make_unique<ShaderIncluder>(File::GetUserPath(D_SHADERS_IDX) + sub_dir,
|
||||||
|
File::GetSysDirectory() + SHADERS_DIR DIR_SEP + sub_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PostProcessingConfiguration::LoadDefaultShader()
|
void PostProcessingConfiguration::LoadDefaultShader()
|
||||||
@ -809,14 +813,14 @@ bool PostProcessing::CompileVertexShader()
|
|||||||
std::ostringstream ss_default;
|
std::ostringstream ss_default;
|
||||||
ss_default << GetUniformBufferHeader(false);
|
ss_default << GetUniformBufferHeader(false);
|
||||||
ss_default << GetVertexShaderBody();
|
ss_default << GetVertexShaderBody();
|
||||||
m_default_vertex_shader = g_gfx->CreateShaderFromSource(ShaderStage::Vertex, ss_default.str(),
|
m_default_vertex_shader = g_gfx->CreateShaderFromSource(
|
||||||
"Default post-processing vertex shader");
|
ShaderStage::Vertex, ss_default.str(), nullptr, "Default post-processing vertex shader");
|
||||||
|
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
ss << GetUniformBufferHeader(true);
|
ss << GetUniformBufferHeader(true);
|
||||||
ss << GetVertexShaderBody();
|
ss << GetVertexShaderBody();
|
||||||
m_vertex_shader =
|
m_vertex_shader = g_gfx->CreateShaderFromSource(ShaderStage::Vertex, ss.str(), nullptr,
|
||||||
g_gfx->CreateShaderFromSource(ShaderStage::Vertex, ss.str(), "Post-processing vertex shader");
|
"Post-processing vertex shader");
|
||||||
|
|
||||||
if (!m_default_vertex_shader || !m_vertex_shader)
|
if (!m_default_vertex_shader || !m_vertex_shader)
|
||||||
{
|
{
|
||||||
@ -966,7 +970,7 @@ bool PostProcessing::CompilePixelShader()
|
|||||||
if (LoadShaderFromFile(s_default_pixel_shader_name, "", default_pixel_shader_code))
|
if (LoadShaderFromFile(s_default_pixel_shader_name, "", default_pixel_shader_code))
|
||||||
{
|
{
|
||||||
m_default_pixel_shader = g_gfx->CreateShaderFromSource(
|
m_default_pixel_shader = g_gfx->CreateShaderFromSource(
|
||||||
ShaderStage::Pixel, GetHeader(false) + default_pixel_shader_code + GetFooter(),
|
ShaderStage::Pixel, GetHeader(false) + default_pixel_shader_code + GetFooter(), nullptr,
|
||||||
"Default post-processing pixel shader");
|
"Default post-processing pixel shader");
|
||||||
// We continue even if all of this failed, it doesn't matter
|
// We continue even if all of this failed, it doesn't matter
|
||||||
m_default_uniform_staging_buffer.resize(CalculateUniformsSize(false));
|
m_default_uniform_staging_buffer.resize(CalculateUniformsSize(false));
|
||||||
@ -979,6 +983,7 @@ bool PostProcessing::CompilePixelShader()
|
|||||||
m_config.LoadShader(g_ActiveConfig.sPostProcessingShader);
|
m_config.LoadShader(g_ActiveConfig.sPostProcessingShader);
|
||||||
m_pixel_shader = g_gfx->CreateShaderFromSource(
|
m_pixel_shader = g_gfx->CreateShaderFromSource(
|
||||||
ShaderStage::Pixel, GetHeader(true) + m_config.GetShaderCode() + GetFooter(),
|
ShaderStage::Pixel, GetHeader(true) + m_config.GetShaderCode() + GetFooter(),
|
||||||
|
m_config.GetShaderIncluder(),
|
||||||
fmt::format("User post-processing pixel shader: {}", m_config.GetShader()));
|
fmt::format("User post-processing pixel shader: {}", m_config.GetShader()));
|
||||||
if (!m_pixel_shader)
|
if (!m_pixel_shader)
|
||||||
{
|
{
|
||||||
@ -987,7 +992,7 @@ bool PostProcessing::CompilePixelShader()
|
|||||||
// Use default shader.
|
// Use default shader.
|
||||||
m_config.LoadDefaultShader();
|
m_config.LoadDefaultShader();
|
||||||
m_pixel_shader = g_gfx->CreateShaderFromSource(
|
m_pixel_shader = g_gfx->CreateShaderFromSource(
|
||||||
ShaderStage::Pixel, GetHeader(true) + m_config.GetShaderCode() + GetFooter(),
|
ShaderStage::Pixel, GetHeader(true) + m_config.GetShaderCode() + GetFooter(), nullptr,
|
||||||
"Default user post-processing pixel shader");
|
"Default user post-processing pixel shader");
|
||||||
if (!m_pixel_shader)
|
if (!m_pixel_shader)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -20,6 +20,8 @@ class AbstractFramebuffer;
|
|||||||
|
|
||||||
namespace VideoCommon
|
namespace VideoCommon
|
||||||
{
|
{
|
||||||
|
class ShaderIncluder;
|
||||||
|
|
||||||
class PostProcessingConfiguration
|
class PostProcessingConfiguration
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -68,6 +70,7 @@ public:
|
|||||||
void SaveOptionsConfiguration();
|
void SaveOptionsConfiguration();
|
||||||
const std::string& GetShader() const { return m_current_shader; }
|
const std::string& GetShader() const { return m_current_shader; }
|
||||||
const std::string& GetShaderCode() const { return m_current_shader_code; }
|
const std::string& GetShaderCode() const { return m_current_shader_code; }
|
||||||
|
ShaderIncluder* GetShaderIncluder() { return m_shader_includer.get(); }
|
||||||
bool IsDirty() const { return m_any_options_dirty; }
|
bool IsDirty() const { return m_any_options_dirty; }
|
||||||
void SetDirty(bool dirty) { m_any_options_dirty = dirty; }
|
void SetDirty(bool dirty) { m_any_options_dirty = dirty; }
|
||||||
bool HasOptions() const { return m_options.size() > 0; }
|
bool HasOptions() const { return m_options.size() > 0; }
|
||||||
@ -81,6 +84,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_any_options_dirty = false;
|
bool m_any_options_dirty = false;
|
||||||
|
std::unique_ptr<ShaderIncluder> m_shader_includer;
|
||||||
std::string m_current_shader;
|
std::string m_current_shader;
|
||||||
std::string m_current_shader_code;
|
std::string m_current_shader_code;
|
||||||
ConfigMap m_options;
|
ConfigMap m_options;
|
||||||
|
|||||||
@ -442,7 +442,7 @@ ShaderCache::CompileVertexUberShader(const UberShader::VertexShaderUid& uid) con
|
|||||||
{
|
{
|
||||||
const ShaderCode source_code =
|
const ShaderCode source_code =
|
||||||
UberShader::GenVertexShader(m_api_type, m_host_config, uid.GetUidData());
|
UberShader::GenVertexShader(m_api_type, m_host_config, uid.GetUidData());
|
||||||
return g_gfx->CreateShaderFromSource(ShaderStage::Vertex, source_code.GetBuffer(),
|
return g_gfx->CreateShaderFromSource(ShaderStage::Vertex, source_code.GetBuffer(), nullptr,
|
||||||
fmt::to_string(*uid.GetUidData()));
|
fmt::to_string(*uid.GetUidData()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -458,7 +458,7 @@ ShaderCache::CompilePixelUberShader(const UberShader::PixelShaderUid& uid) const
|
|||||||
{
|
{
|
||||||
const ShaderCode source_code =
|
const ShaderCode source_code =
|
||||||
UberShader::GenPixelShader(m_api_type, m_host_config, uid.GetUidData());
|
UberShader::GenPixelShader(m_api_type, m_host_config, uid.GetUidData());
|
||||||
return g_gfx->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer(),
|
return g_gfx->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer(), nullptr,
|
||||||
fmt::to_string(*uid.GetUidData()));
|
fmt::to_string(*uid.GetUidData()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -555,7 +555,7 @@ const AbstractShader* ShaderCache::CreateGeometryShader(const GeometryShaderUid&
|
|||||||
const ShaderCode source_code =
|
const ShaderCode source_code =
|
||||||
GenerateGeometryShaderCode(m_api_type, m_host_config, uid.GetUidData());
|
GenerateGeometryShaderCode(m_api_type, m_host_config, uid.GetUidData());
|
||||||
std::unique_ptr<AbstractShader> shader =
|
std::unique_ptr<AbstractShader> shader =
|
||||||
g_gfx->CreateShaderFromSource(ShaderStage::Geometry, source_code.GetBuffer(),
|
g_gfx->CreateShaderFromSource(ShaderStage::Geometry, source_code.GetBuffer(), nullptr,
|
||||||
fmt::format("Geometry shader: {}", *uid.GetUidData()));
|
fmt::format("Geometry shader: {}", *uid.GetUidData()));
|
||||||
|
|
||||||
auto& entry = m_gs_cache.shader_map[uid];
|
auto& entry = m_gs_cache.shader_map[uid];
|
||||||
@ -1393,7 +1393,7 @@ ShaderCache::GetEFBCopyToVRAMPipeline(const TextureConversionShaderGen::TCShader
|
|||||||
|
|
||||||
auto shader_code = TextureConversionShaderGen::GeneratePixelShader(m_api_type, uid.GetUidData());
|
auto shader_code = TextureConversionShaderGen::GeneratePixelShader(m_api_type, uid.GetUidData());
|
||||||
auto shader = g_gfx->CreateShaderFromSource(
|
auto shader = g_gfx->CreateShaderFromSource(
|
||||||
ShaderStage::Pixel, shader_code.GetBuffer(),
|
ShaderStage::Pixel, shader_code.GetBuffer(), nullptr,
|
||||||
fmt::format("EFB copy to VRAM pixel shader: {}", *uid.GetUidData()));
|
fmt::format("EFB copy to VRAM pixel shader: {}", *uid.GetUidData()));
|
||||||
if (!shader)
|
if (!shader)
|
||||||
{
|
{
|
||||||
@ -1424,8 +1424,9 @@ const AbstractPipeline* ShaderCache::GetEFBCopyToRAMPipeline(const EFBCopyParams
|
|||||||
|
|
||||||
const std::string shader_code =
|
const std::string shader_code =
|
||||||
TextureConversionShaderTiled::GenerateEncodingShader(uid, m_api_type);
|
TextureConversionShaderTiled::GenerateEncodingShader(uid, m_api_type);
|
||||||
const auto shader = g_gfx->CreateShaderFromSource(
|
const auto shader =
|
||||||
ShaderStage::Pixel, shader_code, fmt::format("EFB copy to RAM pixel shader: {}", uid));
|
g_gfx->CreateShaderFromSource(ShaderStage::Pixel, shader_code, nullptr,
|
||||||
|
fmt::format("EFB copy to RAM pixel shader: {}", uid));
|
||||||
if (!shader)
|
if (!shader)
|
||||||
{
|
{
|
||||||
m_efb_copy_to_ram_pipelines.emplace(uid, nullptr);
|
m_efb_copy_to_ram_pipelines.emplace(uid, nullptr);
|
||||||
@ -1447,14 +1448,14 @@ const AbstractPipeline* ShaderCache::GetEFBCopyToRAMPipeline(const EFBCopyParams
|
|||||||
bool ShaderCache::CompileSharedPipelines()
|
bool ShaderCache::CompileSharedPipelines()
|
||||||
{
|
{
|
||||||
m_screen_quad_vertex_shader = g_gfx->CreateShaderFromSource(
|
m_screen_quad_vertex_shader = g_gfx->CreateShaderFromSource(
|
||||||
ShaderStage::Vertex, FramebufferShaderGen::GenerateScreenQuadVertexShader(),
|
ShaderStage::Vertex, FramebufferShaderGen::GenerateScreenQuadVertexShader(), nullptr,
|
||||||
"Screen quad vertex shader");
|
"Screen quad vertex shader");
|
||||||
m_texture_copy_vertex_shader = g_gfx->CreateShaderFromSource(
|
m_texture_copy_vertex_shader = g_gfx->CreateShaderFromSource(
|
||||||
ShaderStage::Vertex, FramebufferShaderGen::GenerateTextureCopyVertexShader(),
|
ShaderStage::Vertex, FramebufferShaderGen::GenerateTextureCopyVertexShader(), nullptr,
|
||||||
"Texture copy vertex shader");
|
"Texture copy vertex shader");
|
||||||
m_efb_copy_vertex_shader = g_gfx->CreateShaderFromSource(
|
m_efb_copy_vertex_shader = g_gfx->CreateShaderFromSource(
|
||||||
ShaderStage::Vertex, TextureConversionShaderGen::GenerateVertexShader(m_api_type).GetBuffer(),
|
ShaderStage::Vertex, TextureConversionShaderGen::GenerateVertexShader(m_api_type).GetBuffer(),
|
||||||
"EFB copy vertex shader");
|
nullptr, "EFB copy vertex shader");
|
||||||
if (!m_screen_quad_vertex_shader || !m_texture_copy_vertex_shader || !m_efb_copy_vertex_shader)
|
if (!m_screen_quad_vertex_shader || !m_texture_copy_vertex_shader || !m_efb_copy_vertex_shader)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -1462,19 +1463,20 @@ bool ShaderCache::CompileSharedPipelines()
|
|||||||
{
|
{
|
||||||
m_texcoord_geometry_shader = g_gfx->CreateShaderFromSource(
|
m_texcoord_geometry_shader = g_gfx->CreateShaderFromSource(
|
||||||
ShaderStage::Geometry, FramebufferShaderGen::GeneratePassthroughGeometryShader(1, 0),
|
ShaderStage::Geometry, FramebufferShaderGen::GeneratePassthroughGeometryShader(1, 0),
|
||||||
"Texcoord passthrough geometry shader");
|
nullptr, "Texcoord passthrough geometry shader");
|
||||||
m_color_geometry_shader = g_gfx->CreateShaderFromSource(
|
m_color_geometry_shader = g_gfx->CreateShaderFromSource(
|
||||||
ShaderStage::Geometry, FramebufferShaderGen::GeneratePassthroughGeometryShader(0, 1),
|
ShaderStage::Geometry, FramebufferShaderGen::GeneratePassthroughGeometryShader(0, 1),
|
||||||
"Color passthrough geometry shader");
|
nullptr, "Color passthrough geometry shader");
|
||||||
if (!m_texcoord_geometry_shader || !m_color_geometry_shader)
|
if (!m_texcoord_geometry_shader || !m_color_geometry_shader)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_texture_copy_pixel_shader = g_gfx->CreateShaderFromSource(
|
m_texture_copy_pixel_shader = g_gfx->CreateShaderFromSource(
|
||||||
ShaderStage::Pixel, FramebufferShaderGen::GenerateTextureCopyPixelShader(),
|
ShaderStage::Pixel, FramebufferShaderGen::GenerateTextureCopyPixelShader(), nullptr,
|
||||||
"Texture copy pixel shader");
|
"Texture copy pixel shader");
|
||||||
m_color_pixel_shader = g_gfx->CreateShaderFromSource(
|
m_color_pixel_shader = g_gfx->CreateShaderFromSource(
|
||||||
ShaderStage::Pixel, FramebufferShaderGen::GenerateColorPixelShader(), "Color pixel shader");
|
ShaderStage::Pixel, FramebufferShaderGen::GenerateColorPixelShader(), nullptr,
|
||||||
|
"Color pixel shader");
|
||||||
if (!m_texture_copy_pixel_shader || !m_color_pixel_shader)
|
if (!m_texture_copy_pixel_shader || !m_color_pixel_shader)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -1511,7 +1513,7 @@ bool ShaderCache::CompileSharedPipelines()
|
|||||||
auto shader = g_gfx->CreateShaderFromSource(
|
auto shader = g_gfx->CreateShaderFromSource(
|
||||||
ShaderStage::Pixel,
|
ShaderStage::Pixel,
|
||||||
TextureConversionShaderTiled::GeneratePaletteConversionShader(format, m_api_type),
|
TextureConversionShaderTiled::GeneratePaletteConversionShader(format, m_api_type),
|
||||||
fmt::format("Palette conversion pixel shader: {}", format));
|
nullptr, fmt::format("Palette conversion pixel shader: {}", format));
|
||||||
if (!shader)
|
if (!shader)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -1546,7 +1548,7 @@ const AbstractPipeline* ShaderCache::GetTextureReinterpretPipeline(TextureFormat
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader> shader = g_gfx->CreateShaderFromSource(
|
std::unique_ptr<AbstractShader> shader = g_gfx->CreateShaderFromSource(
|
||||||
ShaderStage::Pixel, shader_source,
|
ShaderStage::Pixel, shader_source, nullptr,
|
||||||
fmt::format("Texture reinterpret pixel shader: {} to {}", from_format, to_format));
|
fmt::format("Texture reinterpret pixel shader: {} to {}", from_format, to_format));
|
||||||
if (!shader)
|
if (!shader)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -1586,7 +1588,7 @@ ShaderCache::GetTextureDecodingShader(TextureFormat format,
|
|||||||
fmt::format("Texture decoding compute shader: {}", format);
|
fmt::format("Texture decoding compute shader: {}", format);
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader> shader =
|
std::unique_ptr<AbstractShader> shader =
|
||||||
g_gfx->CreateShaderFromSource(ShaderStage::Compute, shader_source, name);
|
g_gfx->CreateShaderFromSource(ShaderStage::Compute, shader_source, nullptr, name);
|
||||||
if (!shader)
|
if (!shader)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
|||||||
93
Source/Core/VideoCommon/ShaderCompileUtils.cpp
Normal file
93
Source/Core/VideoCommon/ShaderCompileUtils.cpp
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
// Copyright 2025 Dolphin Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "VideoCommon/ShaderCompileUtils.h"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <ranges>
|
||||||
|
|
||||||
|
#include "Common/FileUtil.h"
|
||||||
|
#include "Common/StringUtil.h"
|
||||||
|
|
||||||
|
namespace VideoCommon
|
||||||
|
{
|
||||||
|
ShaderIncluder::ShaderIncluder(const std::string& user_path, const std::string& system_path)
|
||||||
|
: m_root_user_path(user_path), m_root_system_path(system_path)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> ShaderIncluder::GetIncludes() const
|
||||||
|
{
|
||||||
|
const auto keys = std::views::keys(m_include_results);
|
||||||
|
return {keys.begin(), keys.end()};
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderIncluder::IncludeResult*
|
||||||
|
ShaderIncluder::includeLocal(const char* header_name, const char* includer_name, std::size_t depth)
|
||||||
|
{
|
||||||
|
return ProcessInclude(m_root_user_path, header_name, includer_name, depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderIncluder::IncludeResult*
|
||||||
|
ShaderIncluder::includeSystem(const char* header_name, const char* includer_name, std::size_t depth)
|
||||||
|
{
|
||||||
|
return ProcessInclude(m_root_system_path, header_name, includer_name, depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderIncluder::releaseInclude(IncludeResult* result)
|
||||||
|
{
|
||||||
|
m_include_results.erase(result->headerName);
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderIncluder::IncludeResult* ShaderIncluder::ProcessInclude(const std::string& root,
|
||||||
|
const char* header_name,
|
||||||
|
const char* includer_name,
|
||||||
|
std::size_t depth)
|
||||||
|
{
|
||||||
|
m_dirs.resize(depth);
|
||||||
|
if (depth == 1)
|
||||||
|
{
|
||||||
|
const auto includer_dir = GetDirectory(includer_name);
|
||||||
|
if (includer_dir == ".")
|
||||||
|
{
|
||||||
|
m_dirs.push_back(root);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_dirs.push_back(std::string{includer_dir});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search through directories back to front
|
||||||
|
for (auto iter = m_dirs.rbegin(); iter != m_dirs.rend(); iter++)
|
||||||
|
{
|
||||||
|
const std::string full_path = WithUnifiedPathSeparators(*iter + '/' + header_name);
|
||||||
|
|
||||||
|
std::string file_data;
|
||||||
|
if (File::ReadFileToString(full_path, file_data))
|
||||||
|
{
|
||||||
|
m_dirs.push_back(std::string{GetDirectory(full_path)});
|
||||||
|
|
||||||
|
const char* file_bytes = file_data.data();
|
||||||
|
const std::size_t file_size = file_data.size();
|
||||||
|
IncludeResultData result_data{
|
||||||
|
.result = std::make_unique<IncludeResult>(full_path, file_bytes, file_size, nullptr),
|
||||||
|
.file_data = std::move(file_data)};
|
||||||
|
|
||||||
|
auto ptr = result_data.result.get();
|
||||||
|
m_include_results[full_path] = std::move(result_data);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string_view ShaderIncluder::GetDirectory(std::string_view path) const
|
||||||
|
{
|
||||||
|
const auto last_pos = path.find_last_of('/');
|
||||||
|
if (last_pos == std::string_view::npos)
|
||||||
|
return ".";
|
||||||
|
|
||||||
|
return path.substr(0, last_pos);
|
||||||
|
}
|
||||||
|
} // namespace VideoCommon
|
||||||
46
Source/Core/VideoCommon/ShaderCompileUtils.h
Normal file
46
Source/Core/VideoCommon/ShaderCompileUtils.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// Copyright 2025 Dolphin Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "ShaderLang.h"
|
||||||
|
|
||||||
|
namespace VideoCommon
|
||||||
|
{
|
||||||
|
class ShaderIncluder final : public glslang::TShader::Includer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ShaderIncluder(const std::string& user_path, const std::string& system_path);
|
||||||
|
~ShaderIncluder() override = default;
|
||||||
|
|
||||||
|
std::vector<std::string> GetIncludes() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
IncludeResult* includeLocal(const char* header_name, const char* includer_name,
|
||||||
|
std::size_t depth) override;
|
||||||
|
IncludeResult* includeSystem(const char* header_name, const char* includer_name,
|
||||||
|
std::size_t depth) override;
|
||||||
|
void releaseInclude(IncludeResult* result) override;
|
||||||
|
|
||||||
|
IncludeResult* ProcessInclude(const std::string& root, const char* header_name,
|
||||||
|
const char* includer_name, std::size_t depth);
|
||||||
|
std::string_view GetDirectory(std::string_view path) const;
|
||||||
|
|
||||||
|
std::string m_root_user_path;
|
||||||
|
std::string m_root_system_path;
|
||||||
|
std::vector<std::string> m_dirs;
|
||||||
|
|
||||||
|
struct IncludeResultData
|
||||||
|
{
|
||||||
|
std::unique_ptr<IncludeResult> result;
|
||||||
|
std::string file_data;
|
||||||
|
};
|
||||||
|
std::map<std::string, IncludeResultData, std::less<>> m_include_results;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace VideoCommon
|
||||||
@ -159,14 +159,14 @@ const TBuiltInResource* GetCompilerResourceLimits()
|
|||||||
std::optional<SPIRV::CodeVector>
|
std::optional<SPIRV::CodeVector>
|
||||||
CompileShaderToSPV(EShLanguage stage, APIType api_type,
|
CompileShaderToSPV(EShLanguage stage, APIType api_type,
|
||||||
glslang::EShTargetLanguageVersion language_version, const char* stage_filename,
|
glslang::EShTargetLanguageVersion language_version, const char* stage_filename,
|
||||||
std::string_view source)
|
std::string_view source, glslang::TShader::Includer* shader_includer)
|
||||||
{
|
{
|
||||||
if (!InitializeGlslang())
|
if (!InitializeGlslang())
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
|
||||||
std::unique_ptr<glslang::TShader> shader = std::make_unique<glslang::TShader>(stage);
|
std::unique_ptr<glslang::TShader> shader = std::make_unique<glslang::TShader>(stage);
|
||||||
std::unique_ptr<glslang::TProgram> program;
|
std::unique_ptr<glslang::TProgram> program;
|
||||||
glslang::TShader::ForbidIncluder includer;
|
glslang::TShader::ForbidIncluder forbid_includer;
|
||||||
EProfile profile = ECoreProfile;
|
EProfile profile = ECoreProfile;
|
||||||
EShMessages messages = static_cast<EShMessages>(EShMsgDefault | EShMsgSpvRules);
|
EShMessages messages = static_cast<EShMessages>(EShMsgDefault | EShMsgSpvRules);
|
||||||
if (api_type == APIType::Vulkan || api_type == APIType::Metal)
|
if (api_type == APIType::Vulkan || api_type == APIType::Metal)
|
||||||
@ -209,7 +209,7 @@ CompileShaderToSPV(EShLanguage stage, APIType api_type,
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (!shader->parse(GetCompilerResourceLimits(), default_version, profile, false, true, messages,
|
if (!shader->parse(GetCompilerResourceLimits(), default_version, profile, false, true, messages,
|
||||||
includer))
|
shader_includer ? *shader_includer : forbid_includer))
|
||||||
{
|
{
|
||||||
DumpBadShader("Failed to parse shader");
|
DumpBadShader("Failed to parse shader");
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
@ -277,26 +277,34 @@ CompileShaderToSPV(EShLanguage stage, APIType api_type,
|
|||||||
namespace SPIRV
|
namespace SPIRV
|
||||||
{
|
{
|
||||||
std::optional<CodeVector> CompileVertexShader(std::string_view source_code, APIType api_type,
|
std::optional<CodeVector> CompileVertexShader(std::string_view source_code, APIType api_type,
|
||||||
glslang::EShTargetLanguageVersion language_version)
|
glslang::EShTargetLanguageVersion language_version,
|
||||||
|
glslang::TShader::Includer* shader_includer)
|
||||||
{
|
{
|
||||||
return CompileShaderToSPV(EShLangVertex, api_type, language_version, "vs", source_code);
|
return CompileShaderToSPV(EShLangVertex, api_type, language_version, "vs", source_code,
|
||||||
|
shader_includer);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<CodeVector> CompileGeometryShader(std::string_view source_code, APIType api_type,
|
std::optional<CodeVector> CompileGeometryShader(std::string_view source_code, APIType api_type,
|
||||||
glslang::EShTargetLanguageVersion language_version)
|
glslang::EShTargetLanguageVersion language_version,
|
||||||
|
glslang::TShader::Includer* shader_includer)
|
||||||
{
|
{
|
||||||
return CompileShaderToSPV(EShLangGeometry, api_type, language_version, "gs", source_code);
|
return CompileShaderToSPV(EShLangGeometry, api_type, language_version, "gs", source_code,
|
||||||
|
shader_includer);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<CodeVector> CompileFragmentShader(std::string_view source_code, APIType api_type,
|
std::optional<CodeVector> CompileFragmentShader(std::string_view source_code, APIType api_type,
|
||||||
glslang::EShTargetLanguageVersion language_version)
|
glslang::EShTargetLanguageVersion language_version,
|
||||||
|
glslang::TShader::Includer* shader_includer)
|
||||||
{
|
{
|
||||||
return CompileShaderToSPV(EShLangFragment, api_type, language_version, "ps", source_code);
|
return CompileShaderToSPV(EShLangFragment, api_type, language_version, "ps", source_code,
|
||||||
|
shader_includer);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<CodeVector> CompileComputeShader(std::string_view source_code, APIType api_type,
|
std::optional<CodeVector> CompileComputeShader(std::string_view source_code, APIType api_type,
|
||||||
glslang::EShTargetLanguageVersion language_version)
|
glslang::EShTargetLanguageVersion language_version,
|
||||||
|
glslang::TShader::Includer* shader_includer)
|
||||||
{
|
{
|
||||||
return CompileShaderToSPV(EShLangCompute, api_type, language_version, "cs", source_code);
|
return CompileShaderToSPV(EShLangCompute, api_type, language_version, "cs", source_code,
|
||||||
|
shader_includer);
|
||||||
}
|
}
|
||||||
} // namespace SPIRV
|
} // namespace SPIRV
|
||||||
|
|||||||
@ -21,17 +21,21 @@ using CodeVector = std::vector<CodeType>;
|
|||||||
|
|
||||||
// Compile a vertex shader to SPIR-V.
|
// Compile a vertex shader to SPIR-V.
|
||||||
std::optional<CodeVector> CompileVertexShader(std::string_view source_code, APIType api_type,
|
std::optional<CodeVector> CompileVertexShader(std::string_view source_code, APIType api_type,
|
||||||
glslang::EShTargetLanguageVersion language_version);
|
glslang::EShTargetLanguageVersion language_version,
|
||||||
|
glslang::TShader::Includer* shader_includer);
|
||||||
|
|
||||||
// Compile a geometry shader to SPIR-V.
|
// Compile a geometry shader to SPIR-V.
|
||||||
std::optional<CodeVector> CompileGeometryShader(std::string_view source_code, APIType api_type,
|
std::optional<CodeVector> CompileGeometryShader(std::string_view source_code, APIType api_type,
|
||||||
glslang::EShTargetLanguageVersion language_version);
|
glslang::EShTargetLanguageVersion language_version,
|
||||||
|
glslang::TShader::Includer* shader_includer);
|
||||||
|
|
||||||
// Compile a fragment shader to SPIR-V.
|
// Compile a fragment shader to SPIR-V.
|
||||||
std::optional<CodeVector> CompileFragmentShader(std::string_view source_code, APIType api_type,
|
std::optional<CodeVector> CompileFragmentShader(std::string_view source_code, APIType api_type,
|
||||||
glslang::EShTargetLanguageVersion language_version);
|
glslang::EShTargetLanguageVersion language_version,
|
||||||
|
glslang::TShader::Includer* shader_includer);
|
||||||
|
|
||||||
// Compile a compute shader to SPIR-V.
|
// Compile a compute shader to SPIR-V.
|
||||||
std::optional<CodeVector> CompileComputeShader(std::string_view source_code, APIType api_type,
|
std::optional<CodeVector> CompileComputeShader(std::string_view source_code, APIType api_type,
|
||||||
glslang::EShTargetLanguageVersion language_version);
|
glslang::EShTargetLanguageVersion language_version,
|
||||||
|
glslang::TShader::Includer* shader_includer);
|
||||||
} // namespace SPIRV
|
} // namespace SPIRV
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user