forked from ShuriZma/suyu
Refactor VideoCore to use AS sepparate from Channel.
This commit is contained in:
parent
bb74973bba
commit
e462191482
|
@ -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 {
|
||||||
|
size_t ref_count;
|
||||||
|
size_t storage_id;
|
||||||
|
Tegra::MemoryManager* gpu_memory;
|
||||||
|
};
|
||||||
|
std::unordered_map<size_t, AddresSpaceRef> address_spaces;
|
||||||
|
mutable std::mutex config_mutex;
|
||||||
|
|
||||||
P* channel_state;
|
virtual void OnGPUASRegister([[maybe_unused]] size_t map_id) {}
|
||||||
size_t current_channel_id{UNSET_CHANNEL};
|
|
||||||
Tegra::Engines::Maxwell3D* maxwell3d;
|
|
||||||
Tegra::Engines::KeplerCompute* kepler_compute;
|
|
||||||
Tegra::MemoryManager* gpu_memory;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // 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
|
||||||
|
|
|
@ -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{};
|
||||||
|
|
Loading…
Reference in New Issue