Refactor VideoCore to use AS sepparate from Channel.
This commit is contained in:
		| @@ -18,4 +18,11 @@ struct PairHash { | |||||||
|     } |     } | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | template <typename T> | ||||||
|  | struct IdentityHash { | ||||||
|  |     [[nodiscard]] size_t operator()(T value) const noexcept { | ||||||
|  |         return static_cast<size_t>(value); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
| } // namespace Common | } // namespace Common | ||||||
|   | |||||||
| @@ -203,6 +203,7 @@ add_library(video_core STATIC | |||||||
|     texture_cache/render_targets.h |     texture_cache/render_targets.h | ||||||
|     texture_cache/samples_helper.h |     texture_cache/samples_helper.h | ||||||
|     texture_cache/slot_vector.h |     texture_cache/slot_vector.h | ||||||
|  |     texture_cache/texture_cache.cpp | ||||||
|     texture_cache/texture_cache.h |     texture_cache/texture_cache.h | ||||||
|     texture_cache/texture_cache_base.h |     texture_cache/texture_cache_base.h | ||||||
|     texture_cache/types.h |     texture_cache/types.h | ||||||
|   | |||||||
| @@ -1,5 +1,11 @@ | |||||||
| #include "video_core/control/channel_state_cache.inc" | #include "video_core/control/channel_state_cache.inc" | ||||||
|  |  | ||||||
| namespace VideoCommon { | namespace VideoCommon { | ||||||
|  |  | ||||||
|  | ChannelInfo::ChannelInfo(Tegra::Control::ChannelState& channel_state) | ||||||
|  |     : maxwell3d{*channel_state.maxwell_3d}, kepler_compute{*channel_state.kepler_compute}, | ||||||
|  |       gpu_memory{*channel_state.memory_manager} {} | ||||||
|  |  | ||||||
| template class VideoCommon::ChannelSetupCaches<VideoCommon::ChannelInfo>; | template class VideoCommon::ChannelSetupCaches<VideoCommon::ChannelInfo>; | ||||||
| } |  | ||||||
|  | } // namespace VideoCommon | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ | |||||||
|  |  | ||||||
| #include <deque> | #include <deque> | ||||||
| #include <limits> | #include <limits> | ||||||
|  | #include <mutex> | ||||||
| #include <unordered_map> | #include <unordered_map> | ||||||
|  |  | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
| @@ -41,9 +42,10 @@ template <class P> | |||||||
| class ChannelSetupCaches { | class ChannelSetupCaches { | ||||||
| public: | public: | ||||||
|     /// Operations for seting the channel of execution. |     /// Operations for seting the channel of execution. | ||||||
|  |     virtual ~ChannelSetupCaches(); | ||||||
|  |  | ||||||
|     /// Create channel state. |     /// Create channel state. | ||||||
|     void CreateChannel(Tegra::Control::ChannelState& channel); |     virtual void CreateChannel(Tegra::Control::ChannelState& channel); | ||||||
|  |  | ||||||
|     /// Bind a channel for execution. |     /// Bind a channel for execution. | ||||||
|     void BindToChannel(s32 id); |     void BindToChannel(s32 id); | ||||||
| @@ -51,18 +53,34 @@ public: | |||||||
|     /// Erase channel's state. |     /// Erase channel's state. | ||||||
|     void EraseChannel(s32 id); |     void EraseChannel(s32 id); | ||||||
|  |  | ||||||
|  |     Tegra::MemoryManager* GetFromID(size_t id) const { | ||||||
|  |         std::unique_lock<std::mutex> lk(config_mutex); | ||||||
|  |         const auto ref = address_spaces.find(id); | ||||||
|  |         return ref->second.gpu_memory; | ||||||
|  |     } | ||||||
|  |  | ||||||
| protected: | protected: | ||||||
|     static constexpr size_t UNSET_CHANNEL{std::numeric_limits<size_t>::max()}; |     static constexpr size_t UNSET_CHANNEL{std::numeric_limits<size_t>::max()}; | ||||||
|  |  | ||||||
|  |     P* channel_state; | ||||||
|  |     size_t current_channel_id{UNSET_CHANNEL}; | ||||||
|  |     size_t current_address_space{}; | ||||||
|  |     Tegra::Engines::Maxwell3D* maxwell3d; | ||||||
|  |     Tegra::Engines::KeplerCompute* kepler_compute; | ||||||
|  |     Tegra::MemoryManager* gpu_memory; | ||||||
|  |  | ||||||
|     std::deque<P> channel_storage; |     std::deque<P> channel_storage; | ||||||
|     std::deque<size_t> free_channel_ids; |     std::deque<size_t> free_channel_ids; | ||||||
|     std::unordered_map<s32, size_t> channel_map; |     std::unordered_map<s32, size_t> channel_map; | ||||||
|  |     struct AddresSpaceRef { | ||||||
|     P* channel_state; |         size_t ref_count; | ||||||
|     size_t current_channel_id{UNSET_CHANNEL}; |         size_t storage_id; | ||||||
|     Tegra::Engines::Maxwell3D* maxwell3d; |  | ||||||
|     Tegra::Engines::KeplerCompute* kepler_compute; |  | ||||||
|         Tegra::MemoryManager* gpu_memory; |         Tegra::MemoryManager* gpu_memory; | ||||||
|  |     }; | ||||||
|  |     std::unordered_map<size_t, AddresSpaceRef> address_spaces; | ||||||
|  |     mutable std::mutex config_mutex; | ||||||
|  |  | ||||||
|  |     virtual void OnGPUASRegister([[maybe_unused]] size_t map_id) {} | ||||||
| }; | }; | ||||||
|  |  | ||||||
| } // namespace VideoCommon | } // namespace VideoCommon | ||||||
|   | |||||||
| @@ -6,18 +6,18 @@ | |||||||
|  |  | ||||||
| namespace VideoCommon { | namespace VideoCommon { | ||||||
|  |  | ||||||
| ChannelInfo::ChannelInfo(Tegra::Control::ChannelState& channel_state) | template <class P> | ||||||
|     : maxwell3d{*channel_state.maxwell_3d}, kepler_compute{*channel_state.kepler_compute}, | ChannelSetupCaches<P>::~ChannelSetupCaches() = default; | ||||||
|       gpu_memory{*channel_state.memory_manager} {} |  | ||||||
|  |  | ||||||
| template <class P> | template <class P> | ||||||
| void ChannelSetupCaches<P>::CreateChannel(struct Tegra::Control::ChannelState& channel) { | void ChannelSetupCaches<P>::CreateChannel(struct Tegra::Control::ChannelState& channel) { | ||||||
|  |     std::unique_lock<std::mutex> lk(config_mutex); | ||||||
|     ASSERT(channel_map.find(channel.bind_id) == channel_map.end() && channel.bind_id >= 0); |     ASSERT(channel_map.find(channel.bind_id) == channel_map.end() && channel.bind_id >= 0); | ||||||
|     auto new_id = [this, &channel]() { |     auto new_id = [this, &channel]() { | ||||||
|         if (!free_channel_ids.empty()) { |         if (!free_channel_ids.empty()) { | ||||||
|             auto id = free_channel_ids.front(); |             auto id = free_channel_ids.front(); | ||||||
|             free_channel_ids.pop_front(); |             free_channel_ids.pop_front(); | ||||||
|             new (&channel_storage[id]) ChannelInfo(channel); |             new (&channel_storage[id]) P(channel); | ||||||
|             return id; |             return id; | ||||||
|         } |         } | ||||||
|         channel_storage.emplace_back(channel); |         channel_storage.emplace_back(channel); | ||||||
| @@ -27,11 +27,24 @@ void ChannelSetupCaches<P>::CreateChannel(struct Tegra::Control::ChannelState& c | |||||||
|     if (current_channel_id != UNSET_CHANNEL) { |     if (current_channel_id != UNSET_CHANNEL) { | ||||||
|         channel_state = &channel_storage[current_channel_id]; |         channel_state = &channel_storage[current_channel_id]; | ||||||
|     } |     } | ||||||
|  |     auto as_it = address_spaces.find(channel.memory_manager->GetID()); | ||||||
|  |     if (as_it != address_spaces.end()) { | ||||||
|  |       as_it->second.ref_count++; | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     AddresSpaceRef new_gpu_mem_ref{ | ||||||
|  |       .ref_count = 1, | ||||||
|  |       .storage_id = address_spaces.size(), | ||||||
|  |       .gpu_memory = channel.memory_manager.get(), | ||||||
|  |     }; | ||||||
|  |     address_spaces.emplace(channel.memory_manager->GetID(), new_gpu_mem_ref); | ||||||
|  |     OnGPUASRegister(channel.memory_manager->GetID()); | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Bind a channel for execution. | /// Bind a channel for execution. | ||||||
| template <class P> | template <class P> | ||||||
| void ChannelSetupCaches<P>::BindToChannel(s32 id) { | void ChannelSetupCaches<P>::BindToChannel(s32 id) { | ||||||
|  |     std::unique_lock<std::mutex> lk(config_mutex); | ||||||
|     auto it = channel_map.find(id); |     auto it = channel_map.find(id); | ||||||
|     ASSERT(it != channel_map.end() && id >= 0); |     ASSERT(it != channel_map.end() && id >= 0); | ||||||
|     current_channel_id = it->second; |     current_channel_id = it->second; | ||||||
| @@ -39,11 +52,13 @@ void ChannelSetupCaches<P>::BindToChannel(s32 id) { | |||||||
|     maxwell3d = &channel_state->maxwell3d; |     maxwell3d = &channel_state->maxwell3d; | ||||||
|     kepler_compute = &channel_state->kepler_compute; |     kepler_compute = &channel_state->kepler_compute; | ||||||
|     gpu_memory = &channel_state->gpu_memory; |     gpu_memory = &channel_state->gpu_memory; | ||||||
|  |     current_address_space = gpu_memory->GetID(); | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Erase channel's channel_state. | /// Erase channel's channel_state. | ||||||
| template <class P> | template <class P> | ||||||
| void ChannelSetupCaches<P>::EraseChannel(s32 id) { | void ChannelSetupCaches<P>::EraseChannel(s32 id) { | ||||||
|  |     std::unique_lock<std::mutex> lk(config_mutex); | ||||||
|     const auto it = channel_map.find(id); |     const auto it = channel_map.find(id); | ||||||
|     ASSERT(it != channel_map.end() && id >= 0); |     ASSERT(it != channel_map.end() && id >= 0); | ||||||
|     const auto this_id = it->second; |     const auto this_id = it->second; | ||||||
|   | |||||||
| @@ -16,9 +16,12 @@ | |||||||
|  |  | ||||||
| namespace Tegra { | namespace Tegra { | ||||||
|  |  | ||||||
|  | std::atomic<size_t> MemoryManager::unique_identifier_generator{}; | ||||||
|  |  | ||||||
| MemoryManager::MemoryManager(Core::System& system_, u64 address_space_bits_, u64 page_bits_) | MemoryManager::MemoryManager(Core::System& system_, u64 address_space_bits_, u64 page_bits_) | ||||||
|     : system{system_}, address_space_bits{address_space_bits_}, page_bits{page_bits_}, entries{}, |     : system{system_}, address_space_bits{address_space_bits_}, page_bits{page_bits_}, entries{}, | ||||||
|       page_table{address_space_bits, address_space_bits + page_bits - 38, page_bits} { |       page_table{address_space_bits, address_space_bits + page_bits - 38, page_bits}, | ||||||
|  |       unique_identifier{unique_identifier_generator.fetch_add(1, std::memory_order_acq_rel)} { | ||||||
|     address_space_size = 1ULL << address_space_bits; |     address_space_size = 1ULL << address_space_bits; | ||||||
|     allocate_start = address_space_bits > 32 ? 1ULL << 32 : 0; |     allocate_start = address_space_bits > 32 ? 1ULL << 32 : 0; | ||||||
|     page_size = 1ULL << page_bits; |     page_size = 1ULL << page_bits; | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ | |||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
|  | #include <atomic> | ||||||
| #include <map> | #include <map> | ||||||
| #include <optional> | #include <optional> | ||||||
| #include <vector> | #include <vector> | ||||||
| @@ -26,6 +27,10 @@ public: | |||||||
|                            u64 page_bits_ = 16); |                            u64 page_bits_ = 16); | ||||||
|     ~MemoryManager(); |     ~MemoryManager(); | ||||||
|  |  | ||||||
|  |     size_t GetID() const { | ||||||
|  |         return unique_identifier; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /// Binds a renderer to the memory manager. |     /// Binds a renderer to the memory manager. | ||||||
|     void BindRasterizer(VideoCore::RasterizerInterface* rasterizer); |     void BindRasterizer(VideoCore::RasterizerInterface* rasterizer); | ||||||
|  |  | ||||||
| @@ -140,6 +145,10 @@ private: | |||||||
|     void SetEntry(size_t position, EntryType entry); |     void SetEntry(size_t position, EntryType entry); | ||||||
|  |  | ||||||
|     Common::MultiLevelPageTable<u32> page_table; |     Common::MultiLevelPageTable<u32> page_table; | ||||||
|  |  | ||||||
|  |     const size_t unique_identifier; | ||||||
|  |  | ||||||
|  |     static std::atomic<size_t> unique_identifier_generator; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| } // namespace Tegra | } // namespace Tegra | ||||||
|   | |||||||
							
								
								
									
										16
									
								
								src/video_core/texture_cache/texture_cache.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/video_core/texture_cache/texture_cache.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | // Copyright 2021 yuzu Emulator Project | ||||||
|  | // Licensed under GPLv3 or any later version | ||||||
|  | // Refer to the license.txt file included. | ||||||
|  |  | ||||||
|  | #include "video_core/control/channel_state_cache.inc" | ||||||
|  | #include "video_core/texture_cache/texture_cache_base.h" | ||||||
|  |  | ||||||
|  | namespace VideoCommon { | ||||||
|  |  | ||||||
|  | TextureCacheChannelInfo::TextureCacheChannelInfo(Tegra::Control::ChannelState& state) noexcept | ||||||
|  |     : ChannelInfo(state), graphics_image_table{gpu_memory}, graphics_sampler_table{gpu_memory}, | ||||||
|  |       compute_image_table{gpu_memory}, compute_sampler_table{gpu_memory} {} | ||||||
|  |  | ||||||
|  | template class VideoCommon::ChannelSetupCaches<VideoCommon::TextureCacheChannelInfo>; | ||||||
|  |  | ||||||
|  | } // namespace VideoCommon | ||||||
| @@ -1,5 +1,7 @@ | |||||||
| // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | // SPDX-FileCopyrightText: 2021 yuzu emulator team | ||||||
| // SPDX-License-Identifier: GPL-2.0-or-later | // (https://github.com/skyline-emu/) | ||||||
|  | // SPDX-License-Identifier: GPL-3.0-or-later Licensed under GPLv3 | ||||||
|  | // or any later version Refer to the license.txt file included. | ||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| @@ -41,10 +43,6 @@ TextureCache<P>::TextureCache(Runtime& runtime_, VideoCore::RasterizerInterface& | |||||||
|  |  | ||||||
|     // Setup channels |     // Setup channels | ||||||
|     current_channel_id = UNSET_CHANNEL; |     current_channel_id = UNSET_CHANNEL; | ||||||
|     state = nullptr; |  | ||||||
|     maxwell3d = nullptr; |  | ||||||
|     kepler_compute = nullptr; |  | ||||||
|     gpu_memory = nullptr; |  | ||||||
|  |  | ||||||
|     // Make sure the first index is reserved for the null resources |     // Make sure the first index is reserved for the null resources | ||||||
|     // This way the null resource becomes a compile time constant |     // This way the null resource becomes a compile time constant | ||||||
| @@ -156,23 +154,24 @@ void TextureCache<P>::MarkModification(ImageId id) noexcept { | |||||||
| template <class P> | template <class P> | ||||||
| template <bool has_blacklists> | template <bool has_blacklists> | ||||||
| void TextureCache<P>::FillGraphicsImageViews(std::span<ImageViewInOut> views) { | void TextureCache<P>::FillGraphicsImageViews(std::span<ImageViewInOut> views) { | ||||||
|     FillImageViews<has_blacklists>(state->graphics_image_table, state->graphics_image_view_ids, |     FillImageViews<has_blacklists>(channel_state->graphics_image_table, | ||||||
|                                    views); |                                    channel_state->graphics_image_view_ids, views); | ||||||
| } | } | ||||||
|  |  | ||||||
| template <class P> | template <class P> | ||||||
| void TextureCache<P>::FillComputeImageViews(std::span<ImageViewInOut> views) { | void TextureCache<P>::FillComputeImageViews(std::span<ImageViewInOut> views) { | ||||||
|     FillImageViews<true>(state->compute_image_table, state->compute_image_view_ids, views); |     FillImageViews<true>(channel_state->compute_image_table, channel_state->compute_image_view_ids, | ||||||
|  |                          views); | ||||||
| } | } | ||||||
|  |  | ||||||
| template <class P> | template <class P> | ||||||
| typename P::Sampler* TextureCache<P>::GetGraphicsSampler(u32 index) { | typename P::Sampler* TextureCache<P>::GetGraphicsSampler(u32 index) { | ||||||
|     if (index > state->graphics_sampler_table.Limit()) { |     if (index > channel_state->graphics_sampler_table.Limit()) { | ||||||
|         LOG_DEBUG(HW_GPU, "Invalid sampler index={}", index); |         LOG_DEBUG(HW_GPU, "Invalid sampler index={}", index); | ||||||
|         return &slot_samplers[NULL_SAMPLER_ID]; |         return &slot_samplers[NULL_SAMPLER_ID]; | ||||||
|     } |     } | ||||||
|     const auto [descriptor, is_new] = state->graphics_sampler_table.Read(index); |     const auto [descriptor, is_new] = channel_state->graphics_sampler_table.Read(index); | ||||||
|     SamplerId& id = state->graphics_sampler_ids[index]; |     SamplerId& id = channel_state->graphics_sampler_ids[index]; | ||||||
|     if (is_new) { |     if (is_new) { | ||||||
|         id = FindSampler(descriptor); |         id = FindSampler(descriptor); | ||||||
|     } |     } | ||||||
| @@ -181,12 +180,12 @@ typename P::Sampler* TextureCache<P>::GetGraphicsSampler(u32 index) { | |||||||
|  |  | ||||||
| template <class P> | template <class P> | ||||||
| typename P::Sampler* TextureCache<P>::GetComputeSampler(u32 index) { | typename P::Sampler* TextureCache<P>::GetComputeSampler(u32 index) { | ||||||
|     if (index > state->compute_sampler_table.Limit()) { |     if (index > channel_state->compute_sampler_table.Limit()) { | ||||||
|         LOG_DEBUG(HW_GPU, "Invalid sampler index={}", index); |         LOG_DEBUG(HW_GPU, "Invalid sampler index={}", index); | ||||||
|         return &slot_samplers[NULL_SAMPLER_ID]; |         return &slot_samplers[NULL_SAMPLER_ID]; | ||||||
|     } |     } | ||||||
|     const auto [descriptor, is_new] = state->compute_sampler_table.Read(index); |     const auto [descriptor, is_new] = channel_state->compute_sampler_table.Read(index); | ||||||
|     SamplerId& id = state->compute_sampler_ids[index]; |     SamplerId& id = channel_state->compute_sampler_ids[index]; | ||||||
|     if (is_new) { |     if (is_new) { | ||||||
|         id = FindSampler(descriptor); |         id = FindSampler(descriptor); | ||||||
|     } |     } | ||||||
| @@ -199,11 +198,12 @@ void TextureCache<P>::SynchronizeGraphicsDescriptors() { | |||||||
|     const bool linked_tsc = maxwell3d->regs.sampler_index == SamplerIndex::ViaHeaderIndex; |     const bool linked_tsc = maxwell3d->regs.sampler_index == SamplerIndex::ViaHeaderIndex; | ||||||
|     const u32 tic_limit = maxwell3d->regs.tic.limit; |     const u32 tic_limit = maxwell3d->regs.tic.limit; | ||||||
|     const u32 tsc_limit = linked_tsc ? tic_limit : maxwell3d->regs.tsc.limit; |     const u32 tsc_limit = linked_tsc ? tic_limit : maxwell3d->regs.tsc.limit; | ||||||
|     if (state->graphics_sampler_table.Synchornize(maxwell3d->regs.tsc.Address(), tsc_limit)) { |     if (channel_state->graphics_sampler_table.Synchornize(maxwell3d->regs.tsc.Address(), | ||||||
|         state->graphics_sampler_ids.resize(tsc_limit + 1, CORRUPT_ID); |                                                           tsc_limit)) { | ||||||
|  |         channel_state->graphics_sampler_ids.resize(tsc_limit + 1, CORRUPT_ID); | ||||||
|     } |     } | ||||||
|     if (state->graphics_image_table.Synchornize(maxwell3d->regs.tic.Address(), tic_limit)) { |     if (channel_state->graphics_image_table.Synchornize(maxwell3d->regs.tic.Address(), tic_limit)) { | ||||||
|         state->graphics_image_view_ids.resize(tic_limit + 1, CORRUPT_ID); |         channel_state->graphics_image_view_ids.resize(tic_limit + 1, CORRUPT_ID); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -213,11 +213,12 @@ void TextureCache<P>::SynchronizeComputeDescriptors() { | |||||||
|     const u32 tic_limit = kepler_compute->regs.tic.limit; |     const u32 tic_limit = kepler_compute->regs.tic.limit; | ||||||
|     const u32 tsc_limit = linked_tsc ? tic_limit : kepler_compute->regs.tsc.limit; |     const u32 tsc_limit = linked_tsc ? tic_limit : kepler_compute->regs.tsc.limit; | ||||||
|     const GPUVAddr tsc_gpu_addr = kepler_compute->regs.tsc.Address(); |     const GPUVAddr tsc_gpu_addr = kepler_compute->regs.tsc.Address(); | ||||||
|     if (state->compute_sampler_table.Synchornize(tsc_gpu_addr, tsc_limit)) { |     if (channel_state->compute_sampler_table.Synchornize(tsc_gpu_addr, tsc_limit)) { | ||||||
|         state->compute_sampler_ids.resize(tsc_limit + 1, CORRUPT_ID); |         channel_state->compute_sampler_ids.resize(tsc_limit + 1, CORRUPT_ID); | ||||||
|     } |     } | ||||||
|     if (state->compute_image_table.Synchornize(kepler_compute->regs.tic.Address(), tic_limit)) { |     if (channel_state->compute_image_table.Synchornize(kepler_compute->regs.tic.Address(), | ||||||
|         state->compute_image_view_ids.resize(tic_limit + 1, CORRUPT_ID); |                                                        tic_limit)) { | ||||||
|  |         channel_state->compute_image_view_ids.resize(tic_limit + 1, CORRUPT_ID); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -738,7 +739,7 @@ ImageViewId TextureCache<P>::FindImageView(const TICEntry& config) { | |||||||
|     if (!IsValidEntry(*gpu_memory, config)) { |     if (!IsValidEntry(*gpu_memory, config)) { | ||||||
|         return NULL_IMAGE_VIEW_ID; |         return NULL_IMAGE_VIEW_ID; | ||||||
|     } |     } | ||||||
|     const auto [pair, is_new] = state->image_views.try_emplace(config); |     const auto [pair, is_new] = channel_state->image_views.try_emplace(config); | ||||||
|     ImageViewId& image_view_id = pair->second; |     ImageViewId& image_view_id = pair->second; | ||||||
|     if (is_new) { |     if (is_new) { | ||||||
|         image_view_id = CreateImageView(config); |         image_view_id = CreateImageView(config); | ||||||
| @@ -1198,7 +1199,7 @@ SamplerId TextureCache<P>::FindSampler(const TSCEntry& config) { | |||||||
|     if (std::ranges::all_of(config.raw, [](u64 value) { return value == 0; })) { |     if (std::ranges::all_of(config.raw, [](u64 value) { return value == 0; })) { | ||||||
|         return NULL_SAMPLER_ID; |         return NULL_SAMPLER_ID; | ||||||
|     } |     } | ||||||
|     const auto [pair, is_new] = state->samplers.try_emplace(config); |     const auto [pair, is_new] = channel_state->samplers.try_emplace(config); | ||||||
|     if (is_new) { |     if (is_new) { | ||||||
|         pair->second = slot_samplers.insert(runtime, config); |         pair->second = slot_samplers.insert(runtime, config); | ||||||
|     } |     } | ||||||
| @@ -1327,8 +1328,8 @@ void TextureCache<P>::ForEachImageInRegionGPU(GPUVAddr gpu_addr, size_t size, Fu | |||||||
|     static constexpr bool BOOL_BREAK = std::is_same_v<FuncReturn, bool>; |     static constexpr bool BOOL_BREAK = std::is_same_v<FuncReturn, bool>; | ||||||
|     boost::container::small_vector<ImageId, 8> images; |     boost::container::small_vector<ImageId, 8> images; | ||||||
|     ForEachGPUPage(gpu_addr, size, [this, &images, gpu_addr, size, func](u64 page) { |     ForEachGPUPage(gpu_addr, size, [this, &images, gpu_addr, size, func](u64 page) { | ||||||
|         const auto it = state->gpu_page_table.find(page); |         const auto it = channel_state->gpu_page_table->find(page); | ||||||
|         if (it == state->gpu_page_table.end()) { |         if (it == channel_state->gpu_page_table->end()) { | ||||||
|             if constexpr (BOOL_BREAK) { |             if constexpr (BOOL_BREAK) { | ||||||
|                 return false; |                 return false; | ||||||
|             } else { |             } else { | ||||||
| @@ -1454,8 +1455,9 @@ void TextureCache<P>::RegisterImage(ImageId image_id) { | |||||||
|     } |     } | ||||||
|     image.lru_index = lru_cache.Insert(image_id, frame_tick); |     image.lru_index = lru_cache.Insert(image_id, frame_tick); | ||||||
|  |  | ||||||
|     ForEachGPUPage(image.gpu_addr, image.guest_size_bytes, |     ForEachGPUPage(image.gpu_addr, image.guest_size_bytes, [this, image_id](u64 page) { | ||||||
|                    [this, image_id](u64 page) { state->gpu_page_table[page].push_back(image_id); }); |         (*channel_state->gpu_page_table)[page].push_back(image_id); | ||||||
|  |     }); | ||||||
|     if (False(image.flags & ImageFlagBits::Sparse)) { |     if (False(image.flags & ImageFlagBits::Sparse)) { | ||||||
|         auto map_id = |         auto map_id = | ||||||
|             slot_map_views.insert(image.gpu_addr, image.cpu_addr, image.guest_size_bytes, image_id); |             slot_map_views.insert(image.gpu_addr, image.cpu_addr, image.guest_size_bytes, image_id); | ||||||
| @@ -1486,9 +1488,9 @@ void TextureCache<P>::UnregisterImage(ImageId image_id) { | |||||||
|     image.flags &= ~ImageFlagBits::BadOverlap; |     image.flags &= ~ImageFlagBits::BadOverlap; | ||||||
|     lru_cache.Free(image.lru_index); |     lru_cache.Free(image.lru_index); | ||||||
|     const auto& clear_page_table = |     const auto& clear_page_table = | ||||||
|         [this, image_id]( |         [this, image_id](u64 page, | ||||||
|             u64 page, |                          std::unordered_map<u64, std::vector<ImageId>, Common::IdentityHash<u64>>& | ||||||
|             std::unordered_map<u64, std::vector<ImageId>, IdentityHash<u64>>& selected_page_table) { |                              selected_page_table) { | ||||||
|             const auto page_it = selected_page_table.find(page); |             const auto page_it = selected_page_table.find(page); | ||||||
|             if (page_it == selected_page_table.end()) { |             if (page_it == selected_page_table.end()) { | ||||||
|                 ASSERT_MSG(false, "Unregistering unregistered page=0x{:x}", page << YUZU_PAGEBITS); |                 ASSERT_MSG(false, "Unregistering unregistered page=0x{:x}", page << YUZU_PAGEBITS); | ||||||
| @@ -1504,7 +1506,7 @@ void TextureCache<P>::UnregisterImage(ImageId image_id) { | |||||||
|             image_ids.erase(vector_it); |             image_ids.erase(vector_it); | ||||||
|         }; |         }; | ||||||
|     ForEachGPUPage(image.gpu_addr, image.guest_size_bytes, [this, &clear_page_table](u64 page) { |     ForEachGPUPage(image.gpu_addr, image.guest_size_bytes, [this, &clear_page_table](u64 page) { | ||||||
|         clear_page_table(page, state->gpu_page_table); |         clear_page_table(page, (*channel_state->gpu_page_table)); | ||||||
|     }); |     }); | ||||||
|     if (False(image.flags & ImageFlagBits::Sparse)) { |     if (False(image.flags & ImageFlagBits::Sparse)) { | ||||||
|         const auto map_id = image.map_view_id; |         const auto map_id = image.map_view_id; | ||||||
| @@ -1701,11 +1703,11 @@ void TextureCache<P>::DeleteImage(ImageId image_id, bool immediate_delete) { | |||||||
|  |  | ||||||
| template <class P> | template <class P> | ||||||
| void TextureCache<P>::RemoveImageViewReferences(std::span<const ImageViewId> removed_views) { | void TextureCache<P>::RemoveImageViewReferences(std::span<const ImageViewId> removed_views) { | ||||||
|     auto it = state->image_views.begin(); |     auto it = channel_state->image_views.begin(); | ||||||
|     while (it != state->image_views.end()) { |     while (it != channel_state->image_views.end()) { | ||||||
|         const auto found = std::ranges::find(removed_views, it->second); |         const auto found = std::ranges::find(removed_views, it->second); | ||||||
|         if (found != removed_views.end()) { |         if (found != removed_views.end()) { | ||||||
|             it = state->image_views.erase(it); |             it = channel_state->image_views.erase(it); | ||||||
|         } else { |         } else { | ||||||
|             ++it; |             ++it; | ||||||
|         } |         } | ||||||
| @@ -1967,61 +1969,19 @@ bool TextureCache<P>::IsFullClear(ImageViewId id) { | |||||||
|            scissor.max_y >= size.height; |            scissor.max_y >= size.height; | ||||||
| } | } | ||||||
|  |  | ||||||
| template <class P> |  | ||||||
| TextureCache<P>::ChannelInfo::ChannelInfo(Tegra::Control::ChannelState& state) noexcept |  | ||||||
|     : maxwell3d{*state.maxwell_3d}, kepler_compute{*state.kepler_compute}, |  | ||||||
|       gpu_memory{*state.memory_manager}, graphics_image_table{gpu_memory}, |  | ||||||
|       graphics_sampler_table{gpu_memory}, compute_image_table{gpu_memory}, compute_sampler_table{ |  | ||||||
|                                                                                gpu_memory} {} |  | ||||||
|  |  | ||||||
| template <class P> | template <class P> | ||||||
| void TextureCache<P>::CreateChannel(struct Tegra::Control::ChannelState& channel) { | void TextureCache<P>::CreateChannel(struct Tegra::Control::ChannelState& channel) { | ||||||
|     ASSERT(channel_map.find(channel.bind_id) == channel_map.end() && channel.bind_id >= 0); |     VideoCommon::ChannelSetupCaches<TextureCacheChannelInfo>::CreateChannel(channel); | ||||||
|     auto new_id = [this, &channel]() { |     const auto it = channel_map.find(channel.bind_id); | ||||||
|         if (!free_channel_ids.empty()) { |     auto* this_state = &channel_storage[it->second]; | ||||||
|             auto id = free_channel_ids.front(); |     const auto& this_as_ref = address_spaces[channel.memory_manager->GetID()]; | ||||||
|             free_channel_ids.pop_front(); |     this_state->gpu_page_table = &gpu_page_table_storage[this_as_ref.storage_id]; | ||||||
|             new (&channel_storage[id]) ChannelInfo(channel); |  | ||||||
|             return id; |  | ||||||
|         } |  | ||||||
|         channel_storage.emplace_back(channel); |  | ||||||
|         return channel_storage.size() - 1; |  | ||||||
|     }(); |  | ||||||
|     channel_map.emplace(channel.bind_id, new_id); |  | ||||||
|     if (current_channel_id != UNSET_CHANNEL) { |  | ||||||
|         state = &channel_storage[current_channel_id]; |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Bind a channel for execution. | /// Bind a channel for execution. | ||||||
| template <class P> | template <class P> | ||||||
| void TextureCache<P>::BindToChannel(s32 id) { | void TextureCache<P>::OnGPUASRegister([[maybe_unused]] size_t map_id) { | ||||||
|     auto it = channel_map.find(id); |     gpu_page_table_storage.emplace_back(); | ||||||
|     ASSERT(it != channel_map.end() && id >= 0); |  | ||||||
|     current_channel_id = it->second; |  | ||||||
|     state = &channel_storage[current_channel_id]; |  | ||||||
|     maxwell3d = &state->maxwell3d; |  | ||||||
|     kepler_compute = &state->kepler_compute; |  | ||||||
|     gpu_memory = &state->gpu_memory; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /// Erase channel's state. |  | ||||||
| template <class P> |  | ||||||
| void TextureCache<P>::EraseChannel(s32 id) { |  | ||||||
|     const auto it = channel_map.find(id); |  | ||||||
|     ASSERT(it != channel_map.end() && id >= 0); |  | ||||||
|     const auto this_id = it->second; |  | ||||||
|     free_channel_ids.push_back(this_id); |  | ||||||
|     channel_map.erase(it); |  | ||||||
|     if (this_id == current_channel_id) { |  | ||||||
|         current_channel_id = UNSET_CHANNEL; |  | ||||||
|         state = nullptr; |  | ||||||
|         maxwell3d = nullptr; |  | ||||||
|         kepler_compute = nullptr; |  | ||||||
|         gpu_memory = nullptr; |  | ||||||
|     } else if (current_channel_id != UNSET_CHANNEL) { |  | ||||||
|         state = &channel_storage[current_channel_id]; |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| } // namespace VideoCommon | } // namespace VideoCommon | ||||||
|   | |||||||
| @@ -1,5 +1,7 @@ | |||||||
| // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | // SPDX-FileCopyrightText: 2021 yuzu emulator team | ||||||
| // SPDX-License-Identifier: GPL-2.0-or-later | // (https://github.com/skyline-emu/) | ||||||
|  | // SPDX-License-Identifier: GPL-3.0-or-later Licensed under GPLv3 | ||||||
|  | // or any later version Refer to the license.txt file included. | ||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| @@ -13,9 +15,11 @@ | |||||||
| #include <queue> | #include <queue> | ||||||
|  |  | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
|  | #include "common/hash.h" | ||||||
| #include "common/literals.h" | #include "common/literals.h" | ||||||
| #include "common/lru_cache.h" | #include "common/lru_cache.h" | ||||||
| #include "video_core/compatible_formats.h" | #include "video_core/compatible_formats.h" | ||||||
|  | #include "video_core/control/channel_state_cache.h" | ||||||
| #include "video_core/delayed_destruction_ring.h" | #include "video_core/delayed_destruction_ring.h" | ||||||
| #include "video_core/engines/fermi_2d.h" | #include "video_core/engines/fermi_2d.h" | ||||||
| #include "video_core/surface.h" | #include "video_core/surface.h" | ||||||
| @@ -50,8 +54,35 @@ struct ImageViewInOut { | |||||||
|     ImageViewId id{}; |     ImageViewId id{}; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | using TextureCacheGPUMap = std::unordered_map<u64, std::vector<ImageId>, Common::IdentityHash<u64>>; | ||||||
|  |  | ||||||
|  | class TextureCacheChannelInfo : public ChannelInfo { | ||||||
|  | public: | ||||||
|  |     TextureCacheChannelInfo() = delete; | ||||||
|  |     TextureCacheChannelInfo(Tegra::Control::ChannelState& state) noexcept; | ||||||
|  |     TextureCacheChannelInfo(const TextureCacheChannelInfo& state) = delete; | ||||||
|  |     TextureCacheChannelInfo& operator=(const TextureCacheChannelInfo&) = delete; | ||||||
|  |     TextureCacheChannelInfo(TextureCacheChannelInfo&& other) noexcept = default; | ||||||
|  |     TextureCacheChannelInfo& operator=(TextureCacheChannelInfo&& other) noexcept = default; | ||||||
|  |  | ||||||
|  |     DescriptorTable<TICEntry> graphics_image_table{gpu_memory}; | ||||||
|  |     DescriptorTable<TSCEntry> graphics_sampler_table{gpu_memory}; | ||||||
|  |     std::vector<SamplerId> graphics_sampler_ids; | ||||||
|  |     std::vector<ImageViewId> graphics_image_view_ids; | ||||||
|  |  | ||||||
|  |     DescriptorTable<TICEntry> compute_image_table{gpu_memory}; | ||||||
|  |     DescriptorTable<TSCEntry> compute_sampler_table{gpu_memory}; | ||||||
|  |     std::vector<SamplerId> compute_sampler_ids; | ||||||
|  |     std::vector<ImageViewId> compute_image_view_ids; | ||||||
|  |  | ||||||
|  |     std::unordered_map<TICEntry, ImageViewId> image_views; | ||||||
|  |     std::unordered_map<TSCEntry, SamplerId> samplers; | ||||||
|  |  | ||||||
|  |     TextureCacheGPUMap* gpu_page_table; | ||||||
|  | }; | ||||||
|  |  | ||||||
| template <class P> | template <class P> | ||||||
| class TextureCache { | class TextureCache : public VideoCommon::ChannelSetupCaches<TextureCacheChannelInfo> { | ||||||
|     /// Address shift for caching images into a hash table |     /// Address shift for caching images into a hash table | ||||||
|     static constexpr u64 YUZU_PAGEBITS = 20; |     static constexpr u64 YUZU_PAGEBITS = 20; | ||||||
|  |  | ||||||
| @@ -85,13 +116,6 @@ class TextureCache { | |||||||
|         PixelFormat src_format; |         PixelFormat src_format; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     template <typename T> |  | ||||||
|     struct IdentityHash { |  | ||||||
|         [[nodiscard]] size_t operator()(T value) const noexcept { |  | ||||||
|             return static_cast<size_t>(value); |  | ||||||
|         } |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
| public: | public: | ||||||
|     explicit TextureCache(Runtime&, VideoCore::RasterizerInterface&); |     explicit TextureCache(Runtime&, VideoCore::RasterizerInterface&); | ||||||
|  |  | ||||||
| @@ -179,13 +203,7 @@ public: | |||||||
|     [[nodiscard]] bool IsRescaling(const ImageViewBase& image_view) const noexcept; |     [[nodiscard]] bool IsRescaling(const ImageViewBase& image_view) const noexcept; | ||||||
|  |  | ||||||
|     /// Create channel state. |     /// Create channel state. | ||||||
|     void CreateChannel(struct Tegra::Control::ChannelState& channel); |     void CreateChannel(Tegra::Control::ChannelState& channel) final override; | ||||||
|  |  | ||||||
|     /// Bind a channel for execution. |  | ||||||
|     void BindToChannel(s32 id); |  | ||||||
|  |  | ||||||
|     /// Erase channel's state. |  | ||||||
|     void EraseChannel(s32 id); |  | ||||||
|  |  | ||||||
|     std::mutex mutex; |     std::mutex mutex; | ||||||
|  |  | ||||||
| @@ -221,6 +239,8 @@ private: | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     void OnGPUASRegister(size_t map_id) final override; | ||||||
|  |  | ||||||
|     /// Runs the Garbage Collector. |     /// Runs the Garbage Collector. | ||||||
|     void RunGarbageCollector(); |     void RunGarbageCollector(); | ||||||
|  |  | ||||||
| @@ -355,51 +375,15 @@ private: | |||||||
|  |  | ||||||
|     Runtime& runtime; |     Runtime& runtime; | ||||||
|  |  | ||||||
|     struct ChannelInfo { |  | ||||||
|         ChannelInfo() = delete; |  | ||||||
|         ChannelInfo(struct Tegra::Control::ChannelState& state) noexcept; |  | ||||||
|         ChannelInfo(const ChannelInfo& state) = delete; |  | ||||||
|         ChannelInfo& operator=(const ChannelInfo&) = delete; |  | ||||||
|         ChannelInfo(ChannelInfo&& other) noexcept = default; |  | ||||||
|         ChannelInfo& operator=(ChannelInfo&& other) noexcept = default; |  | ||||||
|  |  | ||||||
|         Tegra::Engines::Maxwell3D& maxwell3d; |  | ||||||
|         Tegra::Engines::KeplerCompute& kepler_compute; |  | ||||||
|         Tegra::MemoryManager& gpu_memory; |  | ||||||
|  |  | ||||||
|         DescriptorTable<TICEntry> graphics_image_table{gpu_memory}; |  | ||||||
|         DescriptorTable<TSCEntry> graphics_sampler_table{gpu_memory}; |  | ||||||
|         std::vector<SamplerId> graphics_sampler_ids; |  | ||||||
|         std::vector<ImageViewId> graphics_image_view_ids; |  | ||||||
|  |  | ||||||
|         DescriptorTable<TICEntry> compute_image_table{gpu_memory}; |  | ||||||
|         DescriptorTable<TSCEntry> compute_sampler_table{gpu_memory}; |  | ||||||
|         std::vector<SamplerId> compute_sampler_ids; |  | ||||||
|         std::vector<ImageViewId> compute_image_view_ids; |  | ||||||
|  |  | ||||||
|         std::unordered_map<TICEntry, ImageViewId> image_views; |  | ||||||
|         std::unordered_map<TSCEntry, SamplerId> samplers; |  | ||||||
|  |  | ||||||
|         std::unordered_map<u64, std::vector<ImageId>, IdentityHash<u64>> gpu_page_table; |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     std::deque<ChannelInfo> channel_storage; |  | ||||||
|     std::deque<size_t> free_channel_ids; |  | ||||||
|     std::unordered_map<s32, size_t> channel_map; |  | ||||||
|  |  | ||||||
|     ChannelInfo* state; |  | ||||||
|     size_t current_channel_id{UNSET_CHANNEL}; |  | ||||||
|     VideoCore::RasterizerInterface& rasterizer; |     VideoCore::RasterizerInterface& rasterizer; | ||||||
|     Tegra::Engines::Maxwell3D* maxwell3d; |     std::deque<TextureCacheGPUMap> gpu_page_table_storage; | ||||||
|     Tegra::Engines::KeplerCompute* kepler_compute; |  | ||||||
|     Tegra::MemoryManager* gpu_memory; |  | ||||||
|  |  | ||||||
|     RenderTargets render_targets; |     RenderTargets render_targets; | ||||||
|  |  | ||||||
|     std::unordered_map<RenderTargets, FramebufferId> framebuffers; |     std::unordered_map<RenderTargets, FramebufferId> framebuffers; | ||||||
|  |  | ||||||
|     std::unordered_map<u64, std::vector<ImageMapId>, IdentityHash<u64>> page_table; |     std::unordered_map<u64, std::vector<ImageMapId>, Common::IdentityHash<u64>> page_table; | ||||||
|     std::unordered_map<u64, std::vector<ImageId>, IdentityHash<u64>> sparse_page_table; |     std::unordered_map<u64, std::vector<ImageId>, Common::IdentityHash<u64>> sparse_page_table; | ||||||
|     std::unordered_map<ImageId, std::vector<ImageViewId>> sparse_views; |     std::unordered_map<ImageId, std::vector<ImageViewId>> sparse_views; | ||||||
|  |  | ||||||
|     VAddr virtual_invalid_space{}; |     VAddr virtual_invalid_space{}; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user