Merge pull request #6111 from stenzek/enable-vk-nv-glsl
Vulkan: Use VK_NV_glsl extension where available, and skip glslang
This commit is contained in:
commit
bb0794715c
|
@ -3,9 +3,11 @@
|
|||
// Refer to the license.txt file included.
|
||||
|
||||
#include "VideoBackends/Vulkan/ShaderCompiler.h"
|
||||
#include "VideoBackends/Vulkan/VulkanContext.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
@ -37,6 +39,11 @@ 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);
|
||||
|
||||
// Copy GLSL source code to a SPIRVCodeVector, for use with VK_NV_glsl_shader.
|
||||
static void CopyGLSLToSPVVector(SPIRVCodeVector* out_code, 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
|
||||
|
@ -219,6 +226,42 @@ bool CompileShaderToSPV(SPIRVCodeVector* out_code, EShLanguage stage, const char
|
|||
return true;
|
||||
}
|
||||
|
||||
void CopyGLSLToSPVVector(SPIRVCodeVector* out_code, const char* stage_filename,
|
||||
const char* source_code, size_t source_code_length, const char* header,
|
||||
size_t header_length)
|
||||
{
|
||||
std::string full_source_code;
|
||||
if (header_length > 0)
|
||||
{
|
||||
full_source_code.reserve(header_length + source_code_length);
|
||||
full_source_code.append(header, header_length);
|
||||
full_source_code.append(source_code, source_code_length);
|
||||
}
|
||||
else
|
||||
{
|
||||
full_source_code.append(source_code, source_code_length);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
size_t padding = full_source_code.size() % 4;
|
||||
if (padding != 0)
|
||||
full_source_code.append(4 - padding, '\n');
|
||||
|
||||
out_code->resize(full_source_code.size() / 4);
|
||||
std::memcpy(out_code->data(), full_source_code.c_str(), full_source_code.size());
|
||||
}
|
||||
|
||||
bool InitializeGlslang()
|
||||
{
|
||||
static bool glslang_initialized = false;
|
||||
|
@ -338,29 +381,57 @@ const TBuiltInResource* GetCompilerResourceLimits()
|
|||
}
|
||||
|
||||
bool CompileVertexShader(SPIRVCodeVector* out_code, const char* source_code,
|
||||
size_t source_code_length, bool prepend_header)
|
||||
size_t source_code_length)
|
||||
{
|
||||
if (g_vulkan_context->SupportsNVGLSLExtension())
|
||||
{
|
||||
CopyGLSLToSPVVector(out_code, "vs", source_code, source_code_length, SHADER_HEADER,
|
||||
sizeof(SHADER_HEADER) - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
return CompileShaderToSPV(out_code, EShLangVertex, "vs", source_code, source_code_length,
|
||||
SHADER_HEADER, sizeof(SHADER_HEADER) - 1);
|
||||
}
|
||||
|
||||
bool CompileGeometryShader(SPIRVCodeVector* out_code, const char* source_code,
|
||||
size_t source_code_length, bool prepend_header)
|
||||
size_t source_code_length)
|
||||
{
|
||||
if (g_vulkan_context->SupportsNVGLSLExtension())
|
||||
{
|
||||
CopyGLSLToSPVVector(out_code, "gs", source_code, source_code_length, SHADER_HEADER,
|
||||
sizeof(SHADER_HEADER) - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
return CompileShaderToSPV(out_code, EShLangGeometry, "gs", source_code, source_code_length,
|
||||
SHADER_HEADER, sizeof(SHADER_HEADER) - 1);
|
||||
}
|
||||
|
||||
bool CompileFragmentShader(SPIRVCodeVector* out_code, const char* source_code,
|
||||
size_t source_code_length, bool prepend_header)
|
||||
size_t source_code_length)
|
||||
{
|
||||
if (g_vulkan_context->SupportsNVGLSLExtension())
|
||||
{
|
||||
CopyGLSLToSPVVector(out_code, "ps", source_code, source_code_length, SHADER_HEADER,
|
||||
sizeof(SHADER_HEADER) - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
return CompileShaderToSPV(out_code, EShLangFragment, "ps", source_code, source_code_length,
|
||||
SHADER_HEADER, sizeof(SHADER_HEADER) - 1);
|
||||
}
|
||||
|
||||
bool CompileComputeShader(SPIRVCodeVector* out_code, const char* source_code,
|
||||
size_t source_code_length, bool prepend_header)
|
||||
size_t source_code_length)
|
||||
{
|
||||
if (g_vulkan_context->SupportsNVGLSLExtension())
|
||||
{
|
||||
CopyGLSLToSPVVector(out_code, "cs", source_code, source_code_length, COMPUTE_SHADER_HEADER,
|
||||
sizeof(COMPUTE_SHADER_HEADER) - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
return CompileShaderToSPV(out_code, EShLangCompute, "cs", source_code, source_code_length,
|
||||
COMPUTE_SHADER_HEADER, sizeof(COMPUTE_SHADER_HEADER) - 1);
|
||||
}
|
||||
|
|
|
@ -19,19 +19,19 @@ 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, bool prepend_header = true);
|
||||
size_t source_code_length);
|
||||
|
||||
// Compile a geometry shader to SPIR-V.
|
||||
bool CompileGeometryShader(SPIRVCodeVector* out_code, const char* source_code,
|
||||
size_t source_code_length, bool prepend_header = true);
|
||||
size_t source_code_length);
|
||||
|
||||
// Compile a fragment shader to SPIR-V.
|
||||
bool CompileFragmentShader(SPIRVCodeVector* out_code, const char* source_code,
|
||||
size_t source_code_length, bool prepend_header = true);
|
||||
size_t source_code_length);
|
||||
|
||||
// Compile a compute shader to SPIR-V.
|
||||
bool CompileComputeShader(SPIRVCodeVector* out_code, const char* source_code,
|
||||
size_t source_code_length, bool prepend_header = true);
|
||||
size_t source_code_length);
|
||||
|
||||
} // namespace ShaderCompiler
|
||||
} // namespace Vulkan
|
||||
|
|
|
@ -407,7 +407,7 @@ bool TextureConverter::SupportsTextureDecoding(TextureFormat format, TLUTFormat
|
|||
std::string shader_source =
|
||||
TextureConversionShader::GenerateDecodingShader(format, palette_format, APIType::Vulkan);
|
||||
|
||||
pipeline.compute_shader = Util::CompileAndCreateComputeShader(shader_source, true);
|
||||
pipeline.compute_shader = Util::CompileAndCreateComputeShader(shader_source);
|
||||
if (pipeline.compute_shader == VK_NULL_HANDLE)
|
||||
{
|
||||
m_decoding_pipelines.emplace(key, pipeline);
|
||||
|
|
|
@ -249,50 +249,38 @@ VkShaderModule CreateShaderModule(const u32* spv, size_t spv_word_count)
|
|||
return module;
|
||||
}
|
||||
|
||||
VkShaderModule CompileAndCreateVertexShader(const std::string& source_code, bool prepend_header)
|
||||
VkShaderModule CompileAndCreateVertexShader(const std::string& source_code)
|
||||
{
|
||||
ShaderCompiler::SPIRVCodeVector code;
|
||||
if (!ShaderCompiler::CompileVertexShader(&code, source_code.c_str(), source_code.length(),
|
||||
prepend_header))
|
||||
{
|
||||
if (!ShaderCompiler::CompileVertexShader(&code, source_code.c_str(), source_code.length()))
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
return CreateShaderModule(code.data(), code.size());
|
||||
}
|
||||
|
||||
VkShaderModule CompileAndCreateGeometryShader(const std::string& source_code, bool prepend_header)
|
||||
VkShaderModule CompileAndCreateGeometryShader(const std::string& source_code)
|
||||
{
|
||||
ShaderCompiler::SPIRVCodeVector code;
|
||||
if (!ShaderCompiler::CompileGeometryShader(&code, source_code.c_str(), source_code.length(),
|
||||
prepend_header))
|
||||
{
|
||||
if (!ShaderCompiler::CompileGeometryShader(&code, source_code.c_str(), source_code.length()))
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
return CreateShaderModule(code.data(), code.size());
|
||||
}
|
||||
|
||||
VkShaderModule CompileAndCreateFragmentShader(const std::string& source_code, bool prepend_header)
|
||||
VkShaderModule CompileAndCreateFragmentShader(const std::string& source_code)
|
||||
{
|
||||
ShaderCompiler::SPIRVCodeVector code;
|
||||
if (!ShaderCompiler::CompileFragmentShader(&code, source_code.c_str(), source_code.length(),
|
||||
prepend_header))
|
||||
{
|
||||
if (!ShaderCompiler::CompileFragmentShader(&code, source_code.c_str(), source_code.length()))
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
return CreateShaderModule(code.data(), code.size());
|
||||
}
|
||||
|
||||
VkShaderModule CompileAndCreateComputeShader(const std::string& source_code, bool prepend_header)
|
||||
VkShaderModule CompileAndCreateComputeShader(const std::string& source_code)
|
||||
{
|
||||
ShaderCompiler::SPIRVCodeVector code;
|
||||
if (!ShaderCompiler::CompileComputeShader(&code, source_code.c_str(), source_code.length(),
|
||||
prepend_header))
|
||||
{
|
||||
if (!ShaderCompiler::CompileComputeShader(&code, source_code.c_str(), source_code.length()))
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
return CreateShaderModule(code.data(), code.size());
|
||||
}
|
||||
|
|
|
@ -57,20 +57,16 @@ void ExecuteCurrentCommandsAndRestoreState(bool execute_off_thread,
|
|||
VkShaderModule CreateShaderModule(const u32* spv, size_t spv_word_count);
|
||||
|
||||
// Compile a vertex shader and create a shader module, discarding the intermediate SPIR-V.
|
||||
VkShaderModule CompileAndCreateVertexShader(const std::string& source_code,
|
||||
bool prepend_header = true);
|
||||
VkShaderModule CompileAndCreateVertexShader(const std::string& source_code);
|
||||
|
||||
// Compile a geometry shader and create a shader module, discarding the intermediate SPIR-V.
|
||||
VkShaderModule CompileAndCreateGeometryShader(const std::string& source_code,
|
||||
bool prepend_header = true);
|
||||
VkShaderModule CompileAndCreateGeometryShader(const std::string& source_code);
|
||||
|
||||
// Compile a fragment shader and create a shader module, discarding the intermediate SPIR-V.
|
||||
VkShaderModule CompileAndCreateFragmentShader(const std::string& source_code,
|
||||
bool prepend_header = true);
|
||||
VkShaderModule CompileAndCreateFragmentShader(const std::string& source_code);
|
||||
|
||||
// Compile a compute shader and create a shader module, discarding the intermediate SPIR-V.
|
||||
VkShaderModule CompileAndCreateComputeShader(const std::string& source_code,
|
||||
bool prepend_header = true);
|
||||
VkShaderModule CompileAndCreateComputeShader(const std::string& source_code);
|
||||
}
|
||||
|
||||
// Utility shader vertex format
|
||||
|
|
|
@ -153,7 +153,7 @@ bool VulkanContext::SelectInstanceExtensions(ExtensionList* extension_list, bool
|
|||
for (const auto& extension_properties : available_extension_list)
|
||||
INFO_LOG(VIDEO, "Available extension: %s", extension_properties.extensionName);
|
||||
|
||||
auto CheckForExtension = [&](const char* name, bool required) -> bool {
|
||||
auto SupportsExtension = [&](const char* name, bool required) {
|
||||
if (std::find_if(available_extension_list.begin(), available_extension_list.end(),
|
||||
[&](const VkExtensionProperties& properties) {
|
||||
return !strcmp(name, properties.extensionName);
|
||||
|
@ -165,36 +165,31 @@ bool VulkanContext::SelectInstanceExtensions(ExtensionList* extension_list, bool
|
|||
}
|
||||
|
||||
if (required)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Vulkan: Missing required extension %s.", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
// Common extensions
|
||||
if (enable_surface && !CheckForExtension(VK_KHR_SURFACE_EXTENSION_NAME, true))
|
||||
{
|
||||
if (enable_surface && !SupportsExtension(VK_KHR_SURFACE_EXTENSION_NAME, true))
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(VK_USE_PLATFORM_WIN32_KHR)
|
||||
if (enable_surface && !CheckForExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME, true))
|
||||
if (enable_surface && !SupportsExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME, true))
|
||||
return false;
|
||||
#elif defined(VK_USE_PLATFORM_XLIB_KHR)
|
||||
if (enable_surface && !CheckForExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME, true))
|
||||
if (enable_surface && !SupportsExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME, true))
|
||||
return false;
|
||||
#elif defined(VK_USE_PLATFORM_XCB_KHR)
|
||||
if (enable_surface && !CheckForExtension(VK_KHR_XCB_SURFACE_EXTENSION_NAME, true))
|
||||
if (enable_surface && !SupportsExtension(VK_KHR_XCB_SURFACE_EXTENSION_NAME, true))
|
||||
return false;
|
||||
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
|
||||
if (enable_surface && !CheckForExtension(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, true))
|
||||
if (enable_surface && !SupportsExtension(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, true))
|
||||
return false;
|
||||
#endif
|
||||
|
||||
// VK_EXT_debug_report
|
||||
if (enable_debug_report && !CheckForExtension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, true))
|
||||
if (enable_debug_report && !SupportsExtension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, false))
|
||||
WARN_LOG(VIDEO, "Vulkan: Debug report requested, but extension is not available.");
|
||||
|
||||
return true;
|
||||
|
@ -403,7 +398,7 @@ bool VulkanContext::SelectDeviceExtensions(ExtensionList* extension_list, bool e
|
|||
for (const auto& extension_properties : available_extension_list)
|
||||
INFO_LOG(VIDEO, "Available extension: %s", extension_properties.extensionName);
|
||||
|
||||
auto CheckForExtension = [&](const char* name, bool required) -> bool {
|
||||
auto SupportsExtension = [&](const char* name, bool required) {
|
||||
if (std::find_if(available_extension_list.begin(), available_extension_list.end(),
|
||||
[&](const VkExtensionProperties& properties) {
|
||||
return !strcmp(name, properties.extensionName);
|
||||
|
@ -415,17 +410,15 @@ bool VulkanContext::SelectDeviceExtensions(ExtensionList* extension_list, bool e
|
|||
}
|
||||
|
||||
if (required)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Vulkan: Missing required extension %s.", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
if (enable_surface && !CheckForExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME, true))
|
||||
if (enable_surface && !SupportsExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME, true))
|
||||
return false;
|
||||
|
||||
m_supports_nv_glsl_extension = SupportsExtension(VK_NV_GLSL_SHADER_EXTENSION_NAME, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -83,6 +83,7 @@ public:
|
|||
{
|
||||
return m_device_features.occlusionQueryPrecise == VK_TRUE;
|
||||
}
|
||||
bool SupportsNVGLSLExtension() const { return m_supports_nv_glsl_extension; }
|
||||
// Helpers for getting constants
|
||||
VkDeviceSize GetUniformBufferAlignment() const
|
||||
{
|
||||
|
@ -129,6 +130,8 @@ private:
|
|||
VkPhysicalDeviceFeatures m_device_features = {};
|
||||
VkPhysicalDeviceProperties m_device_properties = {};
|
||||
VkPhysicalDeviceMemoryProperties m_device_memory_properties = {};
|
||||
|
||||
bool m_supports_nv_glsl_extension = false;
|
||||
};
|
||||
|
||||
extern std::unique_ptr<VulkanContext> g_vulkan_context;
|
||||
|
|
Loading…
Reference in New Issue