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 5e8037cd2e..a28d7fbd19 100644 --- a/gfx/drivers_shader/glslang_util.hpp +++ b/gfx/drivers_shader/glslang_util.hpp @@ -20,9 +20,53 @@ #include #include +enum glslang_format +{ + // 8-bit + SLANG_FORMAT_R8_UNORM = 0, + SLANG_FORMAT_R8_UINT, + SLANG_FORMAT_R8_SINT, + SLANG_FORMAT_R8G8_UNORM, + SLANG_FORMAT_R8G8_UINT, + SLANG_FORMAT_R8G8_SINT, + SLANG_FORMAT_R8G8B8A8_UNORM, + SLANG_FORMAT_R8G8B8A8_UINT, + SLANG_FORMAT_R8G8B8A8_SINT, + SLANG_FORMAT_R8G8B8A8_SRGB, + + // 10-bit + SLANG_FORMAT_A2B10G10R10_UNORM_PACK32, + SLANG_FORMAT_A2B10G10R10_UINT_PACK32, + + // 16-bit + SLANG_FORMAT_R16_UINT, + SLANG_FORMAT_R16_SINT, + SLANG_FORMAT_R16_SFLOAT, + SLANG_FORMAT_R16G16_UINT, + SLANG_FORMAT_R16G16_SINT, + SLANG_FORMAT_R16G16_SFLOAT, + SLANG_FORMAT_R16G16B16A16_UINT, + SLANG_FORMAT_R16G16B16A16_SINT, + SLANG_FORMAT_R16G16B16A16_SFLOAT, + + // 32-bit + SLANG_FORMAT_R32_UINT, + SLANG_FORMAT_R32_SINT, + SLANG_FORMAT_R32_SFLOAT, + SLANG_FORMAT_R32G32_UINT, + SLANG_FORMAT_R32G32_SINT, + SLANG_FORMAT_R32G32_SFLOAT, + SLANG_FORMAT_R32G32B32A32_UINT, + SLANG_FORMAT_R32G32B32A32_SINT, + SLANG_FORMAT_R32G32B32A32_SFLOAT, + + SLANG_FORMAT_UNKNOWN +}; + struct glslang_meta { std::string name; + glslang_format rt_format = SLANG_FORMAT_UNKNOWN; }; struct glslang_output @@ -33,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) {