aboutsummaryrefslogtreecommitdiff
path: root/src/video_core
diff options
context:
space:
mode:
authorTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-28 15:19:44 -0400
committerTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-28 15:19:44 -0400
commit8393e2912616ce475619900be8cb29e551ff2997 (patch)
tree3893adb820a45908b270208ca8b5911cabf25a7e /src/video_core
parent0a692577b5c7d63a252d5099e39c088a117e7818 (diff)
Fix the P6 scratch save in R2UR/MATCH/HFMA2.RELU; GPU memory dump tool
The colour cast on title 1 (magenta/cyan, then red/green, changing per course) came from the sky/atmosphere volume shader (a pixel shader drawing a 32^3 RGBA16F table slice by slice), which starts with an unguarded R2UR. R2UR, MATCH and HFMA2.RELU use P6 as scratch and saved/restored it with the uniform-guard mask, 1 << (6 - 7) for an unguarded instruction: undefined, in practice bit 31, which shifted into the opcode bits and turned the save into another instruction. They now always save and restore P6. Debugging aids used to find it: - EDEN_NX2_DUMP=<present>:<addr>:<size>,...: flush GPU memory ranges at a present (on the GPU thread) and save them next to the frame captures; nx2work/vol3d.py untiles Switch 2 3D textures from such dumps. - GPU::RunOnGpuThread. - Logs of Switch 2 3D images and descriptors.
Diffstat (limited to 'src/video_core')
-rw-r--r--src/video_core/gpu.cpp4
-rw-r--r--src/video_core/gpu.h3
-rw-r--r--src/video_core/texture_cache/image_info.cpp15
-rw-r--r--src/video_core/texture_cache/texture_cache.h6
4 files changed, 27 insertions, 1 deletions
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index 2a61a66d82..6441b9511a 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -411,6 +411,10 @@ u64 GPU::RequestFlush(DAddr addr, std::size_t size) {
});
}
+u64 GPU::RunOnGpuThread(std::function<void()>&& action) {
+ return impl->RequestSyncOperation(std::move(action));
+}
+
u64 GPU::CurrentSyncRequestFence() const {
return impl->CurrentSyncRequestFence();
}
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index 41ba186cd3..3a6546b41b 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -164,6 +164,9 @@ public:
/// Request a host GPU memory flush from the CPU.
[[nodiscard]] u64 RequestFlush(DAddr addr, std::size_t size);
+ /// Runs an action on the GPU thread between command lists (returns its sync fence).
+ u64 RunOnGpuThread(std::function<void()>&& action);
+
/// Obtains current flush request fence id.
[[nodiscard]] u64 CurrentSyncRequestFence() const;
diff --git a/src/video_core/texture_cache/image_info.cpp b/src/video_core/texture_cache/image_info.cpp
index 8b59eb6841..7e86bf00cf 100644
--- a/src/video_core/texture_cache/image_info.cpp
+++ b/src/video_core/texture_cache/image_info.cpp
@@ -4,9 +4,13 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
+#include <algorithm>
+#include <array>
+#include <vector>
#include <fmt/ranges.h>
#include "common/assert.h"
+#include "common/logging.h"
#include "common/settings.h"
#include "video_core/surface.h"
#include "video_core/texture_cache/format_lookup_table.h"
@@ -109,14 +113,23 @@ ImageInfo::ImageInfo(const TICEntry& config) noexcept {
size.height = config.Height();
resources.layers = config.BaseLayer() + config.Depth() * 6;
break;
- case TextureType::Texture3D:
+ case TextureType::Texture3D: {
ASSERT(config.BaseLayer() == 0);
type = ImageType::e3D;
size.width = config.Width();
size.height = config.Height();
size.depth = config.Depth();
resources.layers = 1;
+ // A few distinct 3D descriptors, raw (to check Switch 2 volume fields).
+ static std::vector<std::array<u64, 4>> logged;
+ if (logged.size() < 16 && std::find(logged.begin(), logged.end(), config.raw) == logged.end()) {
+ logged.push_back(config.raw);
+ LOG_INFO(HW_GPU, "3D TIC {:016x} {:016x} {:016x} {:016x}: {}x{}x{} block_depth {} levels {}",
+ config.raw[0], config.raw[1], config.raw[2], config.raw[3], size.width, size.height,
+ size.depth, config.block_depth.Value(), config.max_mip_level.Value() + 1);
+ }
break;
+ }
case TextureType::Texture1DBuffer:
type = ImageType::Buffer;
size.width = config.Width();
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index f3da5684a5..75005f0731 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -1569,6 +1569,12 @@ ImageId TextureCache<P>::InsertImage(const ImageInfo& info, GPUVAddr gpu_addr,
ASSERT_MSG(cpu_addr, "Tried to insert an image to an invalid gpu_addr={:#x}", gpu_addr);
ImageInfo storage_info = info;
storage_info.native_tiling = gpu_memory->UsesNativeTiling();
+ if (storage_info.native_tiling && info.type == ImageType::e3D) {
+ // Switch 2 3D images (lighting/fog volumes) are rare: log each one's shape.
+ LOG_INFO(HW_GPU, "3D image at {:#x}: {}x{}x{} levels {} format {} block {}x{}x{}",
+ gpu_addr, info.size.width, info.size.height, info.size.depth, info.resources.levels,
+ static_cast<u32>(info.format), info.block.width, info.block.height, info.block.depth);
+ }
const ImageId image_id = JoinImages(storage_info, gpu_addr, *cpu_addr);
const Image& image = slot_images[image_id];
// Using "image.gpu_addr" instead of "gpu_addr" is important because it might be different