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).
This commit is contained in:
Hans-Kristian Arntzen 2016-03-26 23:49:57 +01:00
parent 236200ef63
commit 8c2664e5fb
3 changed files with 191 additions and 19 deletions

View File

@ -99,7 +99,7 @@ static string build_stage_source(const vector<string> &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<string> &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<string> &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<string> &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<string> &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;

View File

@ -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

View File

@ -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)
{