diff options
| author | Duck <350528965+Duck912@users.noreply.github.com> | 2026-11-03 02:47:54 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-11-03 08:47:54 +0100 |
| commit | a667551cdf6e9044e43e1d0c37320c3ec82a1213 (patch) | |
| tree | e9575ab1653eed1d046f2868a5509b5f4178fb10 /src | |
| parent | 881a47751455debec3b9ea7596aa0a1b207f0571 (diff) | |
video_core: cut per-draw work on the GPU back thread in crowded scenes (#374)
* video_core: demote the texture cache's per-draw debug logs to trace
The invalid sampler and image view index messages fire for unused
binding slots on every draw. Filtered LOG_DEBUG messages still cost a
call and argument packing: in a Fire Emblem: Fortune's Weave city scene
(about 2,100 draws per frame) they were 3.1% of the GPUBack thread's
samples. LOG_TRACE compiles them out of release builds.
Assisted-by: Claude Opus 5.5 (profiling, porting and drafting)
Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
* texture_cache: read a descriptor with one page lookup
DescriptorTable::Read runs for every texture and sampler of every draw,
and it read each 32-byte TIC/TSC entry through the generic
ReadBlockUnsafe page walk. In a Fire Emblem: Fortune's Weave city scene
(about 2,100 draws per frame) that was 5.0% of the GPUBack thread's
samples. An entry within one page is contiguous in host memory, so it
is now a single page lookup and memcpy. Entries that cross a page and
pages without host memory still take the block read, so unmapped and
unbacked entries still read as zero.
The same change in another Eden-based build cut these reads from 6.4%
to 0.4% of its GPU thread.
Assisted-by: Claude Opus 5.5 (profiling, porting and drafting)
Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
---------
Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/texture_cache/descriptor_table.h | 12 | ||||
| -rw-r--r-- | src/video_core/texture_cache/texture_cache.h | 4 |
2 files changed, 13 insertions, 3 deletions
diff --git a/src/video_core/texture_cache/descriptor_table.h b/src/video_core/texture_cache/descriptor_table.h index a441e572de..2c768b72fc 100644 --- a/src/video_core/texture_cache/descriptor_table.h +++ b/src/video_core/texture_cache/descriptor_table.h @@ -7,12 +7,14 @@ #pragma once #include <algorithm> +#include <cstring> #include <vector> #include "common/alignment.h" #include "common/common_types.h" #include "common/div_ceil.h" #include "common/assert.h" +#include "core/memory.h" #include "video_core/memory_manager.h" #include "video_core/rasterizer_interface.h" @@ -44,7 +46,15 @@ public: } const GPUVAddr gpu_addr = current_gpu_addr + index * sizeof(T); std::pair<T, bool> result; - gpu_memory.ReadBlockUnsafe(gpu_addr, std::addressof(result.first), sizeof(T)); + // This runs for every texture and sampler of every draw. An entry within one page is + // contiguous in host memory, so a single page lookup replaces the generic block read. + const bool one_page = + (gpu_addr & Core::Memory::YUZU_PAGEMASK) + sizeof(T) <= Core::Memory::YUZU_PAGESIZE; + if (const u8* const host = one_page ? gpu_memory.GetPointer(gpu_addr) : nullptr) { + std::memcpy(std::addressof(result.first), host, sizeof(T)); + } else { + gpu_memory.ReadBlockUnsafe(gpu_addr, std::addressof(result.first), sizeof(T)); + } if ((read_descriptors[index / 64] & (1ULL << (index % 64))) != 0) { result.second = result.first != descriptors[index]; } else { diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index abb22b9bfb..ea82ab02e7 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -580,7 +580,7 @@ template <class P> SamplerId TextureCache<P>::GetSamplerId(u32 index, bool compute) { auto& table = compute ? channel_state->compute_sampler_table : channel_state->graphics_sampler_table; if (index > table.current_limit) { - LOG_DEBUG(HW_GPU, "Invalid sampler index={}", index); + LOG_TRACE(HW_GPU, "Invalid sampler index={}", index); return NULL_SAMPLER_ID; } auto const map_index = index | (compute ? Common::SlotId::TAGGED_VALUE : 0); @@ -812,7 +812,7 @@ ImageViewId TextureCache<P>::VisitImageView(u32 index, bool compute) { index = Tegra::Texture::TextureHeaderIndex(index, table.current_limit, gpu_memory->UsesNativeTiling()); if (index > table.current_limit) { - LOG_DEBUG(HW_GPU, "Invalid image view index={}", index); + LOG_TRACE(HW_GPU, "Invalid image view index={}", index); return NULL_IMAGE_VIEW_ID; } auto const map_index = index | (compute ? Common::SlotId::TAGGED_VALUE : 0); |
