d3dx12_resource_helpers.h 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602
  1. //*********************************************************
  2. //
  3. // Copyright (c) Microsoft Corporation.
  4. // Licensed under the MIT License (MIT).
  5. //
  6. //*********************************************************
  7. #pragma once
  8. #ifndef __cplusplus
  9. #error D3DX12 requires C++
  10. #endif
  11. #include "d3d12.h"
  12. #include "d3dx12_core.h"
  13. #include "d3dx12_property_format_table.h"
  14. //------------------------------------------------------------------------------------------------
  15. template <typename T, typename U, typename V>
  16. inline void D3D12DecomposeSubresource( UINT Subresource, UINT MipLevels, UINT ArraySize, _Out_ T& MipSlice, _Out_ U& ArraySlice, _Out_ V& PlaneSlice ) noexcept
  17. {
  18. MipSlice = static_cast<T>(Subresource % MipLevels);
  19. ArraySlice = static_cast<U>((Subresource / MipLevels) % ArraySize);
  20. PlaneSlice = static_cast<V>(Subresource / (MipLevels * ArraySize));
  21. }
  22. //------------------------------------------------------------------------------------------------
  23. // Row-by-row memcpy
  24. inline void MemcpySubresource(
  25. _In_ const D3D12_MEMCPY_DEST* pDest,
  26. _In_ const D3D12_SUBRESOURCE_DATA* pSrc,
  27. SIZE_T RowSizeInBytes,
  28. UINT NumRows,
  29. UINT NumSlices) noexcept
  30. {
  31. for (UINT z = 0; z < NumSlices; ++z)
  32. {
  33. auto pDestSlice = static_cast<BYTE*>(pDest->pData) + pDest->SlicePitch * z;
  34. auto pSrcSlice = static_cast<const BYTE*>(pSrc->pData) + pSrc->SlicePitch * LONG_PTR(z);
  35. for (UINT y = 0; y < NumRows; ++y)
  36. {
  37. memcpy(pDestSlice + pDest->RowPitch * y,
  38. pSrcSlice + pSrc->RowPitch * LONG_PTR(y),
  39. RowSizeInBytes);
  40. }
  41. }
  42. }
  43. //------------------------------------------------------------------------------------------------
  44. // Row-by-row memcpy
  45. inline void MemcpySubresource(
  46. _In_ const D3D12_MEMCPY_DEST* pDest,
  47. _In_ const void* pResourceData,
  48. _In_ const D3D12_SUBRESOURCE_INFO* pSrc,
  49. SIZE_T RowSizeInBytes,
  50. UINT NumRows,
  51. UINT NumSlices) noexcept
  52. {
  53. for (UINT z = 0; z < NumSlices; ++z)
  54. {
  55. auto pDestSlice = static_cast<BYTE*>(pDest->pData) + pDest->SlicePitch * z;
  56. auto pSrcSlice = (static_cast<const BYTE*>(pResourceData) + pSrc->Offset) + pSrc->DepthPitch * ULONG_PTR(z);
  57. for (UINT y = 0; y < NumRows; ++y)
  58. {
  59. memcpy(pDestSlice + pDest->RowPitch * y,
  60. pSrcSlice + pSrc->RowPitch * ULONG_PTR(y),
  61. RowSizeInBytes);
  62. }
  63. }
  64. }
  65. //------------------------------------------------------------------------------------------------
  66. // Returns required size of a buffer to be used for data upload
  67. inline UINT64 GetRequiredIntermediateSize(
  68. _In_ ID3D12Resource* pDestinationResource,
  69. _In_range_(0,D3D12_REQ_SUBRESOURCES) UINT FirstSubresource,
  70. _In_range_(0,D3D12_REQ_SUBRESOURCES-FirstSubresource) UINT NumSubresources) noexcept
  71. {
  72. #if defined(_MSC_VER) || !defined(_WIN32)
  73. const auto Desc = pDestinationResource->GetDesc();
  74. #else
  75. D3D12_RESOURCE_DESC tmpDesc;
  76. const auto& Desc = *pDestinationResource->GetDesc(&tmpDesc);
  77. #endif
  78. UINT64 RequiredSize = 0;
  79. ID3D12Device* pDevice = nullptr;
  80. pDestinationResource->GetDevice(IID_ID3D12Device, reinterpret_cast<void**>(&pDevice));
  81. pDevice->GetCopyableFootprints(&Desc, FirstSubresource, NumSubresources, 0, nullptr, nullptr, nullptr, &RequiredSize);
  82. pDevice->Release();
  83. return RequiredSize;
  84. }
  85. //------------------------------------------------------------------------------------------------
  86. // All arrays must be populated (e.g. by calling GetCopyableFootprints)
  87. inline UINT64 UpdateSubresources(
  88. _In_ ID3D12GraphicsCommandList* pCmdList,
  89. _In_ ID3D12Resource* pDestinationResource,
  90. _In_ ID3D12Resource* pIntermediate,
  91. _In_range_(0,D3D12_REQ_SUBRESOURCES) UINT FirstSubresource,
  92. _In_range_(0,D3D12_REQ_SUBRESOURCES-FirstSubresource) UINT NumSubresources,
  93. UINT64 RequiredSize,
  94. _In_reads_(NumSubresources) const D3D12_PLACED_SUBRESOURCE_FOOTPRINT* pLayouts,
  95. _In_reads_(NumSubresources) const UINT* pNumRows,
  96. _In_reads_(NumSubresources) const UINT64* pRowSizesInBytes,
  97. _In_reads_(NumSubresources) const D3D12_SUBRESOURCE_DATA* pSrcData) noexcept
  98. {
  99. // Minor validation
  100. #if defined(_MSC_VER) || !defined(_WIN32)
  101. const auto IntermediateDesc = pIntermediate->GetDesc();
  102. const auto DestinationDesc = pDestinationResource->GetDesc();
  103. #else
  104. D3D12_RESOURCE_DESC tmpDesc1, tmpDesc2;
  105. const auto& IntermediateDesc = *pIntermediate->GetDesc(&tmpDesc1);
  106. const auto& DestinationDesc = *pDestinationResource->GetDesc(&tmpDesc2);
  107. #endif
  108. if (IntermediateDesc.Dimension != D3D12_RESOURCE_DIMENSION_BUFFER ||
  109. IntermediateDesc.Width < RequiredSize + pLayouts[0].Offset ||
  110. RequiredSize > SIZE_T(-1) ||
  111. (DestinationDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER &&
  112. (FirstSubresource != 0 || NumSubresources != 1)))
  113. {
  114. return 0;
  115. }
  116. BYTE* pData;
  117. HRESULT hr = pIntermediate->Map(0, nullptr, reinterpret_cast<void**>(&pData));
  118. if (FAILED(hr))
  119. {
  120. return 0;
  121. }
  122. for (UINT i = 0; i < NumSubresources; ++i)
  123. {
  124. if (pRowSizesInBytes[i] > SIZE_T(-1)) return 0;
  125. D3D12_MEMCPY_DEST DestData = { pData + pLayouts[i].Offset, pLayouts[i].Footprint.RowPitch, SIZE_T(pLayouts[i].Footprint.RowPitch) * SIZE_T(pNumRows[i]) };
  126. MemcpySubresource(&DestData, &pSrcData[i], static_cast<SIZE_T>(pRowSizesInBytes[i]), pNumRows[i], pLayouts[i].Footprint.Depth);
  127. }
  128. pIntermediate->Unmap(0, nullptr);
  129. if (DestinationDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
  130. {
  131. pCmdList->CopyBufferRegion(
  132. pDestinationResource, 0, pIntermediate, pLayouts[0].Offset, pLayouts[0].Footprint.Width);
  133. }
  134. else
  135. {
  136. for (UINT i = 0; i < NumSubresources; ++i)
  137. {
  138. const CD3DX12_TEXTURE_COPY_LOCATION Dst(pDestinationResource, i + FirstSubresource);
  139. const CD3DX12_TEXTURE_COPY_LOCATION Src(pIntermediate, pLayouts[i]);
  140. pCmdList->CopyTextureRegion(&Dst, 0, 0, 0, &Src, nullptr);
  141. }
  142. }
  143. return RequiredSize;
  144. }
  145. //------------------------------------------------------------------------------------------------
  146. // All arrays must be populated (e.g. by calling GetCopyableFootprints)
  147. inline UINT64 UpdateSubresources(
  148. _In_ ID3D12GraphicsCommandList* pCmdList,
  149. _In_ ID3D12Resource* pDestinationResource,
  150. _In_ ID3D12Resource* pIntermediate,
  151. _In_range_(0,D3D12_REQ_SUBRESOURCES) UINT FirstSubresource,
  152. _In_range_(0,D3D12_REQ_SUBRESOURCES-FirstSubresource) UINT NumSubresources,
  153. UINT64 RequiredSize,
  154. _In_reads_(NumSubresources) const D3D12_PLACED_SUBRESOURCE_FOOTPRINT* pLayouts,
  155. _In_reads_(NumSubresources) const UINT* pNumRows,
  156. _In_reads_(NumSubresources) const UINT64* pRowSizesInBytes,
  157. _In_ const void* pResourceData,
  158. _In_reads_(NumSubresources) const D3D12_SUBRESOURCE_INFO* pSrcData) noexcept
  159. {
  160. // Minor validation
  161. #if defined(_MSC_VER) || !defined(_WIN32)
  162. const auto IntermediateDesc = pIntermediate->GetDesc();
  163. const auto DestinationDesc = pDestinationResource->GetDesc();
  164. #else
  165. D3D12_RESOURCE_DESC tmpDesc1, tmpDesc2;
  166. const auto& IntermediateDesc = *pIntermediate->GetDesc(&tmpDesc1);
  167. const auto& DestinationDesc = *pDestinationResource->GetDesc(&tmpDesc2);
  168. #endif
  169. if (IntermediateDesc.Dimension != D3D12_RESOURCE_DIMENSION_BUFFER ||
  170. IntermediateDesc.Width < RequiredSize + pLayouts[0].Offset ||
  171. RequiredSize > SIZE_T(-1) ||
  172. (DestinationDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER &&
  173. (FirstSubresource != 0 || NumSubresources != 1)))
  174. {
  175. return 0;
  176. }
  177. BYTE* pData;
  178. HRESULT hr = pIntermediate->Map(0, nullptr, reinterpret_cast<void**>(&pData));
  179. if (FAILED(hr))
  180. {
  181. return 0;
  182. }
  183. for (UINT i = 0; i < NumSubresources; ++i)
  184. {
  185. if (pRowSizesInBytes[i] > SIZE_T(-1)) return 0;
  186. D3D12_MEMCPY_DEST DestData = { pData + pLayouts[i].Offset, pLayouts[i].Footprint.RowPitch, SIZE_T(pLayouts[i].Footprint.RowPitch) * SIZE_T(pNumRows[i]) };
  187. MemcpySubresource(&DestData, pResourceData, &pSrcData[i], static_cast<SIZE_T>(pRowSizesInBytes[i]), pNumRows[i], pLayouts[i].Footprint.Depth);
  188. }
  189. pIntermediate->Unmap(0, nullptr);
  190. if (DestinationDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
  191. {
  192. pCmdList->CopyBufferRegion(
  193. pDestinationResource, 0, pIntermediate, pLayouts[0].Offset, pLayouts[0].Footprint.Width);
  194. }
  195. else
  196. {
  197. for (UINT i = 0; i < NumSubresources; ++i)
  198. {
  199. const CD3DX12_TEXTURE_COPY_LOCATION Dst(pDestinationResource, i + FirstSubresource);
  200. const CD3DX12_TEXTURE_COPY_LOCATION Src(pIntermediate, pLayouts[i]);
  201. pCmdList->CopyTextureRegion(&Dst, 0, 0, 0, &Src, nullptr);
  202. }
  203. }
  204. return RequiredSize;
  205. }
  206. //------------------------------------------------------------------------------------------------
  207. // Heap-allocating UpdateSubresources implementation
  208. inline UINT64 UpdateSubresources(
  209. _In_ ID3D12GraphicsCommandList* pCmdList,
  210. _In_ ID3D12Resource* pDestinationResource,
  211. _In_ ID3D12Resource* pIntermediate,
  212. UINT64 IntermediateOffset,
  213. _In_range_(0,D3D12_REQ_SUBRESOURCES) UINT FirstSubresource,
  214. _In_range_(0,D3D12_REQ_SUBRESOURCES-FirstSubresource) UINT NumSubresources,
  215. _In_reads_(NumSubresources) const D3D12_SUBRESOURCE_DATA* pSrcData) noexcept
  216. {
  217. UINT64 RequiredSize = 0;
  218. const auto MemToAlloc = static_cast<UINT64>(sizeof(D3D12_PLACED_SUBRESOURCE_FOOTPRINT) + sizeof(UINT) + sizeof(UINT64)) * NumSubresources;
  219. if (MemToAlloc > SIZE_MAX)
  220. {
  221. return 0;
  222. }
  223. void* pMem = HeapAlloc(GetProcessHeap(), 0, static_cast<SIZE_T>(MemToAlloc));
  224. if (pMem == nullptr)
  225. {
  226. return 0;
  227. }
  228. auto pLayouts = static_cast<D3D12_PLACED_SUBRESOURCE_FOOTPRINT*>(pMem);
  229. auto pRowSizesInBytes = reinterpret_cast<UINT64*>(pLayouts + NumSubresources);
  230. auto pNumRows = reinterpret_cast<UINT*>(pRowSizesInBytes + NumSubresources);
  231. #if defined(_MSC_VER) || !defined(_WIN32)
  232. const auto Desc = pDestinationResource->GetDesc();
  233. #else
  234. D3D12_RESOURCE_DESC tmpDesc;
  235. const auto& Desc = *pDestinationResource->GetDesc(&tmpDesc);
  236. #endif
  237. ID3D12Device* pDevice = nullptr;
  238. pDestinationResource->GetDevice(IID_ID3D12Device, reinterpret_cast<void**>(&pDevice));
  239. pDevice->GetCopyableFootprints(&Desc, FirstSubresource, NumSubresources, IntermediateOffset, pLayouts, pNumRows, pRowSizesInBytes, &RequiredSize);
  240. pDevice->Release();
  241. const UINT64 Result = UpdateSubresources(pCmdList, pDestinationResource, pIntermediate, FirstSubresource, NumSubresources, RequiredSize, pLayouts, pNumRows, pRowSizesInBytes, pSrcData);
  242. HeapFree(GetProcessHeap(), 0, pMem);
  243. return Result;
  244. }
  245. //------------------------------------------------------------------------------------------------
  246. // Heap-allocating UpdateSubresources implementation
  247. inline UINT64 UpdateSubresources(
  248. _In_ ID3D12GraphicsCommandList* pCmdList,
  249. _In_ ID3D12Resource* pDestinationResource,
  250. _In_ ID3D12Resource* pIntermediate,
  251. UINT64 IntermediateOffset,
  252. _In_range_(0,D3D12_REQ_SUBRESOURCES) UINT FirstSubresource,
  253. _In_range_(0,D3D12_REQ_SUBRESOURCES-FirstSubresource) UINT NumSubresources,
  254. _In_ const void* pResourceData,
  255. _In_reads_(NumSubresources) const D3D12_SUBRESOURCE_INFO* pSrcData) noexcept
  256. {
  257. UINT64 RequiredSize = 0;
  258. const auto MemToAlloc = static_cast<UINT64>(sizeof(D3D12_PLACED_SUBRESOURCE_FOOTPRINT) + sizeof(UINT) + sizeof(UINT64)) * NumSubresources;
  259. if (MemToAlloc > SIZE_MAX)
  260. {
  261. return 0;
  262. }
  263. void* pMem = HeapAlloc(GetProcessHeap(), 0, static_cast<SIZE_T>(MemToAlloc));
  264. if (pMem == nullptr)
  265. {
  266. return 0;
  267. }
  268. auto pLayouts = static_cast<D3D12_PLACED_SUBRESOURCE_FOOTPRINT*>(pMem);
  269. auto pRowSizesInBytes = reinterpret_cast<UINT64*>(pLayouts + NumSubresources);
  270. auto pNumRows = reinterpret_cast<UINT*>(pRowSizesInBytes + NumSubresources);
  271. #if defined(_MSC_VER) || !defined(_WIN32)
  272. const auto Desc = pDestinationResource->GetDesc();
  273. #else
  274. D3D12_RESOURCE_DESC tmpDesc;
  275. const auto& Desc = *pDestinationResource->GetDesc(&tmpDesc);
  276. #endif
  277. ID3D12Device* pDevice = nullptr;
  278. pDestinationResource->GetDevice(IID_ID3D12Device, reinterpret_cast<void**>(&pDevice));
  279. pDevice->GetCopyableFootprints(&Desc, FirstSubresource, NumSubresources, IntermediateOffset, pLayouts, pNumRows, pRowSizesInBytes, &RequiredSize);
  280. pDevice->Release();
  281. const UINT64 Result = UpdateSubresources(pCmdList, pDestinationResource, pIntermediate, FirstSubresource, NumSubresources, RequiredSize, pLayouts, pNumRows, pRowSizesInBytes, pResourceData, pSrcData);
  282. HeapFree(GetProcessHeap(), 0, pMem);
  283. return Result;
  284. }
  285. //------------------------------------------------------------------------------------------------
  286. // Stack-allocating UpdateSubresources implementation
  287. template <UINT MaxSubresources>
  288. inline UINT64 UpdateSubresources(
  289. _In_ ID3D12GraphicsCommandList* pCmdList,
  290. _In_ ID3D12Resource* pDestinationResource,
  291. _In_ ID3D12Resource* pIntermediate,
  292. UINT64 IntermediateOffset,
  293. _In_range_(0,MaxSubresources) UINT FirstSubresource,
  294. _In_range_(1,MaxSubresources-FirstSubresource) UINT NumSubresources,
  295. _In_reads_(NumSubresources) const D3D12_SUBRESOURCE_DATA* pSrcData) noexcept
  296. {
  297. UINT64 RequiredSize = 0;
  298. D3D12_PLACED_SUBRESOURCE_FOOTPRINT Layouts[MaxSubresources];
  299. UINT NumRows[MaxSubresources];
  300. UINT64 RowSizesInBytes[MaxSubresources];
  301. #if defined(_MSC_VER) || !defined(_WIN32)
  302. const auto Desc = pDestinationResource->GetDesc();
  303. #else
  304. D3D12_RESOURCE_DESC tmpDesc;
  305. const auto& Desc = *pDestinationResource->GetDesc(&tmpDesc);
  306. #endif
  307. ID3D12Device* pDevice = nullptr;
  308. pDestinationResource->GetDevice(IID_ID3D12Device, reinterpret_cast<void**>(&pDevice));
  309. pDevice->GetCopyableFootprints(&Desc, FirstSubresource, NumSubresources, IntermediateOffset, Layouts, NumRows, RowSizesInBytes, &RequiredSize);
  310. pDevice->Release();
  311. return UpdateSubresources(pCmdList, pDestinationResource, pIntermediate, FirstSubresource, NumSubresources, RequiredSize, Layouts, NumRows, RowSizesInBytes, pSrcData);
  312. }
  313. //------------------------------------------------------------------------------------------------
  314. // Stack-allocating UpdateSubresources implementation
  315. template <UINT MaxSubresources>
  316. inline UINT64 UpdateSubresources(
  317. _In_ ID3D12GraphicsCommandList* pCmdList,
  318. _In_ ID3D12Resource* pDestinationResource,
  319. _In_ ID3D12Resource* pIntermediate,
  320. UINT64 IntermediateOffset,
  321. _In_range_(0,MaxSubresources) UINT FirstSubresource,
  322. _In_range_(1,MaxSubresources-FirstSubresource) UINT NumSubresources,
  323. _In_ const void* pResourceData,
  324. _In_reads_(NumSubresources) const D3D12_SUBRESOURCE_INFO* pSrcData) noexcept
  325. {
  326. UINT64 RequiredSize = 0;
  327. D3D12_PLACED_SUBRESOURCE_FOOTPRINT Layouts[MaxSubresources];
  328. UINT NumRows[MaxSubresources];
  329. UINT64 RowSizesInBytes[MaxSubresources];
  330. #if defined(_MSC_VER) || !defined(_WIN32)
  331. const auto Desc = pDestinationResource->GetDesc();
  332. #else
  333. D3D12_RESOURCE_DESC tmpDesc;
  334. const auto& Desc = *pDestinationResource->GetDesc(&tmpDesc);
  335. #endif
  336. ID3D12Device* pDevice = nullptr;
  337. pDestinationResource->GetDevice(IID_ID3D12Device, reinterpret_cast<void**>(&pDevice));
  338. pDevice->GetCopyableFootprints(&Desc, FirstSubresource, NumSubresources, IntermediateOffset, Layouts, NumRows, RowSizesInBytes, &RequiredSize);
  339. pDevice->Release();
  340. return UpdateSubresources(pCmdList, pDestinationResource, pIntermediate, FirstSubresource, NumSubresources, RequiredSize, Layouts, NumRows, RowSizesInBytes, pResourceData, pSrcData);
  341. }
  342. //------------------------------------------------------------------------------------------------
  343. constexpr bool D3D12IsLayoutOpaque( D3D12_TEXTURE_LAYOUT Layout ) noexcept
  344. { return Layout == D3D12_TEXTURE_LAYOUT_UNKNOWN || Layout == D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE; }
  345. //------------------------------------------------------------------------------------------------
  346. template< typename T >
  347. inline T D3DX12Align(T uValue, T uAlign)
  348. {
  349. // Assert power of 2 alignment
  350. D3DX12_ASSERT(0 == (uAlign & (uAlign - 1)));
  351. T uMask = uAlign - 1;
  352. T uResult = (uValue + uMask) & ~uMask;
  353. D3DX12_ASSERT(uResult >= uValue);
  354. D3DX12_ASSERT(0 == (uResult % uAlign));
  355. return uResult;
  356. }
  357. //------------------------------------------------------------------------------------------------
  358. template< typename T >
  359. inline T D3DX12AlignAtLeast(T uValue, T uAlign)
  360. {
  361. T aligned = D3DX12Align(uValue, uAlign);
  362. return aligned > uAlign ? aligned : uAlign;
  363. }
  364. inline const CD3DX12_RESOURCE_DESC1* D3DX12ConditionallyExpandAPIDesc(
  365. D3D12_RESOURCE_DESC1& LclDesc,
  366. const D3D12_RESOURCE_DESC1* pDesc)
  367. {
  368. return D3DX12ConditionallyExpandAPIDesc(static_cast<CD3DX12_RESOURCE_DESC1&>(LclDesc), static_cast<const CD3DX12_RESOURCE_DESC1*>(pDesc));
  369. }
  370. #if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 606)
  371. //------------------------------------------------------------------------------------------------
  372. // The difference between D3DX12GetCopyableFootprints and ID3D12Device::GetCopyableFootprints
  373. // is that this one loses a lot of error checking by assuming the arguments are correct
  374. inline bool D3DX12GetCopyableFootprints(
  375. _In_ const D3D12_RESOURCE_DESC1& ResourceDesc,
  376. _In_range_(0, D3D12_REQ_SUBRESOURCES) UINT FirstSubresource,
  377. _In_range_(0, D3D12_REQ_SUBRESOURCES - FirstSubresource) UINT NumSubresources,
  378. UINT64 BaseOffset,
  379. _Out_writes_opt_(NumSubresources) D3D12_PLACED_SUBRESOURCE_FOOTPRINT* pLayouts,
  380. _Out_writes_opt_(NumSubresources) UINT* pNumRows,
  381. _Out_writes_opt_(NumSubresources) UINT64* pRowSizeInBytes,
  382. _Out_opt_ UINT64* pTotalBytes)
  383. {
  384. constexpr UINT64 uint64_max = ~0ull;
  385. UINT64 TotalBytes = uint64_max;
  386. UINT uSubRes = 0;
  387. bool bResourceOverflow = false;
  388. TotalBytes = 0;
  389. const DXGI_FORMAT Format = ResourceDesc.Format;
  390. CD3DX12_RESOURCE_DESC1 LresourceDesc;
  391. const CD3DX12_RESOURCE_DESC1& resourceDesc = *D3DX12ConditionallyExpandAPIDesc(LresourceDesc, &ResourceDesc);
  392. // Check if its a valid format
  393. D3DX12_ASSERT(D3D12_PROPERTY_LAYOUT_FORMAT_TABLE::FormatExists(Format));
  394. const UINT WidthAlignment = D3D12_PROPERTY_LAYOUT_FORMAT_TABLE::GetWidthAlignment( Format );
  395. const UINT HeightAlignment = D3D12_PROPERTY_LAYOUT_FORMAT_TABLE::GetHeightAlignment( Format );
  396. const UINT16 DepthAlignment = UINT16( D3D12_PROPERTY_LAYOUT_FORMAT_TABLE::GetDepthAlignment( Format ) );
  397. for (; uSubRes < NumSubresources; ++uSubRes)
  398. {
  399. bool bOverflow = false;
  400. UINT Subresource = FirstSubresource + uSubRes;
  401. D3DX12_ASSERT(resourceDesc.MipLevels != 0);
  402. UINT subresourceCount = resourceDesc.MipLevels * resourceDesc.ArraySize() * D3D12_PROPERTY_LAYOUT_FORMAT_TABLE::GetPlaneCount(resourceDesc.Format);
  403. if (Subresource > subresourceCount)
  404. {
  405. break;
  406. }
  407. TotalBytes = D3DX12Align< UINT64 >( TotalBytes, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT );
  408. UINT MipLevel, ArraySlice, PlaneSlice;
  409. D3D12DecomposeSubresource(Subresource, resourceDesc.MipLevels, resourceDesc.ArraySize(), /*_Out_*/MipLevel, /*_Out_*/ArraySlice, /*_Out_*/PlaneSlice);
  410. const UINT64 Width = D3DX12AlignAtLeast<UINT64>(resourceDesc.Width >> MipLevel, WidthAlignment);
  411. const UINT Height = D3DX12AlignAtLeast(resourceDesc.Height >> MipLevel, HeightAlignment);
  412. const UINT16 Depth = D3DX12AlignAtLeast<UINT16>(resourceDesc.Depth() >> MipLevel, DepthAlignment);
  413. // Adjust for the current PlaneSlice. Most formats have only one plane.
  414. DXGI_FORMAT PlaneFormat;
  415. UINT32 MinPlanePitchWidth, PlaneWidth, PlaneHeight;
  416. D3D12_PROPERTY_LAYOUT_FORMAT_TABLE::GetPlaneSubsampledSizeAndFormatForCopyableLayout(PlaneSlice, Format, (UINT)Width, Height, /*_Out_*/ PlaneFormat, /*_Out_*/ MinPlanePitchWidth, /* _Out_ */ PlaneWidth, /*_Out_*/ PlaneHeight);
  417. D3D12_SUBRESOURCE_FOOTPRINT LocalPlacement;
  418. auto& Placement = pLayouts ? pLayouts[uSubRes].Footprint : LocalPlacement;
  419. Placement.Format = PlaneFormat;
  420. Placement.Width = PlaneWidth;
  421. Placement.Height = PlaneHeight;
  422. Placement.Depth = Depth;
  423. // Calculate row pitch
  424. UINT MinPlaneRowPitch = 0;
  425. D3D12_PROPERTY_LAYOUT_FORMAT_TABLE::CalculateMinimumRowMajorRowPitch(PlaneFormat, MinPlanePitchWidth, MinPlaneRowPitch);
  426. // Formats with more than one plane choose a larger pitch alignment to ensure that each plane begins on the row
  427. // immediately following the previous plane while still adhering to subresource alignment restrictions.
  428. static_assert( D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT >= D3D12_TEXTURE_DATA_PITCH_ALIGNMENT
  429. && ((D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT % D3D12_TEXTURE_DATA_PITCH_ALIGNMENT) == 0),
  430. "D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT must be >= and evenly divisible by D3D12_TEXTURE_DATA_PITCH_ALIGNMENT." );
  431. Placement.RowPitch = D3D12_PROPERTY_LAYOUT_FORMAT_TABLE::Planar(Format)
  432. ? D3DX12Align< UINT >( MinPlaneRowPitch, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT )
  433. : D3DX12Align< UINT >( MinPlaneRowPitch, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT );
  434. if (pRowSizeInBytes)
  435. {
  436. UINT PlaneRowSize = 0;
  437. D3D12_PROPERTY_LAYOUT_FORMAT_TABLE::CalculateMinimumRowMajorRowPitch(PlaneFormat, PlaneWidth, PlaneRowSize);
  438. pRowSizeInBytes[uSubRes] = PlaneRowSize;
  439. }
  440. // Number of rows (accounting for block compression and additional planes)
  441. UINT NumRows = 0;
  442. if (D3D12_PROPERTY_LAYOUT_FORMAT_TABLE::Planar(Format))
  443. {
  444. NumRows = PlaneHeight;
  445. }
  446. else
  447. {
  448. D3DX12_ASSERT(Height % HeightAlignment == 0);
  449. NumRows = Height / HeightAlignment;
  450. }
  451. if (pNumRows)
  452. {
  453. pNumRows[uSubRes] = NumRows;
  454. }
  455. // Offsetting
  456. if (pLayouts)
  457. {
  458. pLayouts[uSubRes].Offset = (bOverflow ? uint64_max : TotalBytes + BaseOffset);
  459. }
  460. const UINT16 NumSlices = Depth;
  461. const UINT64 SubresourceSize = (NumRows * NumSlices - 1) * Placement.RowPitch + MinPlaneRowPitch;
  462. // uint64 addition with overflow checking
  463. TotalBytes = TotalBytes + SubresourceSize;
  464. if(TotalBytes < SubresourceSize)
  465. {
  466. TotalBytes = uint64_max;
  467. }
  468. bResourceOverflow = bResourceOverflow || bOverflow;
  469. }
  470. // Overflow error
  471. if (bResourceOverflow)
  472. {
  473. TotalBytes = uint64_max;
  474. }
  475. if (pLayouts)
  476. {
  477. memset( pLayouts + uSubRes, -1, sizeof( *pLayouts ) * (NumSubresources - uSubRes) );
  478. }
  479. if (pNumRows)
  480. {
  481. memset(pNumRows + uSubRes, -1, sizeof(*pNumRows) * (NumSubresources - uSubRes));
  482. }
  483. if (pRowSizeInBytes)
  484. {
  485. memset(pRowSizeInBytes + uSubRes, -1, sizeof(*pRowSizeInBytes) * (NumSubresources - uSubRes));
  486. }
  487. if (pTotalBytes)
  488. {
  489. *pTotalBytes = TotalBytes;
  490. }
  491. if(TotalBytes == uint64_max)
  492. {
  493. return false;
  494. }
  495. return true;
  496. }
  497. //------------------------------------------------------------------------------------------------
  498. inline D3D12_RESOURCE_DESC1 D3DX12ResourceDesc0ToDesc1(D3D12_RESOURCE_DESC const& desc0)
  499. {
  500. D3D12_RESOURCE_DESC1 desc1;
  501. desc1.Dimension = desc0.Dimension;
  502. desc1.Alignment = desc0.Alignment;
  503. desc1.Width = desc0.Width;
  504. desc1.Height = desc0.Height;
  505. desc1.DepthOrArraySize = desc0.DepthOrArraySize;
  506. desc1.MipLevels = desc0.MipLevels;
  507. desc1.Format = desc0.Format;
  508. desc1.SampleDesc.Count = desc0.SampleDesc.Count;
  509. desc1.SampleDesc.Quality = desc0.SampleDesc.Quality;
  510. desc1.Layout = desc0.Layout;
  511. desc1.Flags = desc0.Flags;
  512. desc1.SamplerFeedbackMipRegion.Width = 0;
  513. desc1.SamplerFeedbackMipRegion.Height = 0;
  514. desc1.SamplerFeedbackMipRegion.Depth = 0;
  515. return desc1;
  516. }
  517. //------------------------------------------------------------------------------------------------
  518. inline bool D3DX12GetCopyableFootprints(
  519. _In_ const D3D12_RESOURCE_DESC& pResourceDesc,
  520. _In_range_(0, D3D12_REQ_SUBRESOURCES) UINT FirstSubresource,
  521. _In_range_(0, D3D12_REQ_SUBRESOURCES - FirstSubresource) UINT NumSubresources,
  522. UINT64 BaseOffset,
  523. _Out_writes_opt_(NumSubresources) D3D12_PLACED_SUBRESOURCE_FOOTPRINT* pLayouts,
  524. _Out_writes_opt_(NumSubresources) UINT* pNumRows,
  525. _Out_writes_opt_(NumSubresources) UINT64* pRowSizeInBytes,
  526. _Out_opt_ UINT64* pTotalBytes)
  527. {
  528. // From D3D12_RESOURCE_DESC to D3D12_RESOURCE_DESC1
  529. D3D12_RESOURCE_DESC1 desc = D3DX12ResourceDesc0ToDesc1(pResourceDesc);
  530. return D3DX12GetCopyableFootprints(
  531. *static_cast<CD3DX12_RESOURCE_DESC1*>(&desc),// From D3D12_RESOURCE_DESC1 to CD3DX12_RESOURCE_DESC1
  532. FirstSubresource,
  533. NumSubresources,
  534. BaseOffset,
  535. pLayouts,
  536. pNumRows,
  537. pRowSizeInBytes,
  538. pTotalBytes);
  539. }
  540. #endif // D3D12_SDK_VERSION >= 606