From 07fe67092fa9329f9d0f24ead17d7d267510290c Mon Sep 17 00:00:00 2001 From: Skyth <19259897+blueskythlikesclouds@users.noreply.github.com> Date: Tue, 18 Mar 2025 19:26:59 +0300 Subject: [PATCH 1/5] Initial work for GPU upload heap & UMA. --- UnleashedRecomp/CMakeLists.txt | 6 +- UnleashedRecomp/gpu/rhi/plume_d3d12.cpp | 7 +- .../gpu/rhi/plume_render_interface_types.h | 6 +- UnleashedRecomp/gpu/rhi/plume_vulkan.cpp | 7 ++ UnleashedRecomp/gpu/video.cpp | 64 ++++++++++++------- 5 files changed, 63 insertions(+), 27 deletions(-) diff --git a/UnleashedRecomp/CMakeLists.txt b/UnleashedRecomp/CMakeLists.txt index 66b60a44..7a6c2774 100644 --- a/UnleashedRecomp/CMakeLists.txt +++ b/UnleashedRecomp/CMakeLists.txt @@ -310,7 +310,11 @@ endif() if (UNLEASHED_RECOMP_D3D12) find_package(directx-headers CONFIG REQUIRED) find_package(directx12-agility CONFIG REQUIRED) - target_compile_definitions(UnleashedRecomp PRIVATE UNLEASHED_RECOMP_D3D12) + target_compile_definitions(UnleashedRecomp PRIVATE + UNLEASHED_RECOMP_D3D12 + D3D12MA_USING_DIRECTX_HEADERS + D3D12MA_OPTIONS16_SUPPORTED + ) endif() if (CMAKE_SYSTEM_NAME MATCHES "Linux") diff --git a/UnleashedRecomp/gpu/rhi/plume_d3d12.cpp b/UnleashedRecomp/gpu/rhi/plume_d3d12.cpp index 395630c2..1ac7dfc4 100644 --- a/UnleashedRecomp/gpu/rhi/plume_d3d12.cpp +++ b/UnleashedRecomp/gpu/rhi/plume_d3d12.cpp @@ -442,6 +442,8 @@ namespace plume { return D3D12_HEAP_TYPE_UPLOAD; case RenderHeapType::READBACK: return D3D12_HEAP_TYPE_READBACK; + case RenderHeapType::GPU_UPLOAD: + return D3D12_HEAP_TYPE_GPU_UPLOAD; default: assert(false && "Unknown heap type."); return D3D12_HEAP_TYPE_DEFAULT; @@ -3391,12 +3393,14 @@ namespace plume { triangleFanSupportOption = d3d12Options15.TriangleFanSupported; } - // Check if dynamic depth bias is supported. + // Check if dynamic depth bias and GPU upload heap are supported. bool dynamicDepthBiasOption = false; + bool gpuUploadHeapOption = false; D3D12_FEATURE_DATA_D3D12_OPTIONS16 d3d12Options16 = {}; res = deviceOption->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS16, &d3d12Options16, sizeof(d3d12Options16)); if (SUCCEEDED(res)) { dynamicDepthBiasOption = d3d12Options16.DynamicDepthBiasSupported; + gpuUploadHeapOption = d3d12Options16.GPUUploadHeapSupported; } // Check if the architecture has UMA. @@ -3431,6 +3435,7 @@ namespace plume { capabilities.triangleFan = triangleFanSupportOption; capabilities.dynamicDepthBias = dynamicDepthBiasOption; capabilities.uma = uma; + capabilities.gpuUploadHeap = gpuUploadHeapOption; description.name = deviceName; description.dedicatedVideoMemory = adapterDesc.DedicatedVideoMemory; description.vendor = RenderDeviceVendor(adapterDesc.VendorId); diff --git a/UnleashedRecomp/gpu/rhi/plume_render_interface_types.h b/UnleashedRecomp/gpu/rhi/plume_render_interface_types.h index b0be1592..568160a8 100644 --- a/UnleashedRecomp/gpu/rhi/plume_render_interface_types.h +++ b/UnleashedRecomp/gpu/rhi/plume_render_interface_types.h @@ -351,7 +351,8 @@ namespace plume { UNKNOWN, DEFAULT, UPLOAD, - READBACK + READBACK, + GPU_UPLOAD }; enum class RenderTextureArrangement { @@ -1807,6 +1808,9 @@ namespace plume { // UMA. bool uma = false; + + // GPU Upload heap. + bool gpuUploadHeap = false; }; struct RenderInterfaceCapabilities { diff --git a/UnleashedRecomp/gpu/rhi/plume_vulkan.cpp b/UnleashedRecomp/gpu/rhi/plume_vulkan.cpp index 477a431a..7269ad05 100644 --- a/UnleashedRecomp/gpu/rhi/plume_vulkan.cpp +++ b/UnleashedRecomp/gpu/rhi/plume_vulkan.cpp @@ -808,6 +808,12 @@ namespace plume { bufferInfo.usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; createInfo.flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT; break; + case RenderHeapType::GPU_UPLOAD: + bufferInfo.usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + bufferInfo.usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; + createInfo.flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; + createInfo.requiredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; + break; default: assert(false && "Unknown heap type."); break; @@ -3907,6 +3913,7 @@ namespace plume { capabilities.preferHDR = memoryHeapSize > (512 * 1024 * 1024); capabilities.triangleFan = true; capabilities.dynamicDepthBias = true; + capabilities.gpuUploadHeap = true; // TODO: Do a test buffer allocation with the required flags to set this. // Fill Vulkan-only capabilities. loadStoreOpNoneSupported = supportedOptionalExtensions.find(VK_EXT_LOAD_STORE_OP_NONE_EXTENSION_NAME) != supportedOptionalExtensions.end(); diff --git a/UnleashedRecomp/gpu/video.cpp b/UnleashedRecomp/gpu/video.cpp index e24ce4de..4dfa2e7e 100644 --- a/UnleashedRecomp/gpu/video.cpp +++ b/UnleashedRecomp/gpu/video.cpp @@ -2112,36 +2112,46 @@ static void* LockVertexBuffer(GuestBuffer* buffer, uint32_t, uint32_t, uint32_t template static void UnlockBuffer(GuestBuffer* buffer, bool useCopyQueue) { - auto uploadBuffer = g_device->createBuffer(RenderBufferDesc::UploadBuffer(buffer->dataSize)); - - auto dest = reinterpret_cast(uploadBuffer->map()); - auto src = reinterpret_cast(buffer->mappedMemory); - - for (size_t i = 0; i < buffer->dataSize; i += sizeof(T)) - { - *dest = ByteSwap(*src); - ++dest; - ++src; - } + auto copyBuffer = [&](T* dest) + { + auto src = reinterpret_cast(buffer->mappedMemory); - uploadBuffer->unmap(); + for (size_t i = 0; i < buffer->dataSize; i += sizeof(T)) + { + *dest = ByteSwap(*src); + ++dest; + ++src; + } + }; - if (useCopyQueue) + if (useCopyQueue && (g_capabilities.uma || g_capabilities.gpuUploadHeap)) { - ExecuteCopyCommandList([&] - { - g_copyCommandList->copyBufferRegion(buffer->buffer->at(0), uploadBuffer->at(0), buffer->dataSize); - }); + copyBuffer(reinterpret_cast(buffer->buffer->map())); + buffer->buffer->unmap(); } else { - auto& commandList = g_commandLists[g_frame]; + auto uploadBuffer = g_device->createBuffer(RenderBufferDesc::UploadBuffer(buffer->dataSize)); + copyBuffer(reinterpret_cast(uploadBuffer->map())); + uploadBuffer->unmap(); - commandList->barriers(RenderBarrierStage::COPY, RenderBufferBarrier(buffer->buffer.get(), RenderBufferAccess::WRITE)); - commandList->copyBufferRegion(buffer->buffer->at(0), uploadBuffer->at(0), buffer->dataSize); - commandList->barriers(RenderBarrierStage::GRAPHICS, RenderBufferBarrier(buffer->buffer.get(), RenderBufferAccess::READ)); + if (useCopyQueue) + { + ExecuteCopyCommandList([&] + { + g_copyCommandList->copyBufferRegion(buffer->buffer->at(0), uploadBuffer->at(0), buffer->dataSize); + }); + } + else + { + auto& commandList = g_commandLists[g_frame]; + + commandList->barriers(RenderBarrierStage::COPY, RenderBufferBarrier(buffer->buffer.get(), RenderBufferAccess::WRITE)); + commandList->copyBufferRegion(buffer->buffer->at(0), uploadBuffer->at(0), buffer->dataSize); + commandList->barriers(RenderBarrierStage::GRAPHICS, RenderBufferBarrier(buffer->buffer.get(), RenderBufferAccess::READ)); - g_tempBuffers[g_frame].emplace_back(std::move(uploadBuffer)); + g_tempBuffers[g_frame].emplace_back(std::move(uploadBuffer)); + } } } @@ -2339,6 +2349,7 @@ static void DrawProfiler() ImGui::Text("Device Type: %s", DeviceTypeName(g_device->getDescription().type)); ImGui::Text("VRAM: %.2f MiB", (double)(g_device->getDescription().dedicatedVideoMemory) / (1024.0 * 1024.0)); ImGui::Text("UMA: %s", g_capabilities.uma ? "Supported" : "Unsupported"); + ImGui::Text("GPU Upload Heap: %s", g_capabilities.gpuUploadHeap ? "Supported" : "Unsupported"); const char* sdlVideoDriver = SDL_GetCurrentVideoDriver(); if (sdlVideoDriver != nullptr) @@ -3019,10 +3030,15 @@ static GuestTexture* CreateTexture(uint32_t width, uint32_t height, uint32_t dep return texture; } +static RenderHeapType GetBufferHeapType() +{ + return g_capabilities.gpuUploadHeap ? RenderHeapType::GPU_UPLOAD : RenderHeapType::DEFAULT; +} + static GuestBuffer* CreateVertexBuffer(uint32_t length) { auto buffer = g_userHeap.AllocPhysical(ResourceType::VertexBuffer); - buffer->buffer = g_device->createBuffer(RenderBufferDesc::VertexBuffer(length, RenderHeapType::DEFAULT, RenderBufferFlag::INDEX)); + buffer->buffer = g_device->createBuffer(RenderBufferDesc::VertexBuffer(length, GetBufferHeapType(), RenderBufferFlag::INDEX)); buffer->dataSize = length; #ifdef _DEBUG buffer->buffer->setName(fmt::format("Vertex Buffer {:X}", g_memory.MapVirtual(buffer))); @@ -3033,7 +3049,7 @@ static GuestBuffer* CreateVertexBuffer(uint32_t length) static GuestBuffer* CreateIndexBuffer(uint32_t length, uint32_t, uint32_t format) { auto buffer = g_userHeap.AllocPhysical(ResourceType::IndexBuffer); - buffer->buffer = g_device->createBuffer(RenderBufferDesc::IndexBuffer(length, RenderHeapType::DEFAULT)); + buffer->buffer = g_device->createBuffer(RenderBufferDesc::IndexBuffer(length, GetBufferHeapType())); buffer->dataSize = length; buffer->format = ConvertFormat(format); buffer->guestFormat = format; From 6a24d35dec5b1619f2ab470a94e2a9d50e31b040 Mon Sep 17 00:00:00 2001 From: Dario Date: Tue, 18 Mar 2025 22:33:03 -0300 Subject: [PATCH 2/5] Finish D3D12 Support. --- UnleashedRecomp/gpu/rhi/plume_d3d12.cpp | 33 +++++++++++++++++++++---- UnleashedRecomp/gpu/rhi/plume_d3d12.h | 1 + UnleashedRecomp/gpu/video.cpp | 9 +++++-- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/UnleashedRecomp/gpu/rhi/plume_d3d12.cpp b/UnleashedRecomp/gpu/rhi/plume_d3d12.cpp index 1ac7dfc4..97bb942a 100644 --- a/UnleashedRecomp/gpu/rhi/plume_d3d12.cpp +++ b/UnleashedRecomp/gpu/rhi/plume_d3d12.cpp @@ -2387,7 +2387,7 @@ namespace plume { range.End = readRange->end; } - void *outputData; + void *outputData = nullptr; d3d->Map(subresource, (readRange != nullptr) ? &range : nullptr, &outputData); return outputData; } @@ -2638,7 +2638,15 @@ namespace plume { this->desc = desc; D3D12MA::POOL_DESC poolDesc = {}; - poolDesc.HeapProperties.Type = toD3D12(desc.heapType); + + // When using an UMA architecture without explicit support for GPU Upload heaps, we instead just make a custom heap with the same properties as Upload heaps. + if (desc.heapType == RenderHeapType::GPU_UPLOAD && device->capabilities.uma && !device->capabilities.gpuUploadHeap) { + poolDesc.HeapProperties = device->d3d->GetCustomHeapProperties(0, D3D12_HEAP_TYPE_UPLOAD); + } + else { + poolDesc.HeapProperties.Type = toD3D12(desc.heapType); + } + poolDesc.MinBlockCount = desc.minBlockCount; poolDesc.MaxBlockCount = desc.maxBlockCount; poolDesc.Flags |= desc.useLinearAlgorithm ? D3D12MA::POOL_FLAG_ALGORITHM_LINEAR : D3D12MA::POOL_FLAG_NONE; @@ -3392,7 +3400,7 @@ namespace plume { if (SUCCEEDED(res)) { triangleFanSupportOption = d3d12Options15.TriangleFanSupported; } - + // Check if dynamic depth bias and GPU upload heap are supported. bool dynamicDepthBiasOption = false; bool gpuUploadHeapOption = false; @@ -3435,7 +3443,10 @@ namespace plume { capabilities.triangleFan = triangleFanSupportOption; capabilities.dynamicDepthBias = dynamicDepthBiasOption; capabilities.uma = uma; - capabilities.gpuUploadHeap = gpuUploadHeapOption; + + // Pretend GPU Upload heaps are supported if UMA is supported, as the backend has a workaround using a custom pool for it. + capabilities.gpuUploadHeap = uma || gpuUploadHeapOption; + description.name = deviceName; description.dedicatedVideoMemory = adapterDesc.DedicatedVideoMemory; description.vendor = RenderDeviceVendor(adapterDesc.VendorId); @@ -3533,6 +3544,13 @@ namespace plume { colorTargetHeapAllocator = std::make_unique(this, TargetDescriptorHeapSize, D3D12_DESCRIPTOR_HEAP_TYPE_RTV); depthTargetHeapAllocator = std::make_unique(this, TargetDescriptorHeapSize, D3D12_DESCRIPTOR_HEAP_TYPE_DSV); + // Create the custom upload pool that will be used as the fallback when using an UMA architecture without explicit support for GPU Upload heaps. + if (capabilities.uma && !capabilities.gpuUploadHeap) { + RenderPoolDesc poolDesc; + poolDesc.heapType = RenderHeapType::GPU_UPLOAD; + customUploadPool = std::make_unique(this, poolDesc); + } + // Create a command queue only for retrieving the timestamp frequency. Delete it immediately afterwards. std::unique_ptr timestampCommandQueue = std::make_unique(this, RenderCommandListType::DIRECT); res = timestampCommandQueue->d3d->GetTimestampFrequency(×tampFrequency); @@ -3582,7 +3600,12 @@ namespace plume { } std::unique_ptr D3D12Device::createBuffer(const RenderBufferDesc &desc) { - return std::make_unique(this, nullptr, desc); + if ((desc.heapType == RenderHeapType::GPU_UPLOAD) && capabilities.uma && !capabilities.gpuUploadHeap) { + return std::make_unique(this, customUploadPool.get(), desc); + } + else { + return std::make_unique(this, nullptr, desc); + } } std::unique_ptr D3D12Device::createTexture(const RenderTextureDesc &desc) { diff --git a/UnleashedRecomp/gpu/rhi/plume_d3d12.h b/UnleashedRecomp/gpu/rhi/plume_d3d12.h index d4987fbc..87980e56 100644 --- a/UnleashedRecomp/gpu/rhi/plume_d3d12.h +++ b/UnleashedRecomp/gpu/rhi/plume_d3d12.h @@ -430,6 +430,7 @@ namespace plume { std::unique_ptr samplerHeapAllocator; std::unique_ptr colorTargetHeapAllocator; std::unique_ptr depthTargetHeapAllocator; + std::unique_ptr customUploadPool; RenderDeviceCapabilities capabilities; RenderDeviceDescription description; uint64_t timestampFrequency = 1; diff --git a/UnleashedRecomp/gpu/video.cpp b/UnleashedRecomp/gpu/video.cpp index 4dfa2e7e..28caa169 100644 --- a/UnleashedRecomp/gpu/video.cpp +++ b/UnleashedRecomp/gpu/video.cpp @@ -2109,6 +2109,8 @@ static void* LockVertexBuffer(GuestBuffer* buffer, uint32_t, uint32_t, uint32_t return LockBuffer(buffer, flags); } +static std::atomic g_bufferUploadCount = 0; + template static void UnlockBuffer(GuestBuffer* buffer, bool useCopyQueue) { @@ -2124,7 +2126,7 @@ static void UnlockBuffer(GuestBuffer* buffer, bool useCopyQueue) } }; - if (useCopyQueue && (g_capabilities.uma || g_capabilities.gpuUploadHeap)) + if (useCopyQueue && g_capabilities.gpuUploadHeap) { copyBuffer(reinterpret_cast(buffer->buffer->map())); buffer->buffer->unmap(); @@ -2153,6 +2155,8 @@ static void UnlockBuffer(GuestBuffer* buffer, bool useCopyQueue) g_tempBuffers[g_frame].emplace_back(std::move(uploadBuffer)); } } + + g_bufferUploadCount++; } template @@ -2330,10 +2334,11 @@ static void DrawProfiler() std::lock_guard lock(g_userHeap.physicalMutex); physicalDiagnostics = o1heapGetDiagnostics(g_userHeap.physicalHeap); } - + ImGui::Text("Heap Allocated: %d MB", int32_t(diagnostics.allocated / (1024 * 1024))); ImGui::Text("Physical Heap Allocated: %d MB", int32_t(physicalDiagnostics.allocated / (1024 * 1024))); ImGui::Text("GPU Waits: %d", int32_t(g_waitForGPUCount)); + ImGui::Text("Buffer Uploads: %d", int32_t(g_bufferUploadCount)); ImGui::NewLine(); ImGui::Text("Present Wait: %s", g_capabilities.presentWait ? "Supported" : "Unsupported"); From 2c710f4115668d6e482230364bfddffdf1b0c5f2 Mon Sep 17 00:00:00 2001 From: Dario Date: Tue, 18 Mar 2025 22:41:35 -0300 Subject: [PATCH 3/5] Rework the logic for the GPU Upload Heap fallback. --- UnleashedRecomp/gpu/rhi/plume_d3d12.cpp | 11 ++++++----- UnleashedRecomp/gpu/rhi/plume_d3d12.h | 3 ++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/UnleashedRecomp/gpu/rhi/plume_d3d12.cpp b/UnleashedRecomp/gpu/rhi/plume_d3d12.cpp index 97bb942a..744ef0d2 100644 --- a/UnleashedRecomp/gpu/rhi/plume_d3d12.cpp +++ b/UnleashedRecomp/gpu/rhi/plume_d3d12.cpp @@ -2631,7 +2631,7 @@ namespace plume { // D3D12Pool - D3D12Pool::D3D12Pool(D3D12Device *device, const RenderPoolDesc &desc) { + D3D12Pool::D3D12Pool(D3D12Device *device, const RenderPoolDesc &desc, bool gpuUploadHeapFallback) { assert(device != nullptr); this->device = device; @@ -2640,7 +2640,7 @@ namespace plume { D3D12MA::POOL_DESC poolDesc = {}; // When using an UMA architecture without explicit support for GPU Upload heaps, we instead just make a custom heap with the same properties as Upload heaps. - if (desc.heapType == RenderHeapType::GPU_UPLOAD && device->capabilities.uma && !device->capabilities.gpuUploadHeap) { + if ((desc.heapType == RenderHeapType::GPU_UPLOAD) && gpuUploadHeapFallback) { poolDesc.HeapProperties = device->d3d->GetCustomHeapProperties(0, D3D12_HEAP_TYPE_UPLOAD); } else { @@ -3446,6 +3446,7 @@ namespace plume { // Pretend GPU Upload heaps are supported if UMA is supported, as the backend has a workaround using a custom pool for it. capabilities.gpuUploadHeap = uma || gpuUploadHeapOption; + gpuUploadHeapFallback = uma && !gpuUploadHeapOption; description.name = deviceName; description.dedicatedVideoMemory = adapterDesc.DedicatedVideoMemory; @@ -3545,10 +3546,10 @@ namespace plume { depthTargetHeapAllocator = std::make_unique(this, TargetDescriptorHeapSize, D3D12_DESCRIPTOR_HEAP_TYPE_DSV); // Create the custom upload pool that will be used as the fallback when using an UMA architecture without explicit support for GPU Upload heaps. - if (capabilities.uma && !capabilities.gpuUploadHeap) { + if (gpuUploadHeapFallback) { RenderPoolDesc poolDesc; poolDesc.heapType = RenderHeapType::GPU_UPLOAD; - customUploadPool = std::make_unique(this, poolDesc); + customUploadPool = std::make_unique(this, poolDesc, true); } // Create a command queue only for retrieving the timestamp frequency. Delete it immediately afterwards. @@ -3617,7 +3618,7 @@ namespace plume { } std::unique_ptr D3D12Device::createPool(const RenderPoolDesc &desc) { - return std::make_unique(this, desc); + return std::make_unique(this, desc, gpuUploadHeapFallback); } std::unique_ptr D3D12Device::createPipelineLayout(const RenderPipelineLayoutDesc &desc) { diff --git a/UnleashedRecomp/gpu/rhi/plume_d3d12.h b/UnleashedRecomp/gpu/rhi/plume_d3d12.h index 87980e56..34461c07 100644 --- a/UnleashedRecomp/gpu/rhi/plume_d3d12.h +++ b/UnleashedRecomp/gpu/rhi/plume_d3d12.h @@ -329,7 +329,7 @@ namespace plume { D3D12Device *device = nullptr; RenderPoolDesc desc; - D3D12Pool(D3D12Device *device, const RenderPoolDesc &desc); + D3D12Pool(D3D12Device *device, const RenderPoolDesc &desc, bool gpuUploadHeapFallback); ~D3D12Pool() override; std::unique_ptr createBuffer(const RenderBufferDesc &desc) override; std::unique_ptr createTexture(const RenderTextureDesc &desc) override; @@ -434,6 +434,7 @@ namespace plume { RenderDeviceCapabilities capabilities; RenderDeviceDescription description; uint64_t timestampFrequency = 1; + bool gpuUploadHeapFallback = false; D3D12Device(D3D12Interface *renderInterface, const std::string &preferredDeviceName); ~D3D12Device() override; From e798bc5eb32e87e00a5c833c07b59d89a3083499 Mon Sep 17 00:00:00 2001 From: Dario Date: Tue, 18 Mar 2025 23:47:46 -0300 Subject: [PATCH 4/5] Only enable UMA on Vulkan on integrated GPUs. --- UnleashedRecomp/gpu/rhi/plume_vulkan.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/UnleashedRecomp/gpu/rhi/plume_vulkan.cpp b/UnleashedRecomp/gpu/rhi/plume_vulkan.cpp index 7269ad05..94f91faf 100644 --- a/UnleashedRecomp/gpu/rhi/plume_vulkan.cpp +++ b/UnleashedRecomp/gpu/rhi/plume_vulkan.cpp @@ -839,7 +839,7 @@ namespace plume { } if (res != VK_SUCCESS) { - fprintf(stderr, "vkCreateBuffer failed with error code 0x%X.\n", res); + fprintf(stderr, "vmaCreateBuffer failed with error code 0x%X.\n", res); return; } } @@ -3893,6 +3893,15 @@ namespace plume { VkDeviceSize memoryHeapSize = 0; const VkPhysicalDeviceMemoryProperties *memoryProps = nullptr; vmaGetMemoryProperties(allocator, &memoryProps); + + constexpr VkMemoryPropertyFlags uploadHeapPropertyFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + bool hasHostVisibleDeviceLocalMemory = false; + for (uint32_t i = 0; i < memoryProps->memoryTypeCount; i++) { + if ((memoryProps->memoryTypes[i].propertyFlags & uploadHeapPropertyFlags) == uploadHeapPropertyFlags) { + hasHostVisibleDeviceLocalMemory = true; + } + } + for (uint32_t i = 0; i < memoryProps->memoryHeapCount; i++) { if (memoryProps->memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) { memoryHeapSize = std::max(memoryProps->memoryHeaps[i].size, memoryHeapSize); @@ -3913,7 +3922,8 @@ namespace plume { capabilities.preferHDR = memoryHeapSize > (512 * 1024 * 1024); capabilities.triangleFan = true; capabilities.dynamicDepthBias = true; - capabilities.gpuUploadHeap = true; // TODO: Do a test buffer allocation with the required flags to set this. + capabilities.uma = (description.type == RenderDeviceType::INTEGRATED) && hasHostVisibleDeviceLocalMemory; + capabilities.gpuUploadHeap = capabilities.uma; // Fill Vulkan-only capabilities. loadStoreOpNoneSupported = supportedOptionalExtensions.find(VK_EXT_LOAD_STORE_OP_NONE_EXTENSION_NAME) != supportedOptionalExtensions.end(); From e25d044c28c6f5cb580701fd97f51c61572c9e07 Mon Sep 17 00:00:00 2001 From: Dario Date: Tue, 18 Mar 2025 23:52:17 -0300 Subject: [PATCH 5/5] Fix D3D12 fallback condition. --- UnleashedRecomp/gpu/rhi/plume_d3d12.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UnleashedRecomp/gpu/rhi/plume_d3d12.cpp b/UnleashedRecomp/gpu/rhi/plume_d3d12.cpp index 744ef0d2..073ea68a 100644 --- a/UnleashedRecomp/gpu/rhi/plume_d3d12.cpp +++ b/UnleashedRecomp/gpu/rhi/plume_d3d12.cpp @@ -3601,7 +3601,7 @@ namespace plume { } std::unique_ptr D3D12Device::createBuffer(const RenderBufferDesc &desc) { - if ((desc.heapType == RenderHeapType::GPU_UPLOAD) && capabilities.uma && !capabilities.gpuUploadHeap) { + if ((desc.heapType == RenderHeapType::GPU_UPLOAD) && gpuUploadHeapFallback) { return std::make_unique(this, customUploadPool.get(), desc); } else {