Vulkan: Use VK_NV_glsl extension where available, and skip glslang

This commit is contained in:
Stenzek 2017-10-10 23:09:12 +10:00
parent 90ca2e8042
commit 79188d4f55
7 changed files with 103 additions and 38 deletions

View File

@ -3,9 +3,11 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include "VideoBackends/Vulkan/ShaderCompiler.h" #include "VideoBackends/Vulkan/ShaderCompiler.h"
#include "VideoBackends/Vulkan/VulkanContext.h"
#include <cstddef> #include <cstddef>
#include <cstdlib> #include <cstdlib>
#include <cstring>
#include <fstream> #include <fstream>
#include <memory> #include <memory>
#include <string> #include <string>
@ -37,6 +39,11 @@ static bool CompileShaderToSPV(SPIRVCodeVector* out_code, EShLanguage stage,
const char* stage_filename, const char* source_code, const char* stage_filename, const char* source_code,
size_t source_code_length, const char* header, size_t header_length); 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 // 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). // 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 // 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; 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() bool InitializeGlslang()
{ {
static bool glslang_initialized = false; static bool glslang_initialized = false;
@ -338,29 +381,57 @@ const TBuiltInResource* GetCompilerResourceLimits()
} }
bool CompileVertexShader(SPIRVCodeVector* out_code, const char* source_code, 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, return CompileShaderToSPV(out_code, EShLangVertex, "vs", source_code, source_code_length,
SHADER_HEADER, sizeof(SHADER_HEADER) - 1); SHADER_HEADER, sizeof(SHADER_HEADER) - 1);
} }
bool CompileGeometryShader(SPIRVCodeVector* out_code, const char* source_code, 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, return CompileShaderToSPV(out_code, EShLangGeometry, "gs", source_code, source_code_length,
SHADER_HEADER, sizeof(SHADER_HEADER) - 1); SHADER_HEADER, sizeof(SHADER_HEADER) - 1);
} }
bool CompileFragmentShader(SPIRVCodeVector* out_code, const char* source_code, 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, return CompileShaderToSPV(out_code, EShLangFragment, "ps", source_code, source_code_length,
SHADER_HEADER, sizeof(SHADER_HEADER) - 1); SHADER_HEADER, sizeof(SHADER_HEADER) - 1);
} }
bool CompileComputeShader(SPIRVCodeVector* out_code, const char* source_code, 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, return CompileShaderToSPV(out_code, EShLangCompute, "cs", source_code, source_code_length,
COMPUTE_SHADER_HEADER, sizeof(COMPUTE_SHADER_HEADER) - 1); COMPUTE_SHADER_HEADER, sizeof(COMPUTE_SHADER_HEADER) - 1);
} }

View File

@ -19,19 +19,19 @@ using SPIRVCodeVector = std::vector<SPIRVCodeType>;
// Compile a vertex shader to SPIR-V. // Compile a vertex shader to SPIR-V.
bool CompileVertexShader(SPIRVCodeVector* out_code, const char* source_code, 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. // Compile a geometry shader to SPIR-V.
bool CompileGeometryShader(SPIRVCodeVector* out_code, const char* source_code, 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. // Compile a fragment shader to SPIR-V.
bool CompileFragmentShader(SPIRVCodeVector* out_code, const char* source_code, 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. // Compile a compute shader to SPIR-V.
bool CompileComputeShader(SPIRVCodeVector* out_code, const char* source_code, 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 ShaderCompiler
} // namespace Vulkan } // namespace Vulkan

View File

@ -407,7 +407,7 @@ bool TextureConverter::SupportsTextureDecoding(TextureFormat format, TLUTFormat
std::string shader_source = std::string shader_source =
TextureConversionShader::GenerateDecodingShader(format, palette_format, APIType::Vulkan); 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) if (pipeline.compute_shader == VK_NULL_HANDLE)
{ {
m_decoding_pipelines.emplace(key, pipeline); m_decoding_pipelines.emplace(key, pipeline);

View File

@ -249,50 +249,38 @@ VkShaderModule CreateShaderModule(const u32* spv, size_t spv_word_count)
return module; return module;
} }
VkShaderModule CompileAndCreateVertexShader(const std::string& source_code, bool prepend_header) VkShaderModule CompileAndCreateVertexShader(const std::string& source_code)
{ {
ShaderCompiler::SPIRVCodeVector code; ShaderCompiler::SPIRVCodeVector code;
if (!ShaderCompiler::CompileVertexShader(&code, source_code.c_str(), source_code.length(), if (!ShaderCompiler::CompileVertexShader(&code, source_code.c_str(), source_code.length()))
prepend_header))
{
return VK_NULL_HANDLE; return VK_NULL_HANDLE;
}
return CreateShaderModule(code.data(), code.size()); 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; ShaderCompiler::SPIRVCodeVector code;
if (!ShaderCompiler::CompileGeometryShader(&code, source_code.c_str(), source_code.length(), if (!ShaderCompiler::CompileGeometryShader(&code, source_code.c_str(), source_code.length()))
prepend_header))
{
return VK_NULL_HANDLE; return VK_NULL_HANDLE;
}
return CreateShaderModule(code.data(), code.size()); 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; ShaderCompiler::SPIRVCodeVector code;
if (!ShaderCompiler::CompileFragmentShader(&code, source_code.c_str(), source_code.length(), if (!ShaderCompiler::CompileFragmentShader(&code, source_code.c_str(), source_code.length()))
prepend_header))
{
return VK_NULL_HANDLE; return VK_NULL_HANDLE;
}
return CreateShaderModule(code.data(), code.size()); 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; ShaderCompiler::SPIRVCodeVector code;
if (!ShaderCompiler::CompileComputeShader(&code, source_code.c_str(), source_code.length(), if (!ShaderCompiler::CompileComputeShader(&code, source_code.c_str(), source_code.length()))
prepend_header))
{
return VK_NULL_HANDLE; return VK_NULL_HANDLE;
}
return CreateShaderModule(code.data(), code.size()); return CreateShaderModule(code.data(), code.size());
} }

View File

@ -57,20 +57,16 @@ void ExecuteCurrentCommandsAndRestoreState(bool execute_off_thread,
VkShaderModule CreateShaderModule(const u32* spv, size_t spv_word_count); VkShaderModule CreateShaderModule(const u32* spv, size_t spv_word_count);
// Compile a vertex shader and create a shader module, discarding the intermediate SPIR-V. // Compile a vertex shader and create a shader module, discarding the intermediate SPIR-V.
VkShaderModule CompileAndCreateVertexShader(const std::string& source_code, VkShaderModule CompileAndCreateVertexShader(const std::string& source_code);
bool prepend_header = true);
// Compile a geometry shader and create a shader module, discarding the intermediate SPIR-V. // Compile a geometry shader and create a shader module, discarding the intermediate SPIR-V.
VkShaderModule CompileAndCreateGeometryShader(const std::string& source_code, VkShaderModule CompileAndCreateGeometryShader(const std::string& source_code);
bool prepend_header = true);
// Compile a fragment shader and create a shader module, discarding the intermediate SPIR-V. // Compile a fragment shader and create a shader module, discarding the intermediate SPIR-V.
VkShaderModule CompileAndCreateFragmentShader(const std::string& source_code, VkShaderModule CompileAndCreateFragmentShader(const std::string& source_code);
bool prepend_header = true);
// Compile a compute shader and create a shader module, discarding the intermediate SPIR-V. // Compile a compute shader and create a shader module, discarding the intermediate SPIR-V.
VkShaderModule CompileAndCreateComputeShader(const std::string& source_code, VkShaderModule CompileAndCreateComputeShader(const std::string& source_code);
bool prepend_header = true);
} }
// Utility shader vertex format // Utility shader vertex format

View File

@ -403,7 +403,8 @@ bool VulkanContext::SelectDeviceExtensions(ExtensionList* extension_list, bool e
for (const auto& extension_properties : available_extension_list) for (const auto& extension_properties : available_extension_list)
INFO_LOG(VIDEO, "Available extension: %s", extension_properties.extensionName); INFO_LOG(VIDEO, "Available extension: %s", extension_properties.extensionName);
auto CheckForExtension = [&](const char* name, bool required) -> bool { auto CheckForExtension = [&](const char* name, bool required,
bool* has_extension = nullptr) -> bool {
if (std::find_if(available_extension_list.begin(), available_extension_list.end(), if (std::find_if(available_extension_list.begin(), available_extension_list.end(),
[&](const VkExtensionProperties& properties) { [&](const VkExtensionProperties& properties) {
return !strcmp(name, properties.extensionName); return !strcmp(name, properties.extensionName);
@ -411,9 +412,14 @@ bool VulkanContext::SelectDeviceExtensions(ExtensionList* extension_list, bool e
{ {
INFO_LOG(VIDEO, "Enabling extension: %s", name); INFO_LOG(VIDEO, "Enabling extension: %s", name);
extension_list->push_back(name); extension_list->push_back(name);
if (has_extension)
*has_extension = true;
return true; return true;
} }
if (has_extension)
*has_extension = false;
if (required) if (required)
{ {
ERROR_LOG(VIDEO, "Vulkan: Missing required extension %s.", name); ERROR_LOG(VIDEO, "Vulkan: Missing required extension %s.", name);
@ -426,6 +432,7 @@ bool VulkanContext::SelectDeviceExtensions(ExtensionList* extension_list, bool e
if (enable_surface && !CheckForExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME, true)) if (enable_surface && !CheckForExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME, true))
return false; return false;
CheckForExtension(VK_NV_GLSL_SHADER_EXTENSION_NAME, false, &m_supports_nv_glsl_extension);
return true; return true;
} }

View File

@ -83,6 +83,7 @@ public:
{ {
return m_device_features.occlusionQueryPrecise == VK_TRUE; return m_device_features.occlusionQueryPrecise == VK_TRUE;
} }
bool SupportsNVGLSLExtension() const { return m_supports_nv_glsl_extension; }
// Helpers for getting constants // Helpers for getting constants
VkDeviceSize GetUniformBufferAlignment() const VkDeviceSize GetUniformBufferAlignment() const
{ {
@ -129,6 +130,8 @@ private:
VkPhysicalDeviceFeatures m_device_features = {}; VkPhysicalDeviceFeatures m_device_features = {};
VkPhysicalDeviceProperties m_device_properties = {}; VkPhysicalDeviceProperties m_device_properties = {};
VkPhysicalDeviceMemoryProperties m_device_memory_properties = {}; VkPhysicalDeviceMemoryProperties m_device_memory_properties = {};
bool m_supports_nv_glsl_extension = false;
}; };
extern std::unique_ptr<VulkanContext> g_vulkan_context; extern std::unique_ptr<VulkanContext> g_vulkan_context;