From 4f3ade1b95f39b2a76a10dbd4ceb4ea18c42176e Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Fri, 25 Mar 2016 13:26:36 +0100 Subject: [PATCH] Vulkan: Begin sketching out support for complete filter chain. --- gfx/drivers_shader/shader_vulkan.cpp | 19 +-- gfx/drivers_shader/slang_reflection.cpp | 160 ++++++++++++++++++------ gfx/drivers_shader/slang_reflection.hpp | 35 +++++- 3 files changed, 160 insertions(+), 54 deletions(-) diff --git a/gfx/drivers_shader/shader_vulkan.cpp b/gfx/drivers_shader/shader_vulkan.cpp index 4f3c19cdc9..846d7ca3f2 100644 --- a/gfx/drivers_shader/shader_vulkan.cpp +++ b/gfx/drivers_shader/shader_vulkan.cpp @@ -708,11 +708,12 @@ bool Pass::init_pipeline_layout() } // Semantic textures. - for (unsigned i = 0; i < SLANG_NUM_TEXTURE_SEMANTICS; i++) + for (auto &semantic : reflection.semantic_textures) { - if (reflection.semantic_texture_mask & (1u << i)) + for (auto &texture : semantic) { - auto &texture = reflection.semantic_textures[i]; + if (!texture.texture) + continue; VkShaderStageFlags stages = 0; if (texture.stage_mask & SLANG_STAGE_VERTEX_MASK) @@ -1069,17 +1070,17 @@ void Pass::set_texture(VkDescriptorSet set, unsigned binding, void Pass::set_semantic_texture(VkDescriptorSet set, slang_texture_semantic semantic, const Texture &texture) { - if (reflection.semantic_texture_mask & (1u << semantic)) - set_texture(set, reflection.semantic_textures[semantic].binding, texture); + if (reflection.semantic_textures[semantic][0].texture) + set_texture(set, reflection.semantic_textures[semantic][0].binding, texture); } void Pass::build_semantic_texture_vec4(uint8_t *data, slang_texture_semantic semantic, unsigned width, unsigned height) { - if (data && (reflection.semantic_texture_ubo_mask & (1 << semantic))) + if (data && reflection.semantic_textures[semantic][0].uniform) { build_vec4( - reinterpret_cast(data + reflection.semantic_textures[semantic].ubo_offset), + reinterpret_cast(data + reflection.semantic_textures[semantic][0].ubo_offset), width, height); } @@ -1088,7 +1089,7 @@ void Pass::build_semantic_texture_vec4(uint8_t *data, slang_texture_semantic sem void Pass::build_semantic_vec4(uint8_t *data, slang_semantic semantic, unsigned width, unsigned height) { - if (data && (reflection.semantic_ubo_mask & (1 << semantic))) + if (data && reflection.semantics[semantic].uniform) { build_vec4( reinterpret_cast(data + reflection.semantics[semantic].ubo_offset), @@ -1108,7 +1109,7 @@ void Pass::build_semantic_texture(VkDescriptorSet set, uint8_t *buffer, void Pass::build_semantics(VkDescriptorSet set, uint8_t *buffer, const float *mvp, const Texture &original, const Texture &source) { - if (buffer && (reflection.semantic_ubo_mask & (1u << SLANG_SEMANTIC_MVP))) + if (buffer && reflection.semantics[SLANG_SEMANTIC_MVP].uniform) { size_t offset = reflection.semantics[SLANG_SEMANTIC_MVP].ubo_offset; if (mvp) diff --git a/gfx/drivers_shader/slang_reflection.cpp b/gfx/drivers_shader/slang_reflection.cpp index 82f64467dc..ff27c81540 100644 --- a/gfx/drivers_shader/slang_reflection.cpp +++ b/gfx/drivers_shader/slang_reflection.cpp @@ -22,14 +22,46 @@ using namespace std; using namespace spir2cross; +static bool slang_texture_semantic_is_array(slang_texture_semantic sem) +{ + switch (sem) + { + case SLANG_TEXTURE_SEMANTIC_ORIGINAL_HISTORY: + case SLANG_TEXTURE_SEMANTIC_PASS_OUTPUT: + case SLANG_TEXTURE_SEMANTIC_PASS_FEEDBACK: + return true; + + default: + return false; + } +} + +slang_reflection::slang_reflection() +{ + for (unsigned i = 0; i < SLANG_NUM_TEXTURE_SEMANTICS; i++) + { + semantic_textures[i].resize( + slang_texture_semantic_is_array(static_cast(i)) + ? 0 : 1); + } +} + static const char *texture_semantic_names[] = { "Original", "Source", + "OriginalHistory", + "PassOutput", + "PassFeedback", + nullptr }; static const char *texture_semantic_uniform_names[] = { "OriginalSize", "SourceSize", + "OriginalHistorySize", + "PassOutputSize", + "PassFeedbackSize", + nullptr }; static const char *semantic_uniform_names[] = { @@ -38,28 +70,45 @@ static const char *semantic_uniform_names[] = { "FinalViewportSize", }; -static slang_texture_semantic slang_name_to_texture_semantic(const string &name) +static slang_texture_semantic slang_name_to_texture_semantic_array(const string &name, const char **names, + unsigned *index) { unsigned i = 0; - for (auto n : texture_semantic_names) + while (*names) { - if (name == n) - return static_cast(i); + auto n = *names; + auto semantic = static_cast(i); + if (slang_texture_semantic_is_array(semantic)) + { + size_t baselen = strlen(n); + int cmp = strncmp(n, name.c_str(), baselen); + + if (cmp == 0) + { + *index = strtoul(name.c_str() + baselen, nullptr, 0); + return semantic; + } + } + else if (name == n) + { + *index = 0; + return semantic; + } + i++; + names++; } return SLANG_INVALID_TEXTURE_SEMANTIC; } -static slang_texture_semantic slang_uniform_name_to_texture_semantic(const string &name) +static slang_texture_semantic slang_name_to_texture_semantic(const string &name, unsigned *index) { - unsigned i = 0; - for (auto n : texture_semantic_uniform_names) - { - if (name == n) - return static_cast(i); - i++; - } - return SLANG_INVALID_TEXTURE_SEMANTIC; + return slang_name_to_texture_semantic_array(name, texture_semantic_names, index); +} + +static slang_texture_semantic slang_uniform_name_to_texture_semantic(const string &name, unsigned *index) +{ + return slang_name_to_texture_semantic_array(name, texture_semantic_uniform_names, index); } static slang_semantic slang_uniform_name_to_semantic(const string &name) @@ -75,50 +124,64 @@ static slang_semantic slang_uniform_name_to_semantic(const string &name) return SLANG_INVALID_SEMANTIC; } -static bool set_ubo_texture_offset(slang_reflection *reflection, slang_texture_semantic semantic, +template +static void resize_minimum(T &vec, unsigned minimum) +{ + if (vec.size() < minimum) + vec.resize(minimum); +} + +static bool set_ubo_texture_offset(slang_reflection *reflection, + slang_texture_semantic semantic, unsigned index, size_t offset) { - if (reflection->semantic_texture_ubo_mask & (1u << semantic)) + resize_minimum(reflection->semantic_textures[semantic], index + 1); + auto &sem = reflection->semantic_textures[semantic][index]; + + if (sem.uniform) { - if (reflection->semantic_textures[semantic].ubo_offset != offset) + if (sem.ubo_offset != offset) { - RARCH_ERR("[slang]: Vertex and fragment have different offsets for same semantic %s (%u vs. %u).\n", + RARCH_ERR("[slang]: Vertex and fragment have different offsets for same semantic %s #%u (%u vs. %u).\n", texture_semantic_uniform_names[semantic], - unsigned(reflection->semantic_textures[semantic].ubo_offset), + index, + unsigned(sem.ubo_offset), unsigned(offset)); return false; } } - reflection->semantic_texture_ubo_mask |= 1u << semantic; - reflection->semantic_textures[semantic].ubo_offset = offset; + sem.uniform = true; + sem.ubo_offset = offset; return true; } static bool set_ubo_offset(slang_reflection *reflection, slang_semantic semantic, size_t offset, unsigned num_components) { - if (reflection->semantic_ubo_mask & (1u << semantic)) + auto &sem = reflection->semantics[semantic]; + + if (sem.uniform) { - if (reflection->semantics[semantic].ubo_offset != offset) + if (sem.ubo_offset != offset) { RARCH_ERR("[slang]: Vertex and fragment have different offsets for same semantic %s (%u vs. %u).\n", semantic_uniform_names[semantic], - unsigned(reflection->semantics[semantic].ubo_offset), + unsigned(sem.ubo_offset), unsigned(offset)); return false; } - if (reflection->semantics[semantic].num_components != num_components) + if (sem.num_components != num_components) { RARCH_ERR("[slang]: Vertex and fragment have different components for same semantic %s (%u vs. %u).\n", semantic_uniform_names[semantic], - unsigned(reflection->semantics[semantic].num_components), + unsigned(sem.num_components), unsigned(num_components)); } } - reflection->semantic_ubo_mask |= 1u << semantic; - reflection->semantics[semantic].ubo_offset = offset; - reflection->semantics[semantic].num_components = num_components; + sem.uniform = true; + sem.ubo_offset = offset; + sem.num_components = num_components; return true; } @@ -157,8 +220,10 @@ static bool add_active_buffer_ranges(const Compiler &compiler, const Resource &r { auto &name = compiler.get_member_name(resource.type_id, range.index); auto &type = compiler.get_type(compiler.get_type(resource.type_id).member_types[range.index]); - slang_semantic sem = slang_uniform_name_to_semantic(name); - slang_texture_semantic tex_sem = slang_uniform_name_to_texture_semantic(name); + + unsigned tex_sem_index = 0; + auto sem = slang_uniform_name_to_semantic(name); + auto tex_sem = slang_uniform_name_to_texture_semantic(name, &tex_sem_index); if (sem != SLANG_INVALID_SEMANTIC) { @@ -179,7 +244,7 @@ static bool add_active_buffer_ranges(const Compiler &compiler, const Resource &r return false; } - if (!set_ubo_texture_offset(reflection, tex_sem, range.offset)) + if (!set_ubo_texture_offset(reflection, tex_sem, tex_sem_index, range.offset)) return false; } else @@ -346,7 +411,8 @@ static bool slang_reflect(const Compiler &vertex_compiler, const Compiler &fragm } binding_mask |= 1 << binding; - slang_texture_semantic index = slang_name_to_texture_semantic(texture.name); + unsigned array_index = 0; + slang_texture_semantic index = slang_name_to_texture_semantic(texture.name, &array_index); if (index == SLANG_INVALID_TEXTURE_SEMANTIC) { @@ -354,17 +420,25 @@ static bool slang_reflect(const Compiler &vertex_compiler, const Compiler &fragm return false; } - auto &semantic = reflection->semantic_textures[index]; + resize_minimum(reflection->semantic_textures[index], array_index + 1); + auto &semantic = reflection->semantic_textures[index][array_index]; semantic.binding = binding; semantic.stage_mask = SLANG_STAGE_FRAGMENT_MASK; - reflection->semantic_texture_mask |= 1 << index; + semantic.texture = true; } RARCH_LOG("[slang]: Reflection\n"); RARCH_LOG("[slang]: Textures:\n"); for (unsigned i = 0; i < SLANG_NUM_TEXTURE_SEMANTICS; i++) - if (reflection->semantic_texture_mask & (1u << i)) - RARCH_LOG("[slang]: %s\n", texture_semantic_names[i]); + { + unsigned index = 0; + for (auto &sem : reflection->semantic_textures[i]) + { + if (sem.texture) + RARCH_LOG("[slang]: %s (#%u)\n", texture_semantic_names[i], index); + index++; + } + } RARCH_LOG("[slang]:\n"); RARCH_LOG("[slang]: Uniforms (Vertex: %s, Fragment: %s):\n", @@ -372,7 +446,7 @@ static bool slang_reflect(const Compiler &vertex_compiler, const Compiler &fragm reflection->ubo_stage_mask & SLANG_STAGE_FRAGMENT_MASK ? "yes": "no"); for (unsigned i = 0; i < SLANG_NUM_SEMANTICS; i++) { - if (reflection->semantic_ubo_mask & (1u << i)) + if (reflection->semantics[i].uniform) { RARCH_LOG("[slang]: %s (Offset: %u)\n", semantic_uniform_names[i], unsigned(reflection->semantics[i].ubo_offset)); @@ -381,10 +455,16 @@ static bool slang_reflect(const Compiler &vertex_compiler, const Compiler &fragm for (unsigned i = 0; i < SLANG_NUM_TEXTURE_SEMANTICS; i++) { - if (reflection->semantic_texture_ubo_mask & (1u << i)) + unsigned index = 0; + for (auto &sem : reflection->semantic_textures[i]) { - RARCH_LOG("[slang]: %s (Offset: %u)\n", texture_semantic_uniform_names[i], - unsigned(reflection->semantic_textures[i].ubo_offset)); + if (sem.uniform) + { + RARCH_LOG("[slang]: %s (#%u) (Offset: %u)\n", texture_semantic_uniform_names[i], + index, + unsigned(sem.ubo_offset)); + } + index++; } } diff --git a/gfx/drivers_shader/slang_reflection.hpp b/gfx/drivers_shader/slang_reflection.hpp index d5f5a90617..94228b2757 100644 --- a/gfx/drivers_shader/slang_reflection.hpp +++ b/gfx/drivers_shader/slang_reflection.hpp @@ -22,9 +22,31 @@ // Textures with built-in meaning. enum slang_texture_semantic { + // The input texture to the filter chain. + // Canonical name: "Original". SLANG_TEXTURE_SEMANTIC_ORIGINAL = 0, + + // The output from pass N - 1 if executing pass N, or ORIGINAL + // if pass #0 is executed. + // Canonical name: "Source". SLANG_TEXTURE_SEMANTIC_SOURCE = 1, + // The original inputs with a history back in time. + // Canonical name: "OriginalHistory#", e.g. "OriginalHistory2" <- Two frames back. + // "OriginalHistory0" is an alias for SEMANTIC_ORIGINAL. + // Size name: "OriginalHistorySize#". + SLANG_TEXTURE_SEMANTIC_ORIGINAL_HISTORY = 2, + + // The output from pass #N, where pass #0 is the first pass. + // Canonical name: "PassOutput#", e.g. "PassOutput3". + // Size name: "PassOutputSize#". + SLANG_TEXTURE_SEMANTIC_PASS_OUTPUT = 3, + + // The output from pass #N, one frame ago where pass #0 is the first pass. + // It is not valid to use the pass feedback from a pass which is not offscreen. + // Canonical name: "PassFeedback#", e.g. "PassFeedback2". + SLANG_TEXTURE_SEMANTIC_PASS_FEEDBACK = 4, + SLANG_NUM_TEXTURE_SEMANTICS, SLANG_INVALID_TEXTURE_SEMANTIC = -1 }; @@ -44,6 +66,8 @@ enum slang_stage SLANG_STAGE_VERTEX_MASK = 1 << 0, SLANG_STAGE_FRAGMENT_MASK = 1 << 1 }; + +// Vulkan minimum limit. #define SLANG_NUM_BINDINGS 16 struct slang_texture_semantic_meta @@ -51,27 +75,28 @@ struct slang_texture_semantic_meta size_t ubo_offset = 0; unsigned binding = 0; uint32_t stage_mask = 0; + + bool texture = false; + bool uniform = false; }; struct slang_semantic_meta { size_t ubo_offset = 0; unsigned num_components = 0; + bool uniform = false; }; struct slang_reflection { - slang_reflection() = default; + slang_reflection(); size_t ubo_size = 0; unsigned ubo_binding = 0; uint32_t ubo_stage_mask = 0; - slang_texture_semantic_meta semantic_textures[SLANG_NUM_TEXTURE_SEMANTICS]; + std::vector semantic_textures[SLANG_NUM_TEXTURE_SEMANTICS]; slang_semantic_meta semantics[SLANG_NUM_SEMANTICS]; - uint32_t semantic_texture_mask = 0; - uint32_t semantic_texture_ubo_mask = 0; - uint32_t semantic_ubo_mask = 0; }; bool slang_reflect_spirv(const std::vector &vertex,