mirror of
https://github.com/CTCaer/RetroArch.git
synced 2024-12-23 11:18:25 +00:00
Merge pull request #2820 from Themaister/master
Vulkan: Further work on shader backend.
This commit is contained in:
commit
786bdacd4c
@ -1481,6 +1481,7 @@ static bool vulkan_frame(void *data, const void *frame,
|
||||
|
||||
/* Notify filter chain about the new sync index. */
|
||||
vulkan_filter_chain_notify_sync_index(vk->filter_chain, frame_index);
|
||||
vulkan_filter_chain_set_frame_count(vk->filter_chain, frame_count);
|
||||
|
||||
retro_perf_start(&build_cmd);
|
||||
/* Render offscreen filter chain passes. */
|
||||
|
@ -101,8 +101,11 @@ static string build_stage_source(const vector<string> &lines, const char *stage)
|
||||
{
|
||||
if (itr->find("#pragma stage ") != string::npos)
|
||||
{
|
||||
auto expected = string("#pragma stage ") + stage;
|
||||
active = itr->find(expected) != string::npos;
|
||||
if (stage)
|
||||
{
|
||||
auto expected = string("#pragma stage ") + stage;
|
||||
active = itr->find(expected) != string::npos;
|
||||
}
|
||||
|
||||
// Improve debuggability.
|
||||
if (active)
|
||||
@ -112,6 +115,10 @@ static string build_stage_source(const vector<string> &lines, const char *stage)
|
||||
str << '\n';
|
||||
}
|
||||
}
|
||||
else if (itr->find("#pragma name ") != string::npos)
|
||||
{
|
||||
// Ignore
|
||||
}
|
||||
else if (active)
|
||||
str << *itr;
|
||||
str << '\n';
|
||||
@ -120,14 +127,39 @@ static string build_stage_source(const vector<string> &lines, const char *stage)
|
||||
return str.str();
|
||||
}
|
||||
|
||||
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 (!meta->name.empty())
|
||||
{
|
||||
RARCH_ERR("[slang]: Trying to declare multiple names for file.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *str = line.c_str() + strlen("#pragma name ");
|
||||
while (*str == ' ')
|
||||
str++;
|
||||
meta->name = str;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool glslang_compile_shader(const char *shader_path, glslang_output *output)
|
||||
{
|
||||
vector<string> lines;
|
||||
|
||||
RARCH_LOG("Compiling shader \"%s\".\n", shader_path);
|
||||
RARCH_LOG("[slang]: Compiling shader \"%s\".\n", shader_path);
|
||||
if (!read_shader_file(shader_path, &lines))
|
||||
return false;
|
||||
|
||||
if (!glslang_parse_meta(lines, &output->meta))
|
||||
return false;
|
||||
|
||||
auto &header = lines.front();
|
||||
if (header.find_first_of("#version ") == string::npos)
|
||||
{
|
||||
|
@ -18,11 +18,18 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
struct glslang_meta
|
||||
{
|
||||
std::string name;
|
||||
};
|
||||
|
||||
struct glslang_output
|
||||
{
|
||||
std::vector<uint32_t> vertex;
|
||||
std::vector<uint32_t> fragment;
|
||||
glslang_meta meta;
|
||||
};
|
||||
|
||||
bool glslang_compile_shader(const char *shader_path, glslang_output *output);
|
||||
|
@ -219,6 +219,10 @@ struct CommonResources
|
||||
vector<Texture> original_history;
|
||||
vector<Texture> framebuffer_feedback;
|
||||
|
||||
unordered_map<string, slang_texture_semantic_map> texture_semantic_map;
|
||||
unordered_map<string, slang_texture_semantic_map> texture_semantic_uniform_map;
|
||||
unordered_map<string, slang_semantic> semantic_map;
|
||||
|
||||
VkDevice device;
|
||||
};
|
||||
|
||||
@ -276,6 +280,26 @@ class Pass
|
||||
sync_index = index;
|
||||
}
|
||||
|
||||
void set_frame_count(uint64_t count)
|
||||
{
|
||||
frame_count = count;
|
||||
}
|
||||
|
||||
void set_frame_count_period(unsigned period)
|
||||
{
|
||||
frame_count_period = period;
|
||||
}
|
||||
|
||||
void set_name(const char *name)
|
||||
{
|
||||
pass_name = name;
|
||||
}
|
||||
|
||||
const string &get_name() const
|
||||
{
|
||||
return pass_name;
|
||||
}
|
||||
|
||||
vulkan_filter_chain_filter get_source_filter() const
|
||||
{
|
||||
return pass_info.source_filter;
|
||||
@ -291,6 +315,11 @@ class Pass
|
||||
return reflection;
|
||||
}
|
||||
|
||||
void set_pass_number(unsigned pass)
|
||||
{
|
||||
pass_number = pass;
|
||||
}
|
||||
|
||||
void end_frame();
|
||||
|
||||
private:
|
||||
@ -347,6 +376,7 @@ class Pass
|
||||
const float *mvp, const Texture &original, const Texture &source);
|
||||
void build_semantic_vec4(uint8_t *data, slang_semantic semantic,
|
||||
unsigned width, unsigned height);
|
||||
void build_semantic_uint(uint8_t *data, slang_semantic semantic, uint32_t value);
|
||||
void build_semantic_texture_vec4(uint8_t *data,
|
||||
slang_texture_semantic semantic,
|
||||
unsigned width, unsigned height);
|
||||
@ -357,6 +387,12 @@ class Pass
|
||||
slang_texture_semantic semantic, const Texture &texture);
|
||||
void build_semantic_texture_array(VkDescriptorSet set, uint8_t *buffer,
|
||||
slang_texture_semantic semantic, unsigned index, const Texture &texture);
|
||||
|
||||
uint64_t frame_count = 0;
|
||||
unsigned frame_count_period = 0;
|
||||
unsigned pass_number = 0;
|
||||
|
||||
string pass_name;
|
||||
};
|
||||
|
||||
// struct here since we're implementing the opaque typedef from C.
|
||||
@ -391,6 +427,10 @@ struct vulkan_filter_chain
|
||||
void build_viewport_pass(VkCommandBuffer cmd,
|
||||
const VkViewport &vp, const float *mvp);
|
||||
|
||||
void set_frame_count(uint64_t count);
|
||||
void set_frame_count_period(unsigned pass, unsigned period);
|
||||
void set_pass_name(unsigned pass, const char *name);
|
||||
|
||||
private:
|
||||
VkDevice device;
|
||||
const VkPhysicalDeviceMemoryProperties &memory_properties;
|
||||
@ -418,6 +458,7 @@ struct vulkan_filter_chain
|
||||
|
||||
bool init_history();
|
||||
bool init_feedback();
|
||||
bool init_alias();
|
||||
void update_history(DeferredDisposer &disposer, VkCommandBuffer cmd);
|
||||
vector<unique_ptr<Framebuffer>> original_history;
|
||||
bool require_clear = false;
|
||||
@ -479,6 +520,7 @@ void vulkan_filter_chain::set_num_passes(unsigned num_passes)
|
||||
passes.emplace_back(new Pass(device, memory_properties,
|
||||
cache, deferred_calls.size(), i + 1 == num_passes));
|
||||
passes.back()->set_common_resources(common);
|
||||
passes.back()->set_pass_number(i);
|
||||
}
|
||||
}
|
||||
|
||||
@ -511,6 +553,22 @@ void vulkan_filter_chain::set_input_texture(
|
||||
input_texture = texture;
|
||||
}
|
||||
|
||||
void vulkan_filter_chain::set_frame_count(uint64_t count)
|
||||
{
|
||||
for (auto &pass : passes)
|
||||
pass->set_frame_count(count);
|
||||
}
|
||||
|
||||
void vulkan_filter_chain::set_frame_count_period(unsigned pass, unsigned period)
|
||||
{
|
||||
passes[pass]->set_frame_count_period(period);
|
||||
}
|
||||
|
||||
void vulkan_filter_chain::set_pass_name(unsigned pass, const char *name)
|
||||
{
|
||||
passes[pass]->set_name(name);
|
||||
}
|
||||
|
||||
void vulkan_filter_chain::execute_deferred()
|
||||
{
|
||||
for (auto &calls : deferred_calls)
|
||||
@ -642,13 +700,66 @@ bool vulkan_filter_chain::init_feedback()
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename M, typename P>
|
||||
static bool set_unique_map(M &m, const string &name, const P &p)
|
||||
{
|
||||
auto itr = m.find(name);
|
||||
if (itr != end(m))
|
||||
{
|
||||
RARCH_ERR("[slang]: Alias \"%s\" already exists.\n",
|
||||
name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
m[name] = p;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vulkan_filter_chain::init_alias()
|
||||
{
|
||||
common.texture_semantic_map.clear();
|
||||
common.texture_semantic_uniform_map.clear();
|
||||
common.semantic_map.clear();
|
||||
|
||||
unsigned i = 0;
|
||||
for (auto &pass : passes)
|
||||
{
|
||||
auto &name = pass->get_name();
|
||||
if (name.empty())
|
||||
continue;
|
||||
|
||||
if (!set_unique_map(common.texture_semantic_map, name,
|
||||
slang_texture_semantic_map{ SLANG_TEXTURE_SEMANTIC_PASS_OUTPUT, i }))
|
||||
return false;
|
||||
|
||||
if (!set_unique_map(common.texture_semantic_uniform_map, name + "Size",
|
||||
slang_texture_semantic_map{ SLANG_TEXTURE_SEMANTIC_PASS_OUTPUT, i }))
|
||||
return false;
|
||||
|
||||
if (!set_unique_map(common.texture_semantic_map, name + "Feedback",
|
||||
slang_texture_semantic_map{ SLANG_TEXTURE_SEMANTIC_PASS_FEEDBACK, i }))
|
||||
return false;
|
||||
|
||||
if (!set_unique_map(common.texture_semantic_uniform_map, name + "FeedbackSize",
|
||||
slang_texture_semantic_map{ SLANG_TEXTURE_SEMANTIC_PASS_FEEDBACK, i }))
|
||||
return false;
|
||||
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vulkan_filter_chain::init()
|
||||
{
|
||||
Size2D source = max_input_size;
|
||||
|
||||
if (!init_alias())
|
||||
return false;
|
||||
for (unsigned i = 0; i < passes.size(); i++)
|
||||
{
|
||||
auto &pass = passes[i];
|
||||
RARCH_LOG("[slang]: Building pass #%u (%s)\n", i, pass->get_name().empty() ? "N/A" : pass->get_name().c_str());
|
||||
|
||||
source = pass->set_pass_info(max_input_size,
|
||||
source, swapchain_info, pass_info[i]);
|
||||
if (!pass->build())
|
||||
@ -1273,6 +1384,11 @@ bool Pass::build()
|
||||
}
|
||||
|
||||
reflection = slang_reflection{};
|
||||
reflection.pass_number = pass_number;
|
||||
reflection.texture_semantic_map = &common->texture_semantic_map;
|
||||
reflection.texture_semantic_uniform_map = &common->texture_semantic_uniform_map;
|
||||
reflection.semantic_map = &common->semantic_map;
|
||||
|
||||
if (!slang_reflect_spirv(vertex_shader, fragment_shader, &reflection))
|
||||
return false;
|
||||
|
||||
@ -1378,6 +1494,13 @@ void Pass::build_semantic_vec4(uint8_t *data, slang_semantic semantic,
|
||||
}
|
||||
}
|
||||
|
||||
void Pass::build_semantic_uint(uint8_t *data, slang_semantic semantic,
|
||||
uint32_t value)
|
||||
{
|
||||
if (data && reflection.semantics[semantic].uniform)
|
||||
*reinterpret_cast<uint32_t*>(data + reflection.semantics[semantic].ubo_offset) = value;
|
||||
}
|
||||
|
||||
void Pass::build_semantic_texture(VkDescriptorSet set, uint8_t *buffer,
|
||||
slang_texture_semantic semantic, const Texture &texture)
|
||||
{
|
||||
@ -1412,6 +1535,8 @@ void Pass::build_semantics(VkDescriptorSet set, uint8_t *buffer,
|
||||
current_framebuffer_size.width, current_framebuffer_size.height);
|
||||
build_semantic_vec4(buffer, SLANG_SEMANTIC_FINAL_VIEWPORT,
|
||||
unsigned(current_viewport.width), unsigned(current_viewport.height));
|
||||
build_semantic_uint(buffer, SLANG_SEMANTIC_FRAME_COUNT,
|
||||
frame_count_period ? uint32_t(frame_count % frame_count_period) : uint32_t(frame_count));
|
||||
|
||||
// Standard inputs
|
||||
build_semantic_texture(set, buffer, SLANG_TEXTURE_SEMANTIC_ORIGINAL, original);
|
||||
@ -1908,6 +2033,15 @@ vulkan_filter_chain_t *vulkan_filter_chain_create_from_preset(
|
||||
output.fragment.data(),
|
||||
output.fragment.size());
|
||||
|
||||
chain->set_frame_count_period(i, pass->frame_count_mod);
|
||||
|
||||
if (!output.meta.name.empty())
|
||||
chain->set_pass_name(i, output.meta.name.c_str());
|
||||
|
||||
// Preset overrides.
|
||||
if (*pass->alias)
|
||||
chain->set_pass_name(i, pass->alias);
|
||||
|
||||
if (pass->filter == RARCH_FILTER_UNSPEC)
|
||||
pass_info.source_filter = filter;
|
||||
else
|
||||
@ -2067,6 +2201,29 @@ void vulkan_filter_chain_set_input_texture(
|
||||
chain->set_input_texture(*texture);
|
||||
}
|
||||
|
||||
void vulkan_filter_chain_set_frame_count(
|
||||
vulkan_filter_chain_t *chain,
|
||||
uint64_t count)
|
||||
{
|
||||
chain->set_frame_count(count);
|
||||
}
|
||||
|
||||
void vulkan_filter_chain_set_frame_count_period(
|
||||
vulkan_filter_chain_t *chain,
|
||||
unsigned pass,
|
||||
unsigned period)
|
||||
{
|
||||
chain->set_frame_count_period(pass, period);
|
||||
}
|
||||
|
||||
void vulkan_filter_chain_set_pass_name(
|
||||
vulkan_filter_chain_t *chain,
|
||||
unsigned pass,
|
||||
const char *name)
|
||||
{
|
||||
chain->set_pass_name(pass, name);
|
||||
}
|
||||
|
||||
void vulkan_filter_chain_build_offscreen_passes(
|
||||
vulkan_filter_chain_t *chain,
|
||||
VkCommandBuffer cmd, const VkViewport *vp)
|
||||
|
@ -116,6 +116,17 @@ bool vulkan_filter_chain_init(vulkan_filter_chain_t *chain);
|
||||
void vulkan_filter_chain_set_input_texture(vulkan_filter_chain_t *chain,
|
||||
const struct vulkan_filter_chain_texture *texture);
|
||||
|
||||
void vulkan_filter_chain_set_frame_count(vulkan_filter_chain_t *chain,
|
||||
uint64_t count);
|
||||
|
||||
void vulkan_filter_chain_set_frame_count_period(vulkan_filter_chain_t *chain,
|
||||
unsigned pass,
|
||||
unsigned period);
|
||||
|
||||
void vulkan_filter_chain_set_pass_name(vulkan_filter_chain_t *chain,
|
||||
unsigned pass,
|
||||
const char *name);
|
||||
|
||||
void vulkan_filter_chain_build_offscreen_passes(vulkan_filter_chain_t *chain,
|
||||
VkCommandBuffer cmd, const VkViewport *vp);
|
||||
void vulkan_filter_chain_build_viewport_pass(vulkan_filter_chain_t *chain,
|
||||
|
@ -68,6 +68,7 @@ static const char *semantic_uniform_names[] = {
|
||||
"MVP",
|
||||
"OutputSize",
|
||||
"FinalViewportSize",
|
||||
"FrameCount",
|
||||
};
|
||||
|
||||
static slang_texture_semantic slang_name_to_texture_semantic_array(const string &name, const char **names,
|
||||
@ -101,18 +102,42 @@ static slang_texture_semantic slang_name_to_texture_semantic_array(const string
|
||||
return SLANG_INVALID_TEXTURE_SEMANTIC;
|
||||
}
|
||||
|
||||
static slang_texture_semantic slang_name_to_texture_semantic(const string &name, unsigned *index)
|
||||
static slang_texture_semantic slang_name_to_texture_semantic(
|
||||
const unordered_map<string, slang_texture_semantic_map> &semantic_map,
|
||||
const string &name, unsigned *index)
|
||||
{
|
||||
auto itr = semantic_map.find(name);
|
||||
if (itr != end(semantic_map))
|
||||
{
|
||||
*index = itr->second.index;
|
||||
return itr->second.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)
|
||||
static slang_texture_semantic slang_uniform_name_to_texture_semantic(
|
||||
const unordered_map<string, slang_texture_semantic_map> &semantic_map,
|
||||
const string &name, unsigned *index)
|
||||
{
|
||||
auto itr = semantic_map.find(name);
|
||||
if (itr != end(semantic_map))
|
||||
{
|
||||
*index = itr->second.index;
|
||||
return itr->second.semantic;
|
||||
}
|
||||
|
||||
return slang_name_to_texture_semantic_array(name, texture_semantic_uniform_names, index);
|
||||
}
|
||||
|
||||
static slang_semantic slang_uniform_name_to_semantic(const string &name)
|
||||
static slang_semantic slang_uniform_name_to_semantic(
|
||||
const unordered_map<string, slang_semantic> &semantic_map,
|
||||
const string &name)
|
||||
{
|
||||
auto itr = semantic_map.find(name);
|
||||
if (itr != end(semantic_map))
|
||||
return itr->second;
|
||||
|
||||
unsigned i = 0;
|
||||
for (auto n : semantic_uniform_names)
|
||||
{
|
||||
@ -198,6 +223,10 @@ static bool validate_type_for_semantic(const SPIRType &type, slang_semantic sem)
|
||||
// mat4
|
||||
return type.basetype == SPIRType::Float && type.vecsize == 4 && type.columns == 4;
|
||||
|
||||
case SLANG_SEMANTIC_FRAME_COUNT:
|
||||
// uint
|
||||
return type.basetype == SPIRType::UInt && type.vecsize == 1 && type.columns == 1;
|
||||
|
||||
default:
|
||||
// vec4
|
||||
return type.basetype == SPIRType::Float && type.vecsize == 4 && type.columns == 1;
|
||||
@ -222,8 +251,16 @@ static bool add_active_buffer_ranges(const Compiler &compiler, const Resource &r
|
||||
auto &type = compiler.get_type(compiler.get_type(resource.type_id).member_types[range.index]);
|
||||
|
||||
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);
|
||||
auto sem = slang_uniform_name_to_semantic(*reflection->semantic_map, name);
|
||||
auto tex_sem = slang_uniform_name_to_texture_semantic(*reflection->texture_semantic_uniform_map,
|
||||
name, &tex_sem_index);
|
||||
|
||||
if (tex_sem == SLANG_TEXTURE_SEMANTIC_PASS_OUTPUT && tex_sem_index >= reflection->pass_number)
|
||||
{
|
||||
RARCH_ERR("[slang]: Non causal filter chain detected. Shader is trying to use output from pass #%u, but this shader is pass #%u.\n",
|
||||
tex_sem_index, reflection->pass_number);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sem != SLANG_INVALID_SEMANTIC)
|
||||
{
|
||||
@ -250,6 +287,8 @@ static bool add_active_buffer_ranges(const Compiler &compiler, const Resource &r
|
||||
else
|
||||
{
|
||||
// TODO: Handle invalid semantics as user defined.
|
||||
RARCH_ERR("[slang]: Unknown semantic found.\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@ -412,7 +451,8 @@ static bool slang_reflect(const Compiler &vertex_compiler, const Compiler &fragm
|
||||
binding_mask |= 1 << binding;
|
||||
|
||||
unsigned array_index = 0;
|
||||
slang_texture_semantic index = slang_name_to_texture_semantic(texture.name, &array_index);
|
||||
slang_texture_semantic index = slang_name_to_texture_semantic(*reflection->texture_semantic_map,
|
||||
texture.name, &array_index);
|
||||
|
||||
if (index == SLANG_INVALID_TEXTURE_SEMANTIC)
|
||||
{
|
||||
|
@ -17,6 +17,7 @@
|
||||
#define SLANG_REFLECTION_HPP
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <stdint.h>
|
||||
|
||||
// Textures with built-in meaning.
|
||||
@ -56,6 +57,7 @@ enum slang_semantic
|
||||
SLANG_SEMANTIC_MVP = 0,
|
||||
SLANG_SEMANTIC_OUTPUT = 1,
|
||||
SLANG_SEMANTIC_FINAL_VIEWPORT = 2,
|
||||
SLANG_SEMANTIC_FRAME_COUNT = 3,
|
||||
|
||||
SLANG_NUM_SEMANTICS,
|
||||
SLANG_INVALID_SEMANTIC = -1
|
||||
@ -87,6 +89,12 @@ struct slang_semantic_meta
|
||||
bool uniform = false;
|
||||
};
|
||||
|
||||
struct slang_texture_semantic_map
|
||||
{
|
||||
slang_texture_semantic semantic;
|
||||
unsigned index;
|
||||
};
|
||||
|
||||
struct slang_reflection
|
||||
{
|
||||
slang_reflection();
|
||||
@ -97,6 +105,11 @@ struct slang_reflection
|
||||
|
||||
std::vector<slang_texture_semantic_meta> semantic_textures[SLANG_NUM_TEXTURE_SEMANTICS];
|
||||
slang_semantic_meta semantics[SLANG_NUM_SEMANTICS];
|
||||
|
||||
const std::unordered_map<std::string, slang_texture_semantic_map> *texture_semantic_map = nullptr;
|
||||
const std::unordered_map<std::string, slang_texture_semantic_map> *texture_semantic_uniform_map = nullptr;
|
||||
const std::unordered_map<std::string, slang_semantic> *semantic_map = nullptr;
|
||||
unsigned pass_number = 0;
|
||||
};
|
||||
|
||||
bool slang_reflect_spirv(const std::vector<uint32_t> &vertex,
|
||||
|
Loading…
Reference in New Issue
Block a user