DeviceResources.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. // The MIT License(MIT)
  2. //
  3. // Copyright(c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy of
  6. // this software and associated documentation files(the "Software"), to deal in
  7. // the Software without restriction, including without limitation the rights to
  8. // use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of
  9. // the Software, and to permit persons to whom the Software is furnished to do so,
  10. // subject to the following conditions :
  11. //
  12. // The above copyright notice and this permission notice shall be included in all
  13. // copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  17. // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR
  18. // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  19. // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  20. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. #include "DeviceResources.h"
  22. #include "d3dx12.h"
  23. #include "Utilities.h"
  24. #include "DXUtilities.h"
  25. void GPUTimer::Initialize(DeviceResources* deviceResources) {
  26. uint64_t GpuFrequency;
  27. deviceResources->commandQueue()->GetTimestampFrequency(&GpuFrequency);
  28. m_gpuTickDelta = 1.0 / static_cast<double>(GpuFrequency);
  29. deviceResources->CreateBuffer(sizeof(uint64_t) * 2, D3D12_HEAP_TYPE_READBACK, D3D12_RESOURCE_STATE_COPY_DEST, &m_readBackBuffer);
  30. m_readBackBuffer->SetName(L"GpuTimeStamp Buffer");
  31. D3D12_QUERY_HEAP_DESC QueryHeapDesc;
  32. QueryHeapDesc.Count = 2;
  33. QueryHeapDesc.NodeMask = 1;
  34. QueryHeapDesc.Type = D3D12_QUERY_HEAP_TYPE_TIMESTAMP;
  35. deviceResources->device()->CreateQueryHeap(&QueryHeapDesc, __uuidof(ID3D12QueryHeap), &m_queryHeap);
  36. m_queryHeap->SetName(L"GpuTimeStamp QueryHeap");
  37. }
  38. void GPUTimer::ReadBack() {
  39. uint64_t* mappedBuffer = nullptr;
  40. D3D12_RANGE range{ 0, sizeof(uint64_t) * 2 };
  41. m_readBackBuffer->Map(0, &range, reinterpret_cast<void**>(&mappedBuffer));
  42. m_timeStart = mappedBuffer[0];
  43. m_timeEnd = mappedBuffer[1];
  44. m_readBackBuffer->Unmap(0, nullptr);
  45. if (m_timeEnd < m_timeStart)
  46. {
  47. m_timeStart = 0;
  48. m_timeEnd = 0;
  49. }
  50. }
  51. void DeviceResources::create(HWND hWnd, uint32_t adapterIdx)
  52. {
  53. ComPtr<IDXGIFactory> pFactory;
  54. CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&pFactory);
  55. ComPtr<IDXGIAdapter> pAdapter;
  56. if (pFactory->EnumAdapters(adapterIdx, &pAdapter) != DXGI_ERROR_NOT_FOUND)
  57. {
  58. DXGI_ADAPTER_DESC desc;
  59. pAdapter->GetDesc(&desc);
  60. char description[256]{};
  61. snprintf(description, sizeof(description), "%ls", desc.Description);
  62. m_adapter.Description = description;
  63. m_adapter.DeviceId = desc.DeviceId;
  64. m_adapter.VendorId = desc.VendorId;
  65. m_adapter.DedicatedSystemMemory = desc.DedicatedSystemMemory;
  66. m_adapter.DedicatedVideoMemory = desc.DedicatedVideoMemory;
  67. m_adapter.SharedSystemMemory = desc.SharedSystemMemory;
  68. }
  69. else
  70. {
  71. throw std::runtime_error("Adapter not found");
  72. }
  73. #ifdef DX12_ENABLE_DEBUG_LAYER
  74. ComPtr<ID3D12Debug> pdx12Debug = nullptr;
  75. if (D3D12GetDebugInterface(__uuidof(ID3D12Debug), &pdx12Debug) == S_OK)
  76. pdx12Debug->EnableDebugLayer();
  77. #endif
  78. // Create device
  79. D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL_12_0;
  80. HRESULT hr = D3D12CreateDevice(pAdapter.Get(), featureLevel, __uuidof(ID3D12Device), &m_device);
  81. // [DEBUG] Setup debug interface to break on any warnings/errors
  82. #ifdef DX12_ENABLE_DEBUG_LAYER
  83. ComPtr<ID3D12InfoQueue> pInfoQueue;
  84. m_device->QueryInterface(__uuidof(ID3D12InfoQueue), &pInfoQueue);
  85. pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, true);
  86. pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, true);
  87. pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING, true);
  88. pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_INFO, true);
  89. pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_MESSAGE, true);
  90. #endif
  91. {
  92. // Command Queue
  93. D3D12_COMMAND_QUEUE_DESC desc = {};
  94. desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
  95. desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
  96. desc.NodeMask = 1;
  97. DX::ThrowIfFailed(m_device->CreateCommandQueue(&desc, __uuidof(ID3D12CommandQueue), &m_commandQueue));
  98. }
  99. {
  100. // Setup swap chain
  101. DXGI_SWAP_CHAIN_DESC1 desc;
  102. ZeroMemory(&desc, sizeof(DXGI_SWAP_CHAIN_DESC1));
  103. desc.BufferCount = NUM_BACK_BUFFERS;
  104. desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
  105. desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH | DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
  106. desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
  107. desc.SampleDesc.Count = 1;
  108. desc.SampleDesc.Quality = 0;
  109. desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
  110. desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
  111. desc.Scaling = DXGI_SCALING_NONE;
  112. desc.Stereo = false;
  113. ComPtr<IDXGIFactory4> dxgiFactory;
  114. ComPtr<IDXGISwapChain1> swapChain1;
  115. DX::ThrowIfFailed(CreateDXGIFactory1(__uuidof(IDXGIFactory4), &dxgiFactory));
  116. DX::ThrowIfFailed(dxgiFactory->CreateSwapChainForHwnd(m_commandQueue.Get(), hWnd, &desc, nullptr, nullptr, &swapChain1));
  117. DX::ThrowIfFailed(swapChain1->QueryInterface(__uuidof(IDXGISwapChain3), &m_swapChain));
  118. m_swapChain->SetMaximumFrameLatency(NUM_BACK_BUFFERS);
  119. m_swapChainWaitableObject = m_swapChain->GetFrameLatencyWaitableObject();
  120. m_frameIndex = m_swapChain->GetCurrentBackBufferIndex();
  121. }
  122. m_RTVDescHeap.Create(m_device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_RTV, NUM_BACK_BUFFERS, D3D12_DESCRIPTOR_HEAP_FLAG_NONE);
  123. m_SRVDescHeap.Create(m_device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 1, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE);
  124. for (UINT i = 0; i < NUM_BACK_BUFFERS; i++)
  125. {
  126. DX::ThrowIfFailed(m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, __uuidof(ID3D12CommandAllocator), &m_frameContext[i].m_allocator));
  127. DX::ThrowIfFailed(m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, __uuidof(ID3D12CommandAllocator), &m_frameContext[i].m_computeAllocator));
  128. }
  129. DX::ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_frameContext[0].m_allocator.Get(), nullptr, __uuidof(ID3D12GraphicsCommandList), &m_commandList));
  130. DX::ThrowIfFailed(m_commandList->Close());
  131. DX::ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_frameContext[0].m_computeAllocator.Get(), nullptr, __uuidof(ID3D12CommandList), &m_computeCommandList));
  132. m_computeCommandList->Close();
  133. CreateRenderTarget();
  134. m_initialized = true;
  135. m_timer.Initialize(this);
  136. }
  137. void DeviceResources::CreateRenderTarget()
  138. {
  139. for (uint32_t i = 0; i < NUM_BACK_BUFFERS; i++)
  140. {
  141. m_swapChain->GetBuffer(i, __uuidof(ID3D12Resource), &m_RTResource[i]);
  142. m_RTResource[i]->SetName(widen("RenderTarget_" + toStr(i)).c_str());
  143. m_device->CreateRenderTargetView(m_RTResource[i].Get(), nullptr, m_RTVDescHeap.getCPUDescriptorHandle(i));
  144. DX::ThrowIfFailed(m_device->CreateFence(0, D3D12_FENCE_FLAG_NONE, __uuidof(ID3D12Fence), &m_frameContext[i].m_fence));
  145. }
  146. }
  147. void DeviceResources::ReleaseRenderTarget()
  148. {
  149. for (uint32_t i = 0; i < NUM_BACK_BUFFERS; i++)
  150. {
  151. m_RTResource[i].Reset();
  152. m_frameContext[i].m_fenceValue = 0;
  153. }
  154. }
  155. void DeviceResources::resizeRenderTarget(uint32_t width, uint32_t height)
  156. {
  157. WaitForGPU();
  158. ReleaseRenderTarget();
  159. DXGI_MODE_DESC desc;
  160. desc.Width = width;
  161. desc.Height = height;
  162. desc.RefreshRate = DXGI_RATIONAL{ 60, 1 };
  163. desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
  164. desc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
  165. desc.Scaling = DXGI_MODE_SCALING_STRETCHED;
  166. DX::ThrowIfFailed(m_swapChain->ResizeTarget(&desc));
  167. DX::ThrowIfFailed(m_swapChain->ResizeBuffers(NUM_BACK_BUFFERS, width, height, DXGI_FORMAT_R8G8B8A8_UNORM,
  168. DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH | DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT));
  169. CreateRenderTarget();
  170. m_frameIndex = m_swapChain->GetCurrentBackBufferIndex();
  171. m_windowResized = true;
  172. }
  173. void DeviceResources::WaitForGPU()
  174. {
  175. for (int i = 0; i < NUM_BACK_BUFFERS; i++)
  176. {
  177. FrameContext* ctx = &m_frameContext[i];
  178. uint64_t fenceValueForSignal = ctx->m_fenceValue + 1;
  179. m_commandQueue->Signal(ctx->m_fence.Get(), fenceValueForSignal);
  180. if (ctx->m_fence.Get()->GetCompletedValue() < fenceValueForSignal)
  181. {
  182. ctx->m_fence.Get()->SetEventOnCompletion(fenceValueForSignal, m_fenceEvent.Get());
  183. WaitForSingleObject(m_fenceEvent.Get(), INFINITE);
  184. }
  185. }
  186. }
  187. void DeviceResources::PopulateCommandList()
  188. {
  189. FrameContext* ctx = &m_frameContext[m_frameIndex];
  190. DX::ThrowIfFailed(ctx->m_allocator->Reset());
  191. m_commandList->Reset(ctx->m_allocator.Get(), nullptr);
  192. DX::ThrowIfFailed(ctx->m_computeAllocator->Reset());
  193. m_computeCommandList->Reset(ctx->m_computeAllocator.Get(), nullptr);
  194. m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_RTResource[m_frameIndex].Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));
  195. const float clear_color_with_alpha[4] = { 0.45f, 0.55f, 0.6f, 1.f };
  196. m_commandList->ClearRenderTargetView(m_RTVDescHeap.getCPUDescriptorHandle(m_frameIndex), clear_color_with_alpha, 0, nullptr);
  197. m_commandList->OMSetRenderTargets(1, &m_RTVDescHeap.getCPUDescriptorHandle(m_frameIndex), false, nullptr);
  198. std::vector<ID3D12DescriptorHeap*> pHeaps{ m_SRVDescHeap.getDescriptorHeap() };
  199. m_commandList->SetDescriptorHeaps(uint32_t(pHeaps.size()), pHeaps.data());
  200. }
  201. void DeviceResources::MoveToNextFrame()
  202. {
  203. FrameContext* ctx = &m_frameContext[m_frameIndex];
  204. DX::ThrowIfFailed(m_commandQueue->Signal(ctx->m_fence.Get(), ctx->m_fenceValue));
  205. m_frameIndex = m_swapChain->GetCurrentBackBufferIndex();
  206. if (ctx->m_fence->GetCompletedValue() < ctx->m_fenceValue)
  207. {
  208. DX::ThrowIfFailed(ctx->m_fence->SetEventOnCompletion(ctx->m_fenceValue, m_fenceEvent.Get()));
  209. WaitForSingleObjectEx(m_fenceEvent.Get(), INFINITE, false);
  210. }
  211. ctx->m_fenceValue++;
  212. }
  213. void DeviceResources::Present(uint32_t SyncInterval, uint32_t Flags)
  214. {
  215. FrameContext* ctx = &m_frameContext[m_frameIndex];
  216. m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_RTResource[m_frameIndex].Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
  217. ID3D12CommandList* commandList[] = { m_computeCommandList.Get(), m_commandList.Get() };
  218. m_commandList->Close();
  219. m_commandQueue->ExecuteCommandLists(2, commandList);
  220. if (m_windowResized)
  221. {
  222. m_windowResized = false;
  223. WaitForGPU();
  224. }
  225. else
  226. {
  227. m_swapChain->Present(SyncInterval, Flags);
  228. m_timer.ReadBack();
  229. }
  230. MoveToNextFrame();
  231. }
  232. void DeviceResources::CreateTexture2D(uint32_t width, uint32_t height, DXGI_FORMAT format, D3D12_RESOURCE_STATES resourceState, ID3D12Resource** pResource)
  233. {
  234. auto heapProperties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT);
  235. auto resourceDesc = CD3DX12_RESOURCE_DESC::Tex2D(format, width, height, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS);
  236. DX::ThrowIfFailed(m_device->CreateCommittedResource(&heapProperties, D3D12_HEAP_FLAG_NONE, &resourceDesc, resourceState, nullptr, __uuidof(ID3D12Resource), (void**)pResource));
  237. }
  238. void DeviceResources::CreateTexture1D(uint32_t width, DXGI_FORMAT format, D3D12_RESOURCE_STATES resourceState, ID3D12Resource** pResource)
  239. {
  240. auto resourceDesc = CD3DX12_RESOURCE_DESC::Tex1D(format, width, 1, 1, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS);
  241. auto heapProperties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT);
  242. DX::ThrowIfFailed(m_device->CreateCommittedResource(&heapProperties, D3D12_HEAP_FLAG_NONE, &resourceDesc, resourceState, nullptr, __uuidof(ID3D12Resource), (void**)pResource));
  243. }
  244. void DeviceResources::CreateBuffer(uint32_t size, D3D12_HEAP_TYPE heapType, D3D12_RESOURCE_STATES resourceState, ID3D12Resource** pResource)
  245. {
  246. auto resourceDesc = CD3DX12_RESOURCE_DESC::Buffer(size);
  247. auto heapProperties = CD3DX12_HEAP_PROPERTIES(heapType);
  248. DX::ThrowIfFailed(m_device->CreateCommittedResource(&heapProperties, D3D12_HEAP_FLAG_NONE, &resourceDesc, resourceState, nullptr, __uuidof(ID3D12Resource), (void**)pResource));
  249. }
  250. void DeviceResources::UploadBufferData(void* data, uint32_t size, ID3D12Resource* pResource, ID3D12Resource* pStagingResource)
  251. {
  252. m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(pResource, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_COPY_DEST));
  253. uint8_t* mappedData = nullptr;
  254. pStagingResource->Map(0, nullptr, reinterpret_cast<void**>(&mappedData));
  255. memcpy(mappedData, data, size);
  256. pStagingResource->Unmap(0, nullptr);
  257. m_commandList->CopyBufferRegion(pResource, 0, pStagingResource, 0, size);
  258. m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(pResource, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COMMON));
  259. }
  260. void DeviceResources::UploadTextureData(void* data, uint32_t size, uint32_t rowPitch, ID3D12Resource* pResource, ID3D12Resource* pStagingResource)
  261. {
  262. m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(pResource, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_COPY_DEST));
  263. uint8_t* mappedData = nullptr;
  264. pStagingResource->Map(0, nullptr, reinterpret_cast<void**>(&mappedData));
  265. memcpy(mappedData, data, size);
  266. pStagingResource->Unmap(0, nullptr);
  267. D3D12_RESOURCE_DESC desc = pResource->GetDesc();
  268. D3D12_PLACED_SUBRESOURCE_FOOTPRINT footprint = {};
  269. footprint.Footprint.Width = uint32_t(desc.Width);
  270. footprint.Footprint.Height = uint32_t(desc.Height);
  271. footprint.Footprint.Depth = 1;
  272. footprint.Footprint.RowPitch = Align(rowPitch, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
  273. footprint.Footprint.Format = desc.Format;
  274. CD3DX12_TEXTURE_COPY_LOCATION src(pStagingResource, footprint);
  275. CD3DX12_TEXTURE_COPY_LOCATION dst(pResource, 0);
  276. m_commandList->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr);
  277. m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(pResource, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COMMON));
  278. }
  279. ID3D12Resource* DeviceResources::getRenderTarget()
  280. {
  281. uint32_t backBufferIdx = m_swapChain->GetCurrentBackBufferIndex();
  282. return m_RTResource[backBufferIdx].Get();
  283. }
  284. void DeviceResources::CopyToRenderTarget(ID3D12Resource* pSrc)
  285. {
  286. auto pDst = getRenderTarget();
  287. m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(pDst, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_DEST));
  288. D3D12_RESOURCE_DESC desc = pDst->GetDesc();
  289. CD3DX12_TEXTURE_COPY_LOCATION src(pSrc, 0);
  290. CD3DX12_TEXTURE_COPY_LOCATION dst(pDst, 0);
  291. D3D12_BOX box{ 0, 0, 0, uint32_t(desc.Width), uint32_t(desc.Height), 1 };
  292. m_commandList->CopyTextureRegion(&dst, 0, 0, 0, &src, &box);
  293. m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(pDst, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_RENDER_TARGET));
  294. }