aboutsummaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-29 18:01:44 -0400
committerTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-30 01:27:55 -0400
commit18b35b020ef754716f574e6311c651f76f6a8a42 (patch)
tree57378d38640e15556267011b453195998d0d65e8 /src/core
parentd56039ace99338293658f931a871e4dba203e3ab (diff)
nx2: support mapping modify so NVN2 places compressible textures
NVN2 gives a texture in a compressible memory pool its GPU address only after NvRmGpuMappingModify switched the pool's mapping to the texture's kind. NvRm fails that call unless the GPU characteristics report NVGPU_GPU_FLAGS_SUPPORT_MAPPING_MODIFY, so such textures kept address 0 and draws into them went nowhere: title 1's cup-opening movie stayed on its first frame (also its 640x360 and 512x512 passes). Report the flag and answer the request nn::gpu::sdk then sends, gpu sub-session 212 (NormalModifyMemoryKind4K), with the wanted kind and a signalled job slot. The movie now plays on screen and the race follows.
Diffstat (limited to 'src/core')
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp5
-rw-r--r--src/core/hle/service/nx2_gsv.h16
2 files changed, 21 insertions, 0 deletions
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
index df2421cd13..5db984b53d 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
@@ -202,6 +202,11 @@ void ApplyNx2Characteristics(GC& gc) {
gc.flags |= 0x100; // NVGPU_GPU_FLAGS_SUPPORT_TSG: NvRm binds channels to a TSG
gc.flags |= 1ULL << 22; // NVGPU_GPU_FLAGS_SUPPORT_TSG_SUBCONTEXTS (see below)
gc.flags |= 1ULL << 26; // NVGPU_GPU_FLAGS_SUPPORT_SYNCPOINT_ADDRESS: syncpoint shim
+ // NVGPU_GPU_FLAGS_SUPPORT_MAPPING_MODIFY: NVN2 gives a texture in a compressible pool its
+ // address only after NvRmGpuMappingModify switched the pool's mapping to the texture's kind.
+ // Without the flag NvRm fails that call and the texture stays at GPU address 0 (title 1's
+ // movie and the passes rendered into compressible pools never showed).
+ gc.flags |= 1ULL << 34;
// The Switch 2 layout keeps nine s16 interface versions at 0x70..0x80 (like nvgpu's
// *_ioctl_nr_last); its NvRm requires e.g. [0x78] >= 6 and enables features above 0xa, 0x1f
diff --git a/src/core/hle/service/nx2_gsv.h b/src/core/hle/service/nx2_gsv.h
index caf4a452c4..94d28746fe 100644
--- a/src/core/hle/service/nx2_gsv.h
+++ b/src/core/hle/service/nx2_gsv.h
@@ -288,6 +288,7 @@ public:
{101, &INx2GpuSession::SubRegisterMemory, "CreateGpuAccessibleMemory"},
{102, &INx2GpuSession::SubDestroyMemory, "DestroyGpuAccessibleMemory (guessed)"},
{211, &INx2GpuSession::SubSubmitJob, "NormalMapGpuMemory4K"},
+ {212, &INx2GpuSession::SubModifyKind, "NormalModifyMemoryKind4K"},
{213, &INx2GpuSession::SubUnmapJob, "NormalUnmapGpuMemory4K"},
{214, &INx2GpuSession::SubCreateGpuOnlyRegion, "CreateSparseRegion"},
{215, &INx2GpuSession::SubDestroySparseRegion, "DestroySparseRegion"},
@@ -436,6 +437,21 @@ private:
rb.Push(ResultSuccess);
}
+ // Sub 212 (nn::gpu::sdk::NormalModifyMemoryKind4K, behind NvRmGpuMappingModify): word 2 the
+ // address space, 3-4 first GPU address, 5-6 last, 7 the wanted (compressible) kind, 8 the
+ // fallback kind, 9 a sync flag, 10 the job slot. The reply's word 3 is the kind applied. Kinds
+ // do not matter to the emulated GPU, so keep the mapping and report the wanted kind.
+ void SubModifyKind(HLERequestContext& ctx) {
+ const auto* w = ctx.CommandBuffer();
+ const u64 first = u64{w[3]} | (u64{w[4]} << 32);
+ const u64 last = u64{w[5]} | (u64{w[6]} << 32);
+ const u32 kind = w[7] & 0xff;
+ LOG_DEBUG(Service, "nx2:gpu 212 modify [{:#x}, {:#x}] kind={:#x} fallback={:#x} slot={}",
+ first, last, kind, w[8] & 0xff, w[10]);
+ EventFor(w[10])->Signal(system.Kernel());
+ TipcReplyWords(ctx, {kind});
+ }
+
// Sub 213: words 3-4 first GPU address, 5-6 last, job slot in word 8.
void SubUnmapJob(HLERequestContext& ctx) {
const auto* w = ctx.CommandBuffer();