@@ -17,7 +17,6 @@
#include "ShaderLang.h"
#include "disassemble.h"

#include "Common/CommonFuncs.h"
#include "Common/FileUtil.h"
#include "Common/Logging/Log.h"
#include "Common/MsgHandler.h"
@@ -35,11 +34,6 @@ bool InitializeGlslang();
// Resource limits used when compiling shaders
static const TBuiltInResource* GetCompilerResourceLimits();

// Compile a shader to SPIR-V via glslang
static bool CompileShaderToSPV(SPIRVCodeVector* out_code, EShLanguage stage,
const char* stage_filename, const char* source_code,
size_t source_code_length, const char* header, size_t header_length);

// 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
@@ -113,12 +107,11 @@ static const char SUBGROUP_HELPER_HEADER[] = R"(
#define SUBGROUP_MAX(value) value = subgroupMax(value)
)";

bool CompileShaderToSPV(SPIRVCodeVector* out_code, EShLanguage stage, const char* stage_filename,
const char* source_code, size_t source_code_length, const char* header,
size_t header_length)
std::optional<SPIRVCodeVector> CompileShaderToSPV(EShLanguage stage, const char* stage_filename,
std::string_view source, std::string_view header)
{
if (!InitializeGlslang())
return false;
return std::nullopt;

std::unique_ptr<glslang::TShader> shader = std::make_unique<glslang::TShader>(stage);
std::unique_ptr<glslang::TProgram> program;
@@ -129,16 +122,16 @@ bool CompileShaderToSPV(SPIRVCodeVector* out_code, EShLanguage stage, const char
int default_version = 450;

std::string full_source_code;
const char* pass_source_code = source_code;
int pass_source_code_length = static_cast<int>(source_code_length);
if (header_length > 0)
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 = ArraySize(SUBGROUP_HELPER_HEADER) - 1;
full_source_code.reserve(header_length + subgroup_helper_header_length + source_code_length);
full_source_code.append(header, header_length);
constexpr size_t subgroup_helper_header_length = std::size(SUBGROUP_HELPER_HEADER) - 1;
full_source_code.reserve(header.size() + subgroup_helper_header_length + source.size());
full_source_code.append(header);
if (g_vulkan_context->SupportsShaderSubgroupOperations())
full_source_code.append(SUBGROUP_HELPER_HEADER, subgroup_helper_header_length);
full_source_code.append(source_code, source_code_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());
}
@@ -178,7 +171,7 @@ bool CompileShaderToSPV(SPIRVCodeVector* out_code, EShLanguage stage, const char
includer))
{
DumpBadShader("Failed to parse shader");
return false;
return std::nullopt;
}

// Even though there's only a single shader, we still need to link it to generate SPV
@@ -187,18 +180,19 @@ bool CompileShaderToSPV(SPIRVCodeVector* out_code, EShLanguage stage, const char
if (!program->link(messages))
{
DumpBadShader("Failed to link program");
return false;
return std::nullopt;
}

glslang::TIntermediate* intermediate = program->getIntermediate(stage);
if (!intermediate)
{
DumpBadShader("Failed to generate SPIR-V");
return false;
return std::nullopt;
}

SPIRVCodeVector out_code;
spv::SpvBuildLogger logger;
glslang::GlslangToSpv(*intermediate, *out_code, &logger);
glslang::GlslangToSpv(*intermediate, out_code, &logger);

// Write out messages
// Temporary: skip if it contains "Warning, version 450 is not yet complete; most version-specific
@@ -236,11 +230,11 @@ bool CompileShaderToSPV(SPIRVCodeVector* out_code, EShLanguage stage, const char
stream << "SPIR-V conversion messages: " << std::endl;
stream << spv_messages;
stream << "SPIR-V:" << std::endl;
spv::Disassemble(stream, *out_code);
spv::Disassemble(stream, out_code);
}
}

return true;
return out_code;
}

bool InitializeGlslang()
@@ -362,32 +356,24 @@ const TBuiltInResource* GetCompilerResourceLimits()
return &limits;
}

bool CompileVertexShader(SPIRVCodeVector* out_code, const char* source_code,
size_t source_code_length)
std::optional<SPIRVCodeVector> CompileVertexShader(std::string_view source_code)
{
return CompileShaderToSPV(out_code, EShLangVertex, "vs", source_code, source_code_length,
SHADER_HEADER, sizeof(SHADER_HEADER) - 1);
return CompileShaderToSPV(EShLangVertex, "vs", source_code, SHADER_HEADER);
}

bool CompileGeometryShader(SPIRVCodeVector* out_code, const char* source_code,
size_t source_code_length)
std::optional<SPIRVCodeVector> CompileGeometryShader(std::string_view source_code)
{
return CompileShaderToSPV(out_code, EShLangGeometry, "gs", source_code, source_code_length,
SHADER_HEADER, sizeof(SHADER_HEADER) - 1);
return CompileShaderToSPV(EShLangGeometry, "gs", source_code, SHADER_HEADER);
}

bool CompileFragmentShader(SPIRVCodeVector* out_code, const char* source_code,
size_t source_code_length)
std::optional<SPIRVCodeVector> CompileFragmentShader(std::string_view source_code)
{
return CompileShaderToSPV(out_code, EShLangFragment, "ps", source_code, source_code_length,
SHADER_HEADER, sizeof(SHADER_HEADER) - 1);
return CompileShaderToSPV(EShLangFragment, "ps", source_code, SHADER_HEADER);
}

bool CompileComputeShader(SPIRVCodeVector* out_code, const char* source_code,
size_t source_code_length)
std::optional<SPIRVCodeVector> CompileComputeShader(std::string_view source_code)
{
return CompileShaderToSPV(out_code, EShLangCompute, "cs", source_code, source_code_length,
COMPUTE_SHADER_HEADER, sizeof(COMPUTE_SHADER_HEADER) - 1);
return CompileShaderToSPV(EShLangCompute, "cs", source_code, COMPUTE_SHADER_HEADER);
}

} // namespace ShaderCompiler
@@ -5,6 +5,8 @@
#pragma once

#include <cstddef>
#include <optional>
#include <string_view>
#include <vector>

#include "Common/CommonTypes.h"
@@ -18,20 +20,16 @@ using SPIRVCodeType = u32;
using SPIRVCodeVector = std::vector<SPIRVCodeType>;

// Compile a vertex shader to SPIR-V.
bool CompileVertexShader(SPIRVCodeVector* out_code, const char* source_code,
size_t source_code_length);
std::optional<SPIRVCodeVector> CompileVertexShader(std::string_view source_code);

// Compile a geometry shader to SPIR-V.
bool CompileGeometryShader(SPIRVCodeVector* out_code, const char* source_code,
size_t source_code_length);
std::optional<SPIRVCodeVector> CompileGeometryShader(std::string_view source_code);

// Compile a fragment shader to SPIR-V.
bool CompileFragmentShader(SPIRVCodeVector* out_code, const char* source_code,
size_t source_code_length);
std::optional<SPIRVCodeVector> CompileFragmentShader(std::string_view source_code);

// Compile a compute shader to SPIR-V.
bool CompileComputeShader(SPIRVCodeVector* out_code, const char* source_code,
size_t source_code_length);
std::optional<SPIRVCodeVector> CompileComputeShader(std::string_view source_code);

} // namespace ShaderCompiler
} // namespace Vulkan
@@ -86,34 +86,31 @@ static std::unique_ptr<VKShader> CreateShaderObject(ShaderStage stage,
return std::make_unique<VKShader>(std::move(spv), pipeline);
}

std::unique_ptr<VKShader> VKShader::CreateFromSource(ShaderStage stage, const char* source,
size_t length)
std::unique_ptr<VKShader> VKShader::CreateFromSource(ShaderStage stage, std::string_view source)
{
ShaderCompiler::SPIRVCodeVector spv;
bool result;
std::optional<ShaderCompiler::SPIRVCodeVector> spv;
switch (stage)
{
case ShaderStage::Vertex:
result = ShaderCompiler::CompileVertexShader(&spv, source, length);
spv = ShaderCompiler::CompileVertexShader(source);
break;
case ShaderStage::Geometry:
result = ShaderCompiler::CompileGeometryShader(&spv, source, length);
spv = ShaderCompiler::CompileGeometryShader(source);
break;
case ShaderStage::Pixel:
result = ShaderCompiler::CompileFragmentShader(&spv, source, length);
spv = ShaderCompiler::CompileFragmentShader(source);
break;
case ShaderStage::Compute:
result = ShaderCompiler::CompileComputeShader(&spv, source, length);
spv = ShaderCompiler::CompileComputeShader(source);
break;
default:
result = false;
break;
}

if (!result)
if (!spv)
return nullptr;

return CreateShaderObject(stage, std::move(spv));
return CreateShaderObject(stage, std::move(*spv));
}

std::unique_ptr<VKShader> VKShader::CreateFromBinary(ShaderStage stage, const void* data,
@@ -6,6 +6,7 @@

#include <cstddef>
#include <memory>
#include <string_view>
#include <vector>

#include "Common/CommonTypes.h"
@@ -25,8 +26,7 @@ class VKShader final : public AbstractShader
VkPipeline GetComputePipeline() const { return m_compute_pipeline; }
BinaryData GetBinary() const override;

static std::unique_ptr<VKShader> CreateFromSource(ShaderStage stage, const char* source,
size_t length);
static std::unique_ptr<VKShader> CreateFromSource(ShaderStage stage, std::string_view source);
static std::unique_ptr<VKShader> CreateFromBinary(ShaderStage stage, const void* data,
size_t length);

@@ -148,12 +148,6 @@ void Renderer::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer,
m_current_framebuffer = framebuffer;
}

std::unique_ptr<AbstractShader> Renderer::CreateShaderFromSource(ShaderStage stage,
const std::string& source)
{
return CreateShaderFromSource(stage, source.c_str(), source.size());
}

bool Renderer::EFBHasAlphaChannel() const
{
return m_prev_efb_format == PEControl::RGBA6_Z24;
@@ -980,10 +974,10 @@ bool Renderer::InitializeImGui()

const std::string vertex_shader_source = GenerateImGuiVertexShader();
const std::string pixel_shader_source = GenerateImGuiPixelShader();
std::unique_ptr<AbstractShader> vertex_shader = CreateShaderFromSource(
ShaderStage::Vertex, vertex_shader_source.c_str(), vertex_shader_source.size());
std::unique_ptr<AbstractShader> pixel_shader = CreateShaderFromSource(
ShaderStage::Pixel, pixel_shader_source.c_str(), pixel_shader_source.size());
std::unique_ptr<AbstractShader> vertex_shader =
CreateShaderFromSource(ShaderStage::Vertex, vertex_shader_source);
std::unique_ptr<AbstractShader> pixel_shader =
CreateShaderFromSource(ShaderStage::Pixel, pixel_shader_source);
if (!vertex_shader || !pixel_shader)
{
PanicAlert("Failed to compile imgui shaders");
@@ -18,6 +18,7 @@
#include <memory>
#include <mutex>
#include <string>
#include <string_view>
#include <thread>
#include <tuple>
#include <vector>
@@ -123,17 +124,15 @@ class Renderer
virtual void PresentBackbuffer() {}

// Shader modules/objects.
virtual std::unique_ptr<AbstractShader>
CreateShaderFromSource(ShaderStage stage, const char* source, size_t length) = 0;
virtual std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage,
std::string_view source) = 0;
virtual std::unique_ptr<AbstractShader>
CreateShaderFromBinary(ShaderStage stage, const void* data, size_t length) = 0;
virtual std::unique_ptr<NativeVertexFormat>
CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) = 0;
virtual std::unique_ptr<AbstractPipeline> CreatePipeline(const AbstractPipelineConfig& config,
const void* cache_data = nullptr,
size_t cache_data_length = 0) = 0;
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage,
const std::string& source);

AbstractFramebuffer* GetCurrentFramebuffer() const { return m_current_framebuffer; }

@@ -392,32 +392,32 @@ void ShaderCache::CompileMissingPipelines()

std::unique_ptr<AbstractShader> ShaderCache::CompileVertexShader(const VertexShaderUid& uid) const
{
ShaderCode source_code = GenerateVertexShaderCode(m_api_type, m_host_config, uid.GetUidData());
return g_renderer->CreateShaderFromSource(ShaderStage::Vertex, source_code.GetBuffer().c_str(),
source_code.GetBuffer().size());
const ShaderCode source_code =
GenerateVertexShaderCode(m_api_type, m_host_config, uid.GetUidData());
return g_renderer->CreateShaderFromSource(ShaderStage::Vertex, source_code.GetBuffer());
}

std::unique_ptr<AbstractShader>
ShaderCache::CompileVertexUberShader(const UberShader::VertexShaderUid& uid) const
{
ShaderCode source_code = UberShader::GenVertexShader(m_api_type, m_host_config, uid.GetUidData());
return g_renderer->CreateShaderFromSource(ShaderStage::Vertex, source_code.GetBuffer().c_str(),
source_code.GetBuffer().size());
const ShaderCode source_code =
UberShader::GenVertexShader(m_api_type, m_host_config, uid.GetUidData());
return g_renderer->CreateShaderFromSource(ShaderStage::Vertex, source_code.GetBuffer());
}

std::unique_ptr<AbstractShader> ShaderCache::CompilePixelShader(const PixelShaderUid& uid) const
{
ShaderCode source_code = GeneratePixelShaderCode(m_api_type, m_host_config, uid.GetUidData());
return g_renderer->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer().c_str(),
source_code.GetBuffer().size());
const ShaderCode source_code =
GeneratePixelShaderCode(m_api_type, m_host_config, uid.GetUidData());
return g_renderer->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer());
}

std::unique_ptr<AbstractShader>
ShaderCache::CompilePixelUberShader(const UberShader::PixelShaderUid& uid) const
{
ShaderCode source_code = UberShader::GenPixelShader(m_api_type, m_host_config, uid.GetUidData());
return g_renderer->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer().c_str(),
source_code.GetBuffer().size());
const ShaderCode source_code =
UberShader::GenPixelShader(m_api_type, m_host_config, uid.GetUidData());
return g_renderer->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer());
}

const AbstractShader* ShaderCache::InsertVertexShader(const VertexShaderUid& uid,
@@ -510,9 +510,10 @@ const AbstractShader* ShaderCache::InsertPixelUberShader(const UberShader::Pixel

const AbstractShader* ShaderCache::CreateGeometryShader(const GeometryShaderUid& uid)
{
ShaderCode source_code = GenerateGeometryShaderCode(m_api_type, m_host_config, uid.GetUidData());
std::unique_ptr<AbstractShader> shader = g_renderer->CreateShaderFromSource(
ShaderStage::Geometry, source_code.GetBuffer().c_str(), source_code.GetBuffer().size());
const ShaderCode source_code =
GenerateGeometryShaderCode(m_api_type, m_host_config, uid.GetUidData());
std::unique_ptr<AbstractShader> shader =
g_renderer->CreateShaderFromSource(ShaderStage::Geometry, source_code.GetBuffer());

auto& entry = m_gs_cache.shader_map[uid];
entry.pending = false;
@@ -1150,9 +1151,9 @@ const AbstractPipeline* ShaderCache::GetEFBCopyToRAMPipeline(const EFBCopyParams
if (iter != m_efb_copy_to_ram_pipelines.end())
return iter->second.get();

auto shader_code = TextureConversionShaderTiled::GenerateEncodingShader(uid, m_api_type);
auto shader =
g_renderer->CreateShaderFromSource(ShaderStage::Pixel, shader_code, std::strlen(shader_code));
const char* const shader_code =
TextureConversionShaderTiled::GenerateEncodingShader(uid, m_api_type);
const auto shader = g_renderer->CreateShaderFromSource(ShaderStage::Pixel, shader_code);
if (!shader)
{
m_efb_copy_to_ram_pipelines.emplace(uid, nullptr);