summaryrefslogtreecommitdiff
path: root/Source/Core/VideoBackends/Vulkan/ShaderCompiler.cpp
diff options
context:
space:
mode:
authorJMC47 <JMC4789@gmail.com>2022-07-08 15:29:58 -0400
committerGitHub <noreply@github.com>2022-07-08 15:29:58 -0400
commit828afc67356c2299c6056d618eb6b7afe4c843b9 (patch)
treecb7809cf9aad689968ec209e8d886b5457ca68dc /Source/Core/VideoBackends/Vulkan/ShaderCompiler.cpp
parent7cc89f5642cab3b91aef1c8255af857a1607ddf6 (diff)
parenta8b52663479effc0f404f7c0f8b52bc0ee37b742 (diff)
Merge pull request #10673 from iwubcode/spirv-backends
D3D: Generate HLSL from SPIRV*
Diffstat (limited to 'Source/Core/VideoBackends/Vulkan/ShaderCompiler.cpp')
-rw-r--r--Source/Core/VideoBackends/Vulkan/ShaderCompiler.cpp198
1 files changed, 16 insertions, 182 deletions
diff --git a/Source/Core/VideoBackends/Vulkan/ShaderCompiler.cpp b/Source/Core/VideoBackends/Vulkan/ShaderCompiler.cpp
index c9adcc1bf7..fde89ca394 100644
--- a/Source/Core/VideoBackends/Vulkan/ShaderCompiler.cpp
+++ b/Source/Core/VideoBackends/Vulkan/ShaderCompiler.cpp
@@ -4,36 +4,13 @@
#include "VideoBackends/Vulkan/ShaderCompiler.h"
#include <cstddef>
-#include <cstdlib>
-#include <cstring>
-#include <fstream>
-#include <memory>
#include <string>
-// glslang includes
-#include "GlslangToSpv.h"
-#include "ResourceLimits.h"
-#include "ShaderLang.h"
-#include "disassemble.h"
-
-#include "Common/FileUtil.h"
-#include "Common/Logging/Log.h"
-#include "Common/MsgHandler.h"
-#include "Common/StringUtil.h"
-#include "Common/Version.h"
-
#include "VideoBackends/Vulkan/VulkanContext.h"
-#include "VideoCommon/VideoBackendBase.h"
-#include "VideoCommon/VideoConfig.h"
+#include "VideoCommon/Spirv.h"
namespace Vulkan::ShaderCompiler
{
-// Registers itself for cleanup via atexit
-bool InitializeGlslang();
-
-// Resource limits used when compiling shaders
-static const TBuiltInResource* GetCompilerResourceLimits();
-
// Regarding the UBO bind points, we subtract one from the binding index because
// the OpenGL backend requires UBO #0 for non-block uniforms (at least on NV).
// This allows us to share the same shaders but use bind point #0 in the Vulkan
@@ -111,25 +88,9 @@ static const char SUBGROUP_HELPER_HEADER[] = R"(
#define SUBGROUP_MAX(value) value = subgroupMax(value)
)";
-static std::optional<SPIRVCodeVector> CompileShaderToSPV(EShLanguage stage,
- const char* stage_filename,
- std::string_view source,
- std::string_view header)
+static std::string GetShaderCode(std::string_view source, std::string_view header)
{
- if (!InitializeGlslang())
- return std::nullopt;
-
- std::unique_ptr<glslang::TShader> shader = std::make_unique<glslang::TShader>(stage);
- std::unique_ptr<glslang::TProgram> program;
- glslang::TShader::ForbidIncluder includer;
- EProfile profile = ECoreProfile;
- EShMessages messages =
- static_cast<EShMessages>(EShMsgDefault | EShMsgSpvRules | EShMsgVulkanRules);
- int default_version = 450;
-
std::string full_source_code;
- const char* pass_source_code = source.data();
- int pass_source_code_length = static_cast<int>(source.size());
if (!header.empty())
{
constexpr size_t subgroup_helper_header_length = std::size(SUBGROUP_HELPER_HEADER) - 1;
@@ -138,168 +99,41 @@ static std::optional<SPIRVCodeVector> CompileShaderToSPV(EShLanguage stage,
if (g_vulkan_context->SupportsShaderSubgroupOperations())
full_source_code.append(SUBGROUP_HELPER_HEADER, subgroup_helper_header_length);
full_source_code.append(source);
- pass_source_code = full_source_code.c_str();
- pass_source_code_length = static_cast<int>(full_source_code.length());
- }
-
- // Sub-group operations require Vulkan 1.1 and SPIR-V 1.3.
- if (g_vulkan_context->SupportsShaderSubgroupOperations())
- shader->setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_3);
-
- shader->setStringsWithLengths(&pass_source_code, &pass_source_code_length, 1);
-
- auto DumpBadShader = [&](const char* msg) {
- static int counter = 0;
- std::string filename = VideoBackendBase::BadShaderFilename(stage_filename, counter++);
- std::ofstream stream;
- File::OpenFStream(stream, filename, std::ios_base::out);
- if (stream.good())
- {
- stream << full_source_code << std::endl;
- stream << msg << std::endl;
- stream << "Shader Info Log:" << std::endl;
- stream << shader->getInfoLog() << std::endl;
- stream << shader->getInfoDebugLog() << std::endl;
- if (program)
- {
- stream << "Program Info Log:" << std::endl;
- stream << program->getInfoLog() << std::endl;
- stream << program->getInfoDebugLog() << std::endl;
- }
- }
-
- stream << "\n";
- stream << "Dolphin Version: " + Common::GetScmRevStr() + "\n";
- stream << "Video Backend: " + g_video_backend->GetDisplayName();
- stream.close();
-
- PanicAlertFmt("{} (written to {})\nDebug info:\n{}", msg, filename, shader->getInfoLog());
- };
-
- if (!shader->parse(GetCompilerResourceLimits(), default_version, profile, false, true, messages,
- includer))
- {
- DumpBadShader("Failed to parse shader");
- return std::nullopt;
- }
-
- // Even though there's only a single shader, we still need to link it to generate SPV
- program = std::make_unique<glslang::TProgram>();
- program->addShader(shader.get());
- if (!program->link(messages))
- {
- DumpBadShader("Failed to link program");
- return std::nullopt;
- }
-
- glslang::TIntermediate* intermediate = program->getIntermediate(stage);
- if (!intermediate)
- {
- DumpBadShader("Failed to generate SPIR-V");
- return std::nullopt;
- }
-
- SPIRVCodeVector out_code;
- spv::SpvBuildLogger logger;
- glslang::SpvOptions options;
-
- if (g_ActiveConfig.bEnableValidationLayer)
- {
- // Attach the source code to the SPIR-V for tools like RenderDoc.
- intermediate->addSourceText(pass_source_code, pass_source_code_length);
-
- options.generateDebugInfo = true;
- options.disableOptimizer = true;
- options.optimizeSize = false;
- options.disassemble = false;
- options.validate = true;
}
- glslang::GlslangToSpv(*intermediate, out_code, &logger, &options);
-
- // Write out messages
- // Temporary: skip if it contains "Warning, version 450 is not yet complete; most version-specific
- // features are present, but some are missing."
- if (strlen(shader->getInfoLog()) > 108)
- WARN_LOG_FMT(VIDEO, "Shader info log: {}", shader->getInfoLog());
- if (strlen(shader->getInfoDebugLog()) > 0)
- WARN_LOG_FMT(VIDEO, "Shader debug info log: {}", shader->getInfoDebugLog());
- if (strlen(program->getInfoLog()) > 25)
- WARN_LOG_FMT(VIDEO, "Program info log: {}", program->getInfoLog());
- if (strlen(program->getInfoDebugLog()) > 0)
- WARN_LOG_FMT(VIDEO, "Program debug info log: {}", program->getInfoDebugLog());
- const std::string spv_messages = logger.getAllMessages();
- if (!spv_messages.empty())
- WARN_LOG_FMT(VIDEO, "SPIR-V conversion messages: {}", spv_messages);
-
- // Dump source code of shaders out to file if enabled.
- if (g_ActiveConfig.iLog & CONF_SAVESHADERS)
- {
- static int counter = 0;
- std::string filename = StringFromFormat("%s%s_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(),
- stage_filename, counter++);
-
- std::ofstream stream;
- File::OpenFStream(stream, filename, std::ios_base::out);
- if (stream.good())
- {
- stream << full_source_code << std::endl;
- stream << "Shader Info Log:" << std::endl;
- stream << shader->getInfoLog() << std::endl;
- stream << shader->getInfoDebugLog() << std::endl;
- stream << "Program Info Log:" << std::endl;
- stream << program->getInfoLog() << std::endl;
- stream << program->getInfoDebugLog() << std::endl;
- stream << "SPIR-V conversion messages: " << std::endl;
- stream << spv_messages;
- stream << "SPIR-V:" << std::endl;
- spv::Disassemble(stream, out_code);
- }
- }
-
- return out_code;
+ return full_source_code;
}
-bool InitializeGlslang()
+static glslang::EShTargetLanguageVersion GetLanguageVersion()
{
- static bool glslang_initialized = false;
- if (glslang_initialized)
- return true;
-
- if (!glslang::InitializeProcess())
- {
- PanicAlertFmt("Failed to initialize glslang shader compiler");
- return false;
- }
-
- std::atexit([]() { glslang::FinalizeProcess(); });
-
- glslang_initialized = true;
- return true;
-}
+ // Sub-group operations require Vulkan 1.1 and SPIR-V 1.3.
+ if (g_vulkan_context->SupportsShaderSubgroupOperations())
+ return glslang::EShTargetSpv_1_3;
-const TBuiltInResource* GetCompilerResourceLimits()
-{
- return &glslang::DefaultTBuiltInResource;
+ return glslang::EShTargetSpv_1_0;
}
std::optional<SPIRVCodeVector> CompileVertexShader(std::string_view source_code)
{
- return CompileShaderToSPV(EShLangVertex, "vs", source_code, SHADER_HEADER);
+ return SPIRV::CompileVertexShader(GetShaderCode(source_code, SHADER_HEADER), APIType::Vulkan,
+ GetLanguageVersion());
}
std::optional<SPIRVCodeVector> CompileGeometryShader(std::string_view source_code)
{
- return CompileShaderToSPV(EShLangGeometry, "gs", source_code, SHADER_HEADER);
+ return SPIRV::CompileGeometryShader(GetShaderCode(source_code, SHADER_HEADER), APIType::Vulkan,
+ GetLanguageVersion());
}
std::optional<SPIRVCodeVector> CompileFragmentShader(std::string_view source_code)
{
- return CompileShaderToSPV(EShLangFragment, "ps", source_code, SHADER_HEADER);
+ return SPIRV::CompileFragmentShader(GetShaderCode(source_code, SHADER_HEADER), APIType::Vulkan,
+ GetLanguageVersion());
}
std::optional<SPIRVCodeVector> CompileComputeShader(std::string_view source_code)
{
- return CompileShaderToSPV(EShLangCompute, "cs", source_code, COMPUTE_SHADER_HEADER);
+ return SPIRV::CompileComputeShader(GetShaderCode(source_code, SHADER_HEADER), APIType::Vulkan,
+ GetLanguageVersion());
}
} // namespace Vulkan::ShaderCompiler