From 8c2664e5fb5a7f7a80a63448b8460e6416019401 Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Sat, 26 Mar 2016 23:49:57 +0100 Subject: [PATCH] Vulkan: Add explicit render target format support. Supports all required formats in Vulkan 1.0 as well as GLES 3.x/GL 3.x (for future). --- gfx/drivers_shader/glslang_util.cpp | 112 ++++++++++++++++++++++++++- gfx/drivers_shader/glslang_util.hpp | 17 ++-- gfx/drivers_shader/shader_vulkan.cpp | 81 +++++++++++++++++-- 3 files changed, 191 insertions(+), 19 deletions(-) diff --git a/gfx/drivers_shader/glslang_util.cpp b/gfx/drivers_shader/glslang_util.cpp index e112267216..90aee21a75 100644 --- a/gfx/drivers_shader/glslang_util.cpp +++ b/gfx/drivers_shader/glslang_util.cpp @@ -99,7 +99,7 @@ static string build_stage_source(const vector &lines, const char *stage) for (auto itr = begin(lines) + 1; itr != end(lines); ++itr) { - if (itr->find("#pragma stage ") != string::npos) + if (itr->find("#pragma stage ") == 0) { if (stage) { @@ -115,7 +115,8 @@ static string build_stage_source(const vector &lines, const char *stage) str << '\n'; } } - else if (itr->find("#pragma name ") != string::npos) + else if (itr->find("#pragma name ") == 0 || + itr->find("#pragma format ") == 0) { // Ignore } @@ -127,12 +128,96 @@ static string build_stage_source(const vector &lines, const char *stage) return str.str(); } +static const char *glslang_formats[] = { + "R8_UNORM", + "R8_UINT", + "R8_SINT", + "R8G8_UNORM", + "R8G8_UINT", + "R8G8_SINT", + "R8G8B8A8_UNORM", + "R8G8B8A8_UINT", + "R8G8B8A8_SINT", + "R8G8B8A8_SRGB", + + "A2B10G10R10_UNORM_PACK32", + "A2B10G10R10_UINT_PACK32", + + "R16_UINT", + "R16_SINT", + "R16_SFLOAT", + "R16G16_UINT", + "R16G16_SINT", + "R16G16_SFLOAT", + "R16G16B16A16_UINT", + "R16G16B16A16_SINT", + "R16G16B16A16_SFLOAT", + + "R32_UINT", + "R32_SINT", + "R32_SFLOAT", + "R32G32_UINT", + "R32G32_SINT", + "R32G32_SFLOAT", + "R32G32B32A32_UINT", + "R32G32B32A32_SINT", + "R32G32B32A32_SFLOAT", + + "UNKNOWN", +}; + +const char *glslang_format_to_string(enum glslang_format fmt) +{ + return glslang_formats[fmt]; +} + +static glslang_format glslang_find_format(const char *fmt) +{ +#undef FMT +#define FMT(x) if (!strcmp(fmt, #x)) return SLANG_FORMAT_ ## x + FMT(R8_UNORM); + FMT(R8_UINT); + FMT(R8_SINT); + FMT(R8G8_UNORM); + FMT(R8G8_UINT); + FMT(R8G8_SINT); + FMT(R8G8B8A8_UNORM); + FMT(R8G8B8A8_UINT); + FMT(R8G8B8A8_SINT); + FMT(R8G8B8A8_SRGB); + + FMT(A2B10G10R10_UNORM_PACK32); + FMT(A2B10G10R10_UINT_PACK32); + + FMT(R16_UINT); + FMT(R16_SINT); + FMT(R16_SFLOAT); + FMT(R16G16_UINT); + FMT(R16G16_SINT); + FMT(R16G16_SFLOAT); + FMT(R16G16B16A16_UINT); + FMT(R16G16B16A16_SINT); + FMT(R16G16B16A16_SFLOAT); + + FMT(R32_UINT); + FMT(R32_SINT); + FMT(R32_SFLOAT); + FMT(R32G32_UINT); + FMT(R32G32_SINT); + FMT(R32G32_SFLOAT); + FMT(R32G32B32A32_UINT); + FMT(R32G32B32A32_SINT); + FMT(R32G32B32A32_SFLOAT); + + return SLANG_FORMAT_UNKNOWN; +} + static bool glslang_parse_meta(const vector &lines, glslang_meta *meta) { *meta = glslang_meta{}; for (auto &line : lines) { - if (line.find("#pragma name ") != string::npos) + if (line.find("#pragma name ") == 0) { if (!meta->name.empty()) { @@ -145,6 +230,25 @@ static bool glslang_parse_meta(const vector &lines, glslang_meta *meta) str++; meta->name = str; } + else if (line.find("#pragma format ") == 0) + { + if (meta->rt_format != SLANG_FORMAT_UNKNOWN) + { + RARCH_ERR("[slang]: Trying to declare format multiple times for file.\n"); + return false; + } + + const char *str = line.c_str() + strlen("#pragma format "); + while (*str == ' ') + str++; + + meta->rt_format = glslang_find_format(str); + if (meta->rt_format == SLANG_FORMAT_UNKNOWN) + { + RARCH_ERR("[slang]: Failed to find format \"%s\".\n", str); + return false; + } + } } return true; } @@ -161,7 +265,7 @@ bool glslang_compile_shader(const char *shader_path, glslang_output *output) return false; auto &header = lines.front(); - if (header.find_first_of("#version ") == string::npos) + if (header.find_first_of("#version ") != 0) { RARCH_ERR("First line of the shader must contain a valid #version string.\n"); return false; diff --git a/gfx/drivers_shader/glslang_util.hpp b/gfx/drivers_shader/glslang_util.hpp index c705ac057c..a28d7fbd19 100644 --- a/gfx/drivers_shader/glslang_util.hpp +++ b/gfx/drivers_shader/glslang_util.hpp @@ -23,7 +23,7 @@ enum glslang_format { // 8-bit - SLANG_FORMAT_R8_UNORM, + SLANG_FORMAT_R8_UNORM = 0, SLANG_FORMAT_R8_UINT, SLANG_FORMAT_R8_SINT, SLANG_FORMAT_R8G8_UNORM, @@ -35,8 +35,8 @@ enum glslang_format SLANG_FORMAT_R8G8B8A8_SRGB, // 10-bit - SLANG_FORMAT_A2B10G10R10_UNORM, - SLANG_FORMAT_A2B10G10R10_UINT, + SLANG_FORMAT_A2B10G10R10_UNORM_PACK32, + SLANG_FORMAT_A2B10G10R10_UINT_PACK32, // 16-bit SLANG_FORMAT_R16_UINT, @@ -52,20 +52,21 @@ enum glslang_format // 32-bit SLANG_FORMAT_R32_UINT, SLANG_FORMAT_R32_SINT, - SLANG_FORMAT_R32_FLOAT, + SLANG_FORMAT_R32_SFLOAT, SLANG_FORMAT_R32G32_UINT, SLANG_FORMAT_R32G32_SINT, - SLANG_FORMAT_R32G32_FLOAT, + SLANG_FORMAT_R32G32_SFLOAT, SLANG_FORMAT_R32G32B32A32_UINT, SLANG_FORMAT_R32G32B32A32_SINT, - SLANG_FORMAT_R32G32B32A32_FLOAT, + SLANG_FORMAT_R32G32B32A32_SFLOAT, - SLANG_FORMAT_INVALID + SLANG_FORMAT_UNKNOWN }; struct glslang_meta { std::string name; + glslang_format rt_format = SLANG_FORMAT_UNKNOWN; }; struct glslang_output @@ -76,7 +77,7 @@ struct glslang_output }; bool glslang_compile_shader(const char *shader_path, glslang_output *output); - +const char *glslang_format_to_string(enum glslang_format fmt); #endif diff --git a/gfx/drivers_shader/shader_vulkan.cpp b/gfx/drivers_shader/shader_vulkan.cpp index 8bfacb3b89..cd60cb65ae 100644 --- a/gfx/drivers_shader/shader_vulkan.cpp +++ b/gfx/drivers_shader/shader_vulkan.cpp @@ -2029,6 +2029,51 @@ struct ConfigDeleter } }; +static VkFormat glslang_format_to_vk(glslang_format fmt) +{ +#undef FMT +#define FMT(x) case SLANG_FORMAT_##x: return VK_FORMAT_##x + switch (fmt) + { + FMT(R8_UNORM); + FMT(R8_SINT); + FMT(R8_UINT); + FMT(R8G8_UNORM); + FMT(R8G8_SINT); + FMT(R8G8_UINT); + FMT(R8G8B8A8_UNORM); + FMT(R8G8B8A8_SINT); + FMT(R8G8B8A8_UINT); + FMT(R8G8B8A8_SRGB); + + FMT(A2B10G10R10_UNORM_PACK32); + FMT(A2B10G10R10_UINT_PACK32); + + FMT(R16_UINT); + FMT(R16_SINT); + FMT(R16_SFLOAT); + FMT(R16G16_UINT); + FMT(R16G16_SINT); + FMT(R16G16_SFLOAT); + FMT(R16G16B16A16_UINT); + FMT(R16G16B16A16_SINT); + FMT(R16G16B16A16_SFLOAT); + + FMT(R32_UINT); + FMT(R32_SINT); + FMT(R32_SFLOAT); + FMT(R32G32_UINT); + FMT(R32G32_SINT); + FMT(R32G32_SFLOAT); + FMT(R32G32B32A32_UINT); + FMT(R32G32B32A32_SINT); + FMT(R32G32B32A32_SFLOAT); + + default: + return VK_FORMAT_UNDEFINED; + } +} + vulkan_filter_chain_t *vulkan_filter_chain_create_from_preset( const struct vulkan_filter_chain_create_info *info, const char *path, vulkan_filter_chain_filter filter) @@ -2097,6 +2142,12 @@ vulkan_filter_chain_t *vulkan_filter_chain_create_from_preset( VULKAN_FILTER_CHAIN_NEAREST; } + bool explicit_format = output.meta.rt_format != SLANG_FORMAT_UNKNOWN; + + // Set a reasonable default. + if (output.meta.rt_format == SLANG_FORMAT_UNKNOWN) + output.meta.rt_format = SLANG_FORMAT_R8G8B8A8_UNORM; + if (!pass->fbo.valid) { pass_info.scale_type_x = i + 1 == shader->passes @@ -2107,18 +2158,34 @@ vulkan_filter_chain_t *vulkan_filter_chain_create_from_preset( : VULKAN_FILTER_CHAIN_SCALE_SOURCE; pass_info.scale_x = 1.0f; pass_info.scale_y = 1.0f; - pass_info.rt_format = i + 1 == shader->passes - ? tmpinfo.swapchain.format - : VK_FORMAT_R8G8B8A8_UNORM; + + if (i + 1 == shader->passes) + { + pass_info.rt_format = tmpinfo.swapchain.format; + + if (explicit_format) + RARCH_WARN("[slang]: Using explicit format for last pass in chain, but it is not rendered to framebuffer, using swapchain format instead.\n"); + } + else + { + pass_info.rt_format = glslang_format_to_vk(output.meta.rt_format); + RARCH_LOG("[slang]: Using render target format %s for pass output #%u.\n", + glslang_format_to_string(output.meta.rt_format), i); + } } else { - // TODO: Add more general format spec. - pass_info.rt_format = VK_FORMAT_R8G8B8A8_UNORM; + // Preset overrides shader. + // Kinda ugly ... if (pass->fbo.srgb_fbo) - pass_info.rt_format = VK_FORMAT_R8G8B8A8_SRGB; + output.meta.rt_format = SLANG_FORMAT_R8G8B8A8_SRGB; else if (pass->fbo.fp_fbo) - pass_info.rt_format = VK_FORMAT_R16G16B16A16_SFLOAT; + output.meta.rt_format = SLANG_FORMAT_R16G16B16A16_SFLOAT; + /// + + pass_info.rt_format = glslang_format_to_vk(output.meta.rt_format); + RARCH_LOG("[slang]: Using render target format %s for pass output #%u.\n", + glslang_format_to_string(output.meta.rt_format), i); switch (pass->fbo.type_x) {