mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	Rasterizer cache refactor v2 (#6479)
* rasterizer_cache: Switch to template * Eliminates all opengl references in the rasterizer cache headers thus completing the backend abstraction * rasterizer_cache: Switch to page table * Surface storage isn't particularly interval sensitive so we can use a page table to make it faster * rasterizer_cache: Move sampler management out of rasterizer cache * rasterizer_cache: Remove shared_ptr usage * Switches to yuzu's slot vector for improved memory locality. * rasterizer_cache: Rework reinterpretation lookup * citra_qt: Per game texture filter * rasterizer_cache: Log additional settings * gl_texture_runtime: Resolve shadow map comment * rasterizer_cache: Don't use float for viewport * gl_texture_runtime: Fix custom allocation recycling * rasterizer_cache: Minor cleanups * Cleanup texture cubes when all the faces have been unregistered from the cache * custom_tex_manager: Allow multiple hash mappings per texture * code: Move slot vector to common * rasterizer_cache: Prevent texture cube crashes * rasterizer_cache: Improve mipmap validation * CanSubRect now works properly when validating multi-level surfaces, for example Dark Moon validates a 4 level surface from a 3 level one and it works * gl_blit_handler: Unbind sampler on reinterpretation
This commit is contained in:
		
							parent
							
								
									322d7a8287
								
							
						
					
					
						commit
						2e655f73b8
					
				
					 32 changed files with 2238 additions and 1927 deletions
				
			
		|  | @ -100,6 +100,7 @@ add_library(citra_common STATIC | |||
|     scope_exit.h | ||||
|     settings.cpp | ||||
|     settings.h | ||||
|     slot_vector.h | ||||
|     serialization/atomic.h | ||||
|     serialization/boost_discrete_interval.hpp | ||||
|     serialization/boost_flat_set.h | ||||
|  |  | |||
|  | @ -163,6 +163,8 @@ void LogSettings() { | |||
|     log_setting("Layout_LargeScreenProportion", values.large_screen_proportion.GetValue()); | ||||
|     log_setting("Utility_DumpTextures", values.dump_textures.GetValue()); | ||||
|     log_setting("Utility_CustomTextures", values.custom_textures.GetValue()); | ||||
|     log_setting("Utility_PreloadTextures", values.preload_textures.GetValue()); | ||||
|     log_setting("Utility_AsyncCustomLoading", values.async_custom_loading.GetValue()); | ||||
|     log_setting("Utility_UseDiskShaderCache", values.use_disk_shader_cache.GetValue()); | ||||
|     log_setting("Audio_Emulation", GetAudioEmulationName(values.audio_emulation.GetValue())); | ||||
|     log_setting("Audio_OutputType", values.output_type.GetValue()); | ||||
|  |  | |||
							
								
								
									
										154
									
								
								src/common/slot_vector.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								src/common/slot_vector.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,154 @@ | |||
| // Copyright 2020 yuzu Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <bit> | ||||
| #include <compare> | ||||
| #include <numeric> | ||||
| #include <type_traits> | ||||
| #include <utility> | ||||
| #include <vector> | ||||
| #include "common/assert.h" | ||||
| #include "common/common_types.h" | ||||
| 
 | ||||
| namespace Common { | ||||
| 
 | ||||
| struct SlotId { | ||||
|     static constexpr u32 INVALID_INDEX = std::numeric_limits<u32>::max(); | ||||
| 
 | ||||
|     constexpr auto operator<=>(const SlotId&) const noexcept = default; | ||||
| 
 | ||||
|     constexpr explicit operator bool() const noexcept { | ||||
|         return index != INVALID_INDEX; | ||||
|     } | ||||
| 
 | ||||
|     u32 index = INVALID_INDEX; | ||||
| }; | ||||
| 
 | ||||
| template <class T> | ||||
| class SlotVector { | ||||
| public: | ||||
|     ~SlotVector() noexcept { | ||||
|         size_t index = 0; | ||||
|         for (u64 bits : stored_bitset) { | ||||
|             for (size_t bit = 0; bits; ++bit, bits >>= 1) { | ||||
|                 if ((bits & 1) != 0) { | ||||
|                     values[index + bit].object.~T(); | ||||
|                 } | ||||
|             } | ||||
|             index += 64; | ||||
|         } | ||||
|         delete[] values; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] T& operator[](SlotId id) noexcept { | ||||
|         ValidateIndex(id); | ||||
|         return values[id.index].object; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] const T& operator[](SlotId id) const noexcept { | ||||
|         ValidateIndex(id); | ||||
|         return values[id.index].object; | ||||
|     } | ||||
| 
 | ||||
|     template <typename... Args> | ||||
|     [[nodiscard]] SlotId insert(Args&&... args) noexcept { | ||||
|         const u32 index = FreeValueIndex(); | ||||
|         new (&values[index].object) T(std::forward<Args>(args)...); | ||||
|         SetStorageBit(index); | ||||
| 
 | ||||
|         return SlotId{index}; | ||||
|     } | ||||
| 
 | ||||
|     void erase(SlotId id) noexcept { | ||||
|         values[id.index].object.~T(); | ||||
|         free_list.push_back(id.index); | ||||
|         ResetStorageBit(id.index); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     struct NonTrivialDummy { | ||||
|         NonTrivialDummy() noexcept {} | ||||
|     }; | ||||
| 
 | ||||
|     union Entry { | ||||
|         Entry() noexcept : dummy{} {} | ||||
|         ~Entry() noexcept {} | ||||
| 
 | ||||
|         NonTrivialDummy dummy; | ||||
|         T object; | ||||
|     }; | ||||
| 
 | ||||
|     void SetStorageBit(u32 index) noexcept { | ||||
|         stored_bitset[index / 64] |= u64(1) << (index % 64); | ||||
|     } | ||||
| 
 | ||||
|     void ResetStorageBit(u32 index) noexcept { | ||||
|         stored_bitset[index / 64] &= ~(u64(1) << (index % 64)); | ||||
|     } | ||||
| 
 | ||||
|     bool ReadStorageBit(u32 index) noexcept { | ||||
|         return ((stored_bitset[index / 64] >> (index % 64)) & 1) != 0; | ||||
|     } | ||||
| 
 | ||||
|     void ValidateIndex(SlotId id) const noexcept { | ||||
|         DEBUG_ASSERT(id); | ||||
|         DEBUG_ASSERT(id.index / 64 < stored_bitset.size()); | ||||
|         DEBUG_ASSERT(((stored_bitset[id.index / 64] >> (id.index % 64)) & 1) != 0); | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] u32 FreeValueIndex() noexcept { | ||||
|         if (free_list.empty()) { | ||||
|             Reserve(values_capacity ? (values_capacity << 1) : 1); | ||||
|         } | ||||
| 
 | ||||
|         const u32 free_index = free_list.back(); | ||||
|         free_list.pop_back(); | ||||
|         return free_index; | ||||
|     } | ||||
| 
 | ||||
|     void Reserve(size_t new_capacity) noexcept { | ||||
|         Entry* const new_values = new Entry[new_capacity]; | ||||
|         size_t index = 0; | ||||
|         for (u64 bits : stored_bitset) { | ||||
|             for (size_t bit = 0; bits; ++bit, bits >>= 1) { | ||||
|                 const size_t i = index + bit; | ||||
|                 if ((bits & 1) == 0) { | ||||
|                     continue; | ||||
|                 } | ||||
|                 T& old_value = values[i].object; | ||||
|                 new (&new_values[i].object) T(std::move(old_value)); | ||||
|                 old_value.~T(); | ||||
|             } | ||||
|             index += 64; | ||||
|         } | ||||
| 
 | ||||
|         stored_bitset.resize((new_capacity + 63) / 64); | ||||
| 
 | ||||
|         const size_t old_free_size = free_list.size(); | ||||
|         free_list.resize(old_free_size + (new_capacity - values_capacity)); | ||||
|         std::iota(free_list.begin() + old_free_size, free_list.end(), | ||||
|                   static_cast<u32>(values_capacity)); | ||||
| 
 | ||||
|         delete[] values; | ||||
|         values = new_values; | ||||
|         values_capacity = new_capacity; | ||||
|     } | ||||
| 
 | ||||
|     Entry* values = nullptr; | ||||
|     size_t values_capacity = 0; | ||||
| 
 | ||||
|     std::vector<u64> stored_bitset; | ||||
|     std::vector<u32> free_list; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Common
 | ||||
| 
 | ||||
| template <> | ||||
| struct std::hash<Common::SlotId> { | ||||
|     size_t operator()(const Common::SlotId& id) const noexcept { | ||||
|         return std::hash<u32>{}(id.index); | ||||
|     } | ||||
| }; | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue