From 5d6b8b20c4ce0afc0410235ac309ee7271a158c4 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sun, 22 Jun 2025 20:01:39 +0300 Subject: [PATCH] vk: Fix binding of arrays --- rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp | 51 +++++++++++++++++++++--- rpcs3/Emu/RSX/VK/VKProgramPipeline.h | 10 ++++- rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp | 2 +- 3 files changed, 55 insertions(+), 8 deletions(-) diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp index 967828655e..bd12828e08 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp @@ -339,14 +339,23 @@ namespace vk void program::bind_uniform_array(const VkDescriptorImageInfo* image_descriptors, VkDescriptorType type, int count, u32 set_id, u32 binding_point) { + // Non-caching write auto& set = m_sets[set_id]; + auto& arr = set.m_scratch_images_array; + + descriptor_array_ref_t data + { + .first = arr.size(), + .count = static_cast(count) + }; + + arr.reserve(arr.size() + static_cast(count)); for (int i = 0; i < count; ++i) { - if (set.m_descriptor_slots[binding_point + i] != image_descriptors[i]) - { - set.notify_descriptor_slot_updated(binding_point + i, image_descriptors[i]); - } + arr.push_back(image_descriptors[i]); } + + set.notify_descriptor_slot_updated(binding_point, data); } void program::create_pipeline_layout() @@ -499,6 +508,14 @@ namespace vk return; } + if (auto ptr = std::get_if(&slot)) + { + ensure(type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); // Only type supported at the moment + ensure((ptr->first + ptr->count) <= m_scratch_images_array.size()); + m_descriptor_set.push(m_scratch_images_array.data() + ptr->first, ptr->count, type, idx); + return; + } + fmt::throw_exception("Unexpected descriptor structure at index %u", idx); }; @@ -521,6 +538,7 @@ namespace vk m_descriptor_set.on_bind(); m_any_descriptors_dirty = false; + m_scratch_images_array.clear(); return m_descriptor_set.value(); } @@ -537,6 +555,27 @@ namespace vk std::unordered_map descriptor_type_map; + auto descriptor_count = [](const std::string& name) -> u32 + { + const auto start = name.find_last_of("["); + if (start == std::string::npos) + { + return 1; + } + + const auto end = name.find_last_of("]"); + ensure(end != std::string::npos && start < end, "Invalid variable name"); + + const std::string array_size = name.substr(start + 1, end - start - 1); + if (const auto count = std::atoi(array_size.c_str()); + count > 0) + { + return count; + } + + return 1; + }; + for (const auto& type_arr : m_inputs) { if (type_arr.empty() || type_arr.front().type == input_type_push_constant) @@ -553,13 +592,13 @@ namespace vk { .binding = input.location, .descriptorType = type, - .descriptorCount = 1, + .descriptorCount = descriptor_count(input.name), .stageFlags = to_shader_stage_flags(input.domain) }; bindings.push_back(binding); descriptor_type_map[input.location] = type; - m_descriptor_pool_sizes.back().descriptorCount++; + m_descriptor_pool_sizes.back().descriptorCount += binding.descriptorCount; } } diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.h b/rpcs3/Emu/RSX/VK/VKProgramPipeline.h index 81c3ff8525..4b38d23fb8 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.h +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.h @@ -109,7 +109,13 @@ namespace vk VkShaderModule get_handle() const; }; - using descriptor_slot_t = std::variant; + struct descriptor_array_ref_t + { + u32 first = 0; + u32 count = 0; + }; + + using descriptor_slot_t = std::variant; struct descriptor_table_t { @@ -126,6 +132,8 @@ namespace vk std::vector m_descriptors_dirty; bool m_any_descriptors_dirty = false; + rsx::simple_array< VkDescriptorImageInfo> m_scratch_images_array; + void init(VkDevice dev); void destroy(); diff --git a/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp index 4ab6a0fa3d..760e069fb6 100644 --- a/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp +++ b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp @@ -404,7 +404,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 - auto [set, binding] = m_current_interpreter->get_uniform_location(::glsl::glsl_fragment_program, glsl::input_type_texture, "texture1D_array"); + auto [set, binding] = m_current_interpreter->get_uniform_location(::glsl::glsl_fragment_program, glsl::input_type_texture, "sampler1D_array[16]"); if (binding == umax) { return;