Merge pull request #10673 from iwubcode/spirv-backends

D3D: Generate HLSL from SPIRV*
This commit is contained in:
JMC47
2022-07-08 15:29:58 -04:00
committed by GitHub
35 changed files with 1213 additions and 1323 deletions

View File

@ -27,7 +27,8 @@ bool D3DBoundingBox::Initialize()
// Create 2 buffers here.
// First for unordered access on default pool.
auto desc = CD3D11_BUFFER_DESC(NUM_BBOX_VALUES * sizeof(BBoxType), D3D11_BIND_UNORDERED_ACCESS,
D3D11_USAGE_DEFAULT, 0, 0, sizeof(BBoxType));
D3D11_USAGE_DEFAULT, 0, D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS,
sizeof(BBoxType));
const BBoxType initial_values[NUM_BBOX_VALUES] = {0, 0, 0, 0};
D3D11_SUBRESOURCE_DATA data;
data.pSysMem = initial_values;
@ -44,6 +45,7 @@ bool D3DBoundingBox::Initialize()
desc.Usage = D3D11_USAGE_STAGING;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
desc.BindFlags = 0;
desc.MiscFlags = 0;
hr = D3D::device->CreateBuffer(&desc, nullptr, &m_staging_buffer);
ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create BoundingBox Staging Buffer: {}",
DX11HRWrap(hr));
@ -53,10 +55,10 @@ bool D3DBoundingBox::Initialize()
// UAV is required to allow concurrent access.
D3D11_UNORDERED_ACCESS_VIEW_DESC UAVdesc = {};
UAVdesc.Format = DXGI_FORMAT_R32_SINT;
UAVdesc.Format = DXGI_FORMAT_R32_TYPELESS;
UAVdesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
UAVdesc.Buffer.FirstElement = 0;
UAVdesc.Buffer.Flags = 0;
UAVdesc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_RAW;
UAVdesc.Buffer.NumElements = NUM_BBOX_VALUES;
hr = D3D::device->CreateUnorderedAccessView(m_buffer.Get(), &UAVdesc, &m_uav);
ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create BoundingBox UAV: {}", DX11HRWrap(hr));

View File

@ -106,7 +106,8 @@ D3DVertexFormat::D3DVertexFormat(const PortableVertexDeclaration& vtx_decl)
const AttributeFormat* format = &vtx_decl.position;
if (format->enable)
{
m_elems[m_num_elems].SemanticName = "POSITION";
m_elems[m_num_elems].SemanticName = "TEXCOORD";
m_elems[m_num_elems].SemanticIndex = SHADER_POSITION_ATTRIB;
m_elems[m_num_elems].AlignedByteOffset = format->offset;
m_elems[m_num_elems].Format = VarToD3D(format->type, format->components, format->integer);
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
@ -115,12 +116,11 @@ D3DVertexFormat::D3DVertexFormat(const PortableVertexDeclaration& vtx_decl)
for (int i = 0; i < 3; i++)
{
static constexpr std::array<const char*, 3> NAMES = {"NORMAL", "TANGENT", "BINORMAL"};
format = &vtx_decl.normals[i];
if (format->enable)
{
m_elems[m_num_elems].SemanticName = NAMES[i];
m_elems[m_num_elems].SemanticIndex = 0;
m_elems[m_num_elems].SemanticName = "TEXCOORD";
m_elems[m_num_elems].SemanticIndex = SHADER_NORMAL_ATTRIB + i;
m_elems[m_num_elems].AlignedByteOffset = format->offset;
m_elems[m_num_elems].Format = VarToD3D(format->type, format->components, format->integer);
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
@ -133,8 +133,8 @@ D3DVertexFormat::D3DVertexFormat(const PortableVertexDeclaration& vtx_decl)
format = &vtx_decl.colors[i];
if (format->enable)
{
m_elems[m_num_elems].SemanticName = "COLOR";
m_elems[m_num_elems].SemanticIndex = i;
m_elems[m_num_elems].SemanticName = "TEXCOORD";
m_elems[m_num_elems].SemanticIndex = SHADER_COLOR0_ATTRIB + i;
m_elems[m_num_elems].AlignedByteOffset = format->offset;
m_elems[m_num_elems].Format = VarToD3D(format->type, format->components, format->integer);
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
@ -148,7 +148,7 @@ D3DVertexFormat::D3DVertexFormat(const PortableVertexDeclaration& vtx_decl)
if (format->enable)
{
m_elems[m_num_elems].SemanticName = "TEXCOORD";
m_elems[m_num_elems].SemanticIndex = i;
m_elems[m_num_elems].SemanticIndex = SHADER_TEXTURE0_ATTRIB + i;
m_elems[m_num_elems].AlignedByteOffset = format->offset;
m_elems[m_num_elems].Format = VarToD3D(format->type, format->components, format->integer);
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
@ -159,7 +159,8 @@ D3DVertexFormat::D3DVertexFormat(const PortableVertexDeclaration& vtx_decl)
format = &vtx_decl.posmtx;
if (format->enable)
{
m_elems[m_num_elems].SemanticName = "BLENDINDICES";
m_elems[m_num_elems].SemanticName = "TEXCOORD";
m_elems[m_num_elems].SemanticIndex = SHADER_POSMTX_ATTRIB;
m_elems[m_num_elems].AlignedByteOffset = format->offset;
m_elems[m_num_elems].Format = VarToD3D(format->type, format->components, format->integer);
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;

View File

@ -76,6 +76,7 @@ void StateManager::Apply()
if (m_current.vertexConstants != m_pending.vertexConstants)
{
D3D::context->VSSetConstantBuffers(0, 1, &m_pending.vertexConstants);
D3D::context->VSSetConstantBuffers(1, 1, &m_pending.vertexConstants);
m_current.vertexConstants = m_pending.vertexConstants;
}

View File

@ -578,6 +578,8 @@ bool Renderer::ApplyState()
{
cmdlist->SetGraphicsRootConstantBufferView(ROOT_PARAMETER_VS_CBV,
m_state.constant_buffers[1]);
cmdlist->SetGraphicsRootConstantBufferView(ROOT_PARAMETER_VS_CBV2,
m_state.constant_buffers[1]);
if (g_ActiveConfig.bEnablePixelLighting)
{

View File

@ -323,7 +323,7 @@ bool DXContext::CreateRootSignatures()
bool DXContext::CreateGXRootSignature()
{
// GX:
// - 3 constant buffers (bindings 0-2), 0/1 visible in PS, 1 visible in VS, 2 visible in GS.
// - 3 constant buffers (bindings 0-2), 0/1 visible in PS, 2 visible in VS, 1 visible in GS.
// - 8 textures (visible in PS).
// - 8 samplers (visible in PS).
// - 1 UAV (visible in PS).
@ -341,6 +341,8 @@ bool DXContext::CreateGXRootSignature()
param_count++;
SetRootParamCBV(&params[param_count], 0, D3D12_SHADER_VISIBILITY_VERTEX);
param_count++;
SetRootParamCBV(&params[param_count], 1, D3D12_SHADER_VISIBILITY_VERTEX);
param_count++;
SetRootParamCBV(&params[param_count], 0, D3D12_SHADER_VISIBILITY_GEOMETRY);
param_count++;

View File

@ -25,6 +25,7 @@ enum ROOT_PARAMETER
ROOT_PARAMETER_PS_SRV,
ROOT_PARAMETER_PS_SAMPLERS,
ROOT_PARAMETER_VS_CBV,
ROOT_PARAMETER_VS_CBV2,
ROOT_PARAMETER_GS_CBV,
ROOT_PARAMETER_PS_UAV_OR_CBV2,
ROOT_PARAMETER_PS_CBV2, // ROOT_PARAMETER_PS_UAV_OR_CBV2 if bbox is not enabled

View File

@ -83,7 +83,7 @@ void DXVertexFormat::MapAttributes()
if (m_decl.position.enable)
{
AddAttribute(
"POSITION", 0, 0,
"TEXCOORD", SHADER_POSITION_ATTRIB, 0,
VarToDXGIFormat(m_decl.position.type, m_decl.position.components, m_decl.position.integer),
m_decl.position.offset);
}
@ -92,8 +92,7 @@ void DXVertexFormat::MapAttributes()
{
if (m_decl.normals[i].enable)
{
static constexpr std::array<const char*, 3> NAMES = {"NORMAL", "TANGENT", "BINORMAL"};
AddAttribute(NAMES[i], 0, 0,
AddAttribute("TEXCOORD", SHADER_NORMAL_ATTRIB + i, 0,
VarToDXGIFormat(m_decl.normals[i].type, m_decl.normals[i].components,
m_decl.normals[i].integer),
m_decl.normals[i].offset);
@ -104,7 +103,7 @@ void DXVertexFormat::MapAttributes()
{
if (m_decl.colors[i].enable)
{
AddAttribute("COLOR", i, 0,
AddAttribute("TEXCOORD", SHADER_COLOR0_ATTRIB + i, 0,
VarToDXGIFormat(m_decl.colors[i].type, m_decl.colors[i].components,
m_decl.colors[i].integer),
m_decl.colors[i].offset);
@ -115,7 +114,7 @@ void DXVertexFormat::MapAttributes()
{
if (m_decl.texcoords[i].enable)
{
AddAttribute("TEXCOORD", i, 0,
AddAttribute("TEXCOORD", SHADER_TEXTURE0_ATTRIB + i, 0,
VarToDXGIFormat(m_decl.texcoords[i].type, m_decl.texcoords[i].components,
m_decl.texcoords[i].integer),
m_decl.texcoords[i].offset);
@ -125,7 +124,7 @@ void DXVertexFormat::MapAttributes()
if (m_decl.posmtx.enable)
{
AddAttribute(
"BLENDINDICES", 0, 0,
"TEXCOORD", SHADER_POSMTX_ATTRIB, 0,
VarToDXGIFormat(m_decl.posmtx.type, m_decl.posmtx.components, m_decl.posmtx.integer),
m_decl.posmtx.offset);
}

View File

@ -11,6 +11,7 @@ target_link_libraries(videod3dcommon
PUBLIC
common
videocommon
spirv_cross
)
if(MSVC)

View File

@ -4,7 +4,13 @@
#include "VideoBackends/D3DCommon/Shader.h"
#include <fstream>
#include <optional>
#include <string_view>
#include <fmt/format.h>
#include <wrl/client.h>
#include "disassemble.h"
#include "spirv_hlsl.hpp"
#include "Common/Assert.h"
#include "Common/FileUtil.h"
@ -14,9 +20,141 @@
#include "Common/StringUtil.h"
#include "Common/Version.h"
#include "VideoCommon/Spirv.h"
#include "VideoCommon/VideoBackendBase.h"
#include "VideoCommon/VideoConfig.h"
namespace
{
// 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 D3D
// backends. None of the specific shaders use UBOs, instead they use push
// constants, so when/if the GL backend moves to uniform blocks completely this
// subtraction can be removed.
constexpr std::string_view SHADER_HEADER = R"(
// Target GLSL 4.5.
#version 450 core
#define ATTRIBUTE_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 UBO_BINDING(packing, x) layout(packing, binding = (x - 1))
#define SAMPLER_BINDING(x) layout(binding = x)
#define TEXEL_BUFFER_BINDING(x) layout(binding = x)
#define SSBO_BINDING(x) layout(binding = (x + 2))
#define VARYING_LOCATION(x) layout(location = x)
#define FORCE_EARLY_Z layout(early_fragment_tests) in
// hlsl to glsl function translation
#define float2 vec2
#define float3 vec3
#define float4 vec4
#define uint2 uvec2
#define uint3 uvec3
#define uint4 uvec4
#define int2 ivec2
#define int3 ivec3
#define int4 ivec4
#define frac fract
#define lerp mix
#define API_D3D 1
)";
constexpr std::string_view COMPUTE_SHADER_HEADER = R"(
// Target GLSL 4.5.
#version 450 core
// All resources are packed into one descriptor set for compute.
#define UBO_BINDING(packing, x) layout(packing, binding = (x - 1))
#define SAMPLER_BINDING(x) layout(binding = x)
#define TEXEL_BUFFER_BINDING(x) layout(binding = x)
#define IMAGE_BINDING(format, x) layout(format, binding = x)
// hlsl to glsl function translation
#define float2 vec2
#define float3 vec3
#define float4 vec4
#define uint2 uvec2
#define uint3 uvec3
#define uint4 uvec4
#define int2 ivec2
#define int3 ivec3
#define int4 ivec4
#define frac fract
#define lerp mix
#define API_D3D 1
)";
std::optional<std::string> GetHLSLFromSPIRV(SPIRV::CodeVector spv, D3D_FEATURE_LEVEL feature_level)
{
spirv_cross::CompilerHLSL::Options options;
switch (feature_level)
{
case D3D_FEATURE_LEVEL_10_0:
options.shader_model = 40;
break;
case D3D_FEATURE_LEVEL_10_1:
options.shader_model = 41;
break;
default:
options.shader_model = 50;
break;
};
spirv_cross::CompilerHLSL compiler(std::move(spv));
compiler.set_hlsl_options(options);
return compiler.compile();
}
std::optional<SPIRV::CodeVector> GetSpirv(ShaderStage stage, std::string_view source)
{
switch (stage)
{
case ShaderStage::Vertex:
{
const auto full_source = fmt::format("{}{}", SHADER_HEADER, source);
return SPIRV::CompileVertexShader(full_source, APIType::D3D, glslang::EShTargetSpv_1_0);
}
case ShaderStage::Geometry:
{
// Spirv cross does not currently support hlsl geometry shaders
return std::nullopt;
}
case ShaderStage::Pixel:
{
const auto full_source = fmt::format("{}{}", SHADER_HEADER, 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, APIType::D3D, glslang::EShTargetSpv_1_0);
}
};
return std::nullopt;
}
std::optional<std::string> GetHLSL(D3D_FEATURE_LEVEL feature_level, ShaderStage stage,
std::string_view source)
{
if (stage == ShaderStage::Geometry)
{
return std::string{source};
}
else if (const auto spirv = GetSpirv(stage, source))
{
return GetHLSLFromSPIRV(std::move(*spirv), feature_level);
}
return std::nullopt;
}
} // namespace
namespace D3DCommon
{
Shader::Shader(ShaderStage stage, BinaryData bytecode)
@ -95,6 +233,10 @@ static const char* GetCompileTarget(D3D_FEATURE_LEVEL feature_level, ShaderStage
std::optional<Shader::BinaryData> Shader::CompileShader(D3D_FEATURE_LEVEL feature_level,
ShaderStage stage, std::string_view source)
{
const auto hlsl = GetHLSL(feature_level, stage, source);
if (!hlsl)
return std::nullopt;
static constexpr D3D_SHADER_MACRO macros[] = {{"API_D3D", "1"}, {nullptr, nullptr}};
const UINT flags = g_ActiveConfig.bEnableValidationLayer ?
(D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION) :
@ -103,7 +245,7 @@ std::optional<Shader::BinaryData> Shader::CompileShader(D3D_FEATURE_LEVEL featur
Microsoft::WRL::ComPtr<ID3DBlob> code;
Microsoft::WRL::ComPtr<ID3DBlob> errors;
HRESULT hr = d3d_compile(source.data(), source.size(), nullptr, macros, nullptr, "main", target,
HRESULT hr = d3d_compile(hlsl->data(), hlsl->size(), nullptr, macros, nullptr, "main", target,
flags, 0, &code, &errors);
if (FAILED(hr))
{
@ -111,12 +253,20 @@ std::optional<Shader::BinaryData> Shader::CompileShader(D3D_FEATURE_LEVEL featur
std::string filename = VideoBackendBase::BadShaderFilename(target, num_failures++);
std::ofstream file;
File::OpenFStream(file, filename, std::ios_base::out);
file.write(source.data(), source.size());
file.write(hlsl->data(), hlsl->size());
file << "\n";
file.write(static_cast<const char*>(errors->GetBufferPointer()), errors->GetBufferSize());
file << "\n";
file << "Dolphin Version: " + Common::GetScmRevStr() + "\n";
file << "Video Backend: " + g_video_backend->GetDisplayName();
if (const auto spirv = GetSpirv(stage, source))
{
file << "\nOriginal Source: \n";
file << source << std::endl;
file << "SPIRV: \n";
spv::Disassemble(file, *spirv);
}
file.close();
PanicAlertFmt("Failed to compile {}: {}\nDebug info ({}):\n{}", filename, Common::HRWrap(hr),

View File

@ -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)

View File

@ -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