Merge pull request #2820 from Themaister/master

Vulkan: Further work on shader backend.
This commit is contained in:
Twinaphex 2016-03-26 18:46:41 +01:00
commit 786bdacd4c
7 changed files with 270 additions and 9 deletions

View File

@ -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. */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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