diff --git a/rpcs3/Emu/RSX/Common/simple_array.hpp b/rpcs3/Emu/RSX/Common/simple_array.hpp index 5656eb30df..7d3d331686 100644 --- a/rpcs3/Emu/RSX/Common/simple_array.hpp +++ b/rpcs3/Emu/RSX/Common/simple_array.hpp @@ -8,6 +8,13 @@ namespace rsx { + template + concept span_like = + requires(C& c) { + { c.data() } -> std::convertible_to; + { c.size() } -> std::integral; + }; + template requires std::is_trivially_destructible_v struct simple_array @@ -82,6 +89,18 @@ namespace rsx swap(other); } + template + requires span_like + simple_array(const Container& container) + { + resize(container.size()); + + if (_size) + { + std::memcpy(_data, container.data(), size_bytes()); + } + } + simple_array& operator=(const simple_array& other) { if (&other != this) diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp index cf77e75202..122fd5f46d 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp @@ -38,6 +38,12 @@ namespace vk return !!ptr && *ptr == b; } + bool operator == (const descriptor_slot_t& a, const std::span& b) + { + const auto ptr = std::get_if(&a); + return !!ptr && ptr->size() == b.size() && !std::memcmp(ptr->data(), b.data(), b.size_bytes()); + } + VkDescriptorType to_descriptor_type(program_input_type type) { switch (type) @@ -337,25 +343,14 @@ namespace vk m_sets[set_id].notify_descriptor_slot_updated(binding_point, buffer_view); } - void program::bind_uniform_array(const VkDescriptorImageInfo* image_descriptors, int count, u32 set_id, u32 binding_point) + void program::bind_uniform_array(const std::span& image_descriptors, 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 + if (m_sets[set_id].m_descriptor_slots[binding_point] == image_descriptors) { - .first = arr.size(), - .count = static_cast(count) - }; - - arr.reserve(arr.size() + static_cast(count)); - for (int i = 0; i < count; ++i) - { - arr.push_back(image_descriptors[i]); + return; } - set.notify_descriptor_slot_updated(binding_point, data); + m_sets[set_id].notify_descriptor_slot_updated(binding_point, image_descriptors); } void program::create_pipeline_layout() @@ -474,10 +469,16 @@ namespace vk void descriptor_table_t::create_descriptor_template() { - auto push_descriptor_slot = [this](unsigned idx) + auto push_descriptor_slot = [this](unsigned idx, VkWriteDescriptorSet& writer) { const auto& slot = m_descriptor_slots[idx]; const VkDescriptorType type = m_descriptor_types[idx]; + + writer.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writer.dstBinding = idx; + writer.descriptorCount = 1; + writer.descriptorType = type; + if (auto ptr = std::get_if(&slot)) { m_descriptor_set.push(*ptr, type, idx); @@ -496,11 +497,10 @@ namespace vk return; } - if (auto ptr = std::get_if(&slot)) + 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); + writer.descriptorCount = ptr->size(); + m_descriptor_set.push(ptr->data(), ptr->size(), type, idx); return; } @@ -508,23 +508,20 @@ namespace vk }; m_descriptor_template_typemask = 0u; + m_descriptor_template.clear(); for (unsigned i = 0; i < m_descriptor_slots.size(); ++i) { m_descriptor_template_typemask |= (1u << static_cast(m_descriptor_types[i])); - if (m_descriptors_dirty[i]) - { - // Push - push_descriptor_slot(i); - m_descriptors_dirty[i] = false; - continue; - } + VkWriteDescriptorSet _template{}; - push_descriptor_slot(i); + push_descriptor_slot(i, _template); + m_descriptors_dirty[i] = false; + m_descriptor_template.push_back(_template); } - m_descriptor_template = m_descriptor_set.peek(); - m_descriptor_template_cache_id = m_descriptor_set.cache_id(); + m_descriptor_template_cache_id = umax; + ensure(m_descriptor_template.size() == m_descriptor_slots.size()); } void descriptor_table_t::update_descriptor_template() @@ -551,12 +548,10 @@ namespace vk return; } - // FIXME: This sucks even if only used by interpreter. Do better. - if (auto ptr = std::get_if(&slot)) + if (auto ptr = std::get_if(&slot)) { - ensure(type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); - 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); + ensure(m_descriptor_template[idx].descriptorCount == ptr->size()); + m_descriptor_template[idx].pImageInfo = m_descriptor_set.store(*ptr); return; } @@ -611,7 +606,6 @@ namespace vk m_descriptor_set.on_bind(); m_any_descriptors_dirty = false; - m_scratch_images_array.clear(); return m_descriptor_set.value(); } diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.h b/rpcs3/Emu/RSX/VK/VKProgramPipeline.h index 7ddbd0b4d3..f4c5784cfb 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.h +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.h @@ -113,13 +113,8 @@ namespace vk VkShaderModule get_handle() const; }; - struct descriptor_array_ref_t - { - u32 first = 0; - u32 count = 0; - }; - - using descriptor_slot_t = std::variant; + using descriptor_image_array_t = rsx::simple_array; + using descriptor_slot_t = std::variant; struct descriptor_table_t { @@ -140,8 +135,6 @@ 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(); @@ -212,7 +205,7 @@ namespace vk 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, int count, u32 set_id, u32 binding_point); + void bind_uniform_array(const std::span& image_descriptors,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/VKShaderInterpreter.cpp b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp index 3d2bc9875b..3ec8bdc783 100644 --- a/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp +++ b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp @@ -432,7 +432,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, 16, set, binding); + m_current_interpreter->bind_uniform_array({ texture_ptr, 16 }, set, binding); } } diff --git a/rpcs3/Emu/RSX/VK/vkutils/descriptors.h b/rpcs3/Emu/RSX/VK/vkutils/descriptors.h index 56f1448a31..6abb4cfc69 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/descriptors.h +++ b/rpcs3/Emu/RSX/VK/vkutils/descriptors.h @@ -164,6 +164,21 @@ namespace vk return &m_image_info_pool.back(); } + FORCE_INLINE VkDescriptorImageInfo* store(const rsx::simple_array& image_infos) + { + const auto offset = m_image_info_pool.size(); + m_image_info_pool += image_infos; + return &m_image_info_pool[offset]; + } + + FORCE_INLINE bool storage_cache_pressure() const + { + return + m_image_info_pool.size() >= max_cache_size || + m_buffer_info_pool.size() >= max_cache_size || + m_buffer_view_pool.size() >= max_cache_size; + } + // Temporary storage accessors const rsx::simple_array peek() const { return m_pending_writes; } u64 cache_id() const { return m_storage_cache_id; }