GPUDevice: Swap out glslang for shaderc
This commit is contained in:
@ -1,16 +1,19 @@
|
||||
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||
|
||||
#include "vulkan_pipeline.h"
|
||||
#include "spirv_compiler.h"
|
||||
#include "vulkan_builders.h"
|
||||
#include "vulkan_device.h"
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/log.h"
|
||||
|
||||
#include "shaderc/shaderc.hpp"
|
||||
|
||||
Log_SetChannel(VulkanDevice);
|
||||
|
||||
static std::unique_ptr<shaderc::Compiler> s_shaderc_compiler;
|
||||
|
||||
VulkanShader::VulkanShader(GPUShaderStage stage, VkShaderModule mod) : GPUShader(stage), m_module(mod)
|
||||
{
|
||||
}
|
||||
@ -45,29 +48,54 @@ std::unique_ptr<GPUShader> VulkanDevice::CreateShaderFromSource(GPUShaderStage s
|
||||
const char* entry_point,
|
||||
DynamicHeapArray<u8>* out_binary)
|
||||
{
|
||||
if (std::strcmp(entry_point, "main") != 0)
|
||||
static constexpr const std::array<shaderc_shader_kind, static_cast<size_t>(GPUShaderStage::MaxCount)> stage_kinds = {{
|
||||
shaderc_glsl_vertex_shader,
|
||||
shaderc_glsl_fragment_shader,
|
||||
shaderc_glsl_geometry_shader,
|
||||
shaderc_glsl_compute_shader,
|
||||
}};
|
||||
|
||||
// TODO: NOT thread safe, yet.
|
||||
if (!s_shaderc_compiler)
|
||||
s_shaderc_compiler = std::make_unique<shaderc::Compiler>();
|
||||
|
||||
shaderc::CompileOptions options;
|
||||
options.SetSourceLanguage(shaderc_source_language_glsl);
|
||||
options.SetTargetEnvironment(shaderc_target_env_vulkan, 0);
|
||||
|
||||
if (m_debug_device)
|
||||
{
|
||||
Log_ErrorPrintf("Entry point must be 'main', but got '%s' instead.", entry_point);
|
||||
return {};
|
||||
options.SetOptimizationLevel(shaderc_optimization_level_zero);
|
||||
options.SetGenerateDebugInfo();
|
||||
}
|
||||
else
|
||||
{
|
||||
options.SetOptimizationLevel(shaderc_optimization_level_performance);
|
||||
}
|
||||
|
||||
const u32 options = (m_debug_device ? SPIRVCompiler::DebugInfo : 0) | SPIRVCompiler::VulkanRules;
|
||||
|
||||
std::optional<SPIRVCompiler::SPIRVCodeVector> spirv = SPIRVCompiler::CompileShader(stage, source, options);
|
||||
if (!spirv.has_value())
|
||||
const shaderc::SpvCompilationResult result = s_shaderc_compiler->CompileGlslToSpv(
|
||||
source.data(), source.length(), stage_kinds[static_cast<size_t>(stage)], "source", entry_point, options);
|
||||
if (result.GetCompilationStatus() != shaderc_compilation_status_success)
|
||||
{
|
||||
Log_ErrorPrintf("Failed to compile shader to SPIR-V.");
|
||||
const std::string errors = result.GetErrorMessage();
|
||||
DumpBadShader(source, errors);
|
||||
Log_ErrorFmt("Failed to compile shader to SPIR-V:\n{}", errors);
|
||||
return {};
|
||||
}
|
||||
else if (result.GetNumWarnings() > 0)
|
||||
{
|
||||
Log_WarningFmt("Shader compiled with warnings:\n{}", result.GetErrorMessage());
|
||||
}
|
||||
|
||||
const size_t spirv_size = spirv->size() * sizeof(SPIRVCompiler::SPIRVCodeType);
|
||||
const size_t spirv_size = std::distance(result.cbegin(), result.cend()) * sizeof(*result.cbegin());
|
||||
DebugAssert(spirv_size > 0);
|
||||
if (out_binary)
|
||||
{
|
||||
out_binary->resize(spirv_size);
|
||||
std::memcpy(out_binary->data(), spirv->data(), spirv_size);
|
||||
std::copy(result.cbegin(), result.cend(), reinterpret_cast<uint32_t*>(out_binary->data()));
|
||||
}
|
||||
|
||||
return CreateShaderFromBinary(stage, std::span<const u8>(reinterpret_cast<const u8*>(spirv->data()), spirv_size));
|
||||
return CreateShaderFromBinary(stage, std::span<const u8>(reinterpret_cast<const u8*>(result.cbegin()), spirv_size));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Reference in New Issue
Block a user