mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-02 13:01:27 +12:00
vk: Move descriptor management to the pipeline layer
- Frees up callers from managing descriptors themselves (ewww) - Makes descriptor reuse possible - Opens up the door to techniques like descriptor_buffer by abstracting away management to an implementation detail
This commit is contained in:
parent
329655a1bf
commit
49729086ac
19 changed files with 677 additions and 539 deletions
|
@ -8,64 +8,41 @@
|
|||
|
||||
namespace vk
|
||||
{
|
||||
std::vector<std::pair<VkDescriptorType, u8>> compute_task::get_descriptor_layout()
|
||||
std::vector<glsl::program_input> compute_task::get_inputs()
|
||||
{
|
||||
std::vector<std::pair<VkDescriptorType, u8>> result;
|
||||
result.emplace_back(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, ssbo_count);
|
||||
std::vector<glsl::program_input> result;
|
||||
for (unsigned i = 0; i < ssbo_count; ++i)
|
||||
{
|
||||
const auto input = glsl::program_input::make
|
||||
(
|
||||
::glsl::glsl_compute_program,
|
||||
"ssbo" + std::to_string(i),
|
||||
glsl::program_input_type::input_type_storage_buffer,
|
||||
i
|
||||
);
|
||||
result.push_back(input);
|
||||
}
|
||||
|
||||
if (use_push_constants && push_constants_size > 0)
|
||||
{
|
||||
const auto input = glsl::program_input::make
|
||||
(
|
||||
::glsl::glsl_compute_program,
|
||||
"push_constants",
|
||||
glsl::program_input_type::input_type_push_constant,
|
||||
0,
|
||||
glsl::push_constant_ref{ .offset = 0, .size = push_constants_size }
|
||||
);
|
||||
result.push_back(input);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void compute_task::init_descriptors()
|
||||
{
|
||||
rsx::simple_array<VkDescriptorPoolSize> descriptor_pool_sizes;
|
||||
rsx::simple_array<VkDescriptorSetLayoutBinding> bindings;
|
||||
|
||||
const auto layout = get_descriptor_layout();
|
||||
for (const auto &e : layout)
|
||||
{
|
||||
descriptor_pool_sizes.push_back({e.first, e.second});
|
||||
|
||||
for (unsigned n = 0; n < e.second; ++n)
|
||||
{
|
||||
bindings.push_back
|
||||
({
|
||||
u32(bindings.size()),
|
||||
e.first,
|
||||
1,
|
||||
VK_SHADER_STAGE_COMPUTE_BIT,
|
||||
nullptr
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Reserve descriptor pools
|
||||
m_descriptor_pool.create(*g_render_device, descriptor_pool_sizes);
|
||||
m_descriptor_layout = vk::descriptors::create_layout(bindings);
|
||||
|
||||
VkPipelineLayoutCreateInfo layout_info = {};
|
||||
layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||
layout_info.setLayoutCount = 1;
|
||||
layout_info.pSetLayouts = &m_descriptor_layout;
|
||||
|
||||
VkPushConstantRange push_constants{};
|
||||
if (use_push_constants)
|
||||
{
|
||||
push_constants.size = push_constants_size;
|
||||
push_constants.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
|
||||
|
||||
layout_info.pushConstantRangeCount = 1;
|
||||
layout_info.pPushConstantRanges = &push_constants;
|
||||
}
|
||||
|
||||
CHECK_RESULT(vkCreatePipelineLayout(*g_render_device, &layout_info, nullptr, &m_pipeline_layout));
|
||||
}
|
||||
|
||||
void compute_task::create()
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
init_descriptors();
|
||||
|
||||
switch (vk::get_driver_vendor())
|
||||
{
|
||||
case vk::driver_vendor::unknown:
|
||||
|
@ -121,10 +98,6 @@ namespace vk
|
|||
m_program.reset();
|
||||
m_param_buffer.reset();
|
||||
|
||||
vkDestroyDescriptorSetLayout(*g_render_device, m_descriptor_layout, nullptr);
|
||||
vkDestroyPipelineLayout(*g_render_device, m_pipeline_layout, nullptr);
|
||||
m_descriptor_pool.destroy();
|
||||
|
||||
initialized = false;
|
||||
}
|
||||
}
|
||||
|
@ -142,26 +115,23 @@ namespace vk
|
|||
shader_stage.module = handle;
|
||||
shader_stage.pName = "main";
|
||||
|
||||
VkComputePipelineCreateInfo info{};
|
||||
info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
|
||||
info.stage = shader_stage;
|
||||
info.layout = m_pipeline_layout;
|
||||
info.basePipelineIndex = -1;
|
||||
info.basePipelineHandle = VK_NULL_HANDLE;
|
||||
VkComputePipelineCreateInfo create_info
|
||||
{
|
||||
.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
|
||||
.stage = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
.stage = VK_SHADER_STAGE_COMPUTE_BIT,
|
||||
.module = handle,
|
||||
.pName = "main"
|
||||
},
|
||||
};
|
||||
|
||||
auto compiler = vk::get_pipe_compiler();
|
||||
m_program = compiler->compile(info, m_pipeline_layout, vk::pipe_compiler::COMPILE_INLINE);
|
||||
declare_inputs();
|
||||
m_program = compiler->compile(create_info, vk::pipe_compiler::COMPILE_INLINE, {}, get_inputs());
|
||||
}
|
||||
|
||||
ensure(m_used_descriptors < VK_MAX_COMPUTE_TASKS);
|
||||
|
||||
m_descriptor_set = m_descriptor_pool.allocate(m_descriptor_layout, VK_TRUE);
|
||||
|
||||
bind_resources();
|
||||
|
||||
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, m_program->pipeline);
|
||||
m_descriptor_set.bind(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, m_pipeline_layout);
|
||||
m_program->bind(cmd, VK_PIPELINE_BIND_POINT_COMPUTE);
|
||||
}
|
||||
|
||||
void compute_task::run(const vk::command_buffer& cmd, u32 invocations_x, u32 invocations_y, u32 invocations_z)
|
||||
|
@ -273,13 +243,13 @@ namespace vk
|
|||
|
||||
void cs_shuffle_base::bind_resources()
|
||||
{
|
||||
m_program->bind_buffer({ m_data->value, m_data_offset, m_data_length }, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_descriptor_set);
|
||||
m_program->bind_buffer({ m_data->value, m_data_offset, m_data_length }, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||
}
|
||||
|
||||
void cs_shuffle_base::set_parameters(const vk::command_buffer& cmd, const u32* params, u8 count)
|
||||
{
|
||||
ensure(use_push_constants);
|
||||
vkCmdPushConstants(cmd, m_pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, count * 4, params);
|
||||
vkCmdPushConstants(cmd, m_program->layout(), VK_SHADER_STAGE_COMPUTE_BIT, 0, count * 4, params);
|
||||
}
|
||||
|
||||
void cs_shuffle_base::run(const vk::command_buffer& cmd, const vk::buffer* data, u32 data_length, u32 data_offset)
|
||||
|
@ -319,7 +289,7 @@ namespace vk
|
|||
|
||||
void cs_interleave_task::bind_resources()
|
||||
{
|
||||
m_program->bind_buffer({ m_data->value, m_data_offset, m_ssbo_length }, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_descriptor_set);
|
||||
m_program->bind_buffer({ m_data->value, m_data_offset, m_ssbo_length }, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||
}
|
||||
|
||||
void cs_interleave_task::run(const vk::command_buffer& cmd, const vk::buffer* data, u32 data_offset, u32 data_length, u32 zeta_offset, u32 stencil_offset)
|
||||
|
@ -379,8 +349,8 @@ namespace vk
|
|||
|
||||
void cs_aggregator::bind_resources()
|
||||
{
|
||||
m_program->bind_buffer({ src->value, 0, block_length }, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_descriptor_set);
|
||||
m_program->bind_buffer({ dst->value, 0, 4 }, 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_descriptor_set);
|
||||
m_program->bind_buffer({ src->value, 0, block_length }, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||
m_program->bind_buffer({ dst->value, 0, 4 }, 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||
}
|
||||
|
||||
void cs_aggregator::run(const vk::command_buffer& cmd, const vk::buffer* dst, const vk::buffer* src, u32 num_words)
|
||||
|
|
|
@ -19,12 +19,6 @@ namespace vk
|
|||
std::unique_ptr<vk::glsl::program> m_program;
|
||||
std::unique_ptr<vk::buffer> m_param_buffer;
|
||||
|
||||
vk::descriptor_pool m_descriptor_pool;
|
||||
descriptor_set m_descriptor_set;
|
||||
VkDescriptorSetLayout m_descriptor_layout = nullptr;
|
||||
VkPipelineLayout m_pipeline_layout = nullptr;
|
||||
u32 m_used_descriptors = 0;
|
||||
|
||||
bool initialized = false;
|
||||
bool unroll_loops = true;
|
||||
bool use_push_constants = false;
|
||||
|
@ -37,15 +31,11 @@ namespace vk
|
|||
compute_task() = default;
|
||||
virtual ~compute_task() { destroy(); }
|
||||
|
||||
virtual std::vector<std::pair<VkDescriptorType, u8>> get_descriptor_layout();
|
||||
|
||||
void init_descriptors();
|
||||
|
||||
void create();
|
||||
void destroy();
|
||||
|
||||
virtual std::vector<glsl::program_input> get_inputs();
|
||||
virtual void bind_resources() {}
|
||||
virtual void declare_inputs() {}
|
||||
|
||||
void load_program(const vk::command_buffer& cmd);
|
||||
|
||||
|
@ -354,7 +344,7 @@ namespace vk
|
|||
|
||||
void bind_resources() override
|
||||
{
|
||||
m_program->bind_buffer({ m_data->value, m_data_offset, m_ssbo_length }, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_descriptor_set);
|
||||
m_program->bind_buffer({ m_data->value, m_data_offset, m_ssbo_length }, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||
}
|
||||
|
||||
void run(const vk::command_buffer& cmd, const vk::buffer* data, u32 src_offset, u32 src_length, u32 dst_offset)
|
||||
|
@ -455,13 +445,13 @@ namespace vk
|
|||
|
||||
void bind_resources() override
|
||||
{
|
||||
m_program->bind_buffer({ src_buffer->value, in_offset, block_length }, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_descriptor_set);
|
||||
m_program->bind_buffer({ dst_buffer->value, out_offset, block_length }, 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_descriptor_set);
|
||||
m_program->bind_buffer({ src_buffer->value, in_offset, block_length }, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||
m_program->bind_buffer({ dst_buffer->value, out_offset, block_length }, 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||
}
|
||||
|
||||
void set_parameters(const vk::command_buffer& cmd)
|
||||
{
|
||||
vkCmdPushConstants(cmd, m_pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, push_constants_size, params.data);
|
||||
vkCmdPushConstants(cmd, m_program->layout(), VK_SHADER_STAGE_COMPUTE_BIT, 0, push_constants_size, params.data);
|
||||
}
|
||||
|
||||
void run(const vk::command_buffer& cmd, const vk::buffer* dst, u32 out_offset, const vk::buffer* src, u32 in_offset, u32 data_length, u32 width, u32 height, u32 depth, u32 mipmaps) override
|
||||
|
@ -584,13 +574,13 @@ namespace vk
|
|||
void bind_resources() override
|
||||
{
|
||||
const auto op = static_cast<int>(Op);
|
||||
m_program->bind_buffer({ src_buffer->value, in_offset, in_block_length }, 0 ^ op, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_descriptor_set);
|
||||
m_program->bind_buffer({ dst_buffer->value, out_offset, out_block_length }, 1 ^ op, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_descriptor_set);
|
||||
m_program->bind_buffer({ src_buffer->value, in_offset, in_block_length }, 0 ^ op, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||
m_program->bind_buffer({ dst_buffer->value, out_offset, out_block_length }, 1 ^ op, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||
}
|
||||
|
||||
void set_parameters(const vk::command_buffer& cmd)
|
||||
{
|
||||
vkCmdPushConstants(cmd, m_pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, push_constants_size, ¶ms);
|
||||
vkCmdPushConstants(cmd, m_program->layout(), VK_SHADER_STAGE_COMPUTE_BIT, 0, push_constants_size, ¶ms);
|
||||
}
|
||||
|
||||
void run(const vk::command_buffer& cmd, const RSX_detiler_config& config)
|
||||
|
|
|
@ -555,8 +555,7 @@ bool VKGSRender::bind_texture_env()
|
|||
{
|
||||
m_program->bind_uniform({ fs_sampler_handles[i]->value, view->value, view->image()->current_layout },
|
||||
i,
|
||||
::glsl::program_domain::glsl_fragment_program,
|
||||
m_current_frame->descriptor_set);
|
||||
::glsl::program_domain::glsl_fragment_program);
|
||||
|
||||
if (current_fragment_program.texture_state.redirected_textures & (1 << i))
|
||||
{
|
||||
|
@ -578,7 +577,6 @@ bool VKGSRender::bind_texture_env()
|
|||
m_program->bind_uniform({ m_stencil_mirror_sampler->value, stencil_view->value, stencil_view->image()->current_layout },
|
||||
i,
|
||||
::glsl::program_domain::glsl_fragment_program,
|
||||
m_current_frame->descriptor_set,
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
@ -587,15 +585,13 @@ bool VKGSRender::bind_texture_env()
|
|||
const VkImageViewType view_type = vk::get_view_type(current_fragment_program.get_texture_dimension(i));
|
||||
m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL },
|
||||
i,
|
||||
::glsl::program_domain::glsl_fragment_program,
|
||||
m_current_frame->descriptor_set);
|
||||
::glsl::program_domain::glsl_fragment_program);
|
||||
|
||||
if (current_fragment_program.texture_state.redirected_textures & (1 << i))
|
||||
{
|
||||
m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL },
|
||||
i,
|
||||
::glsl::program_domain::glsl_fragment_program,
|
||||
m_current_frame->descriptor_set,
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
@ -611,8 +607,7 @@ bool VKGSRender::bind_texture_env()
|
|||
const auto view_type = vk::get_view_type(current_vertex_program.get_texture_dimension(i));
|
||||
m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL },
|
||||
i,
|
||||
::glsl::program_domain::glsl_vertex_program,
|
||||
m_current_frame->descriptor_set);
|
||||
::glsl::program_domain::glsl_vertex_program);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
@ -635,8 +630,7 @@ bool VKGSRender::bind_texture_env()
|
|||
|
||||
m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL },
|
||||
i,
|
||||
::glsl::program_domain::glsl_vertex_program,
|
||||
m_current_frame->descriptor_set);
|
||||
::glsl::program_domain::glsl_vertex_program);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
@ -645,8 +639,7 @@ bool VKGSRender::bind_texture_env()
|
|||
|
||||
m_program->bind_uniform({ vs_sampler_handles[i]->value, image_ptr->value, image_ptr->image()->current_layout },
|
||||
i,
|
||||
::glsl::program_domain::glsl_vertex_program,
|
||||
m_current_frame->descriptor_set);
|
||||
::glsl::program_domain::glsl_vertex_program);
|
||||
}
|
||||
|
||||
return out_of_memory;
|
||||
|
@ -721,7 +714,7 @@ bool VKGSRender::bind_interpreter_texture_env()
|
|||
}
|
||||
}
|
||||
|
||||
m_shader_interpreter.update_fragment_textures(texture_env, m_current_frame->descriptor_set);
|
||||
m_shader_interpreter.update_fragment_textures(texture_env);
|
||||
return out_of_memory;
|
||||
}
|
||||
|
||||
|
@ -850,6 +843,7 @@ void VKGSRender::emit_geometry(u32 sub_index)
|
|||
}
|
||||
else if (persistent_buffer != old_persistent_buffer || volatile_buffer != old_volatile_buffer)
|
||||
{
|
||||
/*
|
||||
// Need to update descriptors; make a copy for the next draw
|
||||
VkDescriptorSet previous_set = m_current_frame->descriptor_set.value();
|
||||
m_current_frame->descriptor_set.flush();
|
||||
|
@ -874,6 +868,8 @@ void VKGSRender::emit_geometry(u32 sub_index)
|
|||
|
||||
m_current_frame->descriptor_set.push(copy_cmds);
|
||||
update_descriptors = true;
|
||||
*/
|
||||
fmt::throw_exception("Not implemented");
|
||||
}
|
||||
|
||||
// Update vertex fetch parameters
|
||||
|
@ -882,9 +878,9 @@ void VKGSRender::emit_geometry(u32 sub_index)
|
|||
ensure(m_vertex_layout_storage);
|
||||
if (update_descriptors)
|
||||
{
|
||||
m_program->bind_uniform(persistent_buffer, binding_table.vertex_buffers_first_bind_slot, m_current_frame->descriptor_set);
|
||||
m_program->bind_uniform(volatile_buffer, binding_table.vertex_buffers_first_bind_slot + 1, m_current_frame->descriptor_set);
|
||||
m_program->bind_uniform(m_vertex_layout_storage->value, binding_table.vertex_buffers_first_bind_slot + 2, m_current_frame->descriptor_set);
|
||||
m_program->bind_uniform(persistent_buffer, binding_table.vertex_buffers_first_bind_slot);
|
||||
m_program->bind_uniform(volatile_buffer, binding_table.vertex_buffers_first_bind_slot + 1);
|
||||
m_program->bind_uniform(m_vertex_layout_storage->value, binding_table.vertex_buffers_first_bind_slot + 2);
|
||||
}
|
||||
|
||||
bool reload_state = (!m_current_draw.subdraw_id++);
|
||||
|
@ -908,10 +904,12 @@ void VKGSRender::emit_geometry(u32 sub_index)
|
|||
reload_state = true;
|
||||
});
|
||||
|
||||
// Bind both pipe and descriptors in one go
|
||||
// FIXME: We only need to rebind the pipeline when reload state is set. Flags?
|
||||
m_program->bind(*m_current_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS);
|
||||
|
||||
if (reload_state)
|
||||
{
|
||||
vkCmdBindPipeline(*m_current_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_program->pipeline);
|
||||
|
||||
update_draw_state();
|
||||
begin_render_pass();
|
||||
|
||||
|
@ -929,7 +927,6 @@ void VKGSRender::emit_geometry(u32 sub_index)
|
|||
}
|
||||
|
||||
// Bind the new set of descriptors for use with this draw call
|
||||
m_current_frame->descriptor_set.bind(*m_current_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_program->pipeline_layout);
|
||||
m_frame_stats.setup_time += m_profiler.duration();
|
||||
|
||||
if (!upload_info.index_info)
|
||||
|
@ -1083,9 +1080,6 @@ void VKGSRender::end()
|
|||
return;
|
||||
}
|
||||
|
||||
// Allocate descriptor set
|
||||
m_current_frame->descriptor_set = allocate_descriptor_set();
|
||||
|
||||
// Load program execution environment
|
||||
load_program_env();
|
||||
m_frame_stats.setup_time += m_profiler.duration();
|
||||
|
|
|
@ -492,10 +492,6 @@ VKGSRender::VKGSRender(utils::serial* ar) noexcept : GSRender(ar)
|
|||
m_secondary_command_buffer_pool.create((*m_device), m_device->get_graphics_queue_family());
|
||||
m_secondary_cb_list.create(m_secondary_command_buffer_pool, vk::command_buffer::access_type_hint::all);
|
||||
|
||||
//Precalculated stuff
|
||||
rsx::simple_array<VkDescriptorSetLayoutBinding> binding_layout;
|
||||
std::tie(m_pipeline_layout, m_descriptor_layouts, binding_layout) = vk::get_common_pipeline_layout(*m_device);
|
||||
|
||||
//Occlusion
|
||||
m_occlusion_query_manager = std::make_unique<vk::query_pool_manager>(*m_device, VK_QUERY_TYPE_OCCLUSION, OCCLUSION_MAX_POOL_SIZE);
|
||||
m_occlusion_map.resize(rsx::reports::occlusion_query_count);
|
||||
|
@ -508,11 +504,6 @@ VKGSRender::VKGSRender(utils::serial* ar) noexcept : GSRender(ar)
|
|||
m_occlusion_query_manager->set_control_flags(VK_QUERY_CONTROL_PRECISE_BIT, 0);
|
||||
}
|
||||
|
||||
// Generate frame contexts
|
||||
const u32 max_draw_calls = m_device->get_descriptor_max_draw_calls();
|
||||
const auto descriptor_type_sizes = vk::get_descriptor_pool_sizes(binding_layout);
|
||||
m_descriptor_pool.create(*m_device, descriptor_type_sizes, max_draw_calls);
|
||||
|
||||
VkSemaphoreCreateInfo semaphore_info = {};
|
||||
semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||
|
||||
|
@ -852,12 +843,6 @@ VKGSRender::~VKGSRender()
|
|||
|
||||
m_stencil_mirror_sampler.reset();
|
||||
|
||||
// Pipeline descriptors
|
||||
m_descriptor_pool.destroy();
|
||||
|
||||
vkDestroyPipelineLayout(*m_device, m_pipeline_layout, nullptr);
|
||||
vkDestroyDescriptorSetLayout(*m_device, m_descriptor_layouts, nullptr);
|
||||
|
||||
// Queries
|
||||
m_occlusion_query_manager.reset();
|
||||
m_cond_render_buffer.reset();
|
||||
|
@ -1157,18 +1142,6 @@ void VKGSRender::check_present_status()
|
|||
}
|
||||
}
|
||||
|
||||
VkDescriptorSet VKGSRender::allocate_descriptor_set()
|
||||
{
|
||||
if (!m_shader_interpreter.is_interpreter(m_program)) [[likely]]
|
||||
{
|
||||
return m_descriptor_pool.allocate(m_descriptor_layouts, VK_TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
return m_shader_interpreter.allocate_descriptor_set();
|
||||
}
|
||||
}
|
||||
|
||||
void VKGSRender::set_viewport()
|
||||
{
|
||||
const auto [clip_width, clip_height] = rsx::apply_resolution_scale<true>(
|
||||
|
@ -1242,7 +1215,7 @@ void VKGSRender::on_init_thread()
|
|||
if (!m_overlay_manager)
|
||||
{
|
||||
m_frame->hide();
|
||||
m_shaders_cache->load(nullptr, m_pipeline_layout);
|
||||
m_shaders_cache->load(nullptr);
|
||||
m_frame->show();
|
||||
}
|
||||
else
|
||||
|
@ -1250,7 +1223,7 @@ void VKGSRender::on_init_thread()
|
|||
rsx::shader_loading_dialog_native dlg(this);
|
||||
|
||||
// TODO: Handle window resize messages during loading on GPUs without OUT_OF_DATE_KHR support
|
||||
m_shaders_cache->load(&dlg, m_pipeline_layout);
|
||||
m_shaders_cache->load(&dlg);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1870,7 +1843,7 @@ bool VKGSRender::load_program()
|
|||
vertex_program,
|
||||
fragment_program,
|
||||
m_pipeline_properties,
|
||||
shadermode != shader_mode::recompiler, true, m_pipeline_layout);
|
||||
shadermode != shader_mode::recompiler, true);
|
||||
|
||||
vk::leave_uninterruptible();
|
||||
|
||||
|
@ -2103,32 +2076,32 @@ void VKGSRender::load_program_env()
|
|||
|
||||
const auto& binding_table = m_device->get_pipeline_binding_table();
|
||||
|
||||
m_program->bind_uniform(m_vertex_env_buffer_info, binding_table.vertex_params_bind_slot, m_current_frame->descriptor_set);
|
||||
m_program->bind_buffer(m_vertex_constants_buffer_info, binding_table.vertex_constant_buffers_bind_slot, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_current_frame->descriptor_set);
|
||||
m_program->bind_uniform(m_fragment_env_buffer_info, binding_table.fragment_state_bind_slot, m_current_frame->descriptor_set);
|
||||
m_program->bind_uniform(m_fragment_texture_params_buffer_info, binding_table.fragment_texture_params_bind_slot, m_current_frame->descriptor_set);
|
||||
m_program->bind_uniform(m_raster_env_buffer_info, binding_table.rasterizer_env_bind_slot, m_current_frame->descriptor_set);
|
||||
m_program->bind_uniform(m_vertex_env_buffer_info, binding_table.vertex_params_bind_slot);
|
||||
m_program->bind_buffer(m_vertex_constants_buffer_info, binding_table.vertex_constant_buffers_bind_slot, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||
m_program->bind_uniform(m_fragment_env_buffer_info, binding_table.fragment_state_bind_slot);
|
||||
m_program->bind_uniform(m_fragment_texture_params_buffer_info, binding_table.fragment_texture_params_bind_slot);
|
||||
m_program->bind_uniform(m_raster_env_buffer_info, binding_table.rasterizer_env_bind_slot);
|
||||
|
||||
if (!m_shader_interpreter.is_interpreter(m_program))
|
||||
{
|
||||
m_program->bind_uniform(m_fragment_constants_buffer_info, binding_table.fragment_constant_buffers_bind_slot, m_current_frame->descriptor_set);
|
||||
m_program->bind_uniform(m_fragment_constants_buffer_info, binding_table.fragment_constant_buffers_bind_slot);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_program->bind_buffer(m_vertex_instructions_buffer_info, m_shader_interpreter.get_vertex_instruction_location(), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_current_frame->descriptor_set);
|
||||
m_program->bind_buffer(m_fragment_instructions_buffer_info, m_shader_interpreter.get_fragment_instruction_location(), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_current_frame->descriptor_set);
|
||||
m_program->bind_buffer(m_vertex_instructions_buffer_info, m_shader_interpreter.get_vertex_instruction_location(), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||
m_program->bind_buffer(m_fragment_instructions_buffer_info, m_shader_interpreter.get_fragment_instruction_location(), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||
}
|
||||
|
||||
if (vk::emulate_conditional_rendering())
|
||||
{
|
||||
auto predicate = m_cond_render_buffer ? m_cond_render_buffer->value : vk::get_scratch_buffer(*m_current_command_buffer, 4)->value;
|
||||
m_program->bind_buffer({ predicate, 0, 4 }, binding_table.conditional_render_predicate_slot, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_current_frame->descriptor_set);
|
||||
m_program->bind_buffer({ predicate, 0, 4 }, binding_table.conditional_render_predicate_slot, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||
}
|
||||
|
||||
if (current_vertex_program.ctrl & RSX_SHADER_CONTROL_INSTANCED_CONSTANTS)
|
||||
{
|
||||
m_program->bind_buffer(m_instancing_indirection_buffer_info, binding_table.instancing_lookup_table_bind_slot, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_current_frame->descriptor_set);
|
||||
m_program->bind_buffer(m_instancing_constants_array_buffer_info, binding_table.instancing_constants_buffer_slot, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_current_frame->descriptor_set);
|
||||
m_program->bind_buffer(m_instancing_indirection_buffer_info, binding_table.instancing_lookup_table_bind_slot, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||
m_program->bind_buffer(m_instancing_constants_array_buffer_info, binding_table.instancing_constants_buffer_slot, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||
}
|
||||
|
||||
// Clear flags
|
||||
|
@ -2215,7 +2188,7 @@ void VKGSRender::update_vertex_env(u32 id, const vk::vertex_upload_info& vertex_
|
|||
|
||||
vkCmdPushConstants(
|
||||
*m_current_command_buffer,
|
||||
m_pipeline_layout,
|
||||
m_program->layout(),
|
||||
VK_SHADER_STAGE_VERTEX_BIT,
|
||||
0,
|
||||
data_length,
|
||||
|
|
|
@ -105,11 +105,6 @@ private:
|
|||
vk::command_buffer_chunk* m_current_command_buffer = nullptr;
|
||||
|
||||
std::unique_ptr<vk::buffer> m_host_object_data;
|
||||
|
||||
vk::descriptor_pool m_descriptor_pool;
|
||||
VkDescriptorSetLayout m_descriptor_layouts = VK_NULL_HANDLE;
|
||||
VkPipelineLayout m_pipeline_layout = VK_NULL_HANDLE;
|
||||
|
||||
vk::framebuffer_holder* m_draw_fbo = nullptr;
|
||||
|
||||
sizeu m_swapchain_dims{};
|
||||
|
@ -220,8 +215,6 @@ private:
|
|||
void update_draw_state();
|
||||
void check_present_status();
|
||||
|
||||
VkDescriptorSet allocate_descriptor_set();
|
||||
|
||||
vk::vertex_upload_info upload_vertex_data();
|
||||
rsx::simple_array<u8> m_scratch_mem;
|
||||
|
||||
|
|
|
@ -178,8 +178,6 @@ namespace vk
|
|||
VkSemaphore acquire_signal_semaphore = VK_NULL_HANDLE;
|
||||
VkSemaphore present_wait_semaphore = VK_NULL_HANDLE;
|
||||
|
||||
vk::descriptor_set descriptor_set;
|
||||
|
||||
rsx::flags32_t flags = 0;
|
||||
|
||||
u32 present_image = -1;
|
||||
|
@ -193,7 +191,6 @@ namespace vk
|
|||
{
|
||||
present_wait_semaphore = other.present_wait_semaphore;
|
||||
acquire_signal_semaphore = other.acquire_signal_semaphore;
|
||||
descriptor_set.swap(other.descriptor_set);
|
||||
flags = other.flags;
|
||||
heap_snapshot = other.heap_snapshot;
|
||||
}
|
||||
|
|
|
@ -47,77 +47,6 @@ namespace vk
|
|||
}
|
||||
}
|
||||
|
||||
void overlay_pass::init_descriptors()
|
||||
{
|
||||
rsx::simple_array<VkDescriptorPoolSize> descriptor_pool_sizes = {};
|
||||
|
||||
if (m_num_uniform_buffers)
|
||||
{
|
||||
descriptor_pool_sizes.push_back({ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, m_num_uniform_buffers });
|
||||
};
|
||||
|
||||
if (m_num_usable_samplers)
|
||||
{
|
||||
descriptor_pool_sizes.push_back({ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, m_num_usable_samplers });
|
||||
}
|
||||
|
||||
if (m_num_input_attachments)
|
||||
{
|
||||
descriptor_pool_sizes.push_back({ VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, m_num_input_attachments });
|
||||
}
|
||||
|
||||
// Reserve descriptor pools
|
||||
m_descriptor_pool.create(*m_device, descriptor_pool_sizes);
|
||||
|
||||
const auto num_bindings = m_num_uniform_buffers + m_num_usable_samplers + m_num_input_attachments;
|
||||
rsx::simple_array<VkDescriptorSetLayoutBinding> bindings(num_bindings);
|
||||
u32 binding_slot = 0;
|
||||
|
||||
for (u32 n = 0; n < m_num_uniform_buffers; ++n, ++binding_slot)
|
||||
{
|
||||
bindings[binding_slot].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
bindings[binding_slot].descriptorCount = 1;
|
||||
bindings[binding_slot].stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
bindings[binding_slot].binding = binding_slot;
|
||||
bindings[binding_slot].pImmutableSamplers = nullptr;
|
||||
}
|
||||
|
||||
for (u32 n = 0; n < m_num_usable_samplers; ++n, ++binding_slot)
|
||||
{
|
||||
bindings[binding_slot].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
bindings[binding_slot].descriptorCount = 1;
|
||||
bindings[binding_slot].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
bindings[binding_slot].binding = binding_slot;
|
||||
bindings[binding_slot].pImmutableSamplers = nullptr;
|
||||
}
|
||||
|
||||
for (u32 n = 0; n < m_num_input_attachments; ++n, ++binding_slot)
|
||||
{
|
||||
bindings[binding_slot].descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
|
||||
bindings[binding_slot].descriptorCount = 1;
|
||||
bindings[binding_slot].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
bindings[binding_slot].binding = binding_slot;
|
||||
bindings[binding_slot].pImmutableSamplers = nullptr;
|
||||
}
|
||||
|
||||
ensure(binding_slot == num_bindings);
|
||||
m_descriptor_layout = vk::descriptors::create_layout(bindings);
|
||||
|
||||
VkPipelineLayoutCreateInfo layout_info = {};
|
||||
layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||
layout_info.setLayoutCount = 1;
|
||||
layout_info.pSetLayouts = &m_descriptor_layout;
|
||||
|
||||
std::vector<VkPushConstantRange> push_constants = get_push_constants();
|
||||
if (!push_constants.empty())
|
||||
{
|
||||
layout_info.pushConstantRangeCount = u32(push_constants.size());
|
||||
layout_info.pPushConstantRanges = push_constants.data();
|
||||
}
|
||||
|
||||
CHECK_RESULT(vkCreatePipelineLayout(*m_device, &layout_info, nullptr, &m_pipeline_layout));
|
||||
}
|
||||
|
||||
std::vector<vk::glsl::program_input> overlay_pass::get_vertex_inputs()
|
||||
{
|
||||
check_heap();
|
||||
|
@ -126,23 +55,30 @@ namespace vk
|
|||
|
||||
std::vector<vk::glsl::program_input> overlay_pass::get_fragment_inputs()
|
||||
{
|
||||
std::vector<vk::glsl::program_input> fs_inputs;
|
||||
using namespace vk::glsl;
|
||||
|
||||
std::vector<program_input> fs_inputs;
|
||||
u32 binding = 0;
|
||||
|
||||
for (u32 n = 0; n < m_num_uniform_buffers; ++n, ++binding)
|
||||
{
|
||||
const std::string name = std::string("static_data") + (n > 0 ? std::to_string(n) : "");
|
||||
fs_inputs.push_back({ ::glsl::program_domain::glsl_fragment_program, vk::glsl::program_input_type::input_type_uniform_buffer,{},{}, 0, name });
|
||||
const auto input = program_input::make(::glsl::program_domain::glsl_fragment_program, name, program_input_type::input_type_uniform_buffer, 0);
|
||||
fs_inputs.push_back(input);
|
||||
}
|
||||
|
||||
for (u32 n = 0; n < m_num_usable_samplers; ++n, ++binding)
|
||||
{
|
||||
fs_inputs.push_back({ ::glsl::program_domain::glsl_fragment_program, vk::glsl::program_input_type::input_type_texture,{},{}, binding, "fs" + std::to_string(n) });
|
||||
const std::string name = "fs" + std::to_string(n);
|
||||
const auto input = program_input::make(::glsl::program_domain::glsl_fragment_program, name, program_input_type::input_type_texture, binding);
|
||||
fs_inputs.push_back(input);
|
||||
}
|
||||
|
||||
for (u32 n = 0; n < m_num_input_attachments; ++n, ++binding)
|
||||
{
|
||||
fs_inputs.push_back({ ::glsl::program_domain::glsl_fragment_program, vk::glsl::program_input_type::input_type_texture,{},{}, binding, "sp" + std::to_string(n) });
|
||||
const std::string name = "sp" + std::to_string(n);
|
||||
const auto input = program_input::make(::glsl::program_domain::glsl_fragment_program, name, program_input_type::input_type_texture, binding);
|
||||
fs_inputs.push_back(input);
|
||||
}
|
||||
|
||||
return fs_inputs;
|
||||
|
@ -208,20 +144,20 @@ namespace vk
|
|||
info.stageCount = 2;
|
||||
info.pStages = shader_stages;
|
||||
info.pDynamicState = &dynamic_state_info;
|
||||
info.layout = m_pipeline_layout;
|
||||
info.layout = VK_NULL_HANDLE;
|
||||
info.basePipelineIndex = -1;
|
||||
info.basePipelineHandle = VK_NULL_HANDLE;
|
||||
info.renderPass = render_pass;
|
||||
|
||||
auto compiler = vk::get_pipe_compiler();
|
||||
auto program = compiler->compile(info, m_pipeline_layout, vk::pipe_compiler::COMPILE_INLINE, {}, get_vertex_inputs(), get_fragment_inputs());
|
||||
auto program = compiler->compile(info, vk::pipe_compiler::COMPILE_INLINE, {}, get_vertex_inputs(), get_fragment_inputs());
|
||||
auto result = program.get();
|
||||
m_program_cache[storage_key] = std::move(program);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void overlay_pass::load_program(vk::command_buffer& cmd, VkRenderPass pass, const std::vector<vk::image_view*>& src)
|
||||
vk::glsl::program* overlay_pass::load_program(vk::command_buffer& cmd, VkRenderPass pass, const std::vector<vk::image_view*>& src)
|
||||
{
|
||||
vk::glsl::program *program = nullptr;
|
||||
const auto key = get_pipeline_key(pass);
|
||||
|
@ -232,8 +168,6 @@ namespace vk
|
|||
else
|
||||
program = build_pipeline(key, pass);
|
||||
|
||||
m_descriptor_set = m_descriptor_pool.allocate(m_descriptor_layout);
|
||||
|
||||
if (!m_sampler && !src.empty())
|
||||
{
|
||||
m_sampler = std::make_unique<vk::sampler>(*m_device,
|
||||
|
@ -245,21 +179,22 @@ namespace vk
|
|||
|
||||
if (m_num_uniform_buffers > 0)
|
||||
{
|
||||
program->bind_uniform({ m_ubo.heap->value, m_ubo_offset, std::max(m_ubo_length, 4u) }, 0, m_descriptor_set);
|
||||
program->bind_uniform({ m_ubo.heap->value, m_ubo_offset, std::max(m_ubo_length, 4u) }, 0);
|
||||
}
|
||||
|
||||
for (uint n = 0; n < src.size(); ++n)
|
||||
{
|
||||
VkDescriptorImageInfo info = { m_sampler->value, src[n]->value, src[n]->image()->current_layout };
|
||||
program->bind_uniform(info, "fs" + std::to_string(n), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, m_descriptor_set);
|
||||
program->bind_uniform(info, "fs" + std::to_string(n), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
|
||||
}
|
||||
|
||||
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, program->pipeline);
|
||||
m_descriptor_set.bind(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout);
|
||||
program->bind(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS);
|
||||
|
||||
VkBuffer buffers = m_vao.heap->value;
|
||||
VkDeviceSize offsets = m_vao_offset;
|
||||
vkCmdBindVertexBuffers(cmd, 0, 1, &buffers, &offsets);
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
void overlay_pass::create(const vk::render_device& dev)
|
||||
|
@ -267,8 +202,6 @@ namespace vk
|
|||
if (!initialized)
|
||||
{
|
||||
m_device = &dev;
|
||||
init_descriptors();
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
|
@ -282,10 +215,6 @@ namespace vk
|
|||
m_program_cache.clear();
|
||||
m_sampler.reset();
|
||||
|
||||
vkDestroyDescriptorSetLayout(*m_device, m_descriptor_layout, nullptr);
|
||||
vkDestroyPipelineLayout(*m_device, m_pipeline_layout, nullptr);
|
||||
m_descriptor_pool.destroy();
|
||||
|
||||
initialized = false;
|
||||
}
|
||||
}
|
||||
|
@ -303,7 +232,7 @@ namespace vk
|
|||
return vk::get_framebuffer(dev, target->width(), target->height(), m_num_input_attachments > 0, render_pass, { target });
|
||||
}
|
||||
|
||||
void overlay_pass::emit_geometry(vk::command_buffer& cmd)
|
||||
void overlay_pass::emit_geometry(vk::command_buffer& cmd, glsl::program* /*program*/)
|
||||
{
|
||||
vkCmdDraw(cmd, num_drawable_elements, 1, first_vertex, 0);
|
||||
}
|
||||
|
@ -328,11 +257,11 @@ namespace vk
|
|||
// This call clobbers dynamic state
|
||||
cmd.flags |= vk::command_buffer::cb_reload_dynamic_state;
|
||||
|
||||
load_program(cmd, render_pass, src);
|
||||
auto program = load_program(cmd, render_pass, src);
|
||||
set_up_viewport(cmd, viewport.x1, viewport.y1, viewport.width(), viewport.height());
|
||||
|
||||
vk::begin_renderpass(cmd, render_pass, fbo->value, { positionu{0u, 0u}, sizeu{fbo->width(), fbo->height()} });
|
||||
emit_geometry(cmd);
|
||||
emit_geometry(cmd, program);
|
||||
}
|
||||
|
||||
void overlay_pass::run(vk::command_buffer& cmd, const areau& viewport, vk::image* target, const std::vector<vk::image_view*>& src, VkRenderPass render_pass)
|
||||
|
@ -550,24 +479,37 @@ namespace vk
|
|||
false, true, desc->get_data(), owner_uid);
|
||||
}
|
||||
|
||||
std::vector<VkPushConstantRange> ui_overlay_renderer::get_push_constants()
|
||||
std::vector<vk::glsl::program_input> ui_overlay_renderer::get_vertex_inputs()
|
||||
{
|
||||
return
|
||||
{
|
||||
{
|
||||
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
||||
.offset = 0,
|
||||
.size = 68
|
||||
},
|
||||
{
|
||||
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
.offset = 68,
|
||||
.size = 12
|
||||
}
|
||||
};
|
||||
auto result = overlay_pass::get_vertex_inputs();
|
||||
result.push_back(
|
||||
glsl::program_input::make(
|
||||
::glsl::glsl_vertex_program,
|
||||
"push_constants",
|
||||
glsl::input_type_push_constant,
|
||||
0,
|
||||
glsl::push_constant_ref { .size = 68 }
|
||||
)
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
void ui_overlay_renderer::update_uniforms(vk::command_buffer& cmd, vk::glsl::program* /*program*/)
|
||||
std::vector<vk::glsl::program_input> ui_overlay_renderer::get_fragment_inputs()
|
||||
{
|
||||
auto result = overlay_pass::get_fragment_inputs();
|
||||
result.push_back(
|
||||
glsl::program_input::make(
|
||||
::glsl::glsl_fragment_program,
|
||||
"push_constants",
|
||||
glsl::input_type_push_constant,
|
||||
0,
|
||||
glsl::push_constant_ref {.offset = 68, .size = 12 }
|
||||
)
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
void ui_overlay_renderer::update_uniforms(vk::command_buffer& cmd, vk::glsl::program* program)
|
||||
{
|
||||
// Byte Layout
|
||||
// 00: vec4 ui_scale;
|
||||
|
@ -600,7 +542,7 @@ namespace vk
|
|||
.get();
|
||||
push_buf[16] = std::bit_cast<f32>(vert_config);
|
||||
|
||||
vkCmdPushConstants(cmd, m_pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 0, 68, push_buf);
|
||||
vkCmdPushConstants(cmd, program->layout(), VK_SHADER_STAGE_VERTEX_BIT, 0, 68, push_buf);
|
||||
|
||||
// 2. Fragment stuff
|
||||
rsx::overlays::fragment_options frag_opts;
|
||||
|
@ -614,7 +556,7 @@ namespace vk
|
|||
push_buf[1] = m_time;
|
||||
push_buf[2] = m_blur_strength;
|
||||
|
||||
vkCmdPushConstants(cmd, m_pipeline_layout, VK_SHADER_STAGE_FRAGMENT_BIT, 68, 12, push_buf);
|
||||
vkCmdPushConstants(cmd, program->layout(), VK_SHADER_STAGE_FRAGMENT_BIT, 68, 12, push_buf);
|
||||
}
|
||||
|
||||
void ui_overlay_renderer::set_primitive_type(rsx::overlays::primitive_type type)
|
||||
|
@ -641,7 +583,7 @@ namespace vk
|
|||
}
|
||||
}
|
||||
|
||||
void ui_overlay_renderer::emit_geometry(vk::command_buffer& cmd)
|
||||
void ui_overlay_renderer::emit_geometry(vk::command_buffer& cmd, glsl::program* program)
|
||||
{
|
||||
if (m_current_primitive_type == rsx::overlays::primitive_type::quad_list)
|
||||
{
|
||||
|
@ -657,7 +599,7 @@ namespace vk
|
|||
}
|
||||
else
|
||||
{
|
||||
overlay_pass::emit_geometry(cmd);
|
||||
overlay_pass::emit_geometry(cmd, program);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -764,17 +706,20 @@ namespace vk
|
|||
renderpass_config.set_attachment_count(1);
|
||||
}
|
||||
|
||||
std::vector<VkPushConstantRange> attachment_clear_pass::get_push_constants()
|
||||
std::vector<vk::glsl::program_input> attachment_clear_pass::get_vertex_inputs()
|
||||
{
|
||||
VkPushConstantRange constant;
|
||||
constant.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
constant.offset = 0;
|
||||
constant.size = 32;
|
||||
|
||||
return { constant };
|
||||
return
|
||||
{
|
||||
vk::glsl::program_input::make(
|
||||
::glsl::glsl_vertex_program,
|
||||
"push_constants",
|
||||
vk::glsl::input_type_push_constant,
|
||||
0,
|
||||
glsl::push_constant_ref{ .size = 32 })
|
||||
};
|
||||
}
|
||||
|
||||
void attachment_clear_pass::update_uniforms(vk::command_buffer& cmd, vk::glsl::program* /*program*/)
|
||||
void attachment_clear_pass::update_uniforms(vk::command_buffer& cmd, vk::glsl::program* program)
|
||||
{
|
||||
f32 data[8];
|
||||
data[0] = clear_color.r;
|
||||
|
@ -786,7 +731,7 @@ namespace vk
|
|||
data[6] = colormask.b;
|
||||
data[7] = colormask.a;
|
||||
|
||||
vkCmdPushConstants(cmd, m_pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 0, 32, data);
|
||||
vkCmdPushConstants(cmd, program->layout(), VK_SHADER_STAGE_VERTEX_BIT, 0, 32, data);
|
||||
}
|
||||
|
||||
void attachment_clear_pass::set_up_viewport(vk::command_buffer& cmd, u32 x, u32 y, u32 w, u32 h)
|
||||
|
@ -910,19 +855,24 @@ namespace vk
|
|||
m_num_usable_samplers = 2;
|
||||
}
|
||||
|
||||
std::vector<VkPushConstantRange> video_out_calibration_pass::get_push_constants()
|
||||
std::vector<vk::glsl::program_input> video_out_calibration_pass::get_fragment_inputs()
|
||||
{
|
||||
VkPushConstantRange constant;
|
||||
constant.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
constant.offset = 0;
|
||||
constant.size = 16;
|
||||
|
||||
return { constant };
|
||||
auto result = overlay_pass::get_fragment_inputs();
|
||||
result.push_back(
|
||||
vk::glsl::program_input::make(
|
||||
::glsl::glsl_fragment_program,
|
||||
"push_constants",
|
||||
vk::glsl::input_type_push_constant,
|
||||
0,
|
||||
glsl::push_constant_ref{ .size = 16 }
|
||||
)
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
void video_out_calibration_pass::update_uniforms(vk::command_buffer& cmd, vk::glsl::program* /*program*/)
|
||||
void video_out_calibration_pass::update_uniforms(vk::command_buffer& cmd, vk::glsl::program* program)
|
||||
{
|
||||
vkCmdPushConstants(cmd, m_pipeline_layout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, 16, config.data);
|
||||
vkCmdPushConstants(cmd, program->layout(), VK_SHADER_STAGE_FRAGMENT_BIT, 0, 16, config.data);
|
||||
}
|
||||
|
||||
void video_out_calibration_pass::run(vk::command_buffer& cmd, const areau& viewport, vk::framebuffer* target,
|
||||
|
|
|
@ -44,11 +44,6 @@ namespace vk
|
|||
vk::glsl::shader m_vertex_shader;
|
||||
vk::glsl::shader m_fragment_shader;
|
||||
|
||||
vk::descriptor_pool m_descriptor_pool;
|
||||
descriptor_set m_descriptor_set;
|
||||
VkDescriptorSetLayout m_descriptor_layout = nullptr;
|
||||
VkPipelineLayout m_pipeline_layout = nullptr;
|
||||
|
||||
VkFilter m_sampler_filter = VK_FILTER_LINEAR;
|
||||
u32 m_num_usable_samplers = 1;
|
||||
u32 m_num_input_attachments = 0;
|
||||
|
@ -83,8 +78,6 @@ namespace vk
|
|||
|
||||
void check_heap();
|
||||
|
||||
void init_descriptors();
|
||||
|
||||
virtual void update_uniforms(vk::command_buffer& /*cmd*/, vk::glsl::program* /*program*/) {}
|
||||
|
||||
virtual std::vector<vk::glsl::program_input> get_vertex_inputs();
|
||||
|
@ -92,11 +85,6 @@ namespace vk
|
|||
|
||||
virtual void get_dynamic_state_entries(std::vector<VkDynamicState>& /*state_descriptors*/) {}
|
||||
|
||||
virtual std::vector<VkPushConstantRange> get_push_constants()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
int sampler_location(int index) const { return 1 + index; }
|
||||
int input_attachment_location(int index) const { return 1 + m_num_usable_samplers + index; }
|
||||
|
||||
|
@ -113,8 +101,7 @@ namespace vk
|
|||
}
|
||||
|
||||
vk::glsl::program* build_pipeline(u64 storage_key, VkRenderPass render_pass);
|
||||
|
||||
void load_program(vk::command_buffer& cmd, VkRenderPass pass, const std::vector<vk::image_view*>& src);
|
||||
vk::glsl::program* load_program(vk::command_buffer& cmd, VkRenderPass pass, const std::vector<vk::image_view*>& src);
|
||||
|
||||
virtual void create(const vk::render_device& dev);
|
||||
virtual void destroy();
|
||||
|
@ -123,7 +110,7 @@ namespace vk
|
|||
|
||||
vk::framebuffer* get_framebuffer(vk::image* target, VkRenderPass render_pass);
|
||||
|
||||
virtual void emit_geometry(vk::command_buffer& cmd);
|
||||
virtual void emit_geometry(vk::command_buffer& cmd, glsl::program* program);
|
||||
|
||||
virtual void set_up_viewport(vk::command_buffer& cmd, u32 x, u32 y, u32 w, u32 h);
|
||||
|
||||
|
@ -169,13 +156,14 @@ namespace vk
|
|||
vk::image_view* find_font(rsx::overlays::font* font, vk::command_buffer& cmd, vk::data_heap& upload_heap);
|
||||
vk::image_view* find_temp_image(rsx::overlays::image_info_base* desc, vk::command_buffer& cmd, vk::data_heap& upload_heap, u32 owner_uid);
|
||||
|
||||
std::vector<VkPushConstantRange> get_push_constants() override;
|
||||
std::vector<vk::glsl::program_input> get_vertex_inputs() override;
|
||||
std::vector<vk::glsl::program_input> get_fragment_inputs() override;
|
||||
|
||||
void update_uniforms(vk::command_buffer& cmd, vk::glsl::program* program) override;
|
||||
|
||||
void set_primitive_type(rsx::overlays::primitive_type type);
|
||||
|
||||
void emit_geometry(vk::command_buffer& cmd) override;
|
||||
void emit_geometry(vk::command_buffer& cmd, glsl::program* program) override;
|
||||
|
||||
void run(vk::command_buffer& cmd, const areau& viewport, vk::framebuffer* target, VkRenderPass render_pass,
|
||||
vk::data_heap& upload_heap, rsx::overlays::overlay& ui);
|
||||
|
@ -189,7 +177,7 @@ namespace vk
|
|||
|
||||
attachment_clear_pass();
|
||||
|
||||
std::vector<VkPushConstantRange> get_push_constants() override;
|
||||
std::vector<vk::glsl::program_input> get_vertex_inputs() override;
|
||||
|
||||
void update_uniforms(vk::command_buffer& cmd, vk::glsl::program* program) override;
|
||||
|
||||
|
@ -227,7 +215,7 @@ namespace vk
|
|||
|
||||
video_out_calibration_pass();
|
||||
|
||||
std::vector<VkPushConstantRange> get_push_constants() override;
|
||||
std::vector<vk::glsl::program_input> get_fragment_inputs() override;
|
||||
|
||||
void update_uniforms(vk::command_buffer& cmd, vk::glsl::program* /*program*/) override;
|
||||
|
||||
|
|
|
@ -36,12 +36,12 @@ namespace vk
|
|||
{
|
||||
if (job.is_graphics_job)
|
||||
{
|
||||
auto compiled = int_compile_graphics_pipe(job.graphics_data, job.graphics_modules, job.pipe_layout, job.inputs, {});
|
||||
auto compiled = int_compile_graphics_pipe(job.graphics_data, job.graphics_modules, job.inputs, {});
|
||||
job.callback_func(compiled);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto compiled = int_compile_compute_pipe(job.compute_data, job.pipe_layout);
|
||||
auto compiled = int_compile_compute_pipe(job.compute_data, job.inputs);
|
||||
job.callback_func(compiled);
|
||||
}
|
||||
}
|
||||
|
@ -50,25 +50,26 @@ namespace vk
|
|||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<glsl::program> pipe_compiler::int_compile_compute_pipe(const VkComputePipelineCreateInfo& create_info, VkPipelineLayout pipe_layout)
|
||||
std::unique_ptr<glsl::program> pipe_compiler::int_compile_compute_pipe(
|
||||
const VkComputePipelineCreateInfo& create_info,
|
||||
const std::vector<glsl::program_input>& cs_inputs)
|
||||
{
|
||||
VkPipeline pipeline;
|
||||
vkCreateComputePipelines(*g_render_device, nullptr, 1, &create_info, nullptr, &pipeline);
|
||||
return std::make_unique<vk::glsl::program>(*m_device, pipeline, pipe_layout);
|
||||
return std::make_unique<glsl::program>(*m_device, create_info, cs_inputs);
|
||||
}
|
||||
|
||||
std::unique_ptr<glsl::program> pipe_compiler::int_compile_graphics_pipe(const VkGraphicsPipelineCreateInfo& create_info, VkPipelineLayout pipe_layout,
|
||||
const std::vector<glsl::program_input>& vs_inputs, const std::vector<glsl::program_input>& fs_inputs)
|
||||
std::unique_ptr<glsl::program> pipe_compiler::int_compile_graphics_pipe(
|
||||
const VkGraphicsPipelineCreateInfo& create_info,
|
||||
const std::vector<glsl::program_input>& vs_inputs,
|
||||
const std::vector<glsl::program_input>& fs_inputs)
|
||||
{
|
||||
VkPipeline pipeline;
|
||||
CHECK_RESULT(vkCreateGraphicsPipelines(*m_device, VK_NULL_HANDLE, 1, &create_info, nullptr, &pipeline));
|
||||
auto result = std::make_unique<vk::glsl::program>(*m_device, pipeline, pipe_layout, vs_inputs, fs_inputs);
|
||||
result->link();
|
||||
return result;
|
||||
return std::make_unique<glsl::program>(*m_device, create_info, vs_inputs, fs_inputs);
|
||||
}
|
||||
|
||||
std::unique_ptr<glsl::program> pipe_compiler::int_compile_graphics_pipe(const vk::pipeline_props &create_info, VkShaderModule modules[2], VkPipelineLayout pipe_layout,
|
||||
const std::vector<glsl::program_input>& vs_inputs, const std::vector<glsl::program_input>& fs_inputs)
|
||||
std::unique_ptr<glsl::program> pipe_compiler::int_compile_graphics_pipe(
|
||||
const vk::pipeline_props &create_info,
|
||||
VkShaderModule modules[2],
|
||||
const std::vector<glsl::program_input>& vs_inputs,
|
||||
const std::vector<glsl::program_input>& fs_inputs)
|
||||
{
|
||||
VkPipelineShaderStageCreateInfo shader_stages[2] = {};
|
||||
shader_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
|
@ -157,52 +158,54 @@ namespace vk
|
|||
info.stageCount = 2;
|
||||
info.pStages = shader_stages;
|
||||
info.pDynamicState = &dynamic_state_info;
|
||||
info.layout = pipe_layout;
|
||||
info.layout = VK_NULL_HANDLE;
|
||||
info.basePipelineIndex = -1;
|
||||
info.basePipelineHandle = VK_NULL_HANDLE;
|
||||
info.renderPass = vk::get_renderpass(*m_device, create_info.renderpass_key);
|
||||
|
||||
return int_compile_graphics_pipe(info, pipe_layout, vs_inputs, fs_inputs);
|
||||
return int_compile_graphics_pipe(info, vs_inputs, fs_inputs);
|
||||
}
|
||||
|
||||
std::unique_ptr<glsl::program> pipe_compiler::compile(
|
||||
const VkComputePipelineCreateInfo& create_info,
|
||||
VkPipelineLayout pipe_layout,
|
||||
op_flags flags, callback_t callback)
|
||||
op_flags flags, callback_t callback,
|
||||
const std::vector<glsl::program_input>& cs_inputs)
|
||||
{
|
||||
if (flags == COMPILE_INLINE)
|
||||
{
|
||||
return int_compile_compute_pipe(create_info, pipe_layout);
|
||||
return int_compile_compute_pipe(create_info, cs_inputs);
|
||||
}
|
||||
|
||||
m_work_queue.push(create_info, pipe_layout, callback);
|
||||
m_work_queue.push(create_info, cs_inputs, callback);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::unique_ptr<glsl::program> pipe_compiler::compile(
|
||||
const VkGraphicsPipelineCreateInfo& create_info,
|
||||
VkPipelineLayout pipe_layout,
|
||||
op_flags flags, callback_t /*callback*/,
|
||||
const std::vector<glsl::program_input>& vs_inputs, const std::vector<glsl::program_input>& fs_inputs)
|
||||
const std::vector<glsl::program_input>& vs_inputs,
|
||||
const std::vector<glsl::program_input>& fs_inputs)
|
||||
{
|
||||
// It is very inefficient to defer this as all pointers need to be saved
|
||||
ensure(flags == COMPILE_INLINE);
|
||||
return int_compile_graphics_pipe(create_info, pipe_layout, vs_inputs, fs_inputs);
|
||||
return int_compile_graphics_pipe(create_info, vs_inputs, fs_inputs);
|
||||
}
|
||||
|
||||
std::unique_ptr<glsl::program> pipe_compiler::compile(
|
||||
const vk::pipeline_props &create_info,
|
||||
VkShaderModule module_handles[2],
|
||||
VkPipelineLayout pipe_layout,
|
||||
VkShaderModule vs,
|
||||
VkShaderModule fs,
|
||||
op_flags flags, callback_t callback,
|
||||
const std::vector<glsl::program_input>& vs_inputs, const std::vector<glsl::program_input>& fs_inputs)
|
||||
const std::vector<glsl::program_input>& vs_inputs,
|
||||
const std::vector<glsl::program_input>& fs_inputs)
|
||||
{
|
||||
VkShaderModule modules[] = { vs, fs };
|
||||
if (flags == COMPILE_INLINE)
|
||||
{
|
||||
return int_compile_graphics_pipe(create_info, module_handles, pipe_layout, vs_inputs, fs_inputs);
|
||||
return int_compile_graphics_pipe(create_info, modules, vs_inputs, fs_inputs);
|
||||
}
|
||||
|
||||
m_work_queue.push(create_info, pipe_layout, module_handles, vs_inputs, fs_inputs, callback);
|
||||
m_work_queue.push(create_info, modules, vs_inputs, fs_inputs, callback);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
|
@ -68,21 +68,20 @@ namespace vk
|
|||
void initialize(const vk::render_device* pdev);
|
||||
|
||||
std::unique_ptr<glsl::program> compile(
|
||||
const VkComputePipelineCreateInfo& create_info,
|
||||
VkPipelineLayout pipe_layout,
|
||||
op_flags flags, callback_t callback = {});
|
||||
const VkComputePipelineCreateInfo& cs,
|
||||
op_flags flags, callback_t callback = {},
|
||||
const std::vector<glsl::program_input>& cs_inputs = {});
|
||||
|
||||
std::unique_ptr<glsl::program> compile(
|
||||
const VkGraphicsPipelineCreateInfo& create_info,
|
||||
VkPipelineLayout pipe_layout,
|
||||
op_flags flags, callback_t callback = {},
|
||||
const std::vector<glsl::program_input>& vs_inputs = {},
|
||||
const std::vector<glsl::program_input>& fs_inputs = {});
|
||||
|
||||
std::unique_ptr<glsl::program> compile(
|
||||
const vk::pipeline_props &create_info,
|
||||
VkShaderModule module_handles[2],
|
||||
VkPipelineLayout pipe_layout,
|
||||
VkShaderModule vs,
|
||||
VkShaderModule fs,
|
||||
op_flags flags, callback_t callback = {},
|
||||
const std::vector<glsl::program_input>& vs_inputs = {},
|
||||
const std::vector<glsl::program_input>& fs_inputs = {});
|
||||
|
@ -112,13 +111,11 @@ namespace vk
|
|||
|
||||
vk::pipeline_props graphics_data;
|
||||
compute_pipeline_props compute_data;
|
||||
VkPipelineLayout pipe_layout;
|
||||
VkShaderModule graphics_modules[2];
|
||||
std::vector<glsl::program_input> inputs;
|
||||
|
||||
pipe_compiler_job(
|
||||
const vk::pipeline_props& props,
|
||||
VkPipelineLayout layout,
|
||||
VkShaderModule modules[2],
|
||||
const std::vector<glsl::program_input>& vs_in,
|
||||
const std::vector<glsl::program_input>& fs_in,
|
||||
|
@ -126,7 +123,6 @@ namespace vk
|
|||
{
|
||||
callback_func = func;
|
||||
graphics_data = props;
|
||||
pipe_layout = layout;
|
||||
graphics_modules[0] = modules[0];
|
||||
graphics_modules[1] = modules[1];
|
||||
is_graphics_job = true;
|
||||
|
@ -138,24 +134,34 @@ namespace vk
|
|||
|
||||
pipe_compiler_job(
|
||||
const VkComputePipelineCreateInfo& props,
|
||||
VkPipelineLayout layout,
|
||||
const std::vector<glsl::program_input>& cs_in,
|
||||
callback_t func)
|
||||
{
|
||||
callback_func = func;
|
||||
compute_data = props;
|
||||
pipe_layout = layout;
|
||||
is_graphics_job = false;
|
||||
|
||||
inputs = cs_in;
|
||||
}
|
||||
};
|
||||
|
||||
const vk::render_device* m_device = nullptr;
|
||||
lf_queue<pipe_compiler_job> m_work_queue;
|
||||
|
||||
std::unique_ptr<glsl::program> int_compile_compute_pipe(const VkComputePipelineCreateInfo& create_info, VkPipelineLayout pipe_layout);
|
||||
std::unique_ptr<glsl::program> int_compile_graphics_pipe(const VkGraphicsPipelineCreateInfo& create_info, VkPipelineLayout pipe_layout,
|
||||
const std::vector<glsl::program_input>& vs_inputs, const std::vector<glsl::program_input>& fs_inputs);
|
||||
std::unique_ptr<glsl::program> int_compile_graphics_pipe(const vk::pipeline_props &create_info, VkShaderModule modules[2], VkPipelineLayout pipe_layout,
|
||||
const std::vector<glsl::program_input>& vs_inputs, const std::vector<glsl::program_input>& fs_inputs);
|
||||
std::unique_ptr<glsl::program> int_compile_compute_pipe(
|
||||
const VkComputePipelineCreateInfo& create_info,
|
||||
const std::vector<glsl::program_input>& cs_inputs);
|
||||
|
||||
std::unique_ptr<glsl::program> int_compile_graphics_pipe(
|
||||
const VkGraphicsPipelineCreateInfo& create_info,
|
||||
const std::vector<glsl::program_input>& vs_inputs,
|
||||
const std::vector<glsl::program_input>& fs_inputs);
|
||||
|
||||
std::unique_ptr<glsl::program> int_compile_graphics_pipe(
|
||||
const vk::pipeline_props &create_info,
|
||||
VkShaderModule modules[2],
|
||||
const std::vector<glsl::program_input>& vs_inputs,
|
||||
const std::vector<glsl::program_input>& fs_inputs);
|
||||
};
|
||||
|
||||
void initialize_pipe_compiler(int num_worker_threads = -1);
|
||||
|
|
|
@ -46,15 +46,14 @@ namespace vk
|
|||
const fragment_program_type& fragmentProgramData,
|
||||
const vk::pipeline_props& pipelineProperties,
|
||||
bool compile_async,
|
||||
std::function<pipeline_type*(pipeline_storage_type&)> callback,
|
||||
VkPipelineLayout common_pipeline_layout)
|
||||
std::function<pipeline_type*(pipeline_storage_type&)> callback)
|
||||
{
|
||||
const auto compiler_flags = compile_async ? vk::pipe_compiler::COMPILE_DEFERRED : vk::pipe_compiler::COMPILE_INLINE;
|
||||
VkShaderModule modules[2] = { vertexProgramData.handle, fragmentProgramData.handle };
|
||||
|
||||
auto compiler = vk::get_pipe_compiler();
|
||||
auto result = compiler->compile(
|
||||
pipelineProperties, modules, common_pipeline_layout,
|
||||
pipelineProperties,
|
||||
vertexProgramData.handle,
|
||||
fragmentProgramData.handle,
|
||||
compiler_flags, callback,
|
||||
vertexProgramData.uniforms,
|
||||
fragmentProgramData.uniforms);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "stdafx.h"
|
||||
#include "VKProgramPipeline.h"
|
||||
#include "VKResourceManager.h"
|
||||
#include "vkutils/descriptors.h"
|
||||
#include "vkutils/device.h"
|
||||
|
||||
|
@ -7,10 +8,61 @@
|
|||
|
||||
namespace vk
|
||||
{
|
||||
extern vk::render_device* get_current_renderer();
|
||||
|
||||
namespace glsl
|
||||
{
|
||||
using namespace ::glsl;
|
||||
|
||||
VkDescriptorType to_descriptor_type(program_input_type type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case input_type_uniform_buffer:
|
||||
return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
case input_type_texel_buffer:
|
||||
return VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
|
||||
case input_type_texture:
|
||||
return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
case input_type_storage_buffer:
|
||||
return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||
case input_type_storage_texture:
|
||||
return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
|
||||
default:
|
||||
fmt::throw_exception("Unexpected program input type %d", static_cast<int>(type));
|
||||
}
|
||||
}
|
||||
|
||||
VkShaderStageFlags to_shader_stage_flags(::glsl::program_domain domain)
|
||||
{
|
||||
switch (domain)
|
||||
{
|
||||
case glsl_vertex_program:
|
||||
return VK_SHADER_STAGE_VERTEX_BIT;
|
||||
case glsl_fragment_program:
|
||||
return VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
case glsl_compute_program:
|
||||
return VK_SHADER_STAGE_COMPUTE_BIT;
|
||||
default:
|
||||
fmt::throw_exception("Unexpected domain %d", static_cast<int>(domain));
|
||||
}
|
||||
}
|
||||
|
||||
const char* to_string(::glsl::program_domain domain)
|
||||
{
|
||||
switch (domain)
|
||||
{
|
||||
case glsl_vertex_program:
|
||||
return "vertex";
|
||||
case glsl_fragment_program:
|
||||
return "fragment";
|
||||
case glsl_compute_program:
|
||||
return "compute";
|
||||
default:
|
||||
fmt::throw_exception("Unexpected domain %d", static_cast<int>(domain));
|
||||
}
|
||||
}
|
||||
|
||||
void shader::create(::glsl::program_domain domain, const std::string& source)
|
||||
{
|
||||
type = domain;
|
||||
|
@ -23,11 +75,8 @@ namespace vk
|
|||
|
||||
if (!spirv::compile_glsl_to_spv(m_compiled, m_source, type, ::glsl::glsl_rules_vulkan))
|
||||
{
|
||||
const std::string shader_type = type == ::glsl::program_domain::glsl_vertex_program ? "vertex" :
|
||||
type == ::glsl::program_domain::glsl_fragment_program ? "fragment" : "compute";
|
||||
|
||||
rsx_log.notice("%s", m_source);
|
||||
fmt::throw_exception("Failed to compile %s shader", shader_type);
|
||||
fmt::throw_exception("Failed to compile %s shader", to_string(type));
|
||||
}
|
||||
|
||||
VkShaderModuleCreateInfo vs_info;
|
||||
|
@ -69,34 +118,56 @@ namespace vk
|
|||
return m_handle;
|
||||
}
|
||||
|
||||
void program::create_impl()
|
||||
void program::init()
|
||||
{
|
||||
linked = false;
|
||||
attribute_location_mask = 0;
|
||||
vertex_attributes_mask = 0;
|
||||
|
||||
fs_texture_bindings.fill(~0u);
|
||||
fs_texture_mirror_bindings.fill(~0u);
|
||||
vs_texture_bindings.fill(~0u);
|
||||
}
|
||||
|
||||
program::program(VkDevice dev, VkPipeline p, VkPipelineLayout layout, const std::vector<program_input> &vertex_input, const std::vector<program_input>& fragment_inputs)
|
||||
: m_device(dev), pipeline(p), pipeline_layout(layout)
|
||||
program::program(VkDevice dev, const VkGraphicsPipelineCreateInfo& create_info, const std::vector<program_input> &vertex_inputs, const std::vector<program_input>& fragment_inputs)
|
||||
: m_device(dev)
|
||||
{
|
||||
create_impl();
|
||||
load_uniforms(vertex_input);
|
||||
init();
|
||||
|
||||
load_uniforms(vertex_inputs);
|
||||
load_uniforms(fragment_inputs);
|
||||
|
||||
create_pipeline_layout();
|
||||
ensure(m_pipeline_layout);
|
||||
|
||||
auto _create_info = create_info;
|
||||
_create_info.layout = m_pipeline_layout;
|
||||
CHECK_RESULT(vkCreateGraphicsPipelines(dev, nullptr, 1, &create_info, nullptr, &m_pipeline));
|
||||
}
|
||||
|
||||
program::program(VkDevice dev, VkPipeline p, VkPipelineLayout layout)
|
||||
: m_device(dev), pipeline(p), pipeline_layout(layout)
|
||||
program::program(VkDevice dev, const VkComputePipelineCreateInfo& create_info, const std::vector<program_input>& compute_inputs)
|
||||
: m_device(dev)
|
||||
{
|
||||
create_impl();
|
||||
init();
|
||||
|
||||
load_uniforms(compute_inputs);
|
||||
|
||||
create_pipeline_layout();
|
||||
ensure(m_pipeline_layout);
|
||||
|
||||
auto _create_info = create_info;
|
||||
_create_info.layout = m_pipeline_layout;
|
||||
CHECK_RESULT(vkCreateComputePipelines(dev, nullptr, 1, &create_info, nullptr, &m_pipeline));
|
||||
}
|
||||
|
||||
program::~program()
|
||||
{
|
||||
vkDestroyPipeline(m_device, pipeline, nullptr);
|
||||
vkDestroyPipeline(m_device, m_pipeline, nullptr);
|
||||
|
||||
if (m_pipeline_layout)
|
||||
{
|
||||
vkDestroyPipelineLayout(m_device, m_pipeline_layout, nullptr);
|
||||
vkDestroyDescriptorSetLayout(m_device, m_descriptor_set_layout, nullptr);
|
||||
vk::get_resource_manager()->dispose(m_descriptor_pool);
|
||||
}
|
||||
}
|
||||
|
||||
program& program::load_uniforms(const std::vector<program_input>& inputs)
|
||||
|
@ -160,14 +231,36 @@ namespace vk
|
|||
});
|
||||
}
|
||||
|
||||
void program::bind_uniform(const VkDescriptorImageInfo &image_descriptor, const std::string& uniform_name, VkDescriptorType type, vk::descriptor_set &set)
|
||||
u32 program::get_uniform_location(program_input_type type, const std::string& uniform_name)
|
||||
{
|
||||
const auto& uniform = uniforms[type];
|
||||
const auto result = std::find_if(uniform.cbegin(), uniform.cend(), [&uniform_name](const auto& u)
|
||||
{
|
||||
return u.name == uniform_name;
|
||||
});
|
||||
|
||||
if (result == uniform.end())
|
||||
{
|
||||
return { umax };
|
||||
}
|
||||
|
||||
return result->location;
|
||||
}
|
||||
|
||||
void program::bind_uniform(const VkDescriptorImageInfo &image_descriptor, const std::string& uniform_name, VkDescriptorType type)
|
||||
{
|
||||
for (const auto &uniform : uniforms[program_input_type::input_type_texture])
|
||||
{
|
||||
if (uniform.name == uniform_name)
|
||||
{
|
||||
set.push(image_descriptor, type, uniform.location);
|
||||
attribute_location_mask |= (1ull << uniform.location);
|
||||
if (m_descriptor_slots[uniform.location].matches(image_descriptor))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
next_descriptor_set();
|
||||
m_descriptor_set.push(image_descriptor, type, uniform.location);
|
||||
m_descriptors_dirty[uniform.location] = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -175,7 +268,7 @@ namespace vk
|
|||
rsx_log.notice("texture not found in program: %s", uniform_name.c_str());
|
||||
}
|
||||
|
||||
void program::bind_uniform(const VkDescriptorImageInfo & image_descriptor, int texture_unit, ::glsl::program_domain domain, vk::descriptor_set &set, bool is_stencil_mirror)
|
||||
void program::bind_uniform(const VkDescriptorImageInfo & image_descriptor, int texture_unit, ::glsl::program_domain domain, bool is_stencil_mirror)
|
||||
{
|
||||
ensure(domain != ::glsl::program_domain::glsl_compute_program);
|
||||
|
||||
|
@ -189,34 +282,46 @@ namespace vk
|
|||
binding = vs_texture_bindings[texture_unit];
|
||||
}
|
||||
|
||||
if (binding != ~0u)
|
||||
if (binding == ~0u) [[ unlikely ]]
|
||||
{
|
||||
set.push(image_descriptor, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, binding);
|
||||
attribute_location_mask |= (1ull << binding);
|
||||
rsx_log.notice("texture not found in program: %stex%u", (domain == ::glsl::program_domain::glsl_vertex_program) ? "v" : "", texture_unit);
|
||||
return;
|
||||
}
|
||||
|
||||
rsx_log.notice("texture not found in program: %stex%u", (domain == ::glsl::program_domain::glsl_vertex_program)? "v" : "", texture_unit);
|
||||
}
|
||||
|
||||
void program::bind_uniform(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point, vk::descriptor_set &set)
|
||||
if (m_descriptor_slots[binding].matches(image_descriptor))
|
||||
{
|
||||
bind_buffer(buffer_descriptor, binding_point, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, set);
|
||||
return;
|
||||
}
|
||||
|
||||
void program::bind_uniform(const VkBufferView &buffer_view, u32 binding_point, vk::descriptor_set &set)
|
||||
next_descriptor_set();
|
||||
m_descriptor_set.push(image_descriptor, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, binding);
|
||||
m_descriptors_dirty[binding] = false;
|
||||
}
|
||||
|
||||
void program::bind_uniform(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point)
|
||||
{
|
||||
set.push(buffer_view, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, binding_point);
|
||||
attribute_location_mask |= (1ull << binding_point);
|
||||
bind_buffer(buffer_descriptor, binding_point, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
|
||||
}
|
||||
|
||||
void program::bind_uniform(const VkBufferView &buffer_view, program_input_type type, const std::string &binding_name, vk::descriptor_set &set)
|
||||
void program::bind_uniform(const VkBufferView &buffer_view, u32 binding_point)
|
||||
{
|
||||
if (m_descriptor_slots[binding_point].matches(buffer_view))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
next_descriptor_set();
|
||||
m_descriptor_set.push(buffer_view, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, binding_point);
|
||||
m_descriptors_dirty[binding_point] = false;
|
||||
}
|
||||
|
||||
void program::bind_uniform(const VkBufferView &buffer_view, program_input_type type, const std::string &binding_name)
|
||||
{
|
||||
for (const auto &uniform : uniforms[type])
|
||||
{
|
||||
if (uniform.name == binding_name)
|
||||
{
|
||||
bind_uniform(buffer_view, uniform.location, set);
|
||||
bind_uniform(buffer_view, uniform.location);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -224,10 +329,135 @@ namespace vk
|
|||
rsx_log.notice("vertex buffer not found in program: %s", binding_name.c_str());
|
||||
}
|
||||
|
||||
void program::bind_buffer(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point, VkDescriptorType type, vk::descriptor_set &set)
|
||||
void program::bind_buffer(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point, VkDescriptorType type)
|
||||
{
|
||||
set.push(buffer_descriptor, type, binding_point);
|
||||
attribute_location_mask |= (1ull << binding_point);
|
||||
m_descriptor_set.push(buffer_descriptor, type, binding_point);
|
||||
m_descriptors_dirty[binding_point] = false;
|
||||
}
|
||||
|
||||
VkDescriptorSet program::allocate_descriptor_set()
|
||||
{
|
||||
if (!m_descriptor_pool)
|
||||
{
|
||||
create_descriptor_pool();
|
||||
}
|
||||
|
||||
return m_descriptor_pool->allocate(m_descriptor_set_layout);
|
||||
}
|
||||
|
||||
void program::next_descriptor_set()
|
||||
{
|
||||
const auto new_set = allocate_descriptor_set();
|
||||
const auto old_set = m_descriptor_set.value();
|
||||
|
||||
if (old_set)
|
||||
{
|
||||
m_copy_cmds.clear();
|
||||
for (unsigned i = 0; i < m_copy_cmds.size(); ++i)
|
||||
{
|
||||
if (!m_descriptors_dirty[i])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Reuse already initialized memory. Each command is the same anyway.
|
||||
m_copy_cmds.resize(m_copy_cmds.size() + 1);
|
||||
auto& cmd = m_copy_cmds.back();
|
||||
cmd.srcBinding = cmd.dstBinding = i;
|
||||
cmd.srcSet = old_set;
|
||||
cmd.dstSet = new_set;
|
||||
}
|
||||
|
||||
m_descriptor_set.push(m_copy_cmds);
|
||||
}
|
||||
|
||||
m_descriptor_set = allocate_descriptor_set();
|
||||
}
|
||||
|
||||
program& program::bind(const vk::command_buffer& cmd, VkPipelineBindPoint bind_point)
|
||||
{
|
||||
VkDescriptorSet set = m_descriptor_set.value();
|
||||
vkCmdBindPipeline(cmd, bind_point, m_pipeline);
|
||||
vkCmdBindDescriptorSets(cmd, bind_point, m_pipeline_layout, 0, 1, &set, 0, nullptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void program::create_descriptor_set_layout()
|
||||
{
|
||||
ensure(m_descriptor_set_layout == VK_NULL_HANDLE);
|
||||
|
||||
rsx::simple_array<VkDescriptorSetLayoutBinding> bindings;
|
||||
bindings.reserve(16);
|
||||
|
||||
m_descriptor_pool_sizes.clear();
|
||||
m_descriptor_pool_sizes.reserve(input_type_max_enum);
|
||||
|
||||
for (const auto& type_arr : uniforms)
|
||||
{
|
||||
if (type_arr.empty() || type_arr.front().type == input_type_push_constant)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
VkDescriptorType type = to_descriptor_type(type_arr.front().type);
|
||||
m_descriptor_pool_sizes.push_back({ .type = type });
|
||||
|
||||
for (const auto& input : type_arr)
|
||||
{
|
||||
VkDescriptorSetLayoutBinding binding
|
||||
{
|
||||
.binding = input.location,
|
||||
.descriptorType = type,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = to_shader_stage_flags(input.domain)
|
||||
};
|
||||
bindings.push_back(binding);
|
||||
m_descriptor_pool_sizes.back().descriptorCount++;
|
||||
}
|
||||
}
|
||||
|
||||
VkDescriptorSetLayoutCreateInfo set_layout_create_info
|
||||
{
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
||||
.flags = 0,
|
||||
.bindingCount = ::size32(bindings),
|
||||
.pBindings = bindings.data()
|
||||
};
|
||||
CHECK_RESULT(vkCreateDescriptorSetLayout(m_device, &set_layout_create_info, nullptr, &m_descriptor_set_layout));
|
||||
}
|
||||
|
||||
void program::create_pipeline_layout()
|
||||
{
|
||||
ensure(!linked);
|
||||
ensure(m_pipeline_layout == VK_NULL_HANDLE);
|
||||
|
||||
create_descriptor_set_layout();
|
||||
|
||||
rsx::simple_array<VkPushConstantRange> push_constants{};
|
||||
for (const auto& input : uniforms[input_type_push_constant])
|
||||
{
|
||||
const auto& range = input.as_push_constant();
|
||||
push_constants.push_back({ .offset = range.offset, .size = range.size });
|
||||
}
|
||||
|
||||
VkPipelineLayoutCreateInfo create_info
|
||||
{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
||||
.flags = 0,
|
||||
.setLayoutCount = 1,
|
||||
.pSetLayouts = &m_descriptor_set_layout,
|
||||
.pushConstantRangeCount = ::size32(push_constants),
|
||||
.pPushConstantRanges = push_constants.data()
|
||||
};
|
||||
CHECK_RESULT(vkCreatePipelineLayout(m_device, &create_info, nullptr, &m_pipeline_layout));
|
||||
}
|
||||
|
||||
void program::create_descriptor_pool()
|
||||
{
|
||||
ensure(linked);
|
||||
|
||||
m_descriptor_pool = std::make_unique<descriptor_pool>();
|
||||
m_descriptor_pool->create(*vk::get_current_renderer(), m_descriptor_pool_sizes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <variant>
|
||||
|
||||
namespace vk
|
||||
{
|
||||
|
@ -15,18 +16,20 @@ namespace vk
|
|||
enum program_input_type : u32
|
||||
{
|
||||
input_type_uniform_buffer = 0,
|
||||
input_type_texel_buffer = 1,
|
||||
input_type_texture = 2,
|
||||
input_type_storage_buffer = 3,
|
||||
input_type_texel_buffer,
|
||||
input_type_texture,
|
||||
input_type_storage_buffer,
|
||||
input_type_storage_texture,
|
||||
input_type_push_constant,
|
||||
|
||||
input_type_max_enum = 4
|
||||
input_type_max_enum
|
||||
};
|
||||
|
||||
struct bound_sampler
|
||||
{
|
||||
VkFormat format;
|
||||
VkImage image;
|
||||
VkComponentMapping mapping;
|
||||
VkFormat format = VK_FORMAT_UNDEFINED;
|
||||
VkImage image = VK_NULL_HANDLE;
|
||||
VkComponentMapping mapping{};
|
||||
};
|
||||
|
||||
struct bound_buffer
|
||||
|
@ -37,16 +40,73 @@ namespace vk
|
|||
u64 size = 0;
|
||||
};
|
||||
|
||||
struct push_constant_ref
|
||||
{
|
||||
u32 offset = 0;
|
||||
u32 size = 0;
|
||||
};
|
||||
|
||||
struct program_input
|
||||
{
|
||||
::glsl::program_domain domain;
|
||||
program_input_type type;
|
||||
|
||||
bound_buffer as_buffer;
|
||||
bound_sampler as_sampler;
|
||||
using bound_data_t = std::variant<bound_buffer, bound_sampler, push_constant_ref>;
|
||||
bound_data_t bound_data;
|
||||
|
||||
u32 location;
|
||||
std::string name;
|
||||
|
||||
inline bound_buffer& as_buffer() { return *std::get_if<bound_buffer>(&bound_data); }
|
||||
inline bound_sampler& as_sampler() { return *std::get_if<bound_sampler>(&bound_data); }
|
||||
inline push_constant_ref& as_push_constant() { return *std::get_if<push_constant_ref>(&bound_data); }
|
||||
|
||||
inline const bound_buffer& as_buffer() const { return *std::get_if<bound_buffer>(&bound_data); }
|
||||
inline const bound_sampler& as_sampler() const { return *std::get_if<bound_sampler>(&bound_data); }
|
||||
inline const push_constant_ref& as_push_constant() const { return *std::get_if<push_constant_ref>(&bound_data); }
|
||||
|
||||
static program_input make(
|
||||
::glsl::program_domain domain,
|
||||
const std::string& name,
|
||||
program_input_type type,
|
||||
u32 location,
|
||||
const bound_data_t& data = bound_buffer{})
|
||||
{
|
||||
return program_input
|
||||
{
|
||||
.domain = domain,
|
||||
.type = type,
|
||||
.bound_data = data,
|
||||
.location = location,
|
||||
.name = name
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
union descriptor_slot_t
|
||||
{
|
||||
VkDescriptorImageInfo image_info;
|
||||
VkDescriptorBufferInfo buffer_info;
|
||||
VkBufferView buffer_view;
|
||||
|
||||
bool matches(const VkDescriptorImageInfo& test) const
|
||||
{
|
||||
return test.imageView == image_info.imageView &&
|
||||
test.sampler == image_info.sampler &&
|
||||
test.imageLayout == image_info.imageLayout;
|
||||
}
|
||||
|
||||
bool matches(const VkDescriptorBufferInfo& test) const
|
||||
{
|
||||
return test.buffer == buffer_info.buffer &&
|
||||
test.offset == buffer_info.offset &&
|
||||
test.range == buffer_info.range;
|
||||
}
|
||||
|
||||
bool matches(VkBufferView test) const
|
||||
{
|
||||
return test == buffer_view;
|
||||
}
|
||||
};
|
||||
|
||||
class shader
|
||||
|
@ -75,37 +135,61 @@ namespace vk
|
|||
class program
|
||||
{
|
||||
std::array<std::vector<program_input>, input_type_max_enum> uniforms;
|
||||
VkDevice m_device;
|
||||
VkDevice m_device = VK_NULL_HANDLE;
|
||||
|
||||
VkPipeline m_pipeline = VK_NULL_HANDLE;
|
||||
VkPipelineLayout m_pipeline_layout = VK_NULL_HANDLE;
|
||||
|
||||
std::array<u32, 16> fs_texture_bindings;
|
||||
std::array<u32, 16> fs_texture_mirror_bindings;
|
||||
std::array<u32, 4> vs_texture_bindings;
|
||||
bool linked;
|
||||
bool linked = false;
|
||||
|
||||
void create_impl();
|
||||
std::unique_ptr<vk::descriptor_pool> m_descriptor_pool;
|
||||
VkDescriptorSetLayout m_descriptor_set_layout = VK_NULL_HANDLE;
|
||||
vk::descriptor_set m_descriptor_set{};
|
||||
rsx::simple_array<VkDescriptorPoolSize> m_descriptor_pool_sizes;
|
||||
|
||||
std::vector<descriptor_slot_t> m_descriptor_slots;
|
||||
std::vector<bool> m_descriptors_dirty;
|
||||
rsx::simple_array<VkCopyDescriptorSet> m_copy_cmds;
|
||||
|
||||
void init();
|
||||
|
||||
void create_descriptor_set_layout();
|
||||
void create_pipeline_layout();
|
||||
void create_descriptor_pool();
|
||||
|
||||
VkDescriptorSet allocate_descriptor_set();
|
||||
void next_descriptor_set();
|
||||
|
||||
program& load_uniforms(const std::vector<program_input>& inputs);
|
||||
|
||||
public:
|
||||
VkPipeline pipeline;
|
||||
VkPipelineLayout pipeline_layout;
|
||||
u64 attribute_location_mask;
|
||||
u64 vertex_attributes_mask;
|
||||
|
||||
program(VkDevice dev, VkPipeline p, VkPipelineLayout layout, const std::vector<program_input> &vertex_input, const std::vector<program_input>& fragment_inputs);
|
||||
program(VkDevice dev, VkPipeline p, VkPipelineLayout layout);
|
||||
program(VkDevice dev, const VkGraphicsPipelineCreateInfo& create_info, const std::vector<program_input> &vertex_inputs, const std::vector<program_input>& fragment_inputs);
|
||||
program(VkDevice dev, const VkComputePipelineCreateInfo& create_info, const std::vector<program_input>& compute_inputs);
|
||||
program(const program&) = delete;
|
||||
program(program&& other) = delete;
|
||||
~program();
|
||||
|
||||
program& load_uniforms(const std::vector<program_input>& inputs);
|
||||
program& link();
|
||||
program& bind(const vk::command_buffer& cmd, VkPipelineBindPoint bind_point);
|
||||
|
||||
bool has_uniform(program_input_type type, const std::string &uniform_name);
|
||||
void bind_uniform(const VkDescriptorImageInfo &image_descriptor, const std::string &uniform_name, VkDescriptorType type, vk::descriptor_set &set);
|
||||
void bind_uniform(const VkDescriptorImageInfo &image_descriptor, int texture_unit, ::glsl::program_domain domain, vk::descriptor_set &set, bool is_stencil_mirror = false);
|
||||
void bind_uniform(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point, vk::descriptor_set &set);
|
||||
void bind_uniform(const VkBufferView &buffer_view, u32 binding_point, vk::descriptor_set &set);
|
||||
void bind_uniform(const VkBufferView &buffer_view, program_input_type type, const std::string &binding_name, vk::descriptor_set &set);
|
||||
void bind_buffer(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point, VkDescriptorType type, vk::descriptor_set &set);
|
||||
u32 get_uniform_location(program_input_type type, const std::string& uniform_name);
|
||||
|
||||
void bind_uniform(const VkDescriptorImageInfo &image_descriptor, const std::string &uniform_name, VkDescriptorType type);
|
||||
void bind_uniform(const VkDescriptorImageInfo &image_descriptor, int texture_unit, ::glsl::program_domain domain, bool is_stencil_mirror = false);
|
||||
void bind_uniform(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point);
|
||||
void bind_uniform(const VkBufferView &buffer_view, u32 binding_point);
|
||||
void bind_uniform(const VkBufferView &buffer_view, program_input_type type, const std::string &binding_name);
|
||||
void bind_buffer(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point, VkDescriptorType type);
|
||||
|
||||
void bind_uniform_array(const VkDescriptorImageInfo* image_descriptors, VkDescriptorType type, int count, u32 binding_point);
|
||||
|
||||
inline VkPipelineLayout layout() const { return m_pipeline_layout; }
|
||||
inline VkPipeline value() const { return m_pipeline; }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -154,7 +154,7 @@ namespace vk
|
|||
// If we have driver support for FBO loops, set the usage flag for it.
|
||||
if (vk::get_current_renderer()->get_framebuffer_loops_support())
|
||||
{
|
||||
return { VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT, 0 };
|
||||
return { VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT, VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT };
|
||||
}
|
||||
|
||||
// Workarounds to force transition to GENERAL to decompress.
|
||||
|
|
|
@ -23,43 +23,36 @@ namespace vk
|
|||
|
||||
void build(const std::string& format_prefix, bool unresolve, bool bgra_swap);
|
||||
|
||||
std::vector<std::pair<VkDescriptorType, u8>> get_descriptor_layout() override
|
||||
{
|
||||
return
|
||||
{
|
||||
{ VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 2 }
|
||||
};
|
||||
}
|
||||
|
||||
void declare_inputs() override
|
||||
std::vector<glsl::program_input> get_inputs() override
|
||||
{
|
||||
std::vector<vk::glsl::program_input> inputs =
|
||||
{
|
||||
{
|
||||
glsl::program_input::make(
|
||||
::glsl::program_domain::glsl_compute_program,
|
||||
vk::glsl::program_input_type::input_type_texture,
|
||||
{}, {},
|
||||
0,
|
||||
"multisampled"
|
||||
},
|
||||
{
|
||||
"multisampled",
|
||||
glsl::input_type_storage_texture,
|
||||
0
|
||||
),
|
||||
|
||||
glsl::program_input::make(
|
||||
::glsl::program_domain::glsl_compute_program,
|
||||
vk::glsl::program_input_type::input_type_texture,
|
||||
{}, {},
|
||||
1,
|
||||
"resolve"
|
||||
}
|
||||
"resolve",
|
||||
glsl::input_type_storage_texture,
|
||||
1
|
||||
),
|
||||
};
|
||||
|
||||
m_program->load_uniforms(inputs);
|
||||
auto result = compute_task::get_inputs();
|
||||
result.insert(result.end(), inputs.begin(), inputs.end());
|
||||
return result;
|
||||
}
|
||||
|
||||
void bind_resources() override
|
||||
{
|
||||
auto msaa_view = multisampled->get_view(rsx::default_remap_vector.with_encoding(VK_REMAP_VIEW_MULTISAMPLED));
|
||||
auto resolved_view = resolve->get_view(rsx::default_remap_vector.with_encoding(VK_REMAP_IDENTITY));
|
||||
m_program->bind_uniform({ VK_NULL_HANDLE, msaa_view->value, multisampled->current_layout }, "multisampled", VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, m_descriptor_set);
|
||||
m_program->bind_uniform({ VK_NULL_HANDLE, resolved_view->value, resolve->current_layout }, "resolve", VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, m_descriptor_set);
|
||||
m_program->bind_uniform({ VK_NULL_HANDLE, msaa_view->value, multisampled->current_layout }, "multisampled", VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
|
||||
m_program->bind_uniform({ VK_NULL_HANDLE, resolved_view->value, resolve->current_layout }, "resolve", VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
|
||||
}
|
||||
|
||||
void run(const vk::command_buffer& cmd, vk::viewable_image* msaa_image, vk::viewable_image* resolve_image)
|
||||
|
@ -116,19 +109,22 @@ namespace vk
|
|||
|
||||
void build(bool resolve_depth, bool resolve_stencil, bool unresolve);
|
||||
|
||||
std::vector<VkPushConstantRange> get_push_constants() override
|
||||
std::vector<glsl::program_input> get_fragment_inputs() override
|
||||
{
|
||||
VkPushConstantRange constant;
|
||||
constant.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
constant.offset = 0;
|
||||
constant.size = 16;
|
||||
|
||||
return { constant };
|
||||
auto result = overlay_pass::get_fragment_inputs();
|
||||
result.push_back(glsl::program_input::make(
|
||||
::glsl::glsl_fragment_program,
|
||||
"push_constants",
|
||||
glsl::input_type_push_constant,
|
||||
umax,
|
||||
glsl::push_constant_ref{ .size = 16 }
|
||||
));
|
||||
return result;
|
||||
}
|
||||
|
||||
void update_uniforms(vk::command_buffer& cmd, vk::glsl::program* /*program*/) override
|
||||
void update_uniforms(vk::command_buffer& cmd, vk::glsl::program* program) override
|
||||
{
|
||||
vkCmdPushConstants(cmd, m_pipeline_layout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, static_parameters_width * 4, static_parameters);
|
||||
vkCmdPushConstants(cmd, program->layout(), VK_SHADER_STAGE_FRAGMENT_BIT, 0, static_parameters_width * 4, static_parameters);
|
||||
}
|
||||
|
||||
void update_sample_configuration(vk::image* msaa_image)
|
||||
|
@ -226,16 +222,16 @@ namespace vk
|
|||
state_descriptors.push_back(VK_DYNAMIC_STATE_STENCIL_WRITE_MASK);
|
||||
}
|
||||
|
||||
void emit_geometry(vk::command_buffer& cmd) override
|
||||
void emit_geometry(vk::command_buffer& cmd, glsl::program* program) override
|
||||
{
|
||||
vkCmdClearAttachments(cmd, 1, &clear_info, 1, ®ion);
|
||||
|
||||
for (s32 write_mask = 0x1; write_mask <= 0x80; write_mask <<= 1)
|
||||
{
|
||||
vkCmdSetStencilWriteMask(cmd, VK_STENCIL_FRONT_AND_BACK, write_mask);
|
||||
vkCmdPushConstants(cmd, m_pipeline_layout, VK_SHADER_STAGE_FRAGMENT_BIT, 8, 4, &write_mask);
|
||||
vkCmdPushConstants(cmd, program->layout(), VK_SHADER_STAGE_FRAGMENT_BIT, 8, 4, &write_mask);
|
||||
|
||||
overlay_pass::emit_geometry(cmd);
|
||||
overlay_pass::emit_geometry(cmd, program);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -285,16 +281,16 @@ namespace vk
|
|||
state_descriptors.push_back(VK_DYNAMIC_STATE_STENCIL_WRITE_MASK);
|
||||
}
|
||||
|
||||
void emit_geometry(vk::command_buffer& cmd) override
|
||||
void emit_geometry(vk::command_buffer& cmd, glsl::program* program) override
|
||||
{
|
||||
vkCmdClearAttachments(cmd, 1, &clear_info, 1, &clear_region);
|
||||
|
||||
for (s32 write_mask = 0x1; write_mask <= 0x80; write_mask <<= 1)
|
||||
{
|
||||
vkCmdSetStencilWriteMask(cmd, VK_STENCIL_FRONT_AND_BACK, write_mask);
|
||||
vkCmdPushConstants(cmd, m_pipeline_layout, VK_SHADER_STAGE_FRAGMENT_BIT, 8, 4, &write_mask);
|
||||
vkCmdPushConstants(cmd, program->layout(), VK_SHADER_STAGE_FRAGMENT_BIT, 8, 4, &write_mask);
|
||||
|
||||
overlay_pass::emit_geometry(cmd);
|
||||
overlay_pass::emit_geometry(cmd, program);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -254,7 +254,7 @@ namespace vk
|
|||
m_shader_cache[compiler_options].m_fs = std::move(fs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
std::pair<VkDescriptorSetLayout, VkPipelineLayout> shader_interpreter::create_layout(VkDevice dev)
|
||||
{
|
||||
const auto& binding_table = vk::get_current_renderer()->get_pipeline_binding_table();
|
||||
|
@ -356,24 +356,16 @@ namespace vk
|
|||
CHECK_RESULT(vkCreatePipelineLayout(dev, &layout_info, nullptr, &result));
|
||||
return { set_layout, result };
|
||||
}
|
||||
|
||||
void shader_interpreter::create_descriptor_pools(const vk::render_device& dev)
|
||||
{
|
||||
const auto max_draw_calls = dev.get_descriptor_max_draw_calls();
|
||||
m_descriptor_pool.create(dev, m_descriptor_pool_sizes, max_draw_calls);
|
||||
}
|
||||
*/
|
||||
|
||||
void shader_interpreter::init(const vk::render_device& dev)
|
||||
{
|
||||
m_device = dev;
|
||||
std::tie(m_shared_descriptor_layout, m_shared_pipeline_layout) = create_layout(dev);
|
||||
create_descriptor_pools(dev);
|
||||
}
|
||||
|
||||
void shader_interpreter::destroy()
|
||||
{
|
||||
m_program_cache.clear();
|
||||
m_descriptor_pool.destroy();
|
||||
|
||||
for (auto &fs : m_shader_cache)
|
||||
{
|
||||
|
@ -382,18 +374,6 @@ namespace vk
|
|||
}
|
||||
|
||||
m_shader_cache.clear();
|
||||
|
||||
if (m_shared_pipeline_layout)
|
||||
{
|
||||
vkDestroyPipelineLayout(m_device, m_shared_pipeline_layout, nullptr);
|
||||
m_shared_pipeline_layout = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
if (m_shared_descriptor_layout)
|
||||
{
|
||||
vkDestroyDescriptorSetLayout(m_device, m_shared_descriptor_layout, nullptr);
|
||||
m_shared_descriptor_layout = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
glsl::program* shader_interpreter::link(const vk::pipeline_props& properties, u64 compiler_opt)
|
||||
|
@ -478,28 +458,30 @@ namespace vk
|
|||
info.stageCount = 2;
|
||||
info.pStages = shader_stages;
|
||||
info.pDynamicState = &dynamic_state_info;
|
||||
info.layout = m_shared_pipeline_layout;
|
||||
info.layout = VK_NULL_HANDLE;
|
||||
info.basePipelineIndex = -1;
|
||||
info.basePipelineHandle = VK_NULL_HANDLE;
|
||||
info.renderPass = vk::get_renderpass(m_device, properties.renderpass_key);
|
||||
|
||||
auto compiler = vk::get_pipe_compiler();
|
||||
auto program = compiler->compile(info, m_shared_pipeline_layout, vk::pipe_compiler::COMPILE_INLINE, {}, m_vs_inputs, m_fs_inputs);
|
||||
auto program = compiler->compile(info, vk::pipe_compiler::COMPILE_INLINE, {}, m_vs_inputs, m_fs_inputs);
|
||||
return program.release();
|
||||
}
|
||||
|
||||
void shader_interpreter::update_fragment_textures(const std::array<VkDescriptorImageInfo, 68>& sampled_images, vk::descriptor_set &set)
|
||||
void shader_interpreter::update_fragment_textures(const std::array<VkDescriptorImageInfo, 68>& sampled_images)
|
||||
{
|
||||
const VkDescriptorImageInfo* texture_ptr = sampled_images.data();
|
||||
for (u32 i = 0, binding = m_fragment_textures_start; i < 4; ++i, ++binding, texture_ptr += 16)
|
||||
// FIXME: Cannot use m_fragment_textures.start now since each interpreter has its own binding layout
|
||||
u32 binding = m_current_interpreter->get_uniform_location(glsl::input_type_texture, "texture1D_array");
|
||||
if (binding == umax)
|
||||
{
|
||||
set.push(texture_ptr, 16, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, binding);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
VkDescriptorSet shader_interpreter::allocate_descriptor_set()
|
||||
const VkDescriptorImageInfo* texture_ptr = sampled_images.data();
|
||||
for (u32 i = 0; i < 4; ++i, ++binding, texture_ptr += 16)
|
||||
{
|
||||
return m_descriptor_pool.allocate(m_shared_descriptor_layout);
|
||||
m_current_interpreter->bind_uniform_array(texture_ptr, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 16, binding);
|
||||
}
|
||||
}
|
||||
|
||||
glsl::program* shader_interpreter::get(
|
||||
|
|
|
@ -16,8 +16,6 @@ namespace vk
|
|||
std::vector<glsl::program_input> m_fs_inputs;
|
||||
|
||||
VkDevice m_device = VK_NULL_HANDLE;
|
||||
VkDescriptorSetLayout m_shared_descriptor_layout = VK_NULL_HANDLE;
|
||||
VkPipelineLayout m_shared_pipeline_layout = VK_NULL_HANDLE;
|
||||
glsl::program* m_current_interpreter = nullptr;
|
||||
|
||||
struct pipeline_key
|
||||
|
@ -47,8 +45,6 @@ namespace vk
|
|||
|
||||
std::unordered_map<pipeline_key, std::unique_ptr<glsl::program>, key_hasher> m_program_cache;
|
||||
std::unordered_map<u64, shader_cache_entry_t> m_shader_cache;
|
||||
rsx::simple_array<VkDescriptorPoolSize> m_descriptor_pool_sizes;
|
||||
vk::descriptor_pool m_descriptor_pool;
|
||||
|
||||
u32 m_vertex_instruction_start = 0;
|
||||
u32 m_fragment_instruction_start = 0;
|
||||
|
@ -56,9 +52,6 @@ namespace vk
|
|||
|
||||
pipeline_key m_current_key{};
|
||||
|
||||
std::pair<VkDescriptorSetLayout, VkPipelineLayout> create_layout(VkDevice dev);
|
||||
void create_descriptor_pools(const vk::render_device& dev);
|
||||
|
||||
glsl::shader* build_vs(u64 compiler_opt);
|
||||
glsl::shader* build_fs(u64 compiler_opt);
|
||||
glsl::program* link(const vk::pipeline_props& properties, u64 compiler_opt);
|
||||
|
@ -78,7 +71,6 @@ namespace vk
|
|||
u32 get_vertex_instruction_location() const;
|
||||
u32 get_fragment_instruction_location() const;
|
||||
|
||||
void update_fragment_textures(const std::array<VkDescriptorImageInfo, 68>& sampled_images, vk::descriptor_set &set);
|
||||
VkDescriptorSet allocate_descriptor_set();
|
||||
void update_fragment_textures(const std::array<VkDescriptorImageInfo, 68>& sampled_images);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -68,36 +68,28 @@ namespace vk
|
|||
create();
|
||||
}
|
||||
|
||||
std::vector<std::pair<VkDescriptorType, u8>> fsr_pass::get_descriptor_layout()
|
||||
{
|
||||
return
|
||||
{
|
||||
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1 },
|
||||
{ VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1 }
|
||||
};
|
||||
}
|
||||
|
||||
void fsr_pass::declare_inputs()
|
||||
std::vector<glsl::program_input> fsr_pass::get_inputs()
|
||||
{
|
||||
std::vector<vk::glsl::program_input> inputs =
|
||||
{
|
||||
{
|
||||
glsl::program_input::make(
|
||||
::glsl::program_domain::glsl_compute_program,
|
||||
vk::glsl::program_input_type::input_type_texture,
|
||||
{}, {},
|
||||
0,
|
||||
"InputTexture"
|
||||
},
|
||||
{
|
||||
"InputTexture",
|
||||
vk::glsl::input_type_texture,
|
||||
0
|
||||
),
|
||||
|
||||
glsl::program_input::make(
|
||||
::glsl::program_domain::glsl_compute_program,
|
||||
vk::glsl::program_input_type::input_type_texture,
|
||||
{}, {},
|
||||
1,
|
||||
"OutputTexture"
|
||||
}
|
||||
"OutputTexture",
|
||||
vk::glsl::input_type_storage_texture,
|
||||
1
|
||||
),
|
||||
};
|
||||
|
||||
m_program->load_uniforms(inputs);
|
||||
auto result = compute_task::get_inputs();
|
||||
result.insert(result.end(), inputs.begin(), inputs.end());
|
||||
return result;
|
||||
}
|
||||
|
||||
void fsr_pass::bind_resources()
|
||||
|
@ -111,8 +103,8 @@ namespace vk
|
|||
VK_FALSE, 0.f, 1.f, 0.f, 0.f, VK_FILTER_LINEAR, VK_FILTER_LINEAR, VK_SAMPLER_MIPMAP_MODE_NEAREST, VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK);
|
||||
}
|
||||
|
||||
m_program->bind_uniform({ m_sampler->value, m_input_image->value, m_input_image->image()->current_layout }, "InputTexture", VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, m_descriptor_set);
|
||||
m_program->bind_uniform({ VK_NULL_HANDLE, m_output_image->value, m_output_image->image()->current_layout }, "OutputTexture", VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, m_descriptor_set);
|
||||
m_program->bind_uniform({ m_sampler->value, m_input_image->value, m_input_image->image()->current_layout }, "InputTexture", VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
|
||||
m_program->bind_uniform({ VK_NULL_HANDLE, m_output_image->value, m_output_image->image()->current_layout }, "OutputTexture", VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
|
||||
}
|
||||
|
||||
void fsr_pass::run(const vk::command_buffer& cmd, vk::viewable_image* src, vk::viewable_image* dst, const size2u& input_size, const size2u& output_size)
|
||||
|
@ -158,7 +150,7 @@ namespace vk
|
|||
static_cast<f32>(src_image->width()), static_cast<f32>(src_image->height()), // Size of the raw image to upscale (in case viewport does not cover it all)
|
||||
static_cast<f32>(m_output_size.width), static_cast<f32>(m_output_size.height)); // Size of output viewport (target size)
|
||||
|
||||
vkCmdPushConstants(cmd, m_pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, push_constants_size, m_constants_buf);
|
||||
vkCmdPushConstants(cmd, m_program->layout(), VK_SHADER_STAGE_COMPUTE_BIT, 0, push_constants_size, m_constants_buf);
|
||||
}
|
||||
|
||||
rcas_pass::rcas_pass()
|
||||
|
@ -177,7 +169,7 @@ namespace vk
|
|||
auto cas_attenuation = 2.f - (g_cfg.video.vk.rcas_sharpening_intensity / 50.f);
|
||||
FsrRcasCon(&m_constants_buf[0], cas_attenuation);
|
||||
|
||||
vkCmdPushConstants(cmd, m_pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, push_constants_size, m_constants_buf);
|
||||
vkCmdPushConstants(cmd, m_program->layout(), VK_SHADER_STAGE_COMPUTE_BIT, 0, push_constants_size, m_constants_buf);
|
||||
}
|
||||
|
||||
} // Namespace FidelityFX
|
||||
|
|
|
@ -19,8 +19,7 @@ namespace vk
|
|||
size2u m_output_size;
|
||||
u32 m_constants_buf[20];
|
||||
|
||||
std::vector<std::pair<VkDescriptorType, u8>> get_descriptor_layout() override;
|
||||
void declare_inputs() override;
|
||||
std::vector<glsl::program_input> get_inputs() override;
|
||||
void bind_resources() override;
|
||||
|
||||
virtual void configure(const vk::command_buffer& cmd) = 0;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue