From b394ca0a7a34e27d2e0c8378931b6bcaaadad7a4 Mon Sep 17 00:00:00 2001 From: Skyth <19259897+blueskythlikesclouds@users.noreply.github.com> Date: Tue, 16 Dec 2025 11:38:43 +0300 Subject: [PATCH] Upgrade D3D12MA. --- .../d3d12/rendering_device_driver_d3d12.cpp | 2 +- thirdparty/README.md | 4 +- thirdparty/d3d12ma/D3D12MemAlloc.cpp | 512 +++++++++++++----- thirdparty/d3d12ma/D3D12MemAlloc.h | 274 +++++++++- thirdparty/d3d12ma/LICENSE.txt | 2 +- thirdparty/d3d12ma/README.md | 10 +- .../d3d12ma/patches/0001-mingw-support.patch | 34 ++ .../directx_headers/include/dxguids/dxguids.h | 19 + 8 files changed, 696 insertions(+), 161 deletions(-) create mode 100644 thirdparty/d3d12ma/patches/0001-mingw-support.patch diff --git a/drivers/d3d12/rendering_device_driver_d3d12.cpp b/drivers/d3d12/rendering_device_driver_d3d12.cpp index 3471c361cb..4fce881005 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.cpp +++ b/drivers/d3d12/rendering_device_driver_d3d12.cpp @@ -6325,7 +6325,7 @@ Error RenderingDeviceDriverD3D12::_initialize_allocator() { D3D12MA::ALLOCATOR_DESC allocator_desc = {}; allocator_desc.pDevice = device.Get(); allocator_desc.pAdapter = adapter.Get(); - allocator_desc.Flags = D3D12MA::ALLOCATOR_FLAG_DEFAULT_POOLS_NOT_ZEROED | D3D12MA::ALLOCATOR_FLAG_DONT_PREFER_SMALL_BUFFERS_COMMITTED; + allocator_desc.Flags = D3D12MA_RECOMMENDED_ALLOCATOR_FLAGS | D3D12MA::ALLOCATOR_FLAG_DONT_PREFER_SMALL_BUFFERS_COMMITTED; HRESULT res = D3D12MA::CreateAllocator(&allocator_desc, &allocator); ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ERR_CANT_CREATE, "D3D12MA::CreateAllocator failed with error " + vformat("0x%08ux", (uint64_t)res) + "."); diff --git a/thirdparty/README.md b/thirdparty/README.md index 03e267d0f8..30630fff86 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -153,7 +153,7 @@ Patches: ## d3d12ma - Upstream: https://github.com/GPUOpen-LibrariesAndSDKs/D3D12MemoryAllocator -- Version: 2.1.0-development (4d16e802e0b9451c9d3c27cd308928c13b73acd6, 2023) +- Version: 3.1.0 (0fa62ed3a0a69b73230a8ec1faa752d4061c8dc8, 2026) - License: MIT Files extracted from upstream source: @@ -170,7 +170,7 @@ Patches: ## directx_headers - Upstream: https://github.com/microsoft/DirectX-Headers -- Version: 1.618.2 (dde59d560da2760fec612d6634124edc2a26b82f, 2025) +- Version: main (25411c74bb9cc7c416b2ff01b3ad8a306811dfdd, 2025) - License: MIT Files extracted from upstream source: diff --git a/thirdparty/d3d12ma/D3D12MemAlloc.cpp b/thirdparty/d3d12ma/D3D12MemAlloc.cpp index 89b71ffe35..297910708a 100644 --- a/thirdparty/d3d12ma/D3D12MemAlloc.cpp +++ b/thirdparty/d3d12ma/D3D12MemAlloc.cpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2019-2025 Advanced Micro Devices, Inc. All rights reserved. +// Copyright (c) 2019-2026 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -49,6 +49,14 @@ //////////////////////////////////////////////////////////////////////////////// #ifndef _D3D12MA_CONFIGURATION +#if !defined(D3D12MA_CPP20) + #if __cplusplus >= 202002L || _MSVC_LANG >= 202002L // C++20 + #define D3D12MA_CPP20 1 + #else + #define D3D12MA_CPP20 0 + #endif +#endif + #ifdef _WIN32 #if !defined(WINVER) || WINVER < 0x0600 #error Required at least WinAPI version supporting: client = Windows Vista, server = Windows Server 2008. @@ -71,6 +79,10 @@ #define D3D12MA_ASSERT(cond) assert(cond) #endif +#if D3D12MA_CPP20 + #include +#endif + // Assert that will be called very often, like inside data structures e.g. operator[]. // Making it non-empty can make program slow. #ifndef D3D12MA_HEAVY_ASSERT @@ -81,6 +93,14 @@ #endif #endif +#ifndef D3D12MA_DEFAULT_ALIGNMENT + /* + Default alignment of allocations in default pools and custom pools with MinAllocationAlignment == 0. + Can be lowered for custom pools by specifying custom MinAllocationAlignment > 0. + */ + #define D3D12MA_DEFAULT_ALIGNMENT D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT +#endif + #ifndef D3D12MA_DEBUG_ALIGNMENT /* Minimum alignment of all allocations, in bytes. @@ -114,6 +134,14 @@ especially to test compatibility with D3D12_RESOURCE_HEAP_TIER_1 on modern GPUs. #define D3D12MA_DEFAULT_BLOCK_SIZE (64ull * 1024 * 1024) #endif +#ifndef D3D12MA_TIGHT_ALIGNMENT_SUPPORTED + #if D3D12_SDK_VERSION >= 618 + #define D3D12MA_TIGHT_ALIGNMENT_SUPPORTED 1 + #else + #define D3D12MA_TIGHT_ALIGNMENT_SUPPORTED 0 + #endif +#endif + #ifndef D3D12MA_OPTIONS16_SUPPORTED #if D3D12_SDK_VERSION >= 610 #define D3D12MA_OPTIONS16_SUPPORTED 1 @@ -174,6 +202,7 @@ static const D3D12_HEAP_FLAGS RESOURCE_CLASS_HEAP_FLAGS = static const D3D12_RESIDENCY_PRIORITY D3D12_RESIDENCY_PRIORITY_NONE = D3D12_RESIDENCY_PRIORITY(0); static const D3D12_HEAP_TYPE D3D12_HEAP_TYPE_GPU_UPLOAD_COPY = (D3D12_HEAP_TYPE)5; +static const D3D12_RESOURCE_FLAGS D3D12_RESOURCE_FLAG_USE_TIGHT_ALIGNMENT_COPY = (D3D12_RESOURCE_FLAGS)0x400; #ifndef _D3D12MA_ENUM_DECLARATIONS @@ -303,6 +332,10 @@ static UINT8 BitScanLSB(UINT64 mask) if (_BitScanForward64(&pos, mask)) return static_cast(pos); return UINT8_MAX; +#elif D3D12MA_CPP20 + if (mask != 0) + return static_cast(std::countr_zero(mask)); + return UINT8_MAX; #elif defined __GNUC__ || defined __clang__ return static_cast(__builtin_ffsll(mask)) - 1U; #else @@ -325,6 +358,10 @@ static UINT8 BitScanLSB(UINT32 mask) if (_BitScanForward(&pos, mask)) return static_cast(pos); return UINT8_MAX; +#elif D3D12MA_CPP20 + if (mask != 0) + return static_cast(std::countr_zero(mask)); + return UINT8_MAX; #elif defined __GNUC__ || defined __clang__ return static_cast(__builtin_ffs(mask)) - 1U; #else @@ -347,6 +384,9 @@ static UINT8 BitScanMSB(UINT64 mask) unsigned long pos; if (_BitScanReverse64(&pos, mask)) return static_cast(pos); +#elif D3D12MA_CPP20 + if (mask != 0) + return 63 - static_cast(std::countl_zero(mask)); #elif defined __GNUC__ || defined __clang__ if (mask) return 63 - static_cast(__builtin_clzll(mask)); @@ -369,6 +409,9 @@ static UINT8 BitScanMSB(UINT32 mask) unsigned long pos; if (_BitScanReverse(&pos, mask)) return static_cast(pos); +#elif D3D12MA_CPP20 + if (mask != 0) + return 31 - static_cast(std::countl_zero(mask)); #elif defined __GNUC__ || defined __clang__ if (mask) return 31 - static_cast(__builtin_clz(mask)); @@ -761,11 +804,9 @@ static bool ValidateAllocateMemoryParameters( return pAllocDesc && pAllocInfo && ppAllocation && - (pAllocInfo->Alignment == 0 || - pAllocInfo->Alignment == D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT || - pAllocInfo->Alignment == D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT) && - pAllocInfo->SizeInBytes != 0 && - pAllocInfo->SizeInBytes % (64ull * 1024) == 0; + IsPow2(pAllocInfo->Alignment) && + pAllocInfo->SizeInBytes > 0 && + pAllocInfo->SizeInBytes % 4 == 0; } #endif // _D3D12MA_FUNCTIONS @@ -2993,7 +3034,7 @@ void BlockMetadata::DebugLogAllocation(UINT64 offset, UINT64 size, void* private LPCWSTR name = allocation->GetName(); D3D12MA_DEBUG_LOG(L"UNFREED ALLOCATION; Offset: %llu; Size: %llu; PrivateData: %p; Name: %s", - offset, size, privateData, name ? name : L"D3D12MA_Empty"); + offset, size, privateData, name ? name : L""); } } @@ -5380,8 +5421,8 @@ struct CREATE_RESOURCE_PARAMS { CREATE_RESOURCE_PARAMS() = delete; CREATE_RESOURCE_PARAMS( - const D3D12_RESOURCE_DESC* pResourceDesc, - D3D12_RESOURCE_STATES InitialResourceState, + const D3D12_RESOURCE_DESC* pResourceDesc, + D3D12_RESOURCE_STATES InitialResourceState, const D3D12_CLEAR_VALUE* pOptimizedClearValue) : Variant(VARIANT_WITH_STATE) , pResourceDesc(pResourceDesc) @@ -5391,8 +5432,8 @@ struct CREATE_RESOURCE_PARAMS } #ifdef __ID3D12Device8_INTERFACE_DEFINED__ CREATE_RESOURCE_PARAMS( - const D3D12_RESOURCE_DESC1* pResourceDesc, - D3D12_RESOURCE_STATES InitialResourceState, + const D3D12_RESOURCE_DESC1* pResourceDesc, + D3D12_RESOURCE_STATES InitialResourceState, const D3D12_CLEAR_VALUE* pOptimizedClearValue) : Variant(VARIANT_WITH_STATE_AND_DESC1) , pResourceDesc1(pResourceDesc) @@ -5407,7 +5448,7 @@ struct CREATE_RESOURCE_PARAMS D3D12_BARRIER_LAYOUT InitialLayout, const D3D12_CLEAR_VALUE* pOptimizedClearValue, UINT32 NumCastableFormats, - DXGI_FORMAT* pCastableFormats) + const DXGI_FORMAT* pCastableFormats) : Variant(VARIANT_WITH_LAYOUT) , pResourceDesc1(pResourceDesc) , InitialLayout(InitialLayout) @@ -5477,7 +5518,7 @@ struct CREATE_RESOURCE_PARAMS D3D12MA_ASSERT(Variant >= VARIANT_WITH_LAYOUT); return NumCastableFormats; } - DXGI_FORMAT* GetCastableFormats() const + const DXGI_FORMAT* GetCastableFormats() const { D3D12MA_ASSERT(Variant >= VARIANT_WITH_LAYOUT); return pCastableFormats; @@ -5502,7 +5543,7 @@ private: const D3D12_CLEAR_VALUE* pOptimizedClearValue; #ifdef __ID3D12Device10_INTERFACE_DEFINED__ UINT32 NumCastableFormats; - DXGI_FORMAT* pCastableFormats; + const DXGI_FORMAT* pCastableFormats; #endif }; @@ -5552,6 +5593,7 @@ public: UINT64 size, UINT64 alignment, const ALLOCATION_DESC& allocDesc, + bool committedAllowed, size_t allocationCount, Allocation** pAllocations); @@ -5562,6 +5604,7 @@ public: UINT64 alignment, const ALLOCATION_DESC& allocDesc, const CREATE_RESOURCE_PARAMS& createParams, + bool committedAllowed, Allocation** ppAllocation, REFIID riidResource, void** ppvResource); @@ -5612,6 +5655,7 @@ private: UINT64 size, UINT64 alignment, const ALLOCATION_DESC& allocDesc, + bool committedAllowed, Allocation** pAllocation); HRESULT AllocateFromBlock( @@ -5717,29 +5761,31 @@ HRESULT CurrentBudgetData::UpdateBudget(IDXGIAdapter3* adapter3, bool useMutex) DXGI_QUERY_VIDEO_MEMORY_INFO infoLocal = {}; DXGI_QUERY_VIDEO_MEMORY_INFO infoNonLocal = {}; const HRESULT hrLocal = adapter3->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &infoLocal); + if (FAILED(hrLocal)) + { + return hrLocal; + } const HRESULT hrNonLocal = adapter3->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL, &infoNonLocal); + if (FAILED(hrNonLocal)) + { + return hrNonLocal; + } - if (SUCCEEDED(hrLocal) || SUCCEEDED(hrNonLocal)) { MutexLockWrite lockWrite(m_BudgetMutex, useMutex); - if (SUCCEEDED(hrLocal)) - { - m_D3D12Usage[0] = infoLocal.CurrentUsage; - m_D3D12Budget[0] = infoLocal.Budget; - } - if (SUCCEEDED(hrNonLocal)) - { - m_D3D12Usage[1] = infoNonLocal.CurrentUsage; - m_D3D12Budget[1] = infoNonLocal.Budget; - } + m_D3D12Usage[0] = infoLocal.CurrentUsage; + m_D3D12Budget[0] = infoLocal.Budget; + + m_D3D12Usage[1] = infoNonLocal.CurrentUsage; + m_D3D12Budget[1] = infoNonLocal.Budget; m_BlockBytesAtD3D12Fetch[0] = m_BlockBytes[0]; m_BlockBytesAtD3D12Fetch[1] = m_BlockBytes[1]; m_OperationsSinceBudgetFetch = 0; } - return FAILED(hrLocal) ? hrLocal : hrNonLocal; + return S_OK; } #endif // #if D3D12MA_DXGI_1_4 @@ -5915,6 +5961,12 @@ public: #endif #ifdef __ID3D12Device8_INTERFACE_DEFINED__ ID3D12Device8* GetDevice8() const { return m_Device8; } +#endif +#ifdef __ID3D12Device10_INTERFACE_DEFINED__ + ID3D12Device10* GetDevice10() const { return m_Device10; } +#endif +#ifdef __ID3D12Device12_INTERFACE_DEFINED__ + ID3D12Device12* GetDevice12() const { return m_Device12; } #endif // Shortcut for "Allocation Callbacks", because this function is called so often. const ALLOCATION_CALLBACKS& GetAllocs() const { return m_AllocationCallbacks; } @@ -5923,6 +5975,8 @@ public: BOOL IsCacheCoherentUMA() const { return m_D3D12Architecture.CacheCoherentUMA; } bool SupportsResourceHeapTier2() const { return m_D3D12Options.ResourceHeapTier >= D3D12_RESOURCE_HEAP_TIER_2; } bool IsGPUUploadHeapSupported() const { return m_GPUUploadHeapSupported != FALSE; } + bool IsTightAlignmentSupported() const { return m_TightAlignmentSupported != FALSE; } + bool IsTightAlignmentEnabled() const { return IsTightAlignmentSupported() && m_UseTightAlignment; } bool UseMutex() const { return m_UseMutex; } AllocationObjectAllocator& GetAllocationObjectAllocator() { return m_AllocationObjectAllocator; } UINT GetCurrentFrameIndex() const { return m_CurrentFrameIndex.load(); } @@ -6009,7 +6063,8 @@ private: const bool m_UseMutex; const bool m_AlwaysCommitted; const bool m_MsaaAlwaysCommitted; - const bool m_PreferSmallBuffersCommitted; + bool m_PreferSmallBuffersCommitted; + const bool m_UseTightAlignment; bool m_DefaultPoolsNotZeroed = false; ID3D12Device* m_Device; // AddRef #ifdef __ID3D12Device1_INTERFACE_DEFINED__ @@ -6023,6 +6078,9 @@ private: #endif #ifdef __ID3D12Device10_INTERFACE_DEFINED__ ID3D12Device10* m_Device10 = NULL; // AddRef, optional +#endif +#ifdef __ID3D12Device12_INTERFACE_DEFINED__ + ID3D12Device12* m_Device12 = NULL; // AddRef, optional #endif IDXGIAdapter* m_Adapter; // AddRef #if D3D12MA_DXGI_1_4 @@ -6034,6 +6092,7 @@ private: DXGI_ADAPTER_DESC m_AdapterDesc; D3D12_FEATURE_DATA_D3D12_OPTIONS m_D3D12Options; BOOL m_GPUUploadHeapSupported = FALSE; + BOOL m_TightAlignmentSupported = FALSE; D3D12_FEATURE_DATA_ARCHITECTURE m_D3D12Architecture; AllocationObjectAllocator m_AllocationObjectAllocator; @@ -6083,12 +6142,26 @@ private: HRESULT UpdateD3D12Budget(); D3D12_RESOURCE_ALLOCATION_INFO GetResourceAllocationInfoNative(const D3D12_RESOURCE_DESC& resourceDesc) const; + HRESULT GetResourceAllocationInfoMiddle(D3D12_RESOURCE_DESC& inOutResourceDesc, + UINT32 NumCastableFormats, const DXGI_FORMAT* pCastableFormats, + D3D12_RESOURCE_ALLOCATION_INFO& outAllocInfo) const; + #ifdef __ID3D12Device8_INTERFACE_DEFINED__ - D3D12_RESOURCE_ALLOCATION_INFO GetResourceAllocationInfoNative(const D3D12_RESOURCE_DESC1& resourceDesc) const; + D3D12_RESOURCE_ALLOCATION_INFO GetResourceAllocationInfo2Native(const D3D12_RESOURCE_DESC1& resourceDesc) const; + HRESULT GetResourceAllocationInfoMiddle(D3D12_RESOURCE_DESC1& inOutResourceDesc, + UINT32 NumCastableFormats, const DXGI_FORMAT* pCastableFormats, + D3D12_RESOURCE_ALLOCATION_INFO& outAllocInfo) const; +#endif + +#ifdef __ID3D12Device12_INTERFACE_DEFINED__ + D3D12_RESOURCE_ALLOCATION_INFO GetResourceAllocationInfo3Native(const D3D12_RESOURCE_DESC1& resourceDesc, + UINT32 NumCastableFormats, const DXGI_FORMAT* pCastableFormats) const; #endif template - D3D12_RESOURCE_ALLOCATION_INFO GetResourceAllocationInfo(D3D12_RESOURCE_DESC_T& inOutResourceDesc) const; + HRESULT GetResourceAllocationInfo(D3D12_RESOURCE_DESC_T& inOutResourceDesc, + UINT32 NumCastableFormats, const DXGI_FORMAT* pCastableFormats, + D3D12_RESOURCE_ALLOCATION_INFO& outAllocInfo) const; bool NewAllocationWithinBudget(D3D12_HEAP_TYPE heapType, UINT64 size); @@ -6101,7 +6174,8 @@ AllocatorPimpl::AllocatorPimpl(const ALLOCATION_CALLBACKS& allocationCallbacks, : m_UseMutex((desc.Flags & ALLOCATOR_FLAG_SINGLETHREADED) == 0), m_AlwaysCommitted((desc.Flags & ALLOCATOR_FLAG_ALWAYS_COMMITTED) != 0), m_MsaaAlwaysCommitted((desc.Flags & ALLOCATOR_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED) != 0), - m_PreferSmallBuffersCommitted((desc.Flags & ALLOCATOR_FLAG_DONT_PREFER_SMALL_BUFFERS_COMMITTED) == 0), + m_PreferSmallBuffersCommitted((desc.Flags& ALLOCATOR_FLAG_DONT_PREFER_SMALL_BUFFERS_COMMITTED) == 0), + m_UseTightAlignment((desc.Flags & ALLOCATOR_FLAG_DONT_USE_TIGHT_ALIGNMENT) == 0), m_Device(desc.pDevice), m_Adapter(desc.pAdapter), m_PreferredBlockSize(desc.PreferredBlockSize != 0 ? desc.PreferredBlockSize : D3D12MA_DEFAULT_BLOCK_SIZE), @@ -6160,6 +6234,10 @@ HRESULT AllocatorPimpl::Init(const ALLOCATOR_DESC& desc) m_Device->QueryInterface(D3D12MA_IID_PPV_ARGS(&m_Device10)); #endif +#ifdef __ID3D12Device12_INTERFACE_DEFINED__ + m_Device->QueryInterface(D3D12MA_IID_PPV_ARGS(&m_Device12)); +#endif + HRESULT hr = m_Adapter->GetDesc(&m_AdapterDesc); if (FAILED(hr)) { @@ -6186,6 +6264,25 @@ HRESULT AllocatorPimpl::Init(const ALLOCATOR_DESC& desc) } #endif // #if D3D12MA_OPTIONS16_SUPPORTED +#if D3D12MA_TIGHT_ALIGNMENT_SUPPORTED + { + D3D12_FEATURE_DATA_TIGHT_ALIGNMENT tightAlignment = {}; + hr = m_Device->CheckFeatureSupport(D3D12_FEATURE_D3D12_TIGHT_ALIGNMENT, &tightAlignment, sizeof(tightAlignment)); + if (SUCCEEDED(hr)) + { + m_TightAlignmentSupported = tightAlignment.SupportTier >= D3D12_TIGHT_ALIGNMENT_TIER_1; + + // If tight alignment is supported (checked by the code above) and wasn't disabled by the developer + // (with ALLOCATOR_FLAG_DONT_USE_TIGHT_ALIGNMENT), disable the preference for creating small buffers as committed, + // as if ALLOCATOR_FLAG_DONT_PREFER_SMALL_BUFFERS_COMMITTED was specified. + if (IsTightAlignmentEnabled()) + { + m_PreferSmallBuffersCommitted = false; + } + } + } +#endif // #if D3D12MA_TIGHT_ALIGNMENT_SUPPORTED + hr = m_Device->CheckFeatureSupport(D3D12_FEATURE_ARCHITECTURE, &m_D3D12Architecture, sizeof(m_D3D12Architecture)); if (FAILED(hr)) { @@ -6215,7 +6312,7 @@ HRESULT AllocatorPimpl::Init(const ALLOCATOR_DESC& desc) 0, // minBlockCount SIZE_MAX, // maxBlockCount false, // explicitBlockSize - D3D12MA_DEBUG_ALIGNMENT, // minAllocationAlignment + (UINT64)D3D12MA_DEFAULT_ALIGNMENT, // minAllocationAlignment 0, // Default algorithm, m_MsaaAlwaysCommitted, NULL, // pProtectedSession @@ -6232,6 +6329,9 @@ HRESULT AllocatorPimpl::Init(const ALLOCATOR_DESC& desc) AllocatorPimpl::~AllocatorPimpl() { +#ifdef __ID3D12Device12_INTERFACE_DEFINED__ + SAFE_RELEASE(m_Device12); +#endif #ifdef __ID3D12Device10_INTERFACE_DEFINED__ SAFE_RELEASE(m_Device10); #endif @@ -6328,12 +6428,15 @@ HRESULT AllocatorPimpl::CreatePlacedResourceWrap( { return E_NOINTERFACE; } + // Microsoft defined pCastableFormats parameter as pointer to non-const and only fixed it in later Agility SDK, + // thus we need const_cast. return m_Device10->CreatePlacedResource2(pHeap, HeapOffset, createParams.GetResourceDesc1(), createParams.GetInitialLayout(), createParams.GetOptimizedClearValue(), createParams.GetNumCastableFormats(), - createParams.GetCastableFormats(), riidResource, ppvResource); - } else + const_cast(createParams.GetCastableFormats()), riidResource, ppvResource); + } #endif + #ifdef __ID3D12Device8_INTERFACE_DEFINED__ if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE_AND_DESC1) { @@ -6344,21 +6447,19 @@ HRESULT AllocatorPimpl::CreatePlacedResourceWrap( return m_Device8->CreatePlacedResource1(pHeap, HeapOffset, createParams.GetResourceDesc1(), createParams.GetInitialResourceState(), createParams.GetOptimizedClearValue(), riidResource, ppvResource); - } else + } #endif + if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE) { return m_Device->CreatePlacedResource(pHeap, HeapOffset, createParams.GetResourceDesc(), createParams.GetInitialResourceState(), createParams.GetOptimizedClearValue(), riidResource, ppvResource); } - else - { - D3D12MA_ASSERT(0); - return E_INVALIDARG; - } -} + D3D12MA_ASSERT(0); + return E_INVALIDARG; +} HRESULT AllocatorPimpl::CreateResource( const ALLOCATION_DESC* pAllocDesc, @@ -6375,6 +6476,7 @@ HRESULT AllocatorPimpl::CreateResource( *ppvResource = NULL; } + HRESULT hr = E_NOINTERFACE; CREATE_RESOURCE_PARAMS finalCreateParams = createParams; D3D12_RESOURCE_DESC finalResourceDesc; #ifdef __ID3D12Device8_INTERFACE_DEFINED__ @@ -6385,45 +6487,49 @@ HRESULT AllocatorPimpl::CreateResource( { finalResourceDesc = *createParams.GetResourceDesc(); finalCreateParams.AccessResourceDesc() = &finalResourceDesc; - resAllocInfo = GetResourceAllocationInfo(finalResourceDesc); + hr = GetResourceAllocationInfo(finalResourceDesc, 0, NULL, resAllocInfo); } #ifdef __ID3D12Device8_INTERFACE_DEFINED__ else if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE_AND_DESC1) { - if (!m_Device8) + if (m_Device8 != NULL) { - return E_NOINTERFACE; + finalResourceDesc1 = *createParams.GetResourceDesc1(); + finalCreateParams.AccessResourceDesc1() = &finalResourceDesc1; + hr = GetResourceAllocationInfo(finalResourceDesc1, 0, NULL, resAllocInfo); } - finalResourceDesc1 = *createParams.GetResourceDesc1(); - finalCreateParams.AccessResourceDesc1() = &finalResourceDesc1; - resAllocInfo = GetResourceAllocationInfo(finalResourceDesc1); } #endif #ifdef __ID3D12Device10_INTERFACE_DEFINED__ else if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_LAYOUT) { - if (!m_Device10) + if (m_Device10 != NULL) { - return E_NOINTERFACE; + finalResourceDesc1 = *createParams.GetResourceDesc1(); + finalCreateParams.AccessResourceDesc1() = &finalResourceDesc1; + hr = GetResourceAllocationInfo(finalResourceDesc1, + createParams.GetNumCastableFormats(), createParams.GetCastableFormats(), resAllocInfo); } - finalResourceDesc1 = *createParams.GetResourceDesc1(); - finalCreateParams.AccessResourceDesc1() = &finalResourceDesc1; - resAllocInfo = GetResourceAllocationInfo(finalResourceDesc1); } #endif else { D3D12MA_ASSERT(0); - return E_INVALIDARG; + hr = E_INVALIDARG; } + + if (FAILED(hr)) + return hr; + D3D12MA_ASSERT(IsPow2(resAllocInfo.Alignment)); + // We've seen UINT64_MAX returned when the call to GetResourceAllocationInfo was invalid. + D3D12MA_ASSERT(resAllocInfo.SizeInBytes != UINT64_MAX); D3D12MA_ASSERT(resAllocInfo.SizeInBytes > 0); BlockVector* blockVector = NULL; CommittedAllocationParameters committedAllocationParams = {}; bool preferCommitted = false; - HRESULT hr; #ifdef __ID3D12Device8_INTERFACE_DEFINED__ if (createParams.Variant >= CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE_AND_DESC1) { @@ -6454,7 +6560,7 @@ HRESULT AllocatorPimpl::CreateResource( if (blockVector != NULL) { hr = blockVector->CreateResource(resAllocInfo.SizeInBytes, resAllocInfo.Alignment, - *pAllocDesc, finalCreateParams, + *pAllocDesc, finalCreateParams, committedAllocationParams.IsValid(), ppAllocation, riidResource, ppvResource); if (SUCCEEDED(hr)) return hr; @@ -6497,7 +6603,7 @@ HRESULT AllocatorPimpl::AllocateMemory( if (blockVector != NULL) { hr = blockVector->Allocate(pAllocInfo->SizeInBytes, pAllocInfo->Alignment, - *pAllocDesc, 1, (Allocation**)ppAllocation); + *pAllocDesc, committedAllocationParams.IsValid(), 1, (Allocation**)ppAllocation); if (SUCCEEDED(hr)) return hr; } @@ -6519,6 +6625,7 @@ HRESULT AllocatorPimpl::CreateAliasingResource( { *ppvResource = NULL; + HRESULT hr = E_NOINTERFACE; CREATE_RESOURCE_PARAMS finalCreateParams = createParams; D3D12_RESOURCE_DESC finalResourceDesc; #ifdef __ID3D12Device8_INTERFACE_DEFINED__ @@ -6529,37 +6636,40 @@ HRESULT AllocatorPimpl::CreateAliasingResource( { finalResourceDesc = *createParams.GetResourceDesc(); finalCreateParams.AccessResourceDesc() = &finalResourceDesc; - resAllocInfo = GetResourceAllocationInfo(finalResourceDesc); + hr = GetResourceAllocationInfo(finalResourceDesc, 0, NULL, resAllocInfo); } #ifdef __ID3D12Device8_INTERFACE_DEFINED__ else if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE_AND_DESC1) { - if (!m_Device8) + if (m_Device8 != NULL) { - return E_NOINTERFACE; + finalResourceDesc1 = *createParams.GetResourceDesc1(); + finalCreateParams.AccessResourceDesc1() = &finalResourceDesc1; + hr = GetResourceAllocationInfo(finalResourceDesc1, 0, NULL, resAllocInfo); } - finalResourceDesc1 = *createParams.GetResourceDesc1(); - finalCreateParams.AccessResourceDesc1() = &finalResourceDesc1; - resAllocInfo = GetResourceAllocationInfo(finalResourceDesc1); } #endif #ifdef __ID3D12Device10_INTERFACE_DEFINED__ else if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_LAYOUT) { - if (!m_Device10) + if (m_Device10 != NULL) { - return E_NOINTERFACE; + finalResourceDesc1 = *createParams.GetResourceDesc1(); + finalCreateParams.AccessResourceDesc1() = &finalResourceDesc1; + hr = GetResourceAllocationInfo(finalResourceDesc1, + createParams.GetNumCastableFormats(), createParams.GetCastableFormats(), resAllocInfo); } - finalResourceDesc1 = *createParams.GetResourceDesc1(); - finalCreateParams.AccessResourceDesc1() = &finalResourceDesc1; - resAllocInfo = GetResourceAllocationInfo(finalResourceDesc1); } #endif else { D3D12MA_ASSERT(0); - return E_INVALIDARG; + hr = E_INVALIDARG; } + + if (FAILED(hr)) + return hr; + D3D12MA_ASSERT(IsPow2(resAllocInfo.Alignment)); D3D12MA_ASSERT(resAllocInfo.SizeInBytes > 0); @@ -6782,42 +6892,41 @@ void AllocatorPimpl::GetBudget(Budget* outLocalBudget, Budget* outNonLocalBudget outLocalBudget ? &outLocalBudget->BudgetBytes : NULL, outNonLocalBudget ? &outNonLocalBudget->UsageBytes : NULL, outNonLocalBudget ? &outNonLocalBudget->BudgetBytes : NULL); + return; } - else + + if (SUCCEEDED(UpdateD3D12Budget())) { - UpdateD3D12Budget(); - GetBudget(outLocalBudget, outNonLocalBudget); // Recursion + GetBudget(outLocalBudget, outNonLocalBudget); // Recursion. + return; } } - else #endif + + // Fallback path - manual calculation, not real budget. + if (outLocalBudget) { - if (outLocalBudget) - { - outLocalBudget->UsageBytes = outLocalBudget->Stats.BlockBytes; - outLocalBudget->BudgetBytes = GetMemoryCapacity(DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY) * 8 / 10; // 80% heuristics. - } - if (outNonLocalBudget) - { - outNonLocalBudget->UsageBytes = outNonLocalBudget->Stats.BlockBytes; - outNonLocalBudget->BudgetBytes = GetMemoryCapacity(DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY) * 8 / 10; // 80% heuristics. - } + outLocalBudget->UsageBytes = outLocalBudget->Stats.BlockBytes; + outLocalBudget->BudgetBytes = GetMemoryCapacity(DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY) * 8 / 10; // 80% heuristics. + } + if (outNonLocalBudget) + { + outNonLocalBudget->UsageBytes = outNonLocalBudget->Stats.BlockBytes; + outNonLocalBudget->BudgetBytes = GetMemoryCapacity(DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY) * 8 / 10; // 80% heuristics. } } void AllocatorPimpl::GetBudgetForHeapType(Budget& outBudget, D3D12_HEAP_TYPE heapType) { - switch (heapType) + const bool isLocal = StandardHeapTypeToMemorySegmentGroup(heapType) == + DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY; + if (isLocal) { - case D3D12_HEAP_TYPE_DEFAULT: - case D3D12_HEAP_TYPE_GPU_UPLOAD_COPY: GetBudget(&outBudget, NULL); - break; - case D3D12_HEAP_TYPE_UPLOAD: - case D3D12_HEAP_TYPE_READBACK: + } + else + { GetBudget(NULL, &outBudget); - break; - default: D3D12MA_ASSERT(0); } } @@ -6870,6 +6979,9 @@ void AllocatorPimpl::BuildStatsString(WCHAR** ppStatsString, BOOL detailedMap) json.WriteString(L"GPUUploadHeapSupported"); json.WriteBool(m_GPUUploadHeapSupported != FALSE); + + json.WriteString(L"TightAlignmentSupported"); + json.WriteBool(m_TightAlignmentSupported != FALSE); } json.EndObject(); } @@ -7257,12 +7369,15 @@ HRESULT AllocatorPimpl::AllocateCommittedResource( { return E_NOINTERFACE; } + + // Microsoft defined pCastableFormats parameter as pointer to non-const and only fixed it in later Agility SDK, + // thus we need const_cast. hr = m_Device10->CreateCommittedResource3( &committedAllocParams.m_HeapProperties, committedAllocParams.m_HeapFlags & ~RESOURCE_CLASS_HEAP_FLAGS, createParams.GetResourceDesc1(), createParams.GetInitialLayout(), createParams.GetOptimizedClearValue(), committedAllocParams.m_ProtectedSession, - createParams.GetNumCastableFormats(), createParams.GetCastableFormats(), + createParams.GetNumCastableFormats(), const_cast(createParams.GetCastableFormats()), D3D12MA_IID_PPV_ARGS(&res)); } else #endif @@ -7602,7 +7717,7 @@ D3D12_RESOURCE_ALLOCATION_INFO AllocatorPimpl::GetResourceAllocationInfoNative(c } #ifdef __ID3D12Device8_INTERFACE_DEFINED__ -D3D12_RESOURCE_ALLOCATION_INFO AllocatorPimpl::GetResourceAllocationInfoNative(const D3D12_RESOURCE_DESC1& resourceDesc) const +D3D12_RESOURCE_ALLOCATION_INFO AllocatorPimpl::GetResourceAllocationInfo2Native(const D3D12_RESOURCE_DESC1& resourceDesc) const { D3D12MA_ASSERT(m_Device8 != NULL); D3D12_RESOURCE_ALLOCATION_INFO1 info1Unused; @@ -7618,12 +7733,91 @@ D3D12_RESOURCE_ALLOCATION_INFO AllocatorPimpl::GetResourceAllocationInfoNative(c } #endif // #ifdef __ID3D12Device8_INTERFACE_DEFINED__ +#ifdef __ID3D12Device12_INTERFACE_DEFINED__ +D3D12_RESOURCE_ALLOCATION_INFO AllocatorPimpl::GetResourceAllocationInfo3Native(const D3D12_RESOURCE_DESC1& resourceDesc, + UINT32 NumCastableFormats, const DXGI_FORMAT* pCastableFormats) const +{ + D3D12MA_ASSERT(m_Device12 != NULL); + D3D12_RESOURCE_ALLOCATION_INFO1 info1Unused; + + // This is how new D3D12 headers define GetResourceAllocationInfo function - + // different signature depending on these macros. +#if defined(_MSC_VER) || !defined(_WIN32) + return m_Device12->GetResourceAllocationInfo3(0, 1, &resourceDesc, + &NumCastableFormats, &pCastableFormats, &info1Unused); +#else + D3D12_RESOURCE_ALLOCATION_INFO retVal; + return *m_Device12->GetResourceAllocationInfo3(&retVal, 0, 1, &resourceDesc, + &NumCastableFormats, &pCastableFormats, &info1Unused); +#endif +} +#endif // #ifdef __ID3D12Device12_INTERFACE_DEFINED__ + +HRESULT AllocatorPimpl::GetResourceAllocationInfoMiddle( + D3D12_RESOURCE_DESC& inOutResourceDesc, + UINT32 NumCastableFormats, const DXGI_FORMAT* pCastableFormats, + D3D12_RESOURCE_ALLOCATION_INFO& outAllocInfo) const +{ + if (NumCastableFormats > 0) + { + return E_NOTIMPL; + } + + outAllocInfo = GetResourceAllocationInfoNative(inOutResourceDesc); + return outAllocInfo.SizeInBytes != UINT64_MAX ? S_OK : E_INVALIDARG; +} + +#ifdef __ID3D12Device8_INTERFACE_DEFINED__ + +HRESULT AllocatorPimpl::GetResourceAllocationInfoMiddle( + D3D12_RESOURCE_DESC1& inOutResourceDesc, + UINT32 NumCastableFormats, const DXGI_FORMAT* pCastableFormats, + D3D12_RESOURCE_ALLOCATION_INFO& outAllocInfo) const +{ + if (NumCastableFormats > 0) + { +#ifdef __ID3D12Device12_INTERFACE_DEFINED__ + if (m_Device12 != NULL) + { + outAllocInfo = GetResourceAllocationInfo3Native(inOutResourceDesc, NumCastableFormats, pCastableFormats); + return outAllocInfo.SizeInBytes != UINT64_MAX ? S_OK : E_INVALIDARG; + } +#else + return E_NOTIMPL; +#endif + } + + outAllocInfo = GetResourceAllocationInfo2Native(inOutResourceDesc); + return outAllocInfo.SizeInBytes != UINT64_MAX ? S_OK : E_INVALIDARG; +} + +#endif // #ifdef __ID3D12Device8_INTERFACE_DEFINED__ + template -D3D12_RESOURCE_ALLOCATION_INFO AllocatorPimpl::GetResourceAllocationInfo(D3D12_RESOURCE_DESC_T& inOutResourceDesc) const +HRESULT AllocatorPimpl::GetResourceAllocationInfo( + D3D12_RESOURCE_DESC_T& inOutResourceDesc, + UINT32 NumCastableFormats, const DXGI_FORMAT* pCastableFormats, + D3D12_RESOURCE_ALLOCATION_INFO& outAllocInfo) const { #ifdef __ID3D12Device1_INTERFACE_DEFINED__ - /* Optional optimization: Microsoft documentation says: - https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-getresourceallocationinfo + +#if D3D12MA_TIGHT_ALIGNMENT_SUPPORTED + if (IsTightAlignmentEnabled()) + { + // Don't allow USE_TIGHT_ALIGNMENT together with ALLOW_CROSS_ADAPTER as there is a D3D Debug Layer error: + // D3D12 ERROR: ID3D12Device::GetResourceAllocationInfo: D3D12_RESOURCE_DESC::Flag D3D12_RESOURCE_FLAG_USE_TIGHT_ALIGNMENT will be ignored since D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER is set. [ STATE_CREATION ERROR #599: CREATERESOURCE_INVALIDMISCFLAGS] + // Also don't allow it together with D3D12_TEXTURE_LAYOUT_64KB_*_SWIZZLE, as there is this error (see issue #86): + // D3D12 ERROR: ID3D12Device::GetResourceAllocationInfo: D3D12_RESOURCE_DESC::Flag D3D12_RESOURCE_FLAG_USE_TIGHT_ALIGNMENT is not valid when the layout is either D3D12_TEXTURE_LAYOUT_64KB_STANDARD_SWIZZLE or D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE (...). [ STATE_CREATION ERROR #599: CREATERESOURCE_INVALIDMISCFLAGS] + if((inOutResourceDesc.Flags & D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER) == 0 + && (inOutResourceDesc.Layout != D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE && inOutResourceDesc.Layout != D3D12_TEXTURE_LAYOUT_64KB_STANDARD_SWIZZLE)) + { + inOutResourceDesc.Flags |= D3D12_RESOURCE_FLAG_USE_TIGHT_ALIGNMENT; + } + } +#endif // #if D3D12MA_TIGHT_ALIGNMENT_SUPPORTED + + /* Optional optimization: Microsoft documentation of the ID3D12Device:: + GetResourceAllocationInfo function says: Your application can forgo using GetResourceAllocationInfo for buffer resources (D3D12_RESOURCE_DIMENSION_BUFFER). Buffers have the same size on all adapters, @@ -7631,17 +7825,25 @@ D3D12_RESOURCE_ALLOCATION_INFO AllocatorPimpl::GetResourceAllocationInfo(D3D12_R D3D12_RESOURCE_DESC::Width. */ if (inOutResourceDesc.Alignment == 0 && - inOutResourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER) + inOutResourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER && + !IsTightAlignmentEnabled()) { - return { + outAllocInfo = { AlignUp(inOutResourceDesc.Width, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT), // SizeInBytes D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT }; // Alignment + return S_OK; } + #endif // #ifdef __ID3D12Device1_INTERFACE_DEFINED__ + HRESULT hr = S_OK; + #if D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT if (inOutResourceDesc.Alignment == 0 && - inOutResourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D && + (inOutResourceDesc.Flags & D3D12_RESOURCE_FLAG_USE_TIGHT_ALIGNMENT_COPY) == 0 && + (inOutResourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE1D || + inOutResourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D || + inOutResourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D) && (inOutResourceDesc.Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) == 0 #if D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT == 1 && CanUseSmallAlignment(inOutResourceDesc) @@ -7656,17 +7858,19 @@ D3D12_RESOURCE_ALLOCATION_INFO AllocatorPimpl::GetResourceAllocationInfo(D3D12_R D3D12_SMALL_MSAA_RESOURCE_PLACEMENT_ALIGNMENT : D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT; inOutResourceDesc.Alignment = smallAlignmentToTry; - const D3D12_RESOURCE_ALLOCATION_INFO smallAllocInfo = GetResourceAllocationInfoNative(inOutResourceDesc); + hr = GetResourceAllocationInfoMiddle( + inOutResourceDesc, NumCastableFormats, pCastableFormats, outAllocInfo); // Check if alignment requested has been granted. - if (smallAllocInfo.Alignment == smallAlignmentToTry) + if (SUCCEEDED(hr) && outAllocInfo.Alignment == smallAlignmentToTry) { - return smallAllocInfo; + return S_OK; } inOutResourceDesc.Alignment = 0; // Restore original } #endif // #if D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT - return GetResourceAllocationInfoNative(inOutResourceDesc); + return GetResourceAllocationInfoMiddle( + inOutResourceDesc, NumCastableFormats, pCastableFormats, outAllocInfo); } bool AllocatorPimpl::NewAllocationWithinBudget(D3D12_HEAP_TYPE heapType, UINT64 size) @@ -7947,7 +8151,7 @@ BlockVector::BlockVector( m_MinBlockCount(minBlockCount), m_MaxBlockCount(maxBlockCount), m_ExplicitBlockSize(explicitBlockSize), - m_MinAllocationAlignment(minAllocationAlignment), + m_MinAllocationAlignment(D3D12MA_MAX(minAllocationAlignment, (UINT64)D3D12MA_DEBUG_ALIGNMENT)), m_Algorithm(algorithm), m_DenyMsaaTextures(denyMsaaTextures), m_ProtectedSession(pProtectedSession), @@ -7987,6 +8191,7 @@ HRESULT BlockVector::Allocate( UINT64 size, UINT64 alignment, const ALLOCATION_DESC& allocDesc, + bool committedAllowed, size_t allocationCount, Allocation** pAllocations) { @@ -8001,6 +8206,7 @@ HRESULT BlockVector::Allocate( size, alignment, allocDesc, + committedAllowed, pAllocations + allocIndex); if (FAILED(hr)) { @@ -8089,40 +8295,43 @@ HRESULT BlockVector::CreateResource( UINT64 alignment, const ALLOCATION_DESC& allocDesc, const CREATE_RESOURCE_PARAMS& createParams, + bool committedAllowed, Allocation** ppAllocation, REFIID riidResource, void** ppvResource) { - HRESULT hr = Allocate(size, alignment, allocDesc, 1, ppAllocation); + HRESULT hr = Allocate(size, alignment, allocDesc, committedAllowed, 1, ppAllocation); + if (FAILED(hr)) + { + return hr; + } + + ID3D12Resource* res = NULL; + hr = m_hAllocator->CreatePlacedResourceWrap( + (*ppAllocation)->m_Placed.block->GetHeap(), + (*ppAllocation)->GetOffset(), + createParams, + D3D12MA_IID_PPV_ARGS(&res)); if (SUCCEEDED(hr)) { - ID3D12Resource* res = NULL; - hr = m_hAllocator->CreatePlacedResourceWrap( - (*ppAllocation)->m_Placed.block->GetHeap(), - (*ppAllocation)->GetOffset(), - createParams, - D3D12MA_IID_PPV_ARGS(&res)); + if (ppvResource != NULL) + { + hr = res->QueryInterface(riidResource, ppvResource); + } if (SUCCEEDED(hr)) { - if (ppvResource != NULL) - { - hr = res->QueryInterface(riidResource, ppvResource); - } - if (SUCCEEDED(hr)) - { - (*ppAllocation)->SetResourcePointer(res, createParams.GetBaseResourceDesc()); - } - else - { - res->Release(); - SAFE_RELEASE(*ppAllocation); - } + (*ppAllocation)->SetResourcePointer(res, createParams.GetBaseResourceDesc()); } else { + res->Release(); SAFE_RELEASE(*ppAllocation); } } + else + { + SAFE_RELEASE(*ppAllocation); + } return hr; } @@ -8240,6 +8449,7 @@ HRESULT BlockVector::AllocatePage( UINT64 size, UINT64 alignment, const ALLOCATION_DESC& allocDesc, + bool committedAllowed, Allocation** pAllocation) { // Early reject: requested allocation size is larger that maximum block size for this block vector. @@ -8256,13 +8466,19 @@ HRESULT BlockVector::AllocatePage( freeMemory = (budget.UsageBytes < budget.BudgetBytes) ? (budget.BudgetBytes - budget.UsageBytes) : 0; } - const bool canCreateNewBlock = + const bool canExceedFreeMemory = !committedAllowed; + + bool canCreateNewBlock = ((allocDesc.Flags & ALLOCATION_FLAG_NEVER_ALLOCATE) == 0) && - (m_Blocks.size() < m_MaxBlockCount) && - // Even if we don't have to stay within budget with this allocation, when the - // budget would be exceeded, we don't want to allocate new blocks, but always - // create resources as committed. - freeMemory >= size; + (m_Blocks.size() < m_MaxBlockCount); + + // Even if we don't have to stay within budget with this allocation, when the + // budget would be exceeded, we don't want to allocate new blocks, but always + // create resources as committed. + if (freeMemory < size && !canExceedFreeMemory) + { + canCreateNewBlock = false; + } // 1. Search existing allocations { @@ -8312,26 +8528,29 @@ HRESULT BlockVector::AllocatePage( } } - size_t newBlockIndex = 0; - HRESULT hr = newBlockSize <= freeMemory ? - CreateBlock(newBlockSize, &newBlockIndex) : E_OUTOFMEMORY; + size_t newBlockIndex = SIZE_MAX; + HRESULT hr = E_OUTOFMEMORY; + if (newBlockSize <= freeMemory || canExceedFreeMemory) + { + hr = CreateBlock(newBlockSize, &newBlockIndex); + } // Allocation of this size failed? Try 1/2, 1/4, 1/8 of m_PreferredBlockSize. if (!m_ExplicitBlockSize) { while (FAILED(hr) && newBlockSizeShift < NEW_BLOCK_SIZE_SHIFT_MAX) { const UINT64 smallerNewBlockSize = newBlockSize / 2; - if (smallerNewBlockSize >= size) - { - newBlockSize = smallerNewBlockSize; - ++newBlockSizeShift; - hr = newBlockSize <= freeMemory ? - CreateBlock(newBlockSize, &newBlockIndex) : E_OUTOFMEMORY; - } - else + if (smallerNewBlockSize < size) { break; } + + newBlockSize = smallerNewBlockSize; + ++newBlockSizeShift; + if (newBlockSize <= freeMemory || canExceedFreeMemory) + { + hr = CreateBlock(newBlockSize, &newBlockIndex); + } } } @@ -9085,12 +9304,14 @@ PoolPimpl::PoolPimpl(AllocatorPimpl* allocator, const POOL_DESC& desc) D3D12MA_ASSERT(m_Desc.pProtectedSession == NULL); #endif + const UINT64 minAlignment = desc.MinAllocationAlignment > 0 ? desc.MinAllocationAlignment : D3D12MA_DEFAULT_ALIGNMENT; + m_BlockVector = D3D12MA_NEW(allocator->GetAllocs(), BlockVector)( allocator, desc.HeapProperties, desc.HeapFlags, preferredBlockSize, desc.MinBlockCount, maxBlockCount, explicitBlockSize, - D3D12MA_MAX(desc.MinAllocationAlignment, (UINT64)D3D12MA_DEBUG_ALIGNMENT), + minAlignment, (desc.Flags & POOL_FLAG_ALGORITHM_MASK) != 0, (desc.Flags & POOL_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED) != 0, desc.pProtectedSession, @@ -9553,6 +9774,11 @@ BOOL Allocator::IsGPUUploadHeapSupported() const return m_Pimpl->IsGPUUploadHeapSupported(); } +BOOL Allocator::IsTightAlignmentSupported() const +{ + return m_Pimpl->IsTightAlignmentSupported(); +} + UINT64 Allocator::GetMemoryCapacity(UINT memorySegmentGroup) const { return m_Pimpl->GetMemoryCapacity(memorySegmentGroup); @@ -9613,7 +9839,7 @@ HRESULT Allocator::CreateResource3( D3D12_BARRIER_LAYOUT InitialLayout, const D3D12_CLEAR_VALUE* pOptimizedClearValue, UINT32 NumCastableFormats, - DXGI_FORMAT* pCastableFormats, + const DXGI_FORMAT* pCastableFormats, Allocation** ppAllocation, REFIID riidResource, void** ppvResource) @@ -9644,7 +9870,7 @@ HRESULT Allocator::AllocateMemory( return E_INVALIDARG; } D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK - return m_Pimpl->AllocateMemory(pAllocDesc, pAllocInfo, ppAllocation); + return m_Pimpl->AllocateMemory(pAllocDesc, pAllocInfo, ppAllocation); } HRESULT Allocator::CreateAliasingResource( @@ -9703,7 +9929,7 @@ HRESULT Allocator::CreateAliasingResource2( D3D12_BARRIER_LAYOUT InitialLayout, const D3D12_CLEAR_VALUE* pOptimizedClearValue, UINT32 NumCastableFormats, - DXGI_FORMAT* pCastableFormats, + const DXGI_FORMAT* pCastableFormats, REFIID riidResource, void** ppvResource) { diff --git a/thirdparty/d3d12ma/D3D12MemAlloc.h b/thirdparty/d3d12ma/D3D12MemAlloc.h index 9cd1c33ef6..32fe908c24 100644 --- a/thirdparty/d3d12ma/D3D12MemAlloc.h +++ b/thirdparty/d3d12ma/D3D12MemAlloc.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2019-2025 Advanced Micro Devices, Inc. All rights reserved. +// Copyright (c) 2019-2026 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -24,15 +24,16 @@ /** \mainpage D3D12 Memory Allocator -Version 2.1.0-development (2024-07-05) +Version 3.1.0 (2026-02-23) -Copyright (c) 2019-2025 Advanced Micro Devices, Inc. All rights reserved. \n +Copyright (c) 2019-2026 Advanced Micro Devices, Inc. All rights reserved. \n License: MIT Documentation of all members: D3D12MemAlloc.h \section main_table_of_contents Table of contents +- \subpage faq - \subpage quick_start - [Project setup](@ref quick_start_project_setup) - [Creating resources](@ref quick_start_creating_resources) @@ -63,7 +64,7 @@ Documentation of all members: D3D12MemAlloc.h \section main_see_also Web links -- [Direct3D 12 Memory Allocator at GPUOpen.com](https://gpuopen.com/gaming-product/d3d12-memory-allocator/) - product page +- [Direct3D 12 Memory Allocator at GPUOpen.com](https://gpuopen.com/d3d12-memory-allocator/) - product page - [GPUOpen-LibrariesAndSDKs/D3D12MemoryAllocator at GitHub.com](https://github.com/GPUOpen-LibrariesAndSDKs/D3D12MemoryAllocator) - source code repository */ @@ -124,7 +125,7 @@ Documentation of all members: D3D12MemAlloc.h #ifndef D3D12MA_RECOMMENDED_ALLOCATOR_FLAGS /// Set of flags recommended for use in D3D12MA::ALLOCATOR_DESC::Flags for optimal performance. - #define D3D12MA_RECOMMENDED_ALLOCATOR_FLAGS (ALLOCATOR_FLAG_DEFAULT_POOLS_NOT_ZEROED | ALLOCATOR_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED) + #define D3D12MA_RECOMMENDED_ALLOCATOR_FLAGS (D3D12MA::ALLOCATOR_FLAG_DEFAULT_POOLS_NOT_ZEROED | D3D12MA::ALLOCATOR_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED) #endif #ifndef D3D12MA_RECOMMENDED_HEAP_FLAGS @@ -138,7 +139,7 @@ Documentation of all members: D3D12MemAlloc.h #ifndef D3D12MA_RECOMMENDED_POOL_FLAGS /// Set of flags recommended for use in D3D12MA::POOL_DESC::Flags for optimal performance. - #define D3D12MA_RECOMMENDED_POOL_FLAGS (POOL_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED) + #define D3D12MA_RECOMMENDED_POOL_FLAGS (D3D12MA::POOL_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED) #endif @@ -1111,8 +1112,19 @@ enum ALLOCATOR_FLAGS which may take longer than creating placed resources in existing heaps. Passing this flag will disable this committed preference globally for the allocator. It can also be disabled for a single allocation by using #ALLOCATION_FLAG_STRATEGY_MIN_TIME. + + If the tight resource alignment feature is used by the library (which happens automatically whenever supported, + unless you use flag #ALLOCATOR_FLAG_DONT_USE_TIGHT_ALIGNMENT), then small buffers are not preferred as committed. + Long story short, you don't need to specify any of these flags. + The library chooses the most optimal method automatically. */ ALLOCATOR_FLAG_DONT_PREFER_SMALL_BUFFERS_COMMITTED = 0x10, + /** Disables the use of the tight alignment feature even when it is supported on the current system. + By default, the feature is used whenever available. + + Support can be checked by D3D12MA::Allocator::IsTightAlignmentSupported() regardless of using this flag. + */ + ALLOCATOR_FLAG_DONT_USE_TIGHT_ALIGNMENT = 0x20, }; /// \brief Parameters of created Allocator object. To be used with CreateAllocator(). @@ -1188,6 +1200,12 @@ public: This flag is fetched from `D3D12_FEATURE_D3D12_OPTIONS16::GPUUploadHeapSupported`. */ BOOL IsGPUUploadHeapSupported() const; + /** \brief Returns true if resource tight alignment is supported on the current system. + When supported, it is automatically used by the library, unless + #ALLOCATOR_FLAG_DONT_USE_TIGHT_ALIGNMENT flag was specified on allocator creation. + This flag is fetched from `D3D12_FEATURE_DATA_TIGHT_ALIGNMENT::SupportTier`. + */ + BOOL IsTightAlignmentSupported() const; /** \brief Returns total amount of memory of specific segment group, in bytes. \param memorySegmentGroup use `DXGI_MEMORY_SEGMENT_GROUP_LOCAL` or `DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL`. @@ -1267,13 +1285,14 @@ public: It internally uses `ID3D12Device10::CreateCommittedResource3` or `ID3D12Device10::CreatePlacedResource2`. To work correctly, `ID3D12Device10` interface must be available in the current system. Otherwise, `E_NOINTERFACE` is returned. + If you use `pCastableFormats`, `ID3D12Device12` must albo be available. */ HRESULT CreateResource3(const ALLOCATION_DESC* pAllocDesc, const D3D12_RESOURCE_DESC1* pResourceDesc, D3D12_BARRIER_LAYOUT InitialLayout, const D3D12_CLEAR_VALUE* pOptimizedClearValue, UINT32 NumCastableFormats, - DXGI_FORMAT* pCastableFormats, + const DXGI_FORMAT* pCastableFormats, Allocation** ppAllocation, REFIID riidResource, void** ppvResource); @@ -1352,11 +1371,12 @@ public: #ifdef __ID3D12Device10_INTERFACE_DEFINED__ /** \brief Similar to Allocator::CreateAliasingResource1, but there are initial layout instead of state and - castable formats list + castable formats list. It internally uses `ID3D12Device10::CreatePlacedResource2`. To work correctly, `ID3D12Device10` interface must be available in the current system. Otherwise, `E_NOINTERFACE` is returned. + If you use `pCastableFormats`, `ID3D12Device12` must albo be available. */ HRESULT CreateAliasingResource2(Allocation* pAllocation, UINT64 AllocationLocalOffset, @@ -1364,7 +1384,7 @@ public: D3D12_BARRIER_LAYOUT InitialLayout, const D3D12_CLEAR_VALUE* pOptimizedClearValue, UINT32 NumCastableFormats, - DXGI_FORMAT* pCastableFormats, + const DXGI_FORMAT* pCastableFormats, REFIID riidResource, void** ppvResource); #endif // #ifdef __ID3D12Device10_INTERFACE_DEFINED__ @@ -1797,6 +1817,221 @@ DEFINE_ENUM_FLAG_OPERATORS(D3D12MA::VIRTUAL_ALLOCATION_FLAGS); /// \endcond /** +\page faq Frequently asked questions + +What is %D3D12MA? + +D3D12 Memory Allocator (%D3D12MA) is a software library for developers who use the DirectX(R) 12 graphics API in their code. +It is written in C++. + +What is the license of %D3D12MA? + +%D3D12MA is licensed under MIT, which means it is open source and free software. + +What is the purpose of %D3D12MA? + +%D3D12MA helps with handling one aspect of DX12 usage, which is GPU memory management - +allocation of `ID3D12Heap` objects and creation of `ID3D12Resource` objects - buffers and textures. + +Do I need to use %D3D12MA? + +You don't need to, but it may be beneficial in many cases. +DX12 is a complex and low-level API, so libraries like this that abstract certain aspects of the API +and bring them to a higher level are useful. +When developing any non-trivial graphics application, you may benefit from using a memory allocator. +Using %D3D12MA can save time compared to implementing your own. + +In DX12 you can create each resource separately with its own implicit memory heap by calling `CreateCommittedResource`, +but this may not be the optimal solution. +For more information, see [Committed versus placed resources](@ref optimal_allocation_committed_vs_placed). + +When should I not use %D3D12MA? + +While %D3D12MA is useful for many applications that use the DX12 API, there are cases +when it may be a better choice not to use it. +For example, if the application is very simple, e.g. serving as a sample or a learning exercise +to help you understand or teach others the basics of DX12, +and it creates only a small number of buffers and textures, then including %D3D12MA may be an overkill. +Developing your own memory allocator may also be a good learning exercise. + +What are the benefits of using %D3D12MA? + +-# %D3D12MA allocates large blocks of `ID3D12Heap` memory and sub-allocates parts of them to create your placed resources. + Allocating a new block of GPU memory may be a time-consuming operation. + Sub-allocating parts of a memory block requires implementing an allocation algorithm, + which is a non-trivial task. + %D3D12MA does that, using an advanced and efficient algorithm that works well in various use cases. +-# %D3D12MA offers a simple API that allows creating placed buffers and textures within one function call + like D3D12MA::Allocator::CreateResource. + +The library is doing much more under the hood. +For example, it keeps buffers separate from textures when needed, respecting `D3D12_RESOURCE_HEAP_TIER`. +It also makes use of the "small texture alignment" automatically, so you don't need to think about it. + +Which version should I pick? + +You can just pick [the latest version from the "master" branch](https://github.com/GPUOpen-LibrariesAndSDKs/D3D12MemoryAllocator). +It is kept in a good shape most of the time, compiling and working correctly, +with no compatibility-breaking changes and no unfinished code. + +If you want an even more stable version, you can pick +[the latest official release](https://github.com/GPUOpen-LibrariesAndSDKs/D3D12MemoryAllocator/releases). +Current code from the master branch is occasionally tagged as a release, +with [CHANGELOG](https://github.com/GPUOpen-LibrariesAndSDKs/D3D12MemoryAllocator/blob/master/CHANGELOG.md) +carefully curated to enumerate all important changes since the previous version. + +The library uses [Semantic Versioning](https://semver.org/), +which means versions that only differ in the patch number are forward and backward compatible +(e.g., only fixing some bugs), while versions that differ in the minor number are backward compatible +(e.g., only adding new functions to the API, but not removing or changing existing ones). + +How to integrate it with my code? + +%D3D12MA is an small library fully implemented in a single pair of CPP + H files. + +You can pull the entire GitHub repository, e.g. using Git submodules. +The repository contains ancillary files like the Cmake script, Doxygen config file, +sample application, test suite, and others. +You can compile it as a library and link with your project. + +However, a simpler way is taking only files "include\D3D12MemAlloc.h", "src\D3D12MemAlloc.cpp" +and including them in your project. +These files contain all you need: a copyright notice, +declarations of the public library interface (API), its internal implementation, +and even the documentation in form of Doxygen-style comments. + +I am not a fan of modern C++. Can I still use it? + +Very likely yes. +We acknowledge that many C++ developers, especially in the games industry, +do not appreciate all the latest features that the language has to offer. + +- %D3D12MA doesn't throw or catch any C++ exceptions. + It reports errors by returning a `HRESULT` value instead, just like DX12. + If you don't use exceptions in your project, your code is not exception-safe, + or even if you disable exception handling in the compiler options, you can still use %D3D12MA. +- %D3D12MA doesn't use C++ run-time type information like `typeid` or `dynamic_cast`, + so if you disable RTTI in the compiler options, you can still use the library. +- %D3D12MA uses only a limited subset of standard C and C++ library. + It doesn't use STL containers like `std::vector`, `map`, or `string`, + either in the public interface nor in the internal implementation. + It implements its own containers instead. +- If you don't use the default heap memory allocator through `malloc/free` or `new/delete` + but implement your own allocator instead, you can pass it to %D3D12MA as + D3D12MA::ALLOCATOR_DESC::pAllocationCallbacks + and the library will use your functions for every dynamic heap allocation made internally. + +Is it available for other programming languages? + +%D3D12MA is a C++ library in similar style as DX12. +Bindings to other programming languages are out of scope of this project, +but they are welcome as external projects. +Some of them are listed in [README.md, "See also" section](https://github.com/GPUOpen-LibrariesAndSDKs/D3D12MemoryAllocator/?tab=readme-ov-file#see-also), +including binding to C. +Before using any of them, please check if they are still maintained and updated to use a recent version of %D3D12MA. + +What platforms does it support? + +%D3D12MA relies only on DX12 and some parts of the standard C and C++ library, +so it could support any platform where a C++ compiler and DX12 are available. +However, it is developed and tested only on Microsoft(R) Windows(R). + +Does it only work on AMD GPUs? + +No! While %D3D12MA is published by AMD, it works on any GPU that supports DX12, +whether a discrete PC graphics card or a processor integrated graphics. +It doesn't give AMD GPUs any advantage over any other GPUs. + +What DirectX 12 versions are supported? + +%D3D12MA is updated to support latest versions of DirectX 12, as available through recent retail versions of the +[DirectX 12 Agility SDK](https://devblogs.microsoft.com/directx/directx12agility/). +Support for new features added in the preview version of the Agility SDK is developed on separate branches until they are included in the retail version. + +The library also supports older versions down to the base DX12 shipping with Windows SDK. +Features added by later versions of the Agility SDK are automatically enabled conditionally using +`#ifdef` preprocessor macros depending on the version of the SDK that you compile your project with. + +Does it support other graphics APIs, like Vulkan(R)? + +No, but we offer an equivalent library for Vulkan: +[Vulkan Memory Allocator](https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator). +It uses the same core allocation algorithm. +It also shares many features with %D3D12MA, like the support for custom pools and virtual allocator. +However, it is not identical in terms of the features supported. +Its API also looks different, because while the interface of %D3D12MA is similar in style to DX12, +the interface of VMA is similar to Vulkan. + +Is the library lightweight? + +Yes. +%D3D12MA is implemented with high-performance and real-time applications like video games in mind. +The CPU performance overhead of using this library is low. +It uses a high-quality allocation algorithm called Two-Level Segregated Fit (TLSF), +which in most cases can find a free place for a new allocation in few steps. +The library also doesn't perform too many CPU heap allocations. +In many cases, the allocation happens with 0 new CPU heap allocations performed by the library. +Even the creation of a D3D12MA::Allocation object doesn't typically feature an CPU allocation, +because these objects are returned out of a dedicated memory pool. + +That said, %D3D12MA needs some extra memory and extra time +to maintain the metadata about the occupied and free regions of the memory blocks, +and the algorithms and data structures used must be generic enough to work well in most cases. + +Does it have a documentation? + +Yes! %D3D12MA comes with full documentation of all elements of the API (classes, structures, enums), +as well as many generic chapters that provide an introduction, +describe core concepts of the library, good practices, etc. +The entire documentation is written in form of code comments inside "D3D12MemAlloc.h", in Doxygen format. +You can access it in multiple ways: + +- Browsable online: https://gpuopen-librariesandsdks.github.io/D3D12MemoryAllocator/html/ +- Local HTML pages available after you clone the repository and open file "docs\html\index.html". +- You can rebuild the documentation in HTML or some other format from the source code using Doxygen. + Configuration file "Doxyfile" is part of the repository. +- Finally, you can just read the comments preceding declarations of any public classes and functions of the library. + +Is it a mature project? + +Yes! The library is in development since May 2019, has over 300 commits, and multiple contributors. +It is used by many software projects, including some large and popular ones like Qt or Godot Engine, +as well as some AAA games. + +How can I contribute to the project? + +If you have an idea for improvement or a feature request, +you can go to [the library repository](https://github.com/GPUOpen-LibrariesAndSDKs/D3D12MemoryAllocator) +and create an Issue ticket, describing your idea. +You can also implement it yourself by forking the repository, making changes to the code, +and creating a Pull request. + +If you want to ask a question, you can also create a ticket the same way. +Before doing this, please make sure you read the relevant part of the DX12 documentation and %D3D12MA documentation, +where you may find the answers to your question. + +If you want to report a suspected bug, you can also create a ticket the same way. +Before doing this, please put some effort into the investigation of whether the bug is really +in the library and not in your code or in the DX12 implementation (the GPU driver) on your platform: + +- Enable D3D Debug Layer and make sure it is free from any errors. +- Make sure `D3D12MA_ASSERT` is defined to an implementation that can report a failure and not ignore it. +- Try making your allocation using pure DX12 functions like `CreateCommittedResource()` rather than %D3D12MA and see if the bug persists. + +I found some compilation warnings. How can we fix them? + +Seeing compiler warnings may be annoying to some developers, +but it is a design decision to not fix all of them. +Due to the nature of the C++ language, certain preprocessor macros can make some variables unused, +function parameters unreferenced, or conditional expressions constant in some configurations. +The code of this library should not be bigger or more complicated just to silence these warnings. +It is recommended to disable such warnings instead. +For more information, see [Features not supported](@ref general_considerations_features_not_supported). + +However, if you observe a warning that is really dangerous, e.g., +about an implicit conversion from a larger to a smaller integer type, please report it and it will be fixed ASAP. + + \page quick_start Quick start \section quick_start_project_setup Project setup and initialization @@ -2646,6 +2881,23 @@ and D3D12MA::POOL_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED on the creation of any cus With those flags, the alignment of the heaps created by %D3D12MA can be lower, but any MSAA textures are created as committed. You should always use these flags in your code unless you really need to create some MSAA textures as placed. +With DirectX 12 Agility SDK 1.618.1, Microsoft added a new feature called **"tight alignment"**. +Note this is a separate feature than the "small alignment" described earlier. +When using this new SDK and a compatible graphics driver, the API exposes support for this new feature. +Then, a new flag `D3D12_RESOURCE_FLAG_USE_TIGHT_ALIGNMENT` can be added when creating a resource. +D3D12 can then return the alignment required for the resource smaller than the default ones described above. +This library automatically makes use of the tight alignment feature when available and adds that new resource flag. +When the tight alignment is enabled, the heuristics that creates small buffers as committed described above is deactivated, +as it is no longer needed. + +You can check if the tight alignment it is available in the current system by calling D3D12MA::Allocator::IsTightAlignmentSupported(). +You can tell the library to not use it by specifying D3D12MA::ALLOCATOR_FLAG_DONT_USE_TIGHT_ALIGNMENT. +Typically, you don't need to do any of those. + +The library automatically aligns all buffers to at least 256 B, even when the system supports smaller alignment. +This is the alignment required for constant buffers, expressed by `D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT` constant. +You can override this logic for \subpage custom_pools with a specific D3D12MA::POOL_DESC::MinAllocationAlignment. + \page defragmentation Defragmentation Interleaved allocations and deallocations of many objects of varying size can @@ -3340,7 +3592,7 @@ Features deliberately excluded from the scope of this library: - **Descriptor allocation.** Although also called "heaps", objects that represent descriptors are separate part of the D3D12 API from buffers and textures. You can still use \ref virtual_allocator to manage descriptors and their ranges inside a descriptor heap. -- **Support for reserved (tiled) resources.** We don't recommend using them. +- **Support for reserved (tiled) resources.** We don't recommend using them. For more information, see [1]. - Support for `ID3D12Device::Evict` and `MakeResident`. We don't recommend using them. You can call them on the D3D12 objects manually. Plese keep in mind, however, that eviction happens on the level of entire `ID3D12Heap` memory blocks @@ -3357,4 +3609,6 @@ Features deliberately excluded from the scope of this library: It is recommended to disable such warnings instead. - This is a C++ library. **Bindings or ports to any other programming languages** are welcome as external projects but are not going to be included into this repository. + +[1] Antoine Richermoz, Fabrice Neyret. The Sad State of Hardware Virtual Textures. UGA - Universite Grenoble Alpes; INRIA Grenoble - Rhone-Alpes. 2025, pp.13. hal-05138369 */ diff --git a/thirdparty/d3d12ma/LICENSE.txt b/thirdparty/d3d12ma/LICENSE.txt index eb08d9e879..3d5a69a6f5 100644 --- a/thirdparty/d3d12ma/LICENSE.txt +++ b/thirdparty/d3d12ma/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2019-2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2019-2026 Advanced Micro Devices, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/d3d12ma/README.md b/thirdparty/d3d12ma/README.md index 0536781ee9..d13081bf94 100644 --- a/thirdparty/d3d12ma/README.md +++ b/thirdparty/d3d12ma/README.md @@ -1,8 +1,10 @@ Upstream: https://github.com/GPUOpen-LibrariesAndSDKs/D3D12MemoryAllocator -commit d26c54a6f40c66611dd33c77df4198784b53a8e2 -Author: Adam Sawicki -Date: Wed Apr 9 15:07:43 2025 +0200 +commit 0fa62ed3a0a69b73230a8ec1faa752d4061c8dc8 +Author: jlacroixAMD <45055644+jlacroixAMD@users.noreply.github.com> +Date: Tue Feb 24 11:41:07 2026 +0900 - Minor fixes after #71 + Merge pull request #87 from sawickiap/master + + New updates to D3D12 Memory Allocator (v3.1.0) diff --git a/thirdparty/d3d12ma/patches/0001-mingw-support.patch b/thirdparty/d3d12ma/patches/0001-mingw-support.patch new file mode 100644 index 0000000000..6fb330974e --- /dev/null +++ b/thirdparty/d3d12ma/patches/0001-mingw-support.patch @@ -0,0 +1,34 @@ +diff --git a/thirdparty/d3d12ma/D3D12MemAlloc.cpp b/thirdparty/d3d12ma/D3D12MemAlloc.cpp +index 61e9e4a34d..94c646b5fc 100644 +--- a/thirdparty/d3d12ma/D3D12MemAlloc.cpp ++++ b/thirdparty/d3d12ma/D3D12MemAlloc.cpp +@@ -33,24 +33,11 @@ + #include + #endif + +-// On older mingw versions, using the Agility SDK will cause linker errors unless dxguids.h is included. +-// But on newer mingw versions, the includes aren't necessary thus no need to grab DirectX-Headers. +-// Release cycles are slow for LTS distros on Linux, so this codeblock will need to stay for a few years. +-#if defined(__MINGW64_VERSION_MAJOR) && defined(__MINGW64_VERSION_MINOR) && \ +- defined(__MINGW64_VERSION_BUGFIX) && defined(__ID3D12Device8_INTERFACE_DEFINED__) +- #define D3D12MA_MAKE_MINGW_VERSION(x, y, z) ((x << 20u) | (y << 10u) | (z)) +- #if D3D12MA_MAKE_MINGW_VERSION(__MINGW64_VERSION_MAJOR, __MINGW64_VERSION_MINOR, \ +- __MINGW64_VERSION_BUGFIX) <= D3D12MA_MAKE_MINGW_VERSION(11, 0, 1) +- #if defined(__has_include) +- #if !__has_include() +- #error "mingw or gcc detected. dxguids.h is needed. You can grab it from https://github.com/microsoft/DirectX-Headers or if you're on Ubuntu just run sudo apt install directx-headers-dev" +- #endif +- #endif +- #include +- // // guiddef.h must be included first. +- #include +- #endif +- #undef D3D12MA_MAKE_MINGW_VERSION ++// Includes needed for MinGW - see #71. ++#ifndef _MSC_VER ++ #include ++ // guiddef.h must be included first. ++ #include + #endif + + //////////////////////////////////////////////////////////////////////////////// diff --git a/thirdparty/directx_headers/include/dxguids/dxguids.h b/thirdparty/directx_headers/include/dxguids/dxguids.h index 76155708f5..d38a107092 100644 --- a/thirdparty/directx_headers/include/dxguids/dxguids.h +++ b/thirdparty/directx_headers/include/dxguids/dxguids.h @@ -79,6 +79,7 @@ WINADAPTER_IID(ID3D12CommandAllocator, 0x6102dee4, 0xaf59, 0x4b09, 0xb9, 0x99, 0 WINADAPTER_IID(ID3D12Fence, 0x0a753dcf, 0xc4d8, 0x4b91, 0xad, 0xf6, 0xbe, 0x5a, 0x60, 0xd9, 0x5a, 0x76); WINADAPTER_IID(ID3D12Fence1, 0x433685fe, 0xe22b, 0x4ca0, 0xa8, 0xdb, 0xb5, 0xb4, 0xf4, 0xdd, 0x0e, 0x4a); WINADAPTER_IID(ID3D12PipelineState, 0x765a30f3, 0xf624, 0x4c6f, 0xa8, 0x28, 0xac, 0xe9, 0x48, 0x62, 0x24, 0x45); +WINADAPTER_IID(ID3D12PipelineState1, 0x5646804c, 0x9638, 0x48f7, 0x91, 0x82, 0xb3, 0xee, 0x5a, 0x6b, 0x60, 0xfb); WINADAPTER_IID(ID3D12DescriptorHeap, 0x8efb471d, 0x616c, 0x4f49, 0x90, 0xf7, 0x12, 0x7b, 0xb7, 0x63, 0xfa, 0x51); WINADAPTER_IID(ID3D12QueryHeap, 0x0d9658ae, 0xed45, 0x469e, 0xa6, 0x1d, 0x97, 0x0e, 0xc5, 0x83, 0xca, 0xb4); WINADAPTER_IID(ID3D12CommandSignature, 0xc36a797c, 0xec80, 0x4f0a, 0x89, 0x85, 0xa7, 0xb2, 0x47, 0x50, 0x82, 0xd1); @@ -102,6 +103,9 @@ WINADAPTER_IID(ID3D12SwapChainAssistant, 0xf1df64b6, 0x57fd, 0x49cd, 0x88, 0x07, WINADAPTER_IID(ID3D12LifetimeTracker, 0x3fd03d36, 0x4eb1, 0x424a, 0xa5, 0x82, 0x49, 0x4e, 0xcb, 0x8b, 0xa8, 0x13); WINADAPTER_IID(ID3D12StateObject, 0x47016943, 0xfca8, 0x4594, 0x93, 0xea, 0xaf, 0x25, 0x8b, 0x55, 0x34, 0x6d); WINADAPTER_IID(ID3D12StateObjectProperties, 0xde5fa827, 0x9bf9, 0x4f26, 0x89, 0xff, 0xd7, 0xf5, 0x6f, 0xde, 0x38, 0x60); +WINADAPTER_IID(ID3D12StateObjectProperties1, 0x460caac7, 0x1d24, 0x446a, 0xa1, 0x84, 0xca, 0x67, 0xdb, 0x49, 0x41, 0x38); +WINADAPTER_IID(ID3D12StateObjectProperties2, 0xd5e82917, 0xf0f1, 0x44cf, 0xae, 0x5e, 0xce, 0x22, 0x2d, 0xd0, 0xb8, 0x84); +WINADAPTER_IID(ID3D12WorkGraphProperties, 0x065acf71, 0xf863, 0x4b89, 0x82, 0xf4, 0x02, 0xe4, 0xd5, 0x88, 0x67, 0x57); WINADAPTER_IID(ID3D12Device5, 0x8b4f173b, 0x2fea, 0x4b80, 0x8f, 0x58, 0x43, 0x07, 0x19, 0x1a, 0xb9, 0x5d); WINADAPTER_IID(ID3D12DeviceRemovedExtendedDataSettings, 0x82BC481C, 0x6B9B, 0x4030, 0xAE, 0xDB, 0x7E, 0xE3, 0xD1, 0xDF, 0x1E, 0x63); WINADAPTER_IID(ID3D12DeviceRemovedExtendedDataSettings1, 0xDBD5AE51, 0x3317, 0x4F0A, 0xAD, 0xF9, 0x1D, 0x7C, 0xED, 0xCA, 0xAE, 0x0B); @@ -123,16 +127,31 @@ WINADAPTER_IID(ID3D12ShaderCacheSession, 0x28e2495d, 0x0f64, 0x4ae4, 0xa6, 0xec, WINADAPTER_IID(ID3D12Device9, 0x4c80e962, 0xf032, 0x4f60, 0xbc, 0x9e, 0xeb, 0xc2, 0xcf, 0xa1, 0xd8, 0x3c); WINADAPTER_IID(ID3D12Device10, 0x517f8718, 0xaa66, 0x49f9, 0xb0, 0x2b, 0xa7, 0xab, 0x89, 0xc0, 0x60, 0x31); WINADAPTER_IID(ID3D12Device11, 0x5405c344, 0xd457, 0x444e, 0xb4, 0xdd, 0x23, 0x66, 0xe4, 0x5a, 0xee, 0x39); +WINADAPTER_IID(ID3D12Device12, 0x5af5c532, 0x4c91, 0x4cd0, 0xb5, 0x41, 0x15, 0xa4, 0x05, 0x39, 0x5f, 0xc5); +WINADAPTER_IID(ID3D12Device13, 0x14eecffc, 0x4df8, 0x40f7, 0xa1, 0x18, 0x5c, 0x81, 0x6f, 0x45, 0x69, 0x5e); +WINADAPTER_IID(ID3D12Device14, 0x5f6e592d, 0xd895, 0x44c2, 0x8e, 0x4a, 0x88, 0xad, 0x49, 0x26, 0xd3, 0x23); +WINADAPTER_IID(ID3D12StateObjectDatabase, 0xc56060b7, 0xb5fc, 0x4135, 0x98, 0xe0, 0xa1, 0xe9, 0x99, 0x7e, 0xac, 0xe0); WINADAPTER_IID(ID3D12VirtualizationGuestDevice, 0xbc66d368, 0x7373, 0x4943, 0x87, 0x57, 0xfc, 0x87, 0xdc, 0x79, 0xe4, 0x76); WINADAPTER_IID(ID3D12Tools, 0x7071e1f0, 0xe84b, 0x4b33, 0x97, 0x4f, 0x12, 0xfa, 0x49, 0xde, 0x65, 0xc5); +WINADAPTER_IID(ID3D12Tools1, 0xe4fbc019, 0xdd3c, 0x43e1, 0x8f, 0x32, 0x7f, 0x64, 0x95, 0x75, 0xf0, 0xa0); +WINADAPTER_IID(ID3D12Tools2, 0x01d393c5, 0xc9b0, 0x42a1, 0x95, 0x8c, 0xc2, 0x6b, 0x02, 0xd4, 0xd0, 0x97); +WINADAPTER_IID(ID3D12PageableTools, 0x8f1359db, 0xd8d1, 0x42f9, 0xb5, 0xcf, 0x79, 0xf4, 0xcb, 0xad, 0x0d, 0x3d); +WINADAPTER_IID(ID3D12DeviceTools, 0x2ea68e9c, 0x19c3, 0x4e47, 0xa1, 0x09, 0x6c, 0xda, 0xdf, 0xf0, 0xac, 0xa9); +WINADAPTER_IID(ID3D12DeviceTools1, 0xe30e9fc7, 0xe641, 0x4d6e, 0x8a, 0x81, 0x9d, 0xd9, 0x20, 0x6e, 0xc4, 0x7a); WINADAPTER_IID(ID3D12SDKConfiguration, 0xe9eb5314, 0x33aa, 0x42b2, 0xa7, 0x18, 0xd7, 0x7f, 0x58, 0xb1, 0xf1, 0xc7); WINADAPTER_IID(ID3D12SDKConfiguration1, 0x8aaf9303, 0xad25, 0x48b9, 0x9a, 0x57, 0xd9, 0xc3, 0x7e, 0x00, 0x9d, 0x9f); WINADAPTER_IID(ID3D12DeviceFactory, 0x61f307d3, 0xd34e, 0x4e7c, 0x83, 0x74, 0x3b, 0xa4, 0xde, 0x23, 0xcc, 0xcb); WINADAPTER_IID(ID3D12DeviceConfiguration, 0x78dbf87b, 0xf766, 0x422b, 0xa6, 0x1c, 0xc8, 0xc4, 0x46, 0xbd, 0xb9, 0xad); +WINADAPTER_IID(ID3D12DeviceConfiguration1, 0xed342442, 0x6343, 0x4e16, 0xbb, 0x82, 0xa3, 0xa5, 0x77, 0x87, 0x4e, 0x56); +WINADAPTER_IID(ID3D12StateObjectDatabaseFactory, 0xf5b066f0, 0x648a, 0x4611, 0xbd, 0x41, 0x27, 0xfd, 0x09, 0x48, 0xb9, 0xeb); WINADAPTER_IID(ID3D12GraphicsCommandList5, 0x55050859, 0x4024, 0x474c, 0x87, 0xf5, 0x64, 0x72, 0xea, 0xee, 0x44, 0xea); WINADAPTER_IID(ID3D12GraphicsCommandList6, 0xc3827890, 0xe548, 0x4cfa, 0x96, 0xcf, 0x56, 0x89, 0xa9, 0x37, 0x0f, 0x80); WINADAPTER_IID(ID3D12GraphicsCommandList7, 0xdd171223, 0x8b61, 0x4769, 0x90, 0xe3, 0x16, 0x0c, 0xcd, 0xe4, 0xe2, 0xc1); WINADAPTER_IID(ID3D12GraphicsCommandList8, 0xee936ef9, 0x599d, 0x4d28, 0x93, 0x8e, 0x23, 0xc4, 0xad, 0x05, 0xce, 0x51); +WINADAPTER_IID(ID3D12GraphicsCommandList9, 0x34ed2808, 0xffe6, 0x4c2b, 0xb1, 0x1a, 0xca, 0xbd, 0x2b, 0x0c, 0x59, 0xe1); +WINADAPTER_IID(ID3D12GraphicsCommandList10, 0x7013c015, 0xd161, 0x4b63, 0xa0, 0x8c, 0x23, 0x85, 0x52, 0xdd, 0x8a, 0xcc); +WINADAPTER_IID(ID3D12DSRDeviceFactory, 0xf343d1a0, 0xafe3, 0x439f, 0xb1, 0x3d, 0xcd, 0x87, 0xa4, 0x3b, 0x70, 0xca); +WINADAPTER_IID(ID3D12GBVDiagnostics, 0x597985ab, 0x9b75, 0x4dbb, 0xbe, 0x23, 0x07, 0x61, 0x19, 0x5b, 0xeb, 0xee); #endif // Direct3D Video