Fix VRAM leak on quality changes and RGBA16 motion vectors; more games

- Shim: reuse VRAM interop buffers across features instead of freeing them;
  ROCm 7.2.x's hipExternalMemoryGetMappedBuffer retains its view twice, so
  freed buffers never released their memory (~130 MB per quality change)
- Bridge: close the exported fd after hipImportExternalMemory
- Shim: accept R16G16B16A16_TYPELESS motion vectors and convert 4-channel
  motion vectors to RG16F on the GPU, keeping VRAM interop (Dying Light:
  The Beast rendered black)
- Harness: D4R_HARNESS_RECREATE=N quality-change cycles,
  D4R_HARNESS_MV_RGBA16=1 motion vector format
- Supported games: TLOU, Control, Cyberpunk 2077, Rift Apart, HZD Remastered,
  Subnautica 2, Alan Wake 2, Silent Hill 2, Dying Light: The Beast; general notes
- README: GPU support section (native kernels only for gfx1101); ignore videos/
This commit is contained in:
ayo committed 2026-09-28 01:26:51 -04:00
1 parent 1952452830
commit da263ecf75
6 files changed
+249 -28

No files matched your search

+8 -4
View File
@@ -2589,8 +2589,10 @@ CUresult WINAPI cuGetProcAddress(const char* symbol, void** pointer, int cuda_ve
handles (Wine 11 layout: a VkDevice client object holds the unix object
pointer at offset 8; a non-dispatchable client handle is the unix object
pointer; every unix object starts with its host handle), the host fd is
exported with vkGetMemoryFdKHR and imported into HIP, which takes ownership
of the fd. */
exported with vkGetMemoryFdKHR and imported into HIP. HIP does not take
ownership of the fd (hipDestroyExternalMemory leaves it open, and an open fd
keeps the memory alive after vkFreeMemory), so it is closed once imported, as
ROCm's own GL interop does after mapping. */
typedef struct
{
int type; /* hipExternalMemoryHandleTypeOpaqueFd = 1 */
@@ -2697,11 +2699,11 @@ CUresult WINAPI d4rImportVulkanMemory(void* client_device, uint64_t client_memor
desc.flags = 1; /* dedicated allocation */
void* external = NULL;
int result = import(&external, &desc);
close(fd);
if (result != 0)
{
tracef("d4rImportVulkanMemory: hipImportExternalMemory(fd=%d, %llu bytes) failed: %d", fd,
(unsigned long long)bytes, result);
close(fd);
return CUDA_ERROR_INVALID_VALUE;
}
D4rHipExternalMemoryBufferDesc buffer;
@@ -2835,5 +2837,7 @@ CUresult WINAPI d4rSetArrayRedirect(CUarray array, CUdeviceptr pointer, uint32_t
CUresult WINAPI d4rReleaseVulkanMemory(void* memory)
{
HIP_DESTROY_EXTERNAL_MEMORY_FN destroy = (HIP_DESTROY_EXTERNAL_MEMORY_FN)hip_symbol("hipDestroyExternalMemory");
return destroy != NULL && destroy(memory) == 0 ? CUDA_SUCCESS : CUDA_ERROR_INVALID_VALUE;
const int result = destroy != NULL ? destroy(memory) : -1;
tracef("d4rReleaseVulkanMemory: hipDestroyExternalMemory(%p) -> %d", memory, result);
return result == 0 ? CUDA_SUCCESS : CUDA_ERROR_INVALID_VALUE;
}