diff --git a/rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp b/rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp index 01e5cc07aa..1191561625 100644 --- a/rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp +++ b/rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp @@ -35,4 +35,34 @@ namespace vk fmt::throw_exception("Unknown register name: %s", varying_register_name); } + + int get_texture_index(std::string_view name) + { + if (name.length() < 2) + { + fmt::throw_exception("Invalid texture name: '%s'", name); + } + +#define IS_DIGIT(x) (x >= '0' && x <= '9') + + constexpr int max_index_length = 2; + std::string index; + + for (int char_idx = name.length() - max_index_length; char_idx < name.length(); ++char_idx) + { + if (IS_DIGIT(name[char_idx])) + { + index += name[char_idx]; + } + } + +#undef IS_DIGIT + + if (index.empty()) + { + fmt::throw_exception("Invalid texture name: '%s'", name); + } + + return std::atoi(index.c_str()); + } } diff --git a/rpcs3/Emu/RSX/VK/VKCommonDecompiler.h b/rpcs3/Emu/RSX/VK/VKCommonDecompiler.h index b0920e27f5..b17eb83b11 100644 --- a/rpcs3/Emu/RSX/VK/VKCommonDecompiler.h +++ b/rpcs3/Emu/RSX/VK/VKCommonDecompiler.h @@ -6,4 +6,6 @@ namespace vk using namespace ::glsl; int get_varying_register_location(std::string_view varying_register_name); + + int get_texture_index(std::string_view name); } diff --git a/rpcs3/Emu/RSX/VK/VKCompute.cpp b/rpcs3/Emu/RSX/VK/VKCompute.cpp index ae36723b81..c164edddd7 100644 --- a/rpcs3/Emu/RSX/VK/VKCompute.cpp +++ b/rpcs3/Emu/RSX/VK/VKCompute.cpp @@ -18,6 +18,7 @@ namespace vk ::glsl::glsl_compute_program, "ssbo" + std::to_string(i), glsl::program_input_type::input_type_storage_buffer, + 0, i ); result.push_back(input); @@ -31,6 +32,7 @@ namespace vk "push_constants", glsl::program_input_type::input_type_push_constant, 0, + 0, glsl::push_constant_ref{ .offset = 0, .size = push_constants_size } ); result.push_back(input); @@ -243,7 +245,7 @@ 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_program->bind_uniform({ m_data->value, m_data_offset, m_data_length }, 0, 0); } void cs_shuffle_base::set_parameters(const vk::command_buffer& cmd, const u32* params, u8 count) @@ -289,7 +291,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_program->bind_uniform({ m_data->value, m_data_offset, m_ssbo_length }, 0, 0); } 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) @@ -349,8 +351,8 @@ namespace vk void cs_aggregator::bind_resources() { - 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); + m_program->bind_uniform({ src->value, 0, block_length }, 0, 0); + m_program->bind_uniform({ dst->value, 0, 4 }, 0, 1); } void cs_aggregator::run(const vk::command_buffer& cmd, const vk::buffer* dst, const vk::buffer* src, u32 num_words) diff --git a/rpcs3/Emu/RSX/VK/VKCompute.h b/rpcs3/Emu/RSX/VK/VKCompute.h index d4e99d8cf3..fa053afe50 100644 --- a/rpcs3/Emu/RSX/VK/VKCompute.h +++ b/rpcs3/Emu/RSX/VK/VKCompute.h @@ -344,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_program->bind_uniform({ m_data->value, m_data_offset, m_ssbo_length }, 0, 0); } void run(const vk::command_buffer& cmd, const vk::buffer* data, u32 src_offset, u32 src_length, u32 dst_offset) @@ -445,8 +445,8 @@ namespace vk void bind_resources() override { - 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); + m_program->bind_uniform({ src_buffer->value, in_offset, block_length }, 0, 0); + m_program->bind_uniform({ dst_buffer->value, out_offset, block_length }, 0, 1); } void set_parameters(const vk::command_buffer& cmd) @@ -573,9 +573,9 @@ namespace vk void bind_resources() override { - const auto op = static_cast(Op); - 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); + const auto op = static_cast(Op); + m_program->bind_uniform({ src_buffer->value, in_offset, in_block_length }, 0u, 0u ^ op); + m_program->bind_uniform({ dst_buffer->value, out_offset, out_block_length }, 0u, 1u ^ op); } void set_parameters(const vk::command_buffer& cmd) diff --git a/rpcs3/Emu/RSX/VK/VKDraw.cpp b/rpcs3/Emu/RSX/VK/VKDraw.cpp index 4d1253340d..1e96087694 100644 --- a/rpcs3/Emu/RSX/VK/VKDraw.cpp +++ b/rpcs3/Emu/RSX/VK/VKDraw.cpp @@ -554,8 +554,8 @@ bool VKGSRender::bind_texture_env() if (view) [[likely]] { m_program->bind_uniform({ fs_sampler_handles[i]->value, view->value, view->image()->current_layout }, - i, - ::glsl::program_domain::glsl_fragment_program); + vk::glsl::binding_set_index_fragment, + m_fragment_prog->binding_table.ftex_location[i]); if (current_fragment_program.texture_state.redirected_textures & (1 << i)) { @@ -575,24 +575,22 @@ 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, - true); + vk::glsl::binding_set_index_fragment, + m_fragment_prog->binding_table.ftex_stencil_location[i]); } } else { 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); + vk::glsl::binding_set_index_fragment, + m_fragment_prog->binding_table.ftex_location[i]); 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, - true); + vk::glsl::binding_set_index_fragment, + m_fragment_prog->binding_table.ftex_stencil_location[i]); } } } @@ -606,8 +604,8 @@ 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); + vk::glsl::binding_set_index_vertex, + m_vertex_prog->binding_table.vtex_location[i]); continue; } @@ -629,8 +627,8 @@ 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); + vk::glsl::binding_set_index_vertex, + m_vertex_prog->binding_table.vtex_location[i]); continue; } @@ -638,8 +636,8 @@ bool VKGSRender::bind_texture_env() validate_image_layout_for_read_access(*m_current_command_buffer, image_ptr, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, sampler_state); m_program->bind_uniform({ vs_sampler_handles[i]->value, image_ptr->value, image_ptr->image()->current_layout }, - i, - ::glsl::program_domain::glsl_vertex_program); + vk::glsl::binding_set_index_vertex, + m_vertex_prog->binding_table.vtex_location[i]); } return out_of_memory; @@ -820,8 +818,6 @@ void VKGSRender::emit_geometry(u32 sub_index) auto volatile_buffer = m_volatile_attribute_storage ? m_volatile_attribute_storage->value : null_buffer_view->value; bool update_descriptors = false; - const auto& binding_table = m_device->get_pipeline_binding_table(); - if (m_current_draw.subdraw_id == 0) { update_descriptors = true; @@ -878,9 +874,10 @@ 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_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); + const auto& binding_table = m_vertex_prog->binding_table; + m_program->bind_uniform(persistent_buffer, vk::glsl::binding_set_index_vertex, binding_table.vertex_buffers_location); + m_program->bind_uniform(volatile_buffer, vk::glsl::binding_set_index_vertex, binding_table.vertex_buffers_location + 1); + m_program->bind_uniform(m_vertex_layout_storage->value, vk::glsl::binding_set_index_vertex, binding_table.vertex_buffers_location + 2); } bool reload_state = (!m_current_draw.subdraw_id++); diff --git a/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp b/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp index dd654a6736..25f4297dee 100644 --- a/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp @@ -26,8 +26,85 @@ std::string VKFragmentDecompilerThread::compareFunction(COMPARE f, const std::st return glsl::compareFunctionImpl(f, Op0, Op1); } +void VKFragmentDecompilerThread::prepareBindingTable() +{ + // First check if we have constants and textures as those need extra work + bool has_constants = false, has_textures = false; + for (const ParamType& PT : m_parr.params[PF_PARAM_UNIFORM]) + { + if (has_constants && has_textures) + { + break; + } + + if (PT.type.starts_with("sampler")) + { + has_textures = true; + continue; + } + + ensure(PT.type.starts_with("vec")); + has_constants = true; + } + + unsigned location = 0; // All bindings must be set from this var + vk_prog->binding_table.context_buffer_location = location++; + if (has_constants) + { + vk_prog->binding_table.cbuf_location = location++; + } + + vk_prog->binding_table.tex_param_location = location++; + vk_prog->binding_table.polygon_stipple_params_location = location++; + + if (has_textures) [[ likely ]] + { + unsigned num_textures = 0; + for (const ParamType& PT : m_parr.params[PF_PARAM_UNIFORM]) + { + if (!PT.type.starts_with("sampler")) + { + continue; + } + + for (const ParamItem& PI : PT.items) + { + num_textures++; + + const auto texture_id = vk::get_texture_index(PI.name); + const auto mask = 1u << texture_id; + + // Allocate real binding + vk_prog->binding_table.ftex_location[texture_id] = location++; + + // Tag the stencil mirror if required + if (properties.redirected_sampler_mask & mask) [[ unlikely ]] + { + vk_prog->binding_table.ftex_stencil_location[texture_id] = 0; + } + } + + // Normalize stencil offsets + if (properties.redirected_sampler_mask != 0) [[ unlikely ]] + { + for (auto& stencil_location : vk_prog->binding_table.ftex_stencil_location) + { + if (stencil_location == umax) + { + continue; + } + + stencil_location = location++; + } + } + } + } +} + void VKFragmentDecompilerThread::insertHeader(std::stringstream & OS) { + prepareBindingTable(); + std::vector required_extensions; if (device_props.has_native_half_support) @@ -97,21 +174,18 @@ void VKFragmentDecompilerThread::insertOutputs(std::stringstream & OS) void VKFragmentDecompilerThread::insertConstants(std::stringstream & OS) { - u32 location = m_binding_table.textures_first_bind_slot; for (const ParamType& PT : m_parr.params[PF_PARAM_UNIFORM]) { - if (PT.type != "sampler1D" && - PT.type != "sampler2D" && - PT.type != "sampler3D" && - PT.type != "samplerCube") + if (PT.type.starts_with("sampler1D")) + { continue; + } for (const ParamItem& PI : PT.items) { std::string samplerType = PT.type; - ensure(PI.name.length() > 3); - int index = atoi(&PI.name[3]); + const int index = vk::get_texture_index(PI.name); const auto mask = (1 << index); if (properties.multisampled_sampler_mask & mask) @@ -135,39 +209,37 @@ void VKFragmentDecompilerThread::insertConstants(std::stringstream & OS) } } - vk::glsl::program_input in; - in.location = location; - in.domain = glsl::glsl_fragment_program; - in.name = PI.name; - in.type = vk::glsl::input_type_texture; - + const int id = vk::get_texture_index(PI.name); + auto in = vk::glsl::program_input::make( + glsl::glsl_fragment_program, + PI.name, + vk::glsl::input_type_texture, + vk::glsl::binding_set_index_fragment, + vk_prog->binding_table.ftex_location[id] + ); inputs.push_back(in); - OS << "layout(set=0, binding=" << location++ << ") uniform " << samplerType << " " << PI.name << ";\n"; + OS << "layout(set=0, binding=" << in.location << ") uniform " << samplerType << " " << PI.name << ";\n"; if (properties.redirected_sampler_mask & mask) { // Insert stencil mirror declaration in.name += "_stencil"; - in.location = location; - + in.location = vk_prog->binding_table.ftex_stencil_location[id]; inputs.push_back(in); - OS << "layout(set=0, binding=" << location++ << ") uniform u" << samplerType << " " << in.name << ";\n"; + OS << "layout(set=0, binding=" << in.location << ") uniform u" << samplerType << " " << in.name << ";\n"; } } } - ensure(location <= m_binding_table.vertex_textures_first_bind_slot); // "Too many sampler descriptors!" - std::string constants_block; for (const ParamType& PT : m_parr.params[PF_PARAM_UNIFORM]) { - if (PT.type == "sampler1D" || - PT.type == "sampler2D" || - PT.type == "sampler3D" || - PT.type == "samplerCube") + if (PT.type.starts_with("sampler1D")) + { continue; + } for (const ParamItem& PI : PT.items) { @@ -177,13 +249,13 @@ void VKFragmentDecompilerThread::insertConstants(std::stringstream & OS) if (!constants_block.empty()) { - OS << "layout(std140, set = 0, binding = 2) uniform FragmentConstantsBuffer\n"; + OS << "layout(std140, set = 1, binding = " << vk_prog->binding_table.cbuf_location << ") uniform FragmentConstantsBuffer\n"; OS << "{\n"; OS << constants_block; OS << "};\n\n"; } - OS << "layout(std140, set = 0, binding = 3) uniform FragmentStateBuffer\n"; + OS << "layout(std140, set = 1, binding = " << vk_prog->binding_table.context_buffer_location << ") uniform FragmentStateBuffer\n"; OS << "{\n"; OS << " float fog_param0;\n"; OS << " float fog_param1;\n"; @@ -195,32 +267,39 @@ void VKFragmentDecompilerThread::insertConstants(std::stringstream & OS) OS << " float wpos_bias;\n"; OS << "};\n\n"; - OS << "layout(std140, set = 0, binding = 4) uniform TextureParametersBuffer\n"; + OS << "layout(std140, set = 1, binding = " << vk_prog->binding_table.tex_param_location << ") uniform TextureParametersBuffer\n"; OS << "{\n"; OS << " sampler_info texture_parameters[16];\n"; OS << "};\n\n"; - OS << "layout(std140, set = 0, binding = " << std::to_string(m_binding_table.rasterizer_env_bind_slot) << ") uniform RasterizerHeap\n"; + OS << "layout(std140, set = 1, binding = " << vk_prog->binding_table.polygon_stipple_params_location << ") uniform RasterizerHeap\n"; OS << "{\n"; OS << " uvec4 stipple_pattern[8];\n"; OS << "};\n\n"; - vk::glsl::program_input in; - in.location = m_binding_table.fragment_constant_buffers_bind_slot; - in.domain = glsl::glsl_fragment_program; - in.name = "FragmentConstantsBuffer"; - in.type = vk::glsl::input_type_uniform_buffer; - inputs.push_back(in); + vk::glsl::program_input in + { + .domain = glsl::glsl_fragment_program, + .type = vk::glsl::input_type_uniform_buffer, + .set = vk::glsl::binding_set_index_fragment + }; - in.location = m_binding_table.fragment_state_bind_slot; + if (!constants_block.empty()) + { + in.location = vk_prog->binding_table.cbuf_location; + in.name = "FragmentConstantsBuffer"; + inputs.push_back(in); + } + + in.location = vk_prog->binding_table.context_buffer_location; in.name = "FragmentStateBuffer"; inputs.push_back(in); - in.location = m_binding_table.fragment_texture_params_bind_slot; + in.location = vk_prog->binding_table.tex_param_location; in.name = "TextureParametersBuffer"; inputs.push_back(in); - in.location = m_binding_table.rasterizer_env_bind_slot; + in.location = vk_prog->binding_table.polygon_stipple_params_location; in.name = "RasterizerHeap"; inputs.push_back(in); } @@ -372,7 +451,6 @@ void VKFragmentDecompilerThread::insertMainEnd(std::stringstream & OS) void VKFragmentDecompilerThread::Task() { - m_binding_table = vk::g_render_device->get_pipeline_binding_table(); m_shader = Decompile(); vk_prog->SetInputs(inputs); } diff --git a/rpcs3/Emu/RSX/VK/VKFragmentProgram.h b/rpcs3/Emu/RSX/VK/VKFragmentProgram.h index 787f38ec05..049455a866 100644 --- a/rpcs3/Emu/RSX/VK/VKFragmentProgram.h +++ b/rpcs3/Emu/RSX/VK/VKFragmentProgram.h @@ -19,7 +19,8 @@ struct VKFragmentDecompilerThread : public FragmentProgramDecompiler std::vector inputs; class VKFragmentProgram *vk_prog; glsl::shader_properties m_shader_props{}; - vk::pipeline_binding_table m_binding_table{}; + + void prepareBindingTable(); public: VKFragmentDecompilerThread(std::string& shader, ParamArray& parr, const RSXFragmentProgram &prog, u32& size, class VKFragmentProgram& dst) @@ -32,6 +33,7 @@ public: void Task(); const std::vector& get_inputs() { return inputs; } + protected: std::string getFloatTypeName(usz elementCount) override; std::string getHalfTypeName(usz elementCount) override; @@ -63,8 +65,19 @@ public: std::vector FragmentConstantOffsetCache; std::array output_color_masks{ {} }; - std::vector uniforms; + + struct + { + u32 context_buffer_location = umax; // Rasterizer context + u32 cbuf_location = umax; // Constants register file + u32 tex_param_location = umax; // Texture configuration data + u32 polygon_stipple_params_location = umax; // Polygon stipple settings + u32 ftex_location[16]; // Texture locations array + u32 ftex_stencil_location[16]; // Texture stencil mirror array + + } binding_table; + void SetInputs(std::vector& inputs); /** * Decompile a fragment shader located in the PS3's Memory. This function operates synchronously. diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 17f42f45e8..d64551f7e9 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -2074,34 +2074,35 @@ void VKGSRender::load_program_env() } } - const auto& binding_table = m_device->get_pipeline_binding_table(); + const auto& vs_binding_table = m_vertex_prog->binding_table; + const auto& fs_binding_table = m_fragment_prog->binding_table; - 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); + m_program->bind_uniform(m_vertex_env_buffer_info, vk::glsl::binding_set_index_vertex, vs_binding_table.context_buffer_location); + m_program->bind_uniform(m_vertex_constants_buffer_info, vk::glsl::binding_set_index_vertex, vs_binding_table.cbuf_location); + m_program->bind_uniform(m_fragment_env_buffer_info, vk::glsl::binding_set_index_fragment, fs_binding_table.context_buffer_location); + m_program->bind_uniform(m_fragment_texture_params_buffer_info, vk::glsl::binding_set_index_fragment, fs_binding_table.tex_param_location); + m_program->bind_uniform(m_raster_env_buffer_info, vk::glsl::binding_set_index_fragment, fs_binding_table.polygon_stipple_params_location); - if (!m_shader_interpreter.is_interpreter(m_program)) + 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_program->bind_uniform(m_vertex_instructions_buffer_info, vk::glsl::binding_set_index_vertex, m_shader_interpreter.get_vertex_instruction_location()); + m_program->bind_uniform(m_fragment_instructions_buffer_info, vk::glsl::binding_set_index_fragment, m_shader_interpreter.get_fragment_instruction_location()); } - else + else if (fs_binding_table.cbuf_location != umax) { - 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); + m_program->bind_uniform(m_fragment_constants_buffer_info, vk::glsl::binding_set_index_fragment, fs_binding_table.cbuf_location); } 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_program->bind_uniform({ predicate, 0, 4 }, vk::glsl::binding_set_index_vertex, vs_binding_table.cr_pred_buffer_location); } 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_program->bind_buffer(m_instancing_constants_array_buffer_info, binding_table.instancing_constants_buffer_slot, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + m_program->bind_uniform(m_instancing_indirection_buffer_info, vk::glsl::binding_set_index_vertex, vs_binding_table.instanced_lut_buffer_location); + m_program->bind_uniform(m_instancing_constants_array_buffer_info, vk::glsl::binding_set_index_vertex, vs_binding_table.instanced_cbuf_location); } // Clear flags diff --git a/rpcs3/Emu/RSX/VK/VKOverlays.cpp b/rpcs3/Emu/RSX/VK/VKOverlays.cpp index 5cd4761983..6a74f8e646 100644 --- a/rpcs3/Emu/RSX/VK/VKOverlays.cpp +++ b/rpcs3/Emu/RSX/VK/VKOverlays.cpp @@ -63,21 +63,21 @@ namespace vk 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) : ""); - const auto input = program_input::make(::glsl::program_domain::glsl_fragment_program, name, program_input_type::input_type_uniform_buffer, 0); + const auto input = program_input::make(::glsl::program_domain::glsl_fragment_program, name, program_input_type::input_type_uniform_buffer, 0, 0); fs_inputs.push_back(input); } for (u32 n = 0; n < m_num_usable_samplers; ++n, ++binding) { 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); + const auto input = program_input::make(::glsl::program_domain::glsl_fragment_program, name, program_input_type::input_type_texture, 0, binding); fs_inputs.push_back(input); } for (u32 n = 0; n < m_num_input_attachments; ++n, ++binding) { 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); + const auto input = program_input::make(::glsl::program_domain::glsl_fragment_program, name, program_input_type::input_type_texture, 0, binding); fs_inputs.push_back(input); } @@ -179,13 +179,14 @@ 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); + program->bind_uniform({ m_ubo.heap->value, m_ubo_offset, std::max(m_ubo_length, 4u) }, 0, 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); + const auto [set, location] = program->get_uniform_location(::glsl::glsl_fragment_program, glsl::input_type_texture, "fs" + std::to_string(n)); + program->bind_uniform(info, set, location); } program->bind(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS); @@ -488,6 +489,7 @@ namespace vk "push_constants", glsl::input_type_push_constant, 0, + 0, glsl::push_constant_ref { .size = 68 } ) ); @@ -503,6 +505,7 @@ namespace vk "push_constants", glsl::input_type_push_constant, 0, + 0, glsl::push_constant_ref {.offset = 68, .size = 12 } ) ); @@ -715,6 +718,7 @@ namespace vk "push_constants", vk::glsl::input_type_push_constant, 0, + 0, glsl::push_constant_ref{ .size = 32 }) }; } @@ -864,6 +868,7 @@ namespace vk "push_constants", vk::glsl::input_type_push_constant, 0, + 0, glsl::push_constant_ref{ .size = 16 } ) ); diff --git a/rpcs3/Emu/RSX/VK/VKPipelineCompiler.cpp b/rpcs3/Emu/RSX/VK/VKPipelineCompiler.cpp index 13c16513d3..884841ec4b 100644 --- a/rpcs3/Emu/RSX/VK/VKPipelineCompiler.cpp +++ b/rpcs3/Emu/RSX/VK/VKPipelineCompiler.cpp @@ -54,7 +54,9 @@ namespace vk const VkComputePipelineCreateInfo& create_info, const std::vector& cs_inputs) { - return std::make_unique(*m_device, create_info, cs_inputs); + auto program = std::make_unique(*m_device, create_info, cs_inputs); + program->link(false); + return program; } std::unique_ptr pipe_compiler::int_compile_graphics_pipe( @@ -62,7 +64,9 @@ namespace vk const std::vector& vs_inputs, const std::vector& fs_inputs) { - return std::make_unique(*m_device, create_info, vs_inputs, fs_inputs); + auto program = std::make_unique(*m_device, create_info, vs_inputs, fs_inputs); + program->link(true); + return program; } std::unique_ptr pipe_compiler::int_compile_graphics_pipe( @@ -171,7 +175,7 @@ namespace vk op_flags flags, callback_t callback, const std::vector& cs_inputs) { - if (flags == COMPILE_INLINE) + if (flags & COMPILE_INLINE) { return int_compile_compute_pipe(create_info, cs_inputs); } @@ -187,7 +191,7 @@ namespace vk const std::vector& fs_inputs) { // It is very inefficient to defer this as all pointers need to be saved - ensure(flags == COMPILE_INLINE); + ensure(flags & COMPILE_INLINE); return int_compile_graphics_pipe(create_info, vs_inputs, fs_inputs); } @@ -200,7 +204,7 @@ namespace vk const std::vector& fs_inputs) { VkShaderModule modules[] = { vs, fs }; - if (flags == COMPILE_INLINE) + if (flags & COMPILE_INLINE) { return int_compile_graphics_pipe(create_info, modules, vs_inputs, fs_inputs); } diff --git a/rpcs3/Emu/RSX/VK/VKPipelineCompiler.h b/rpcs3/Emu/RSX/VK/VKPipelineCompiler.h index a915595e62..25c0b8e1c0 100644 --- a/rpcs3/Emu/RSX/VK/VKPipelineCompiler.h +++ b/rpcs3/Emu/RSX/VK/VKPipelineCompiler.h @@ -53,13 +53,16 @@ namespace vk class pipe_compiler { public: - enum op_flags + enum op_flag_bits { COMPILE_DEFAULT = 0, COMPILE_INLINE = 1, - COMPILE_DEFERRED = 2 + COMPILE_DEFERRED = 2, + SEPARATE_SHADER_OBJECTS = 4 }; + using op_flags = rsx::flags32_t; + using callback_t = std::function&)>; pipe_compiler(); diff --git a/rpcs3/Emu/RSX/VK/VKProgramHelper.hpp b/rpcs3/Emu/RSX/VK/VKProgramHelper.hpp new file mode 100644 index 0000000000..328df80f1d --- /dev/null +++ b/rpcs3/Emu/RSX/VK/VKProgramHelper.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include "VKProgramPipeline.h" + +namespace vk +{ + namespace glsl + { + + } +} + diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp index 2090b6dd26..5ac4bd9c26 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp @@ -14,6 +14,30 @@ namespace vk { using namespace ::glsl; + bool operator == (const descriptor_slot_t& a, const VkDescriptorImageInfo& b) + { + const auto ptr = std::get_if(&a); + return !!ptr && + ptr->imageView == b.imageView && + ptr->sampler == b.sampler && + ptr->imageLayout == b.imageLayout; + } + + bool operator == (const descriptor_slot_t& a, const VkDescriptorBufferInfo& b) + { + const auto ptr = std::get_if(&a); + return !!ptr && + ptr->buffer == b.buffer && + ptr->offset == b.offset && + ptr->range == b.range; + } + + bool operator == (const descriptor_slot_t& a, const VkBufferView& b) + { + const auto ptr = std::get_if(&a); + return !!ptr && *ptr == b; + } + VkDescriptorType to_descriptor_type(program_input_type type) { switch (type) @@ -120,42 +144,24 @@ namespace vk void program::init() { - linked = false; - - fs_texture_bindings.fill(~0u); - fs_texture_mirror_bindings.fill(~0u); - vs_texture_bindings.fill(~0u); + m_linked = false; } program::program(VkDevice dev, const VkGraphicsPipelineCreateInfo& create_info, const std::vector &vertex_inputs, const std::vector& fragment_inputs) - : m_device(dev) + : m_device(dev), m_info(create_info) { 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, const VkComputePipelineCreateInfo& create_info, const std::vector& compute_inputs) - : m_device(dev) + : m_device(dev), m_info(create_info) { 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() @@ -165,257 +171,352 @@ namespace vk 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); + + for (auto& set : m_sets) + { + set.destroy(); + } } } program& program::load_uniforms(const std::vector& inputs) { - ensure(!linked); // "Cannot change uniforms in already linked program!" + ensure(!m_linked); // "Cannot change uniforms in already linked program!" for (auto &item : inputs) { - uniforms[item.type].push_back(item); + ensure(item.set < binding_set_index_max_enum); // Ensure we have a valid set id + ensure(item.location < 128u || item.type == input_type_push_constant); // Arbitrary limit but useful to catch possibly uninitialized values + m_sets[item.set].m_inputs[item.type].push_back(item); } return *this; } - program& program::link() + program& program::link(bool separate_objects) { - // Preprocess texture bindings - // Link step is only useful for rasterizer programs, compute programs do not need this - for (const auto &uniform : uniforms[program_input_type::input_type_texture]) - { - if (const auto name_start = uniform.name.find("tex"); name_start != umax) - { - const auto name_end = uniform.name.find("_stencil"); - const auto index_start = name_start + 3; // Skip 'tex' part - const auto index_length = (name_end != umax) ? name_end - index_start : name_end; - const auto index_part = uniform.name.substr(index_start, index_length); - const auto index = std::stoi(index_part); + auto p_graphics_info = std::get_if(&m_info); + auto p_compute_info = !p_graphics_info ? std::get_if(&m_info) : nullptr; + const bool is_graphics_pipe = p_graphics_info != nullptr; - if (name_start == 0) + if (!is_graphics_pipe) [[ likely ]] + { + // We only support compute and graphics, so disable this for compute + separate_objects = false; + } + + if (!separate_objects) + { + // Collapse all sets into set 0 if validation passed + auto& sink = m_sets[0]; + for (auto& set : m_sets) + { + for (auto& type_arr : set.m_inputs) { - // Fragment texture (tex...) - if (name_end == umax) + if (type_arr.empty()) { - // Normal texture - fs_texture_bindings[index] = uniform.location; - } - else - { - // Stencil mirror - fs_texture_mirror_bindings[index] = uniform.location; + continue; } + + auto type = type_arr.front().type; + auto& dst = sink.m_inputs[type]; + dst.insert(dst.end(), type_arr.begin(), type_arr.end()); + + // Clear + type_arr.clear(); } - else + } + + sink.validate(); + sink.init(m_device); + } + else + { + for (auto& set : m_sets) + { + for (auto& type_arr : set.m_inputs) { - // Vertex texture (vtex...) - vs_texture_bindings[index] = uniform.location; + if (type_arr.empty()) + { + continue; + } + + // Real set + set.validate(); + set.init(m_device); + break; } } } - linked = true; + create_pipeline_layout(); + ensure(m_pipeline_layout); + + if (is_graphics_pipe) + { + VkGraphicsPipelineCreateInfo create_info = *p_graphics_info; + create_info.layout = m_pipeline_layout; + CHECK_RESULT(vkCreateGraphicsPipelines(m_device, nullptr, 1, &create_info, nullptr, &m_pipeline)); + } + else + { + VkComputePipelineCreateInfo create_info = *p_compute_info; + create_info.layout = m_pipeline_layout; + CHECK_RESULT(vkCreateComputePipelines(m_device, nullptr, 1, &create_info, nullptr, &m_pipeline)); + } + + m_linked = true; return *this; } bool program::has_uniform(program_input_type type, const std::string& uniform_name) { - const auto& uniform = uniforms[type]; - return std::any_of(uniform.cbegin(), uniform.cend(), [&uniform_name](const auto& u) + for (auto& set : m_sets) { - return u.name == uniform_name; - }); - } - - 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) + const auto& uniform = set.m_inputs[type]; + return std::any_of(uniform.cbegin(), uniform.cend(), [&uniform_name](const auto& u) { - if (m_descriptor_slots[uniform.location].matches(image_descriptor)) - { - return; - } + return u.name == uniform_name; + }); + } + } - next_descriptor_set(); - m_descriptor_set.push(image_descriptor, type, uniform.location); - m_descriptors_dirty[uniform.location] = false; - return; + std::pair program::get_uniform_location(::glsl::program_domain domain, program_input_type type, const std::string& uniform_name) + { + for (unsigned i = 0; i < ::size32(m_sets); ++i) + { + const auto& type_arr = m_sets[i].m_inputs[type]; + const auto result = std::find_if(type_arr.cbegin(), type_arr.cend(), [&](const auto& u) + { + return u.domain == domain && u.name == uniform_name; + }); + + if (result != type_arr.end()) + { + return { i, result->location }; } } - rsx_log.notice("texture not found in program: %s", uniform_name.c_str()); + return { umax, umax }; } - void program::bind_uniform(const VkDescriptorImageInfo & image_descriptor, int texture_unit, ::glsl::program_domain domain, bool is_stencil_mirror) + void program::bind_uniform(const VkDescriptorImageInfo& image_descriptor, u32 set_id, u32 binding_point) { - ensure(domain != ::glsl::program_domain::glsl_compute_program); - - u32 binding; - if (domain == ::glsl::program_domain::glsl_fragment_program) - { - binding = (is_stencil_mirror) ? fs_texture_mirror_bindings[texture_unit] : fs_texture_bindings[texture_unit]; - } - else - { - binding = vs_texture_bindings[texture_unit]; - } - - if (binding == ~0u) [[ unlikely ]] - { - rsx_log.notice("texture not found in program: %stex%u", (domain == ::glsl::program_domain::glsl_vertex_program) ? "v" : "", texture_unit); - return; - } - - if (m_descriptor_slots[binding].matches(image_descriptor)) + if (m_sets[set_id].m_descriptor_slots[binding_point] == image_descriptor) { return; } - next_descriptor_set(); - m_descriptor_set.push(image_descriptor, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, binding); - m_descriptors_dirty[binding] = false; + m_sets[set_id].notify_descriptor_slot_updated(binding_point, image_descriptor); } - void program::bind_uniform(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point) + void program::bind_uniform(const VkDescriptorBufferInfo &buffer_descriptor, u32 set_id, u32 binding_point) { - bind_buffer(buffer_descriptor, binding_point, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); - } - - void program::bind_uniform(const VkBufferView &buffer_view, u32 binding_point) - { - if (m_descriptor_slots[binding_point].matches(buffer_view)) + if (m_sets[set_id].m_descriptor_slots[binding_point] == buffer_descriptor) { return; } - next_descriptor_set(); - m_descriptor_set.push(buffer_view, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, binding_point); - m_descriptors_dirty[binding_point] = false; + m_sets[set_id].notify_descriptor_slot_updated(binding_point, buffer_descriptor); } - void program::bind_uniform(const VkBufferView &buffer_view, program_input_type type, const std::string &binding_name) + void program::bind_uniform(const VkBufferView &buffer_view, u32 set_id, u32 binding_point) { - for (const auto &uniform : uniforms[type]) - { - if (uniform.name == binding_name) - { - bind_uniform(buffer_view, uniform.location); - return; - } - } - - 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) - { - if (m_descriptor_slots[binding_point].matches(buffer_descriptor)) + if (m_sets[set_id].m_descriptor_slots[binding_point] == buffer_view) { return; } - next_descriptor_set(); - m_descriptor_set.push(buffer_descriptor, type, binding_point); - m_descriptors_dirty[binding_point] = false; + m_sets[set_id].notify_descriptor_slot_updated(binding_point, buffer_view); } - void program::bind_uniform_array(const VkDescriptorImageInfo* image_descriptors, VkDescriptorType type, int count, u32 binding_point) + void program::bind_uniform_array(const VkDescriptorImageInfo* image_descriptors, VkDescriptorType type, int count, u32 set_id, u32 binding_point) { - // FIXME: Unoptimized... - bool match = true; + auto& set = m_sets[set_id]; for (int i = 0; i < count; ++i) { - if (!m_descriptor_slots[binding_point + i].matches(image_descriptors[i])) + if (set.m_descriptor_slots[binding_point + i] != image_descriptors[i]) + { + set.notify_descriptor_slot_updated(binding_point + i, image_descriptors[i]); + } + } + } + + void program::create_pipeline_layout() + { + ensure(!m_linked); + ensure(m_pipeline_layout == VK_NULL_HANDLE); + + rsx::simple_array push_constants{}; + rsx::simple_array set_layouts{}; + + for (auto& set : m_sets) + { + if (!set.m_device) { - match = false; break; } + + set.next_descriptor_set(); // Initializes the set layout and allocates first set + set_layouts.push_back(set.m_descriptor_set_layout); + + for (const auto& input : set.m_inputs[input_type_push_constant]) + { + const auto& range = input.as_push_constant(); + push_constants.push_back({ + .stageFlags = to_shader_stage_flags(input.domain), + .offset = range.offset, + .size = range.size + }); + } } - if (match) + VkPipelineLayoutCreateInfo create_info + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .flags = 0, + .setLayoutCount = set_layouts.size(), + .pSetLayouts = set_layouts.data(), + .pushConstantRangeCount = push_constants.size(), + .pPushConstantRanges = push_constants.data() + }; + CHECK_RESULT(vkCreatePipelineLayout(m_device, &create_info, nullptr, &m_pipeline_layout)); + } + + program& program::bind(const vk::command_buffer& cmd, VkPipelineBindPoint bind_point) + { + VkDescriptorSet bind_sets[binding_set_index_max_enum]; + unsigned count = 0; + + for (auto& set : m_sets) + { + if (!set.m_device) + { + break; + } + + bind_sets[count++] = set.m_descriptor_set.value(); // Current set pointer for binding + set.next_descriptor_set(); // Flush queue and update pointers + } + + vkCmdBindPipeline(cmd, bind_point, m_pipeline); + vkCmdBindDescriptorSets(cmd, bind_point, m_pipeline_layout, 0, count, bind_sets, 0, nullptr); + return *this; + } + + void descriptor_table_t::destroy() + { + if (!m_device) { return; } - next_descriptor_set(); - m_descriptor_set.push(image_descriptors, static_cast(count), type, binding_point); - - for (int i = 0; i < count; ++i) - { - m_descriptors_dirty[binding_point] = false; - } + vkDestroyDescriptorSetLayout(m_device, m_descriptor_set_layout, nullptr); + vk::get_resource_manager()->dispose(m_descriptor_pool); } - VkDescriptorSet program::allocate_descriptor_set() + void descriptor_table_t::init(VkDevice dev) + { + m_device = dev; + + size_t bind_slots_count = 0; + for (auto& type_arr : m_inputs) + { + if (type_arr.empty() || type_arr.front().type == input_type_push_constant) + { + continue; + } + + bind_slots_count += type_arr.size(); + } + + m_descriptor_slots.resize(bind_slots_count); + std::memset(m_descriptor_slots.data(), 0, sizeof(descriptor_slot_t) * bind_slots_count); + + m_descriptors_dirty.resize(bind_slots_count); + std::fill(m_descriptors_dirty.begin(), m_descriptors_dirty.end(), false); + } + + VkDescriptorSet descriptor_table_t::allocate_descriptor_set() { if (!m_descriptor_pool) { create_descriptor_pool(); + create_descriptor_set_layout(); } return m_descriptor_pool->allocate(m_descriptor_set_layout); } - void program::next_descriptor_set() + void descriptor_table_t::next_descriptor_set() { - const auto new_set = allocate_descriptor_set(); - const auto old_set = m_descriptor_set.value(); - - if (old_set) + if (!m_descriptor_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(); + std::fill(m_descriptors_dirty.begin(), m_descriptors_dirty.end(), false); + return; } - m_descriptor_set = allocate_descriptor_set(); + // Check if we need to actually open a new set + if (!m_any_descriptors_dirty) + { + return; + } + + auto old_set = m_descriptor_set.value(); + auto new_set = allocate_descriptor_set(); + + auto push_descriptor_slot = [this](unsigned idx) + { + const auto& slot = m_descriptor_slots[idx]; + const VkDescriptorType type = m_descriptor_types[idx]; + if (auto ptr = std::get_if(&slot)) + { + m_descriptor_set.push(*ptr, type, idx); + return; + } + + if (auto ptr = std::get_if(&slot)) + { + m_descriptor_set.push(*ptr, type, idx); + return; + } + + if (auto ptr = std::get_if(&slot)) + { + m_descriptor_set.push(*ptr, type, idx); + return; + } + + fmt::throw_exception("Unexpected descriptor structure at index %u", idx); + }; + + m_copy_cmds.clear(); + for (unsigned i = 0; i < m_descriptor_slots.size(); ++i) + { + if (m_descriptors_dirty[i]) + { + // Push + push_descriptor_slot(i); + m_descriptors_dirty[i] = false; + continue; + } + + m_copy_cmds.push_back({ + .sType = VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET, + .srcSet = old_set, + .srcBinding = i, + .dstSet = new_set, + .dstBinding = i, + .descriptorCount = 1 + }); + } + + m_descriptor_set.push(m_copy_cmds); // Write previous state + m_descriptor_set = new_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() + void descriptor_table_t::create_descriptor_set_layout() { ensure(m_descriptor_set_layout == VK_NULL_HANDLE); @@ -425,7 +526,7 @@ namespace vk m_descriptor_pool_sizes.clear(); m_descriptor_pool_sizes.reserve(input_type_max_enum); - for (const auto& type_arr : uniforms) + for (const auto& type_arr : m_inputs) { if (type_arr.empty() || type_arr.front().type == input_type_push_constant) { @@ -445,6 +546,13 @@ namespace vk .stageFlags = to_shader_stage_flags(input.domain) }; bindings.push_back(binding); + + if (m_descriptor_types.size() < (input.location + 1)) + { + m_descriptor_types.resize((input.location + 1)); + } + + m_descriptor_types[input.location] = type; m_descriptor_pool_sizes.back().descriptorCount++; } } @@ -459,38 +567,31 @@ namespace vk CHECK_RESULT(vkCreateDescriptorSetLayout(m_device, &set_layout_create_info, nullptr, &m_descriptor_set_layout)); } - void program::create_pipeline_layout() + void descriptor_table_t::create_descriptor_pool() { - ensure(!linked); - ensure(m_pipeline_layout == VK_NULL_HANDLE); - - create_descriptor_set_layout(); - - rsx::simple_array 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(); m_descriptor_pool->create(*vk::get_current_renderer(), m_descriptor_pool_sizes); } + + void descriptor_table_t::validate() const + { + // Check for overlapping locations + std::set taken_locations; + + for (auto& type_arr : m_inputs) + { + if (type_arr.empty() || + type_arr.front().type == input_type_push_constant) + { + continue; + } + + for (const auto& input : type_arr) + { + ensure(taken_locations.find(input.location) == taken_locations.end(), "Overlapping input locations found."); + taken_locations.insert(input.location); + } + } + } } } diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.h b/rpcs3/Emu/RSX/VK/VKProgramPipeline.h index 0b3e8ed7d1..96940a8efe 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.h +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.h @@ -54,7 +54,8 @@ namespace vk using bound_data_t = std::variant; bound_data_t bound_data; - u32 location; + u32 set = 0; + u32 location = umax; std::string name; inline bound_buffer& as_buffer() { return *std::get_if(&bound_data); } @@ -69,6 +70,7 @@ namespace vk ::glsl::program_domain domain, const std::string& name, program_input_type type, + u32 set, u32 location, const bound_data_t& data = bound_buffer{}) { @@ -77,38 +79,13 @@ namespace vk .domain = domain, .type = type, .bound_data = data, + .set = set, .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 { ::glsl::program_domain type = ::glsl::program_domain::glsl_vertex_program; @@ -132,37 +109,71 @@ namespace vk VkShaderModule get_handle() const; }; - class program + using descriptor_slot_t = std::variant; + + struct descriptor_table_t { - std::array, input_type_max_enum> uniforms; VkDevice m_device = VK_NULL_HANDLE; - - VkPipeline m_pipeline = VK_NULL_HANDLE; - VkPipelineLayout m_pipeline_layout = VK_NULL_HANDLE; - - std::array fs_texture_bindings; - std::array fs_texture_mirror_bindings; - std::array vs_texture_bindings; - bool linked = false; + std::array, input_type_max_enum> m_inputs; std::unique_ptr m_descriptor_pool; VkDescriptorSetLayout m_descriptor_set_layout = VK_NULL_HANDLE; vk::descriptor_set m_descriptor_set{}; rsx::simple_array m_descriptor_pool_sizes; + rsx::simple_array m_descriptor_types; std::vector m_descriptor_slots; std::vector m_descriptors_dirty; rsx::simple_array m_copy_cmds; + bool m_any_descriptors_dirty = false; - void init(); + void init(VkDevice dev); + void destroy(); + + void validate() const; void create_descriptor_set_layout(); - void create_pipeline_layout(); void create_descriptor_pool(); VkDescriptorSet allocate_descriptor_set(); void next_descriptor_set(); + template + inline void notify_descriptor_slot_updated(u32 slot, const T& data) + { + m_descriptors_dirty[slot] = true; + m_descriptor_slots[slot] = data; + m_any_descriptors_dirty = true; + } + }; + + enum binding_set_index : u32 + { + // For separate shader objects + binding_set_index_vertex = 0, + binding_set_index_fragment = 1, + + // Aliases + binding_set_index_compute = 0, + binding_set_index_unified = 0, + + // Meta + binding_set_index_max_enum = 2, + }; + + class program + { + VkDevice m_device = VK_NULL_HANDLE; + VkPipeline m_pipeline = VK_NULL_HANDLE; + VkPipelineLayout m_pipeline_layout = VK_NULL_HANDLE; + + std::variant m_info; + std::array m_sets; + bool m_linked = false; + + void init(); + void create_pipeline_layout(); + program& load_uniforms(const std::vector& inputs); public: @@ -173,20 +184,18 @@ namespace vk program(program&& other) = delete; ~program(); - program& link(); + program& link(bool separate_stages); program& bind(const vk::command_buffer& cmd, VkPipelineBindPoint bind_point); bool has_uniform(program_input_type type, const std::string &uniform_name); - u32 get_uniform_location(program_input_type type, const std::string& uniform_name); + std::pair get_uniform_location(::glsl::program_domain domain, 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(const VkDescriptorImageInfo &image_descriptor, u32 set_id, u32 binding_point); + void bind_uniform(const VkDescriptorBufferInfo &buffer_descriptor, u32 set_id, u32 binding_point); + void bind_uniform(const VkBufferView &buffer_view, u32 set_id, u32 binding_point); + void bind_uniform(const VkBufferView &buffer_view, ::glsl::program_domain domain, program_input_type type, const std::string &binding_name); - void bind_uniform_array(const VkDescriptorImageInfo* image_descriptors, VkDescriptorType type, int count, u32 binding_point); + void bind_uniform_array(const VkDescriptorImageInfo* image_descriptors, VkDescriptorType type, int count, u32 set_id, u32 binding_point); inline VkPipelineLayout layout() const { return m_pipeline_layout; } inline VkPipeline value() const { return m_pipeline; } diff --git a/rpcs3/Emu/RSX/VK/VKResolveHelper.h b/rpcs3/Emu/RSX/VK/VKResolveHelper.h index 2403f5bc59..9bc9e4f532 100644 --- a/rpcs3/Emu/RSX/VK/VKResolveHelper.h +++ b/rpcs3/Emu/RSX/VK/VKResolveHelper.h @@ -31,6 +31,7 @@ namespace vk ::glsl::program_domain::glsl_compute_program, "multisampled", glsl::input_type_storage_texture, + 0, 0 ), @@ -38,6 +39,7 @@ namespace vk ::glsl::program_domain::glsl_compute_program, "resolve", glsl::input_type_storage_texture, + 0, 1 ), }; @@ -51,8 +53,8 @@ namespace vk { 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_program->bind_uniform({ VK_NULL_HANDLE, resolved_view->value, resolve->current_layout }, "resolve", VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); + m_program->bind_uniform({ VK_NULL_HANDLE, msaa_view->value, multisampled->current_layout }, 0, 0); + m_program->bind_uniform({ VK_NULL_HANDLE, resolved_view->value, resolve->current_layout }, 0, 1); } void run(const vk::command_buffer& cmd, vk::viewable_image* msaa_image, vk::viewable_image* resolve_image) @@ -116,6 +118,7 @@ namespace vk ::glsl::glsl_fragment_program, "push_constants", glsl::input_type_push_constant, + 0, umax, glsl::push_constant_ref{ .size = 16 } )); diff --git a/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp index da10965be9..e7c4862dbc 100644 --- a/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp +++ b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp @@ -471,7 +471,7 @@ namespace vk void shader_interpreter::update_fragment_textures(const std::array& sampled_images) { // 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"); + auto [set, binding] = m_current_interpreter->get_uniform_location(::glsl::glsl_fragment_program, glsl::input_type_texture, "texture1D_array"); if (binding == umax) { return; @@ -480,7 +480,7 @@ namespace vk const VkDescriptorImageInfo* texture_ptr = sampled_images.data(); for (u32 i = 0; i < 4; ++i, ++binding, texture_ptr += 16) { - m_current_interpreter->bind_uniform_array(texture_ptr, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 16, binding); + m_current_interpreter->bind_uniform_array(texture_ptr, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 16, set, binding); } } diff --git a/rpcs3/Emu/RSX/VK/VKVertexProgram.cpp b/rpcs3/Emu/RSX/VK/VKVertexProgram.cpp index 60f33f49c5..b6def63136 100644 --- a/rpcs3/Emu/RSX/VK/VKVertexProgram.cpp +++ b/rpcs3/Emu/RSX/VK/VKVertexProgram.cpp @@ -6,7 +6,6 @@ #include "vkutils/device.h" #include "../Program/GLSLCommon.h" - std::string VKVertexDecompilerThread::getFloatTypeName(usz elementCount) { return glsl::getFloatTypeNameImpl(elementCount); @@ -27,14 +26,57 @@ std::string VKVertexDecompilerThread::compareFunction(COMPARE f, const std::stri return glsl::compareFunctionImpl(f, Op0, Op1, scalar); } +void VKVertexDecompilerThread::prepareBindingTable() +{ + u32 location = 0; + vk_prog->binding_table.vertex_buffers_location = location; + location += 3; // Persistent verts, volatile and layout data + + vk_prog->binding_table.context_buffer_location = location++; + if (m_device_props.emulate_conditional_rendering) + { + vk_prog->binding_table.cr_pred_buffer_location = location++; + } + + for (const ParamType& PT : m_parr.params[PF_PARAM_UNIFORM]) + { + const bool is_texture_type = PT.type.starts_with("sampler"); + + for (const ParamItem& PI : PT.items) + { + if (is_texture_type) + { + const int id = vk::get_texture_index(PI.name); + vk_prog->binding_table.vtex_location[id] = location++; + continue; + } + + if (PI.name.starts_with("vc[")) + { + if (!(m_prog.ctrl & RSX_SHADER_CONTROL_INSTANCED_CONSTANTS)) + { + vk_prog->binding_table.cbuf_location = location++; + continue; + } + + vk_prog->binding_table.instanced_lut_buffer_location = location++; + vk_prog->binding_table.instanced_cbuf_location = location++; + continue; + } + } + } +} + void VKVertexDecompilerThread::insertHeader(std::stringstream &OS) { + prepareBindingTable(); + OS << "#version 450\n\n" "#extension GL_ARB_separate_shader_objects : enable\n\n"; OS << - "layout(std140, set = 0, binding = 0) uniform VertexContextBuffer\n" + "layout(std140, set = 0, binding = " << vk_prog->binding_table.context_buffer_location << " ) uniform VertexContextBuffer\n" "{\n" " mat4 scale_offset_mat;\n" " ivec4 user_clip_enabled[2];\n" @@ -45,13 +87,31 @@ void VKVertexDecompilerThread::insertHeader(std::stringstream &OS) " float z_far;\n" "};\n\n"; + vk::glsl::program_input context_input = + { + .domain = glsl::glsl_vertex_program, + .type = vk::glsl::input_type_uniform_buffer, + .location = vk_prog->binding_table.context_buffer_location, + .name = "VertexContextBuffer" + }; + inputs.push_back(context_input); + if (m_device_props.emulate_conditional_rendering) { OS << - "layout(std430, set = 0, binding = 8) readonly buffer EXT_Conditional_Rendering\n" + "layout(std430, set = 0, binding = " << vk_prog->binding_table.cr_pred_buffer_location << ") readonly buffer EXT_Conditional_Rendering\n" "{\n" " uint conditional_rendering_predicate;\n" "};\n\n"; + + vk::glsl::program_input predicate_input = + { + .domain = glsl::glsl_vertex_program, + .type = vk::glsl::input_type_storage_buffer, + .location = vk_prog->binding_table.cr_pred_buffer_location, + .name = "EXT_Conditional_Rendering" + }; + inputs.push_back(predicate_input); } OS << @@ -63,52 +123,50 @@ void VKVertexDecompilerThread::insertHeader(std::stringstream &OS) " uint layout_ptr_offset;\n" " uint xform_constants_offset;\n"; + u32 push_constants_size = 5 * sizeof(u32); if (m_device_props.emulate_conditional_rendering) { + push_constants_size += sizeof(u32); OS << " uint conditional_rendering_enabled;\n"; } OS << "};\n\n"; - vk::glsl::program_input in; - in.location = m_binding_table.vertex_params_bind_slot; - in.domain = glsl::glsl_vertex_program; - in.name = "VertexContextBuffer"; - in.type = vk::glsl::input_type_uniform_buffer; - inputs.push_back(in); + vk::glsl::program_input push_constants = + { + .domain = glsl::glsl_vertex_program, + .type = vk::glsl::input_type_push_constant, + .bound_data = vk::glsl::push_constant_ref{ .offset = 0, .size = push_constants_size } + }; + inputs.push_back(push_constants); } void VKVertexDecompilerThread::insertInputs(std::stringstream& OS, const std::vector& /*inputs*/) { - OS << "layout(set=0, binding=5) uniform usamplerBuffer persistent_input_stream;\n"; // Data stream with persistent vertex data (cacheable) - OS << "layout(set=0, binding=6) uniform usamplerBuffer volatile_input_stream;\n"; // Data stream with per-draw data (registers and immediate draw data) - OS << "layout(set=0, binding=7) uniform usamplerBuffer vertex_layout_stream;\n"; // Data stream defining vertex data layout + static const char* input_streams[] = + { + "persistent_input_stream", // Data stream with persistent vertex data (cacheable) + "volatile_input_stream", // Data stream with per-draw data (registers and immediate draw data) + "vertex_layout_stream" // Data stream defining vertex data layout" + }; - vk::glsl::program_input in; - in.location = m_binding_table.vertex_buffers_first_bind_slot; - in.domain = glsl::glsl_vertex_program; - in.name = "persistent_input_stream"; - in.type = vk::glsl::input_type_texel_buffer; - this->inputs.push_back(in); + int location = vk_prog->binding_table.vertex_buffers_location; + for (const auto& stream : input_streams) + { + OS << "layout(set=0, binding=" << location << ") uniform usamplerBuffer " << stream << ";\n"; - in.location = m_binding_table.vertex_buffers_first_bind_slot + 1; - in.domain = glsl::glsl_vertex_program; - in.name = "volatile_input_stream"; - in.type = vk::glsl::input_type_texel_buffer; - this->inputs.push_back(in); - - in.location = m_binding_table.vertex_buffers_first_bind_slot + 2; - in.domain = glsl::glsl_vertex_program; - in.name = "vertex_layout_stream"; - in.type = vk::glsl::input_type_texel_buffer; - this->inputs.push_back(in); + vk::glsl::program_input in; + in.location = location++; + in.domain = glsl::glsl_vertex_program; + in.name = stream; + in.type = vk::glsl::input_type_texel_buffer; + this->inputs.push_back(in); + } } void VKVertexDecompilerThread::insertConstants(std::stringstream & OS, const std::vector & constants) { vk::glsl::program_input in; - u32 location = m_binding_table.vertex_textures_first_bind_slot; - for (const ParamType &PT : constants) { for (const ParamItem &PI : PT.items) @@ -117,12 +175,12 @@ void VKVertexDecompilerThread::insertConstants(std::stringstream & OS, const std { if (!(m_prog.ctrl & RSX_SHADER_CONTROL_INSTANCED_CONSTANTS)) { - OS << "layout(std430, set=0, binding=" << static_cast(m_binding_table.vertex_constant_buffers_bind_slot) << ") readonly buffer VertexConstantsBuffer\n"; + OS << "layout(std430, set=0, binding=" << vk_prog->binding_table.cbuf_location << ") readonly buffer VertexConstantsBuffer\n"; OS << "{\n"; OS << " vec4 vc[];\n"; OS << "};\n\n"; - in.location = m_binding_table.vertex_constant_buffers_bind_slot; + in.location = vk_prog->binding_table.cbuf_location; in.domain = glsl::glsl_vertex_program; in.name = "VertexConstantsBuffer"; in.type = vk::glsl::input_type_storage_buffer; @@ -133,26 +191,26 @@ void VKVertexDecompilerThread::insertConstants(std::stringstream & OS, const std else { // 1. Bind indirection lookup buffer - OS << "layout(std430, set=0, binding=" << static_cast(m_binding_table.instancing_lookup_table_bind_slot) << ") readonly buffer InstancingData\n"; + OS << "layout(std430, set=0, binding=" << vk_prog->binding_table.instanced_lut_buffer_location << ") readonly buffer InstancingData\n"; OS << "{\n"; OS << " int constants_addressing_lookup[];\n"; OS << "};\n\n"; - in.location = m_binding_table.instancing_lookup_table_bind_slot; + in.location = vk_prog->binding_table.instanced_lut_buffer_location; in.domain = glsl::glsl_vertex_program; in.name = "InstancingData"; in.type = vk::glsl::input_type_storage_buffer; inputs.push_back(in); // 2. Bind actual constants buffer - OS << "layout(std430, set=0, binding=" << static_cast(m_binding_table.instancing_constants_buffer_slot) << ") readonly buffer VertexConstantsBuffer\n"; + OS << "layout(std430, set=0, binding=" << vk_prog->binding_table.instanced_cbuf_location << ") readonly buffer VertexConstantsBuffer\n"; OS << "{\n"; OS << " vec4 instanced_constants_array[];\n"; OS << "};\n\n"; OS << "#define CONSTANTS_ARRAY_LENGTH " << (properties.has_indexed_constants ? 468 : ::size32(m_constant_ids)) << "\n\n"; - in.location = m_binding_table.instancing_constants_buffer_slot; + in.location = vk_prog->binding_table.instanced_cbuf_location; in.domain = glsl::glsl_vertex_program; in.name = "VertexConstantsBuffer"; in.type = vk::glsl::input_type_storage_buffer; @@ -166,7 +224,8 @@ void VKVertexDecompilerThread::insertConstants(std::stringstream & OS, const std PT.type == "sampler1D" || PT.type == "sampler3D") { - in.location = location; + const int id = vk::get_texture_index(PI.name); + in.location = vk_prog->binding_table.vtex_location[id]; in.name = PI.name; in.type = vk::glsl::input_type_texture; @@ -190,7 +249,7 @@ void VKVertexDecompilerThread::insertConstants(std::stringstream & OS, const std } } - OS << "layout(set = 0, binding=" << location++ << ") uniform " << samplerType << " " << PI.name << ";\n"; + OS << "layout(set = 0, binding=" << in.location << ") uniform " << samplerType << " " << PI.name << ";\n"; } } } @@ -371,8 +430,6 @@ void VKVertexDecompilerThread::insertMainEnd(std::stringstream & OS) void VKVertexDecompilerThread::Task() { m_device_props.emulate_conditional_rendering = vk::emulate_conditional_rendering(); - m_binding_table = vk::g_render_device->get_pipeline_binding_table(); - m_shader = Decompile(); vk_prog->SetInputs(inputs); } diff --git a/rpcs3/Emu/RSX/VK/VKVertexProgram.h b/rpcs3/Emu/RSX/VK/VKVertexProgram.h index 1bb6dfd91c..3422333fc6 100644 --- a/rpcs3/Emu/RSX/VK/VKVertexProgram.h +++ b/rpcs3/Emu/RSX/VK/VKVertexProgram.h @@ -15,7 +15,6 @@ struct VKVertexDecompilerThread : public VertexProgramDecompiler std::string &m_shader; std::vector inputs; class VKVertexProgram *vk_prog; - vk::pipeline_binding_table m_binding_table{}; struct { @@ -36,6 +35,8 @@ protected: void insertMainStart(std::stringstream &OS) override; void insertMainEnd(std::stringstream &OS) override; + void prepareBindingTable(); + const RSXVertexProgram &rsx_vertex_program; public: VKVertexDecompilerThread(const RSXVertexProgram &prog, std::string& shader, ParamArray&, class VKVertexProgram &dst) @@ -61,6 +62,19 @@ public: vk::glsl::shader shader; std::vector uniforms; + // Quick attribute indices + struct + { + u32 context_buffer_location = umax; // Vertex program context + u32 cr_pred_buffer_location = umax; // Conditional rendering predicate + u32 vertex_buffers_location = umax; // Vertex input streams (3) + u32 cbuf_location = umax; // Vertex program constants register file + u32 instanced_lut_buffer_location = umax; // Instancing redirection table + u32 instanced_cbuf_location = umax; // Instancing constants register file + u32 vtex_location[4]; // Vertex textures (inf) + + } binding_table; + void Decompile(const RSXVertexProgram& prog); void Compile(); void SetInputs(std::vector& inputs); diff --git a/rpcs3/Emu/RSX/VK/upscalers/fsr1/fsr_pass.cpp b/rpcs3/Emu/RSX/VK/upscalers/fsr1/fsr_pass.cpp index d0b972765c..01a05bf598 100644 --- a/rpcs3/Emu/RSX/VK/upscalers/fsr1/fsr_pass.cpp +++ b/rpcs3/Emu/RSX/VK/upscalers/fsr1/fsr_pass.cpp @@ -76,6 +76,7 @@ namespace vk ::glsl::program_domain::glsl_compute_program, "InputTexture", vk::glsl::input_type_texture, + 0, 0 ), @@ -83,6 +84,7 @@ namespace vk ::glsl::program_domain::glsl_compute_program, "OutputTexture", vk::glsl::input_type_storage_texture, + 0, 1 ), }; @@ -103,8 +105,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_program->bind_uniform({ VK_NULL_HANDLE, m_output_image->value, m_output_image->image()->current_layout }, "OutputTexture", VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); + m_program->bind_uniform({ m_sampler->value, m_input_image->value, m_input_image->image()->current_layout }, 0, 0); + m_program->bind_uniform({ VK_NULL_HANDLE, m_output_image->value, m_output_image->image()->current_layout }, 0, 1); } 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) diff --git a/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp b/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp index 7293180e08..9bc57b0987 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp +++ b/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp @@ -333,11 +333,6 @@ namespace vk return &m_handle; } - VkDescriptorSet descriptor_set::value() const - { - return m_handle; - } - void descriptor_set::push(const VkBufferView& buffer_view, VkDescriptorType type, u32 binding) { m_push_type_mask |= (1ull << type); diff --git a/rpcs3/Emu/RSX/VK/vkutils/descriptors.h b/rpcs3/Emu/RSX/VK/vkutils/descriptors.h index 6c61488b6e..9fd0b436a9 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/descriptors.h +++ b/rpcs3/Emu/RSX/VK/vkutils/descriptors.h @@ -94,8 +94,10 @@ namespace vk void swap(descriptor_set& other); descriptor_set& operator = (VkDescriptorSet set); + VkDescriptorSet value() const { return m_handle; } + operator bool() const { return m_handle != VK_NULL_HANDLE; } + VkDescriptorSet* ptr(); - VkDescriptorSet value() const; void push(const VkBufferView& buffer_view, VkDescriptorType type, u32 binding); void push(const VkDescriptorBufferInfo& buffer_info, VkDescriptorType type, u32 binding); void push(const VkDescriptorImageInfo& image_info, VkDescriptorType type, u32 binding);