@@ -1699,6 +1699,11 @@ static inline bool StatisticsEqual(const D3D12MA::DetailedStatistics& lhs, const
16991699 return memcmp (&lhs, &rhs, sizeof (lhs)) == 0 ;
17001700}
17011701
1702+ static inline bool StatisticsEqual (const D3D12MA::Statistics& lhs, const D3D12MA::Statistics& rhs)
1703+ {
1704+ return memcmp (&lhs, &rhs, sizeof (lhs)) == 0 ;
1705+ }
1706+
17021707static void CheckStatistics (const D3D12MA::DetailedStatistics& stats)
17031708{
17041709 CHECK_BOOL (stats.Stats .AllocationBytes <= stats.Stats .BlockBytes );
@@ -1714,86 +1719,304 @@ static void CheckStatistics(const D3D12MA::DetailedStatistics& stats)
17141719 }
17151720}
17161721
1717- static void TestStats (const TestContext& ctx)
1722+ static void CheckBudgetBasics (const TestContext& ctx,
1723+ const D3D12MA::Budget& localBudget, const D3D12MA::Budget& nonLocalBudget)
17181724{
1719- wprintf (L" Test stats\n " );
1725+ CHECK_BOOL (localBudget.BudgetBytes > 0 );
1726+ CHECK_BOOL (localBudget.BudgetBytes <= ctx.allocator ->GetMemoryCapacity (DXGI_MEMORY_SEGMENT_GROUP_LOCAL));
1727+ CHECK_BOOL (localBudget.Stats .AllocationBytes <= localBudget.Stats .BlockBytes );
17201728
1721- D3D12MA::TotalStatistics begStats = {};
1722- ctx.allocator ->CalculateStatistics (&begStats);
1729+ // Discrete graphics card with separate video memory.
1730+ if (!ctx.allocator ->IsUMA ())
1731+ {
1732+ CHECK_BOOL (nonLocalBudget.BudgetBytes > 0 );
1733+ CHECK_BOOL (nonLocalBudget.BudgetBytes <= ctx.allocator ->GetMemoryCapacity (DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL));
1734+ CHECK_BOOL (nonLocalBudget.Stats .AllocationBytes <= nonLocalBudget.Stats .BlockBytes );
1735+ }
1736+ }
17231737
1724- const UINT count = 10 ;
1725- const UINT64 bufSize = 64ull * 1024 ;
1726- ResourceWithAllocation resources[count];
1738+ static D3D12MA::DetailedStatistics GetEmptyDetailedStatistics ()
1739+ {
1740+ D3D12MA::DetailedStatistics out = {};
1741+ out.AllocationSizeMin = UINT64_MAX;
1742+ out.UnusedRangeSizeMin = UINT64_MAX;
1743+ return out;
1744+ }
17271745
1728- D3D12MA::CALLOCATION_DESC allocDesc = D3D12MA::CALLOCATION_DESC{ D3D12_HEAP_TYPE_UPLOAD };
1746+ static void AddDetailedStatistics (D3D12MA::DetailedStatistics& inoutSum, const D3D12MA::DetailedStatistics& stats)
1747+ {
1748+ inoutSum.Stats .AllocationBytes += stats.Stats .AllocationBytes ;
1749+ inoutSum.Stats .AllocationCount += stats.Stats .AllocationCount ;
1750+ inoutSum.Stats .BlockBytes += stats.Stats .BlockBytes ;
1751+ inoutSum.Stats .BlockCount += stats.Stats .BlockCount ;
1752+ inoutSum.UnusedRangeCount += stats.UnusedRangeCount ;
1753+ inoutSum.AllocationSizeMax = std::max (inoutSum.AllocationSizeMax , stats.AllocationSizeMax );
1754+ inoutSum.AllocationSizeMin = std::min (inoutSum.AllocationSizeMin , stats.AllocationSizeMin );
1755+ inoutSum.UnusedRangeSizeMax = std::max (inoutSum.UnusedRangeSizeMax , stats.UnusedRangeSizeMax );
1756+ inoutSum.UnusedRangeSizeMin = std::min (inoutSum.UnusedRangeSizeMin , stats.UnusedRangeSizeMin );
1757+ }
17291758
1730- D3D12_RESOURCE_DESC resourceDesc;
1731- FillResourceDescForBuffer (resourceDesc, bufSize);
1759+ static void CheckTotalStatistics (const D3D12MA::TotalStatistics& stats)
1760+ {
1761+ D3D12MA::DetailedStatistics sum = GetEmptyDetailedStatistics ();
1762+ for (size_t i = 0 ; i < _countof (stats.HeapType ); ++i)
1763+ {
1764+ AddDetailedStatistics (sum, stats.HeapType [i]);
1765+ }
1766+ CHECK_BOOL (StatisticsEqual (sum, stats.Total ));
17321767
1733- for (UINT i = 0 ; i < count; ++i)
1768+ sum = GetEmptyDetailedStatistics ();
1769+ for (size_t i = 0 ; i < _countof (stats.MemorySegmentGroup ); ++i)
17341770 {
1735- if (i == count / 2 )
1736- allocDesc.Flags |= D3D12MA::ALLOCATION_FLAG_COMMITTED;
1737- CHECK_HR ( ctx.allocator ->CreateResource (
1738- &allocDesc,
1739- &resourceDesc,
1740- D3D12_RESOURCE_STATE_GENERIC_READ,
1741- NULL ,
1742- &resources[i].allocation ,
1743- IID_PPV_ARGS (&resources[i].resource )) );
1771+ AddDetailedStatistics (sum, stats.MemorySegmentGroup [i]);
17441772 }
1773+ CHECK_BOOL (StatisticsEqual (sum, stats.Total ));
1774+ }
17451775
1746- D3D12MA::TotalStatistics endStats = {};
1747- ctx.allocator ->CalculateStatistics (&endStats);
1776+ static void TestStats (const TestContext& ctx)
1777+ {
1778+ using namespace D3D12MA ;
17481779
1749- CHECK_BOOL (endStats.Total .Stats .BlockCount >= begStats.Total .Stats .BlockCount );
1750- CHECK_BOOL (endStats.Total .Stats .AllocationCount == begStats.Total .Stats .AllocationCount + count);
1751- CHECK_BOOL (endStats.Total .Stats .AllocationBytes == begStats.Total .Stats .AllocationBytes + count * bufSize);
1752- CHECK_BOOL (endStats.Total .AllocationSizeMin <= bufSize);
1753- CHECK_BOOL (endStats.Total .AllocationSizeMax >= bufSize);
1780+ wprintf (L" Test stats\n " );
17541781
1755- CHECK_BOOL (endStats.HeapType [1 ].Stats .BlockCount >= begStats.HeapType [1 ].Stats .BlockCount );
1756- CHECK_BOOL (endStats.HeapType [1 ].Stats .AllocationCount >= begStats.HeapType [1 ].Stats .AllocationCount + count);
1757- CHECK_BOOL (endStats.HeapType [1 ].Stats .AllocationBytes >= begStats.HeapType [1 ].Stats .AllocationBytes + count * bufSize);
1758- CHECK_BOOL (endStats.HeapType [1 ].AllocationSizeMin <= bufSize);
1759- CHECK_BOOL (endStats.HeapType [1 ].AllocationSizeMax >= bufSize);
1782+ constexpr UINT64 BUF_SIZE = 10 * MEGABYTE;
1783+ constexpr UINT32 BUF_COUNT = 4 ;
1784+ constexpr UINT64 PREALLOCATED_BLOCK_SIZE = BUF_SIZE * (BUF_COUNT + 1 );
1785+
1786+ /*
1787+ Test 0: ALLOCATION_FLAG_COMMITTED.
1788+ Test 1: normal allocations.
1789+ Test 2: allocations in a custom pool.
1790+ Test 3: allocations in a custom pool, COMMITTED.
1791+ Test 4: allocations in a custom pool with preallocated memory.
1792+ */
1793+ for (uint32_t testIndex = 0 ; testIndex < 5 ; ++testIndex)
1794+ {
1795+ const bool usePool = testIndex >= 2 ;
1796+ const bool useCommitted = testIndex == 0 || testIndex == 3 ;
1797+ const bool usePreallocated = testIndex == 4 ;
17601798
1761- CHECK_BOOL (StatisticsEqual (begStats.HeapType [0 ], endStats.HeapType [0 ]));
1762- CHECK_BOOL (StatisticsEqual (begStats.HeapType [2 ], endStats.HeapType [2 ]));
1799+ // Get stats "Beg".
1800+ Budget localBudgetBeg = {};
1801+ Budget nonLocalBudgetBeg = {};
1802+ ctx.allocator ->GetBudget (&localBudgetBeg, &nonLocalBudgetBeg);
1803+ CheckBudgetBasics (ctx, localBudgetBeg, nonLocalBudgetBeg);
17631804
1764- CheckStatistics (endStats.Total );
1765- CheckStatistics (endStats.HeapType [0 ]);
1766- CheckStatistics (endStats.HeapType [1 ]);
1767- CheckStatistics (endStats.HeapType [2 ]);
1805+ TotalStatistics statsBeg = {};
1806+ ctx.allocator ->CalculateStatistics (&statsBeg);
1807+ CheckTotalStatistics (statsBeg);
17681808
1769- D3D12MA::Budget localBudget = {}, nonLocalBudget = {};
1770- ctx.allocator ->GetBudget (&localBudget, &nonLocalBudget);
1809+ // Create pool.
1810+ ComPtr<Pool> pool;
1811+ if (usePool)
1812+ {
1813+ POOL_DESC poolDesc = CPOOL_DESC (D3D12_HEAP_TYPE_DEFAULT, D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS);
1814+ if (usePreallocated)
1815+ {
1816+ poolDesc.BlockSize = PREALLOCATED_BLOCK_SIZE;
1817+ poolDesc.MinBlockCount = 1 ;
1818+ poolDesc.MaxBlockCount = 1 ;
1819+ }
1820+ CHECK_HR (ctx.allocator ->CreatePool (&poolDesc, &pool));
1821+ }
17711822
1772- CHECK_BOOL (localBudget.Stats .AllocationBytes <= localBudget.Stats .BlockBytes );
1773- CHECK_BOOL (endStats.HeapType [3 ].Stats .BlockCount == 0 ); // No allocation from D3D12_HEAP_TYPE_CUSTOM in this test.
1774- if (!ctx.allocator ->IsUMA ())
1775- {
1776- // Discrete GPU
1777- CHECK_BOOL (localBudget.Stats .AllocationBytes == endStats.HeapType [0 ].Stats .AllocationBytes );
1778- CHECK_BOOL (localBudget.Stats .BlockBytes == endStats.HeapType [0 ].Stats .BlockBytes );
1779-
1780- CHECK_BOOL (nonLocalBudget.Stats .AllocationBytes <= nonLocalBudget.Stats .BlockBytes );
1781- CHECK_BOOL (nonLocalBudget.Stats .AllocationBytes == endStats.HeapType [1 ].Stats .AllocationBytes + endStats.HeapType [2 ].Stats .AllocationBytes );
1782- CHECK_BOOL (nonLocalBudget.Stats .BlockBytes ==
1783- endStats.HeapType [1 ].Stats .BlockBytes + endStats.HeapType [2 ].Stats .BlockBytes );
1784- }
1785- else
1786- {
1787- // Integrated GPU - all memory is local
1788- CHECK_BOOL (localBudget.Stats .AllocationBytes == endStats.HeapType [0 ].Stats .AllocationBytes +
1789- endStats.HeapType [1 ].Stats .AllocationBytes +
1790- endStats.HeapType [2 ].Stats .AllocationBytes );
1791- CHECK_BOOL (localBudget.Stats .BlockBytes == endStats.HeapType [0 ].Stats .BlockBytes +
1792- endStats.HeapType [1 ].Stats .BlockBytes +
1793- endStats.HeapType [2 ].Stats .BlockBytes );
1794-
1795- CHECK_BOOL (nonLocalBudget.Stats .AllocationBytes == 0 );
1796- CHECK_BOOL (nonLocalBudget.Stats .BlockBytes == 0 );
1823+ // Get pool stats "Beg".
1824+ Statistics poolStatsBeg = {};
1825+ DetailedStatistics detailedPoolStatsBeg = {};
1826+ if (usePool)
1827+ {
1828+ pool->GetStatistics (&poolStatsBeg);
1829+ pool->CalculateStatistics (&detailedPoolStatsBeg);
1830+ CheckStatistics (detailedPoolStatsBeg);
1831+ }
1832+
1833+ // Create buffers.
1834+ D3D12_RESOURCE_DESC resDesc;
1835+ FillResourceDescForBuffer (resDesc, BUF_SIZE);
1836+
1837+ ALLOCATION_DESC allocDesc = {};
1838+ if (usePool)
1839+ allocDesc = CALLOCATION_DESC (pool.Get ());
1840+ else
1841+ allocDesc = CALLOCATION_DESC (D3D12_HEAP_TYPE_DEFAULT);
1842+ if (useCommitted)
1843+ allocDesc.Flags |= ALLOCATION_FLAG_COMMITTED;
1844+
1845+ ComPtr<Allocation> allocs[BUF_COUNT];
1846+ for (UINT i = 0 ; i < BUF_COUNT; ++i)
1847+ {
1848+ CHECK_HR (ctx.allocator ->CreateResource (
1849+ &allocDesc, &resDesc, D3D12_RESOURCE_STATE_COMMON,
1850+ NULL , &allocs[i], IID_NULL, NULL ));
1851+ }
1852+
1853+ // Get stats "WithBufs".
1854+ Budget localBudgetWithBufs = {};
1855+ Budget nonLocalBudgetWithBufs = {};
1856+ ctx.allocator ->GetBudget (&localBudgetWithBufs, &nonLocalBudgetWithBufs);
1857+ CheckBudgetBasics (ctx, localBudgetWithBufs, nonLocalBudgetWithBufs);
1858+
1859+ TotalStatistics statsWithBufs = {};
1860+ ctx.allocator ->CalculateStatistics (&statsWithBufs);
1861+ CheckTotalStatistics (statsWithBufs);
1862+
1863+ Statistics poolStatsWithBufs = {};
1864+ DetailedStatistics detailedPoolStatsWithBufs = {};
1865+ if (usePool)
1866+ {
1867+ pool->GetStatistics (&poolStatsWithBufs);
1868+ pool->CalculateStatistics (&detailedPoolStatsWithBufs);
1869+ CheckStatistics (detailedPoolStatsWithBufs);
1870+ }
1871+
1872+ // Destroy buffers.
1873+ for (size_t i = BUF_COUNT; i--; )
1874+ {
1875+ allocs[i].Reset ();
1876+ }
1877+
1878+ // Get pool stats "End".
1879+ Statistics poolStatsEnd = {};
1880+ DetailedStatistics detailedPoolStatsEnd = {};
1881+ if (usePool)
1882+ {
1883+ pool->GetStatistics (&poolStatsEnd);
1884+ pool->CalculateStatistics (&detailedPoolStatsEnd);
1885+ CheckStatistics (detailedPoolStatsEnd);
1886+ }
1887+
1888+ // Destroy the pool.
1889+ pool.Reset ();
1890+
1891+ // Get stats "End".
1892+ Budget localBudgetEnd = {};
1893+ Budget nonLocalBudgetEnd = {};
1894+ ctx.allocator ->GetBudget (&localBudgetEnd, &nonLocalBudgetEnd);
1895+ CheckBudgetBasics (ctx, localBudgetEnd, nonLocalBudgetEnd);
1896+
1897+ TotalStatistics statsEnd = {};
1898+ ctx.allocator ->CalculateStatistics (&statsEnd);
1899+ CheckTotalStatistics (statsEnd);
1900+
1901+ // CHECK THE STATS: Local.
1902+ {
1903+ CHECK_BOOL (localBudgetBeg.Stats .AllocationBytes <= localBudgetEnd.Stats .AllocationBytes );
1904+
1905+ // Budget::UsageBytes.
1906+ CHECK_BOOL (localBudgetWithBufs.UsageBytes >= localBudgetBeg.UsageBytes );
1907+ CHECK_BOOL (localBudgetEnd.UsageBytes <= localBudgetWithBufs.UsageBytes );
1908+
1909+ // Budget - Statistics::AllocationBytes.
1910+ CHECK_BOOL (localBudgetEnd.Stats .AllocationBytes == localBudgetBeg.Stats .AllocationBytes );
1911+ CHECK_BOOL (localBudgetWithBufs.Stats .AllocationBytes == localBudgetBeg.Stats .AllocationBytes + BUF_SIZE * BUF_COUNT);
1912+
1913+ // Budget - Statistics::BlockBytes.
1914+ if (usePool)
1915+ {
1916+ CHECK_BOOL (localBudgetEnd.Stats .BlockBytes == localBudgetBeg.Stats .BlockBytes );
1917+ CHECK_BOOL (localBudgetWithBufs.Stats .BlockBytes > localBudgetBeg.Stats .BlockBytes );
1918+ }
1919+ else
1920+ {
1921+ CHECK_BOOL (localBudgetWithBufs.Stats .BlockBytes >= localBudgetBeg.Stats .BlockBytes );
1922+ }
1923+
1924+ // Budget - Statistics::AllocationCount.
1925+ CHECK_BOOL (localBudgetEnd.Stats .AllocationCount == localBudgetBeg.Stats .AllocationCount );
1926+ CHECK_BOOL (localBudgetWithBufs.Stats .AllocationCount == localBudgetBeg.Stats .AllocationCount + BUF_COUNT);
1927+
1928+ // Budget - Statistics::BlockCount.
1929+ if (useCommitted)
1930+ {
1931+ CHECK_BOOL (localBudgetEnd.Stats .BlockCount == localBudgetBeg.Stats .BlockCount );
1932+ CHECK_BOOL (localBudgetWithBufs.Stats .BlockCount == localBudgetBeg.Stats .BlockCount + BUF_COUNT);
1933+ }
1934+ else if (usePool)
1935+ {
1936+ CHECK_BOOL (localBudgetEnd.Stats .BlockCount == localBudgetBeg.Stats .BlockCount );
1937+ if (usePreallocated)
1938+ {
1939+ CHECK_BOOL (localBudgetWithBufs.Stats .BlockCount == localBudgetBeg.Stats .BlockCount + 1 );
1940+ }
1941+ else
1942+ {
1943+ CHECK_BOOL (localBudgetWithBufs.Stats .BlockCount > localBudgetBeg.Stats .BlockCount );
1944+ }
1945+ }
1946+
1947+ // Compare CalculateStatistics per memory segment group with GetBudget.
1948+ CHECK_BOOL (StatisticsEqual (statsBeg.MemorySegmentGroup [0 ].Stats , localBudgetBeg.Stats ));
1949+ CHECK_BOOL (StatisticsEqual (statsWithBufs.MemorySegmentGroup [0 ].Stats , localBudgetWithBufs.Stats ));
1950+ CHECK_BOOL (StatisticsEqual (statsEnd.MemorySegmentGroup [0 ].Stats , localBudgetEnd.Stats ));
1951+ }
1952+
1953+ // CHECK THE STATS: Non-local.
1954+ {
1955+ CHECK_BOOL (nonLocalBudgetEnd.Stats .AllocationBytes == nonLocalBudgetBeg.Stats .AllocationBytes &&
1956+ nonLocalBudgetEnd.Stats .AllocationBytes == nonLocalBudgetWithBufs.Stats .AllocationBytes );
1957+ CHECK_BOOL (nonLocalBudgetEnd.Stats .BlockBytes == nonLocalBudgetBeg.Stats .BlockBytes &&
1958+ nonLocalBudgetEnd.Stats .BlockBytes == nonLocalBudgetWithBufs.Stats .BlockBytes );
1959+ CHECK_BOOL (nonLocalBudgetEnd.Stats .AllocationCount == nonLocalBudgetBeg.Stats .AllocationCount &&
1960+ nonLocalBudgetEnd.Stats .AllocationCount == nonLocalBudgetWithBufs.Stats .AllocationCount );
1961+ CHECK_BOOL (nonLocalBudgetEnd.Stats .BlockCount == nonLocalBudgetBeg.Stats .BlockCount &&
1962+ nonLocalBudgetEnd.Stats .BlockCount == nonLocalBudgetWithBufs.Stats .BlockCount );
1963+
1964+ // Compare CalculateStatistics per memory segment group with GetBudget.
1965+ CHECK_BOOL (StatisticsEqual (statsBeg.MemorySegmentGroup [1 ].Stats , nonLocalBudgetBeg.Stats ));
1966+ CHECK_BOOL (StatisticsEqual (statsWithBufs.MemorySegmentGroup [1 ].Stats , nonLocalBudgetWithBufs.Stats ));
1967+ CHECK_BOOL (StatisticsEqual (statsEnd.MemorySegmentGroup [1 ].Stats , nonLocalBudgetEnd.Stats ));
1968+ }
1969+
1970+ if (usePool)
1971+ {
1972+ // Compare simple stats with calculated stats to make sure they are identical.
1973+ CHECK_BOOL (StatisticsEqual (poolStatsBeg, detailedPoolStatsBeg.Stats ));
1974+ CHECK_BOOL (StatisticsEqual (poolStatsWithBufs, detailedPoolStatsWithBufs.Stats ));
1975+ CHECK_BOOL (StatisticsEqual (poolStatsEnd, detailedPoolStatsEnd.Stats ));
1976+
1977+ // Validate stats of an empty pool.
1978+ CHECK_BOOL (detailedPoolStatsBeg.AllocationSizeMax == 0 );
1979+ CHECK_BOOL (detailedPoolStatsEnd.AllocationSizeMax == 0 );
1980+ CHECK_BOOL (detailedPoolStatsBeg.AllocationSizeMin == UINT64_MAX);
1981+ CHECK_BOOL (detailedPoolStatsEnd.AllocationSizeMin == UINT64_MAX);
1982+ CHECK_BOOL (poolStatsBeg.AllocationCount == 0 );
1983+ CHECK_BOOL (poolStatsBeg.AllocationBytes == 0 );
1984+ CHECK_BOOL (poolStatsEnd.AllocationCount == 0 );
1985+ CHECK_BOOL (poolStatsEnd.AllocationBytes == 0 );
1986+ if (usePreallocated)
1987+ {
1988+ CHECK_BOOL (poolStatsBeg.BlockCount == 1 );
1989+ CHECK_BOOL (poolStatsEnd.BlockCount == 1 );
1990+ CHECK_BOOL (poolStatsBeg.BlockBytes == PREALLOCATED_BLOCK_SIZE);
1991+ CHECK_BOOL (poolStatsEnd.BlockBytes == PREALLOCATED_BLOCK_SIZE);
1992+ }
1993+ else
1994+ {
1995+ CHECK_BOOL (poolStatsBeg.BlockCount == 0 );
1996+ CHECK_BOOL (poolStatsBeg.BlockBytes == 0 );
1997+ // Not checking poolStatsEnd.blockCount, blockBytes, because an empty block may stay allocated.
1998+ }
1999+
2000+ // Validate stats of a pool with buffers.
2001+ CHECK_BOOL (detailedPoolStatsWithBufs.AllocationSizeMin == BUF_SIZE);
2002+ CHECK_BOOL (detailedPoolStatsWithBufs.AllocationSizeMax == BUF_SIZE);
2003+ CHECK_BOOL (poolStatsWithBufs.AllocationCount == BUF_COUNT);
2004+ CHECK_BOOL (poolStatsWithBufs.AllocationBytes == BUF_COUNT * BUF_SIZE);
2005+ if (usePreallocated)
2006+ {
2007+ CHECK_BOOL (poolStatsWithBufs.BlockCount == 1 );
2008+ CHECK_BOOL (poolStatsWithBufs.BlockBytes == PREALLOCATED_BLOCK_SIZE);
2009+ }
2010+ else
2011+ {
2012+ CHECK_BOOL (poolStatsWithBufs.BlockCount > 0 );
2013+ CHECK_BOOL (poolStatsWithBufs.BlockBytes >= poolStatsWithBufs.AllocationBytes );
2014+ }
2015+ }
2016+
2017+ // No allocation from D3D12_HEAP_TYPE_CUSTOM or GPU_UPLOAD in this test.
2018+ CHECK_BOOL (statsEnd.HeapType [3 ].Stats .BlockCount == 0 );
2019+ CHECK_BOOL (statsEnd.HeapType [4 ].Stats .BlockCount == 0 );
17972020 }
17982021}
17992022
0 commit comments