mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-05 22:41:25 +12:00
vk: Implement optimized pipeline cache
This commit is contained in:
parent
bc5c4c9205
commit
fc5b4026e1
4 changed files with 163 additions and 53 deletions
|
@ -573,6 +573,12 @@ void VKGSRender::bind_texture_env()
|
||||||
|
|
||||||
void VKGSRender::bind_interpreter_texture_env()
|
void VKGSRender::bind_interpreter_texture_env()
|
||||||
{
|
{
|
||||||
|
if (current_fp_metadata.referenced_textures_mask == 0)
|
||||||
|
{
|
||||||
|
// Nothing to do
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::array<VkDescriptorImageInfo, 68> texture_env;
|
std::array<VkDescriptorImageInfo, 68> texture_env;
|
||||||
VkDescriptorImageInfo fallback = { vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, VK_IMAGE_VIEW_TYPE_1D)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL };
|
VkDescriptorImageInfo fallback = { vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, VK_IMAGE_VIEW_TYPE_1D)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL };
|
||||||
|
|
||||||
|
|
|
@ -1573,22 +1573,12 @@ bool VKGSRender::load_program()
|
||||||
}
|
}
|
||||||
|
|
||||||
properties.renderpass_key = m_current_renderpass_key;
|
properties.renderpass_key = m_current_renderpass_key;
|
||||||
vk::glsl::program* active_interpreter = nullptr;
|
if (!m_interpreter_state && m_program) [[likely]]
|
||||||
|
{
|
||||||
if (!m_interpreter_state && m_pipeline_properties == properties) [[likely]]
|
if (!m_shader_interpreter.is_interpreter(m_program) &&
|
||||||
|
m_pipeline_properties == properties)
|
||||||
{
|
{
|
||||||
// Nothing changed
|
// Nothing changed
|
||||||
if (m_shader_interpreter.is_interpreter(m_program))
|
|
||||||
{
|
|
||||||
if (g_cfg.video.shader_interpreter_mode == shader_interpreter_mode::forced)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
active_interpreter = m_program;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1638,14 +1628,7 @@ bool VKGSRender::load_program()
|
||||||
m_interpreter_state = rsx::invalidate_pipeline_bits;
|
m_interpreter_state = rsx::invalidate_pipeline_bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (active_interpreter) [[likely]]
|
m_program = m_shader_interpreter.get(properties, current_fp_metadata);
|
||||||
{
|
|
||||||
m_program = active_interpreter;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_program = m_shader_interpreter.get(properties);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_pipeline_properties = properties;
|
m_pipeline_properties = properties;
|
||||||
|
|
|
@ -80,7 +80,7 @@ namespace vk
|
||||||
// TODO: Bind textures if needed
|
// TODO: Bind textures if needed
|
||||||
}
|
}
|
||||||
|
|
||||||
void shader_interpreter::build_fs()
|
glsl::shader* shader_interpreter::build_fs(u64 compiler_options)
|
||||||
{
|
{
|
||||||
::glsl::shader_properties properties{};
|
::glsl::shader_properties properties{};
|
||||||
properties.domain = ::glsl::program_domain::glsl_fragment_program;
|
properties.domain = ::glsl::program_domain::glsl_fragment_program;
|
||||||
|
@ -102,7 +102,51 @@ namespace vk
|
||||||
::glsl::insert_subheader_block(builder);
|
::glsl::insert_subheader_block(builder);
|
||||||
comp.insertConstants(builder);
|
comp.insertConstants(builder);
|
||||||
|
|
||||||
|
if (compiler_options & program_common::interpreter::COMPILER_OPT_ENABLE_ALPHA_TEST_GE)
|
||||||
|
{
|
||||||
|
builder << "#define ALPHA_TEST_GEQUAL\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compiler_options & program_common::interpreter::COMPILER_OPT_ENABLE_ALPHA_TEST_G)
|
||||||
|
{
|
||||||
|
builder << "#define ALPHA_TEST_GREATER\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compiler_options & program_common::interpreter::COMPILER_OPT_ENABLE_ALPHA_TEST_LE)
|
||||||
|
{
|
||||||
|
builder << "#define ALPHA_TEST_LEQUAL\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compiler_options & program_common::interpreter::COMPILER_OPT_ENABLE_ALPHA_TEST_L)
|
||||||
|
{
|
||||||
|
builder << "#define ALPHA_TEST_LESS\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compiler_options & program_common::interpreter::COMPILER_OPT_ENABLE_ALPHA_TEST_EQ)
|
||||||
|
{
|
||||||
|
builder << "#define ALPHA_TEST_EQUAL\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compiler_options & program_common::interpreter::COMPILER_OPT_ENABLE_ALPHA_TEST_NE)
|
||||||
|
{
|
||||||
|
builder << "#define ALPHA_TEST_NEQUAL\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(compiler_options & program_common::interpreter::COMPILER_OPT_ENABLE_F32_EXPORT))
|
||||||
|
{
|
||||||
|
builder << "#define WITH_HALF_OUTPUT_REGISTER\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compiler_options & program_common::interpreter::COMPILER_OPT_ENABLE_DEPTH_EXPORT)
|
||||||
|
{
|
||||||
|
builder << "#define WITH_DEPTH_EXPORT\n";
|
||||||
|
}
|
||||||
|
|
||||||
const char* type_names[] = { "sampler1D", "sampler2D", "sampler3D", "samplerCube" };
|
const char* type_names[] = { "sampler1D", "sampler2D", "sampler3D", "samplerCube" };
|
||||||
|
if (compiler_options & program_common::interpreter::COMPILER_OPT_ENABLE_TEXTURES)
|
||||||
|
{
|
||||||
|
builder << "#define WITH_TEXTURES\n\n";
|
||||||
|
|
||||||
for (int i = 0, bind_location = m_fragment_textures_start; i < 4; ++i)
|
for (int i = 0, bind_location = m_fragment_textures_start; i < 4; ++i)
|
||||||
{
|
{
|
||||||
builder << "layout(set=0, binding=" << bind_location++ << ") " << "uniform " << type_names[i] << " " << type_names[i] << "_array[16];\n";
|
builder << "layout(set=0, binding=" << bind_location++ << ") " << "uniform " << type_names[i] << " " << type_names[i] << "_array[16];\n";
|
||||||
|
@ -114,6 +158,7 @@ namespace vk
|
||||||
"#define SAMPLER2D(index) sampler2D_array[index]\n"
|
"#define SAMPLER2D(index) sampler2D_array[index]\n"
|
||||||
"#define SAMPLER3D(index) sampler3D_array[index]\n"
|
"#define SAMPLER3D(index) sampler3D_array[index]\n"
|
||||||
"#define SAMPLERCUBE(index) samplerCube_array[index]\n\n";
|
"#define SAMPLERCUBE(index) samplerCube_array[index]\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
builder <<
|
builder <<
|
||||||
"layout(std430, binding=" << m_fragment_instruction_start << ") readonly restrict buffer FragmentInstructionBlock\n"
|
"layout(std430, binding=" << m_fragment_instruction_start << ") readonly restrict buffer FragmentInstructionBlock\n"
|
||||||
|
@ -130,8 +175,9 @@ namespace vk
|
||||||
builder << program_common::interpreter::get_fragment_interpreter();
|
builder << program_common::interpreter::get_fragment_interpreter();
|
||||||
const std::string s = builder.str();
|
const std::string s = builder.str();
|
||||||
|
|
||||||
m_fs.create(::glsl::program_domain::glsl_fragment_program, s);
|
auto fs = new glsl::shader();
|
||||||
m_fs.compile();
|
fs->create(::glsl::program_domain::glsl_fragment_program, s);
|
||||||
|
fs->compile();
|
||||||
|
|
||||||
// Prepare input table
|
// Prepare input table
|
||||||
const auto& binding_table = vk::get_current_renderer()->get_pipeline_binding_table();
|
const auto& binding_table = vk::get_current_renderer()->get_pipeline_binding_table();
|
||||||
|
@ -156,6 +202,9 @@ namespace vk
|
||||||
in.name = std::string(type_names[i]) + "_array[16]";
|
in.name = std::string(type_names[i]) + "_array[16]";
|
||||||
m_fs_inputs.push_back(in);
|
m_fs_inputs.push_back(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_fs_cache[compiler_options].reset(fs);
|
||||||
|
return fs;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<VkDescriptorSetLayout, VkPipelineLayout> shader_interpreter::create_layout(VkDevice dev)
|
std::pair<VkDescriptorSetLayout, VkPipelineLayout> shader_interpreter::create_layout(VkDevice dev)
|
||||||
|
@ -319,19 +368,22 @@ namespace vk
|
||||||
create_descriptor_pools(dev);
|
create_descriptor_pools(dev);
|
||||||
|
|
||||||
build_vs();
|
build_vs();
|
||||||
build_fs();
|
|
||||||
|
|
||||||
// TODO: Seed the cache
|
// TODO: Seed the cache
|
||||||
}
|
}
|
||||||
|
|
||||||
void shader_interpreter::destroy()
|
void shader_interpreter::destroy()
|
||||||
{
|
{
|
||||||
m_vs.destroy();
|
|
||||||
m_fs.destroy();
|
|
||||||
|
|
||||||
m_program_cache.clear();
|
m_program_cache.clear();
|
||||||
m_descriptor_pool.destroy();
|
m_descriptor_pool.destroy();
|
||||||
|
|
||||||
|
for (auto &fs : m_fs_cache)
|
||||||
|
{
|
||||||
|
fs.second->destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_vs.destroy();
|
||||||
|
m_fs_cache.clear();
|
||||||
|
|
||||||
if (m_shared_pipeline_layout)
|
if (m_shared_pipeline_layout)
|
||||||
{
|
{
|
||||||
vkDestroyPipelineLayout(m_device, m_shared_pipeline_layout, nullptr);
|
vkDestroyPipelineLayout(m_device, m_shared_pipeline_layout, nullptr);
|
||||||
|
@ -345,8 +397,18 @@ namespace vk
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glsl::program* shader_interpreter::link(const vk::pipeline_props& properties)
|
glsl::program* shader_interpreter::link(const vk::pipeline_props& properties, u64 compiler_opt)
|
||||||
{
|
{
|
||||||
|
glsl::shader* fs;
|
||||||
|
if (auto found = m_fs_cache.find(compiler_opt); found != m_fs_cache.end())
|
||||||
|
{
|
||||||
|
fs = found->second.get();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fs = build_fs(compiler_opt);
|
||||||
|
}
|
||||||
|
|
||||||
VkPipelineShaderStageCreateInfo shader_stages[2] = {};
|
VkPipelineShaderStageCreateInfo shader_stages[2] = {};
|
||||||
shader_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
shader_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||||
shader_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
|
shader_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||||
|
@ -355,7 +417,7 @@ namespace vk
|
||||||
|
|
||||||
shader_stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
shader_stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||||
shader_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
shader_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
shader_stages[1].module = m_fs.get_handle();
|
shader_stages[1].module = fs->get_handle();
|
||||||
shader_stages[1].pName = "main";
|
shader_stages[1].pName = "main";
|
||||||
|
|
||||||
VkDynamicState dynamic_state_descriptors[VK_DYNAMIC_STATE_RANGE_SIZE] = {};
|
VkDynamicState dynamic_state_descriptors[VK_DYNAMIC_STATE_RANGE_SIZE] = {};
|
||||||
|
@ -462,17 +524,63 @@ namespace vk
|
||||||
return new_descriptor_set;
|
return new_descriptor_set;
|
||||||
}
|
}
|
||||||
|
|
||||||
glsl::program* shader_interpreter::get(const vk::pipeline_props& properties)
|
glsl::program* shader_interpreter::get(const vk::pipeline_props& properties, const program_hash_util::fragment_program_utils::fragment_program_metadata& metadata)
|
||||||
{
|
{
|
||||||
auto found = m_program_cache.find(properties);
|
pipeline_key key;
|
||||||
|
key.compiler_opt = 0;
|
||||||
|
key.properties = properties;
|
||||||
|
|
||||||
|
if (rsx::method_registers.alpha_test_enabled()) [[unlikely]]
|
||||||
|
{
|
||||||
|
switch (rsx::method_registers.alpha_func())
|
||||||
|
{
|
||||||
|
case rsx::comparison_function::always:
|
||||||
|
break;
|
||||||
|
case rsx::comparison_function::never:
|
||||||
|
return nullptr;
|
||||||
|
case rsx::comparison_function::greater_or_equal:
|
||||||
|
key.compiler_opt |= program_common::interpreter::COMPILER_OPT_ENABLE_ALPHA_TEST_GE;
|
||||||
|
break;
|
||||||
|
case rsx::comparison_function::greater:
|
||||||
|
key.compiler_opt |= program_common::interpreter::COMPILER_OPT_ENABLE_ALPHA_TEST_G;
|
||||||
|
break;
|
||||||
|
case rsx::comparison_function::less_or_equal:
|
||||||
|
key.compiler_opt |= program_common::interpreter::COMPILER_OPT_ENABLE_ALPHA_TEST_LE;
|
||||||
|
break;
|
||||||
|
case rsx::comparison_function::less:
|
||||||
|
key.compiler_opt |= program_common::interpreter::COMPILER_OPT_ENABLE_ALPHA_TEST_L;
|
||||||
|
break;
|
||||||
|
case rsx::comparison_function::equal:
|
||||||
|
key.compiler_opt |= program_common::interpreter::COMPILER_OPT_ENABLE_ALPHA_TEST_EQ;
|
||||||
|
break;
|
||||||
|
case rsx::comparison_function::not_equal:
|
||||||
|
key.compiler_opt |= program_common::interpreter::COMPILER_OPT_ENABLE_ALPHA_TEST_NE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rsx::method_registers.shader_control() & CELL_GCM_SHADER_CONTROL_DEPTH_EXPORT) key.compiler_opt |= program_common::interpreter::COMPILER_OPT_ENABLE_DEPTH_EXPORT;
|
||||||
|
if (rsx::method_registers.shader_control() & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS) key.compiler_opt |= program_common::interpreter::COMPILER_OPT_ENABLE_F32_EXPORT;
|
||||||
|
if (metadata.referenced_textures_mask) key.compiler_opt |= program_common::interpreter::COMPILER_OPT_ENABLE_TEXTURES;
|
||||||
|
|
||||||
|
if (m_current_key == key) [[likely]]
|
||||||
|
{
|
||||||
|
return m_current_interpreter;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_current_key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto found = m_program_cache.find(key);
|
||||||
if (found != m_program_cache.end()) [[likely]]
|
if (found != m_program_cache.end()) [[likely]]
|
||||||
{
|
{
|
||||||
m_current_interpreter = found->second.get();
|
m_current_interpreter = found->second.get();
|
||||||
return m_current_interpreter;
|
return m_current_interpreter;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_current_interpreter = link(properties);
|
m_current_interpreter = link(properties, key.compiler_opt);
|
||||||
m_program_cache[properties].reset(m_current_interpreter);
|
m_program_cache[key].reset(m_current_interpreter);
|
||||||
return m_current_interpreter;
|
return m_current_interpreter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ namespace vk
|
||||||
class shader_interpreter
|
class shader_interpreter
|
||||||
{
|
{
|
||||||
glsl::shader m_vs;
|
glsl::shader m_vs;
|
||||||
glsl::shader m_fs;
|
|
||||||
|
|
||||||
std::vector<glsl::program_input> m_vs_inputs;
|
std::vector<glsl::program_input> m_vs_inputs;
|
||||||
std::vector<glsl::program_input> m_fs_inputs;
|
std::vector<glsl::program_input> m_fs_inputs;
|
||||||
|
@ -19,15 +18,27 @@ namespace vk
|
||||||
VkPipelineLayout m_shared_pipeline_layout = VK_NULL_HANDLE;
|
VkPipelineLayout m_shared_pipeline_layout = VK_NULL_HANDLE;
|
||||||
glsl::program* m_current_interpreter = nullptr;
|
glsl::program* m_current_interpreter = nullptr;
|
||||||
|
|
||||||
struct key_hasher
|
struct pipeline_key
|
||||||
{
|
{
|
||||||
size_t operator()(const vk::pipeline_props& props) const
|
u64 compiler_opt;
|
||||||
|
vk::pipeline_props properties;
|
||||||
|
|
||||||
|
bool operator == (const pipeline_key& other) const
|
||||||
{
|
{
|
||||||
return rpcs3::hash_struct(props);
|
return other.compiler_opt == compiler_opt && other.properties == properties;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unordered_map<vk::pipeline_props, std::unique_ptr<glsl::program>, key_hasher> m_program_cache;
|
struct key_hasher
|
||||||
|
{
|
||||||
|
size_t operator()(const pipeline_key& key) const
|
||||||
|
{
|
||||||
|
return rpcs3::hash_struct(key.properties) ^ key.compiler_opt;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unordered_map<pipeline_key, std::unique_ptr<glsl::program>, key_hasher> m_program_cache;
|
||||||
|
std::unordered_map<u64, std::unique_ptr<glsl::shader>> m_fs_cache;
|
||||||
vk::descriptor_pool m_descriptor_pool;
|
vk::descriptor_pool m_descriptor_pool;
|
||||||
size_t m_used_descriptors = 0;
|
size_t m_used_descriptors = 0;
|
||||||
|
|
||||||
|
@ -35,18 +46,20 @@ namespace vk
|
||||||
uint32_t m_fragment_instruction_start = 0;
|
uint32_t m_fragment_instruction_start = 0;
|
||||||
uint32_t m_fragment_textures_start = 0;
|
uint32_t m_fragment_textures_start = 0;
|
||||||
|
|
||||||
|
pipeline_key m_current_key{};
|
||||||
|
|
||||||
std::pair<VkDescriptorSetLayout, VkPipelineLayout> create_layout(VkDevice dev);
|
std::pair<VkDescriptorSetLayout, VkPipelineLayout> create_layout(VkDevice dev);
|
||||||
void create_descriptor_pools(const vk::render_device& dev);
|
void create_descriptor_pools(const vk::render_device& dev);
|
||||||
|
|
||||||
void build_vs();
|
void build_vs();
|
||||||
void build_fs();
|
glsl::shader* build_fs(u64 compiler_opt);
|
||||||
glsl::program* link(const vk::pipeline_props& properties);
|
glsl::program* link(const vk::pipeline_props& properties, u64 compiler_opt);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void init(const vk::render_device& dev);
|
void init(const vk::render_device& dev);
|
||||||
void destroy();
|
void destroy();
|
||||||
|
|
||||||
glsl::program* get(const vk::pipeline_props& properties);
|
glsl::program* get(const vk::pipeline_props& properties, const program_hash_util::fragment_program_utils::fragment_program_metadata& metadata);
|
||||||
bool is_interpreter(const glsl::program* prog) const;
|
bool is_interpreter(const glsl::program* prog) const;
|
||||||
|
|
||||||
uint32_t get_vertex_instruction_location() const;
|
uint32_t get_vertex_instruction_location() const;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue