VideoBackends / VideoCommon: refactor Vulkan to use new SPIRV functionality
This commit is contained in:
parent
c2d3b7e7f5
commit
dda1479ecf
|
@ -114,7 +114,7 @@ std::optional<SPIRV::CodeVector> GetSpirv(ShaderStage stage, std::string_view so
|
|||
case ShaderStage::Vertex:
|
||||
{
|
||||
const auto full_source = fmt::format("{}{}", SHADER_HEADER, source);
|
||||
return SPIRV::CompileVertexShader(full_source);
|
||||
return SPIRV::CompileVertexShader(full_source, APIType::D3D, glslang::EShTargetSpv_1_0);
|
||||
}
|
||||
|
||||
case ShaderStage::Geometry:
|
||||
|
@ -126,13 +126,13 @@ std::optional<SPIRV::CodeVector> GetSpirv(ShaderStage stage, std::string_view so
|
|||
case ShaderStage::Pixel:
|
||||
{
|
||||
const auto full_source = fmt::format("{}{}", SHADER_HEADER, source);
|
||||
return SPIRV::CompileFragmentShader(full_source);
|
||||
return SPIRV::CompileFragmentShader(full_source, APIType::D3D, glslang::EShTargetSpv_1_0);
|
||||
}
|
||||
|
||||
case ShaderStage::Compute:
|
||||
{
|
||||
const auto full_source = fmt::format("{}{}", COMPUTE_SHADER_HEADER, source);
|
||||
return SPIRV::CompileComputeShader(full_source);
|
||||
return SPIRV::CompileComputeShader(full_source, APIType::D3D, glslang::EShTargetSpv_1_0);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -54,15 +54,6 @@ PRIVATE
|
|||
${CMAKE_SOURCE_DIR}/Externals/Vulkan/Include
|
||||
)
|
||||
|
||||
# Silence warnings on glslang by flagging it as a system include
|
||||
target_include_directories(videovulkan
|
||||
SYSTEM PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/Externals/glslang/StandAlone
|
||||
${CMAKE_SOURCE_DIR}/Externals/glslang/glslang/Public
|
||||
${CMAKE_SOURCE_DIR}/Externals/glslang/SPIRV
|
||||
${CMAKE_SOURCE_DIR}/Externals/glslang
|
||||
)
|
||||
|
||||
if(MSVC)
|
||||
# Add precompiled header
|
||||
target_link_libraries(videovulkan PRIVATE use_pch)
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
return full_source_code;
|
||||
}
|
||||
|
||||
static glslang::EShTargetLanguageVersion GetLanguageVersion()
|
||||
{
|
||||
// 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);
|
||||
return 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;
|
||||
}
|
||||
|
||||
bool InitializeGlslang()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
// glslang includes
|
||||
#include "GlslangToSpv.h"
|
||||
#include "ResourceLimits.h"
|
||||
#include "ShaderLang.h"
|
||||
#include "disassemble.h"
|
||||
|
||||
#include "Common/FileUtil.h"
|
||||
|
@ -44,9 +43,9 @@ const TBuiltInResource* GetCompilerResourceLimits()
|
|||
}
|
||||
|
||||
std::optional<SPIRV::CodeVector>
|
||||
CompileShaderToSPV(EShLanguage stage,
|
||||
std::optional<glslang::EShTargetLanguageVersion> language_version,
|
||||
const char* stage_filename, std::string_view source)
|
||||
CompileShaderToSPV(EShLanguage stage, APIType api_type,
|
||||
glslang::EShTargetLanguageVersion language_version, const char* stage_filename,
|
||||
std::string_view source)
|
||||
{
|
||||
if (!InitializeGlslang())
|
||||
return std::nullopt;
|
||||
|
@ -56,13 +55,14 @@ CompileShaderToSPV(EShLanguage stage,
|
|||
glslang::TShader::ForbidIncluder includer;
|
||||
EProfile profile = ECoreProfile;
|
||||
EShMessages messages = static_cast<EShMessages>(EShMsgDefault | EShMsgSpvRules);
|
||||
if (api_type == APIType::Vulkan)
|
||||
messages = static_cast<EShMessages>(messages | EShMsgVulkanRules);
|
||||
int default_version = 450;
|
||||
|
||||
const char* pass_source_code = source.data();
|
||||
int pass_source_code_length = static_cast<int>(source.size());
|
||||
|
||||
if (language_version)
|
||||
shader->setEnvTarget(glslang::EShTargetSpv, *language_version);
|
||||
shader->setEnvTarget(glslang::EShTargetSpv, language_version);
|
||||
|
||||
shader->setStringsWithLengths(&pass_source_code, &pass_source_code_length, 1);
|
||||
|
||||
|
@ -181,23 +181,27 @@ CompileShaderToSPV(EShLanguage stage,
|
|||
|
||||
namespace SPIRV
|
||||
{
|
||||
std::optional<CodeVector> CompileVertexShader(std::string_view source_code)
|
||||
std::optional<CodeVector> CompileVertexShader(std::string_view source_code, APIType api_type,
|
||||
glslang::EShTargetLanguageVersion language_version)
|
||||
{
|
||||
return CompileShaderToSPV(EShLangVertex, std::nullopt, "vs", source_code);
|
||||
return CompileShaderToSPV(EShLangVertex, api_type, language_version, "vs", source_code);
|
||||
}
|
||||
|
||||
std::optional<CodeVector> CompileGeometryShader(std::string_view source_code)
|
||||
std::optional<CodeVector> CompileGeometryShader(std::string_view source_code, APIType api_type,
|
||||
glslang::EShTargetLanguageVersion language_version)
|
||||
{
|
||||
return CompileShaderToSPV(EShLangGeometry, std::nullopt, "gs", source_code);
|
||||
return CompileShaderToSPV(EShLangGeometry, api_type, language_version, "gs", source_code);
|
||||
}
|
||||
|
||||
std::optional<CodeVector> CompileFragmentShader(std::string_view source_code)
|
||||
std::optional<CodeVector> CompileFragmentShader(std::string_view source_code, APIType api_type,
|
||||
glslang::EShTargetLanguageVersion language_version)
|
||||
{
|
||||
return CompileShaderToSPV(EShLangFragment, std::nullopt, "ps", source_code);
|
||||
return CompileShaderToSPV(EShLangFragment, api_type, language_version, "ps", source_code);
|
||||
}
|
||||
|
||||
std::optional<CodeVector> CompileComputeShader(std::string_view source_code)
|
||||
std::optional<CodeVector> CompileComputeShader(std::string_view source_code, APIType api_type,
|
||||
glslang::EShTargetLanguageVersion language_version)
|
||||
{
|
||||
return CompileShaderToSPV(EShLangCompute, std::nullopt, "cs", source_code);
|
||||
return CompileShaderToSPV(EShLangCompute, api_type, language_version, "cs", source_code);
|
||||
}
|
||||
} // namespace SPIRV
|
||||
|
|
|
@ -8,7 +8,10 @@
|
|||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include "ShaderLang.h"
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "VideoCommon/VideoCommon.h"
|
||||
|
||||
namespace SPIRV
|
||||
{
|
||||
|
@ -17,14 +20,18 @@ using CodeType = u32;
|
|||
using CodeVector = std::vector<CodeType>;
|
||||
|
||||
// Compile a vertex shader to SPIR-V.
|
||||
std::optional<CodeVector> CompileVertexShader(std::string_view source_code);
|
||||
std::optional<CodeVector> CompileVertexShader(std::string_view source_code, APIType api_type,
|
||||
glslang::EShTargetLanguageVersion language_version);
|
||||
|
||||
// Compile a geometry shader to SPIR-V.
|
||||
std::optional<CodeVector> CompileGeometryShader(std::string_view source_code);
|
||||
std::optional<CodeVector> CompileGeometryShader(std::string_view source_code, APIType api_type,
|
||||
glslang::EShTargetLanguageVersion language_version);
|
||||
|
||||
// Compile a fragment shader to SPIR-V.
|
||||
std::optional<CodeVector> CompileFragmentShader(std::string_view source_code);
|
||||
std::optional<CodeVector> CompileFragmentShader(std::string_view source_code, APIType api_type,
|
||||
glslang::EShTargetLanguageVersion language_version);
|
||||
|
||||
// Compile a compute shader to SPIR-V.
|
||||
std::optional<CodeVector> CompileComputeShader(std::string_view source_code);
|
||||
std::optional<CodeVector> CompileComputeShader(std::string_view source_code, APIType api_type,
|
||||
glslang::EShTargetLanguageVersion language_version);
|
||||
} // namespace SPIRV
|
||||
|
|
Loading…
Reference in New Issue