diff options
| author | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-10-29 18:01:44 -0400 |
|---|---|---|
| committer | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-10-29 20:49:48 -0400 |
| commit | 32a472c6304ec4ec5e72c28bd0510173093c171b (patch) | |
| tree | 8053234243003323c2f784e12619fc198ae04cfe /src | |
| parent | d327881c44ada520d6ea939af59bdd420906b99f (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')
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp | 5 | ||||
| -rw-r--r-- | src/core/hle/service/nx2_gsv.h | 16 |
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 cfef3f1229..5eab9d420f 100644 --- a/src/core/hle/service/nx2_gsv.h +++ b/src/core/hle/service/nx2_gsv.h @@ -309,6 +309,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"}, @@ -457,6 +458,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(); |
