From 75da7d80dcbba3f4e0de923a33504e1d64e442d7 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Mon, 22 May 2023 20:13:24 +0300 Subject: [PATCH] vk: Reimplement sampler caching to take border color into account --- rpcs3/Emu/RSX/VK/VKResourceManager.cpp | 2 + rpcs3/Emu/RSX/VK/VKResourceManager.h | 58 ++++------------- rpcs3/Emu/RSX/VK/vkutils/device.h | 2 +- rpcs3/Emu/RSX/VK/vkutils/sampler.cpp | 88 ++++++++++++++++++++++++++ rpcs3/Emu/RSX/VK/vkutils/sampler.h | 34 ++++++++++ rpcs3/Emu/RSX/rsx_utils.h | 22 +++++++ 6 files changed, 159 insertions(+), 47 deletions(-) diff --git a/rpcs3/Emu/RSX/VK/VKResourceManager.cpp b/rpcs3/Emu/RSX/VK/VKResourceManager.cpp index 370f869e02..5142b0ce6f 100644 --- a/rpcs3/Emu/RSX/VK/VKResourceManager.cpp +++ b/rpcs3/Emu/RSX/VK/VKResourceManager.cpp @@ -54,6 +54,7 @@ namespace vk ensure(max_allowed_samplers); rsx_log.warning("Trimming allocated samplers. Allocated = %u, Max = %u", allocated_sampler_count, limits.maxSamplerAllocationCount); +#if 0 for (auto It = m_sampler_pool.begin(); It != m_sampler_pool.end();) { if (!It->second->has_refs()) @@ -65,6 +66,7 @@ namespace vk ++It; } +#endif } } diff --git a/rpcs3/Emu/RSX/VK/VKResourceManager.h b/rpcs3/Emu/RSX/VK/VKResourceManager.h index 39bdb35d87..ac2e579e74 100644 --- a/rpcs3/Emu/RSX/VK/VKResourceManager.h +++ b/rpcs3/Emu/RSX/VK/VKResourceManager.h @@ -86,12 +86,8 @@ namespace vk class resource_manager { private: - struct cached_sampler_object_t : public vk::sampler, public rsx::ref_counted - { - using vk::sampler::sampler; - }; + sampler_pool_t m_sampler_pool; - std::unordered_map> m_sampler_pool; std::deque m_eid_map; shared_mutex m_eid_map_lock; @@ -108,28 +104,6 @@ namespace vk return m_eid_map.back(); } - template - u16 encode_fxp(f32 value) - { - u16 raw = u16(std::abs(value) * 256.); - - if constexpr (!_signed) - { - return raw; - } - else - { - if (value >= 0.f) [[likely]] - { - return raw; - } - else - { - return u16(0 - raw) & 0x1fff; - } - } - } - public: resource_manager() = default; @@ -144,20 +118,14 @@ namespace vk vk::sampler* get_sampler(const vk::render_device& dev, vk::sampler* previous, VkSamplerAddressMode clamp_u, VkSamplerAddressMode clamp_v, VkSamplerAddressMode clamp_w, VkBool32 unnormalized_coordinates, float mipLodBias, float max_anisotropy, float min_lod, float max_lod, - VkFilter min_filter, VkFilter mag_filter, VkSamplerMipmapMode mipmap_mode, VkBorderColor border_color, + VkFilter min_filter, VkFilter mag_filter, VkSamplerMipmapMode mipmap_mode, const vk::border_color_t& border_color, VkBool32 depth_compare = VK_FALSE, VkCompareOp depth_compare_mode = VK_COMPARE_OP_NEVER) { - u64 key = u16(clamp_u) | u64(clamp_v) << 3 | u64(clamp_w) << 6; - key |= u64(unnormalized_coordinates) << 9; // 1 bit - key |= u64(min_filter) << 10 | u64(mag_filter) << 11; // 1 bit each - key |= u64(mipmap_mode) << 12; // 1 bit - key |= u64(border_color) << 13; // 3 bits - key |= u64(depth_compare) << 16; // 1 bit - key |= u64(depth_compare_mode) << 17; // 3 bits - key |= u64(encode_fxp(min_lod)) << 20; // 12 bits - key |= u64(encode_fxp(max_lod)) << 32; // 12 bits - key |= u64(encode_fxp(mipLodBias)) << 44; // 13 bits - key |= u64(max_anisotropy) << 57; // 4 bits + const auto key = m_sampler_pool.compute_storage_key( + clamp_u, clamp_v, clamp_w, + unnormalized_coordinates, mipLodBias, max_anisotropy, min_lod, max_lod, + min_filter, mag_filter, mipmap_mode, border_color, + depth_compare, depth_compare_mode); if (previous) { @@ -166,11 +134,9 @@ namespace vk as_cached_object->release(); } - if (const auto found = m_sampler_pool.find(key); - found != m_sampler_pool.end()) + if (const auto found = m_sampler_pool.find(key)) { - found->second->add_ref(); - return found->second.get(); + return found; } auto result = std::make_unique( @@ -179,9 +145,9 @@ namespace vk min_filter, mag_filter, mipmap_mode, border_color, depth_compare, depth_compare_mode); - auto It = m_sampler_pool.emplace(key, std::move(result)); - auto ret = It.first->second.get(); - ret->add_ref(); + result->add_ref(); + auto ret = result.get(); + m_sampler_pool.emplace(key, result); return ret; } diff --git a/rpcs3/Emu/RSX/VK/vkutils/device.h b/rpcs3/Emu/RSX/VK/vkutils/device.h index 9fb32cd084..fcc74356b2 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/device.h +++ b/rpcs3/Emu/RSX/VK/vkutils/device.h @@ -167,7 +167,7 @@ namespace vk bool get_descriptor_indexing_support() const { return pgpu->descriptor_indexing_support; } bool get_framebuffer_loops_support() const { return pgpu->optional_features_support.framebuffer_loops; } bool get_barycoords_support() const { return pgpu->optional_features_support.barycentric_coords; } - bool get_custom_border_color_support() const { pgpu->optional_features_support.custom_border_color; } + bool get_custom_border_color_support() const { return pgpu->optional_features_support.custom_border_color; } u64 get_descriptor_update_after_bind_support() const { return pgpu->descriptor_indexing_support.update_after_bind_mask; } u32 get_descriptor_max_draw_calls() const { return pgpu->descriptor_max_draw_calls; } diff --git a/rpcs3/Emu/RSX/VK/vkutils/sampler.cpp b/rpcs3/Emu/RSX/VK/vkutils/sampler.cpp index 6ab7bca9d2..2e4d5f77c4 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/sampler.cpp +++ b/rpcs3/Emu/RSX/VK/vkutils/sampler.cpp @@ -21,6 +21,7 @@ namespace vk } border_color_t::border_color_t(u32 encoded_color) + : storage_key(0) { value = vk::get_border_color(encoded_color); @@ -34,7 +35,10 @@ namespace vk if (!g_render_device->get_custom_border_color_support()) { value = get_closest_border_color_enum(color_value); + return; } + + storage_key = encoded_color; } sampler::sampler(const vk::render_device& dev, VkSamplerAddressMode clamp_u, VkSamplerAddressMode clamp_v, VkSamplerAddressMode clamp_w, @@ -98,4 +102,88 @@ namespace vk return true; } + + sampler_pool_key_t sampler_pool_t::compute_storage_key( + VkSamplerAddressMode clamp_u, VkSamplerAddressMode clamp_v, VkSamplerAddressMode clamp_w, + VkBool32 unnormalized_coordinates, float mipLodBias, float max_anisotropy, float min_lod, float max_lod, + VkFilter min_filter, VkFilter mag_filter, VkSamplerMipmapMode mipmap_mode, const vk::border_color_t& border_color, + VkBool32 depth_compare, VkCompareOp depth_compare_mode) + { + sampler_pool_key_t key{}; + + bool use_border_encoding = false; + if (border_color.value > VK_BORDER_COLOR_INT_OPAQUE_WHITE) + { + // If there is no clamp to border in use, we can ignore the border color entirely + if (clamp_u == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER || + clamp_v == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER || + clamp_w == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER) + { + use_border_encoding = true; + } + } + + key.base_key = u16(clamp_u) | u64(clamp_v) << 3 | u64(clamp_w) << 6; + key.base_key |= u64(unnormalized_coordinates) << 9; // 1 bit + key.base_key |= u64(min_filter) << 10 | u64(mag_filter) << 11; // 1 bit each + key.base_key |= u64(mipmap_mode) << 12; // 1 bit + + if (!use_border_encoding) + { + // Bits 13-16 are reserved for border color encoding + key.base_key |= u64(border_color.value) << 13; + } + else + { + key.border_color_key = border_color.storage_key; + } + + key.base_key |= u64(depth_compare) << 16; // 1 bit + key.base_key |= u64(depth_compare_mode) << 17; // 3 bits + key.base_key |= u64(rsx::encode_fx12(min_lod)) << 20; // 12 bits + key.base_key |= u64(rsx::encode_fx12(max_lod)) << 32; // 12 bits + key.base_key |= u64(rsx::encode_fx12(mipLodBias)) << 44; // 13 bits (fx12 + sign) + key.base_key |= u64(max_anisotropy) << 57; // 4 bits + + return key; + } + + void sampler_pool_t::clear() + { + m_generic_sampler_pool.clear(); + m_custom_color_sampler_pool.clear(); + } + + vk::sampler* sampler_pool_t::find(const sampler_pool_key_t& key) const + { + if (!key.border_color_key) [[ likely ]] + { + const auto found = m_generic_sampler_pool.find(key.base_key); + return found == m_generic_sampler_pool.end() ? nullptr : found->second.get(); + } + + const auto block = m_custom_color_sampler_pool.equal_range(key.base_key); + for (auto It = block.first; It != block.second; ++It) + { + if (It->second->key.border_color_key == key.border_color_key) + { + return It->second.get(); + } + } + + return nullptr; + } + + void sampler_pool_t::emplace(const sampler_pool_key_t& key, std::unique_ptr& object) + { + object->key = key; + + if (!key.border_color_key) [[ likely ]] + { + m_generic_sampler_pool.emplace(key.base_key, std::move(object)); + return; + } + + m_custom_color_sampler_pool.emplace (key.base_key, std::move(object)); + } } diff --git a/rpcs3/Emu/RSX/VK/vkutils/sampler.h b/rpcs3/Emu/RSX/VK/vkutils/sampler.h index fc0350b802..3faaa66414 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/sampler.h +++ b/rpcs3/Emu/RSX/VK/vkutils/sampler.h @@ -7,6 +7,7 @@ namespace vk { struct border_color_t { + u32 storage_key; VkBorderColor value; color4f color_value; @@ -50,4 +51,37 @@ namespace vk private: VkDevice m_device; }; + + // Caching helpers + struct sampler_pool_key_t + { + u64 base_key; + u32 border_color_key; + }; + + struct cached_sampler_object_t : public vk::sampler, public rsx::ref_counted + { + sampler_pool_key_t key; + using vk::sampler::sampler; + }; + + class sampler_pool_t + { + std::unordered_map> m_generic_sampler_pool; + std::unordered_map> m_custom_color_sampler_pool; + + public: + + sampler_pool_key_t compute_storage_key( + VkSamplerAddressMode clamp_u, VkSamplerAddressMode clamp_v, VkSamplerAddressMode clamp_w, + VkBool32 unnormalized_coordinates, float mipLodBias, float max_anisotropy, float min_lod, float max_lod, + VkFilter min_filter, VkFilter mag_filter, VkSamplerMipmapMode mipmap_mode, const vk::border_color_t& border_color, + VkBool32 depth_compare, VkCompareOp depth_compare_mode); + + void clear(); + + vk::sampler* find(const sampler_pool_key_t& key) const; + + void emplace(const sampler_pool_key_t& key, std::unique_ptr& object); + }; } diff --git a/rpcs3/Emu/RSX/rsx_utils.h b/rpcs3/Emu/RSX/rsx_utils.h index 0f303c989b..7ecfe48857 100644 --- a/rpcs3/Emu/RSX/rsx_utils.h +++ b/rpcs3/Emu/RSX/rsx_utils.h @@ -914,4 +914,26 @@ namespace rsx return base * scale; } + + template + u16 encode_fx12(f32 value) + { + u16 raw = u16(std::abs(value) * 256.); + + if constexpr (!_signed) + { + return raw; + } + else + { + if (value >= 0.f) [[likely]] + { + return raw; + } + else + { + return u16(0 - raw) & 0x1fff; + } + } + } }