Sample3DSceneRenderer.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. #include "pch.h"
  2. #include "Sample3DSceneRenderer.h"
  3. #include "..\Common\DirectXHelper.h"
  4. #include <ppltasks.h>
  5. #include <synchapi.h>
  6. using namespace TemplateApp;
  7. using namespace Concurrency;
  8. using namespace DirectX;
  9. using namespace Microsoft::WRL;
  10. using namespace Windows::Foundation;
  11. using namespace Windows::Storage;
  12. // Indices into the application state map.
  13. Platform::String^ AngleKey = "Angle";
  14. Platform::String^ TrackingKey = "Tracking";
  15. // Loads vertex and pixel shaders from files and instantiates the cube geometry.
  16. Sample3DSceneRenderer::Sample3DSceneRenderer(const std::shared_ptr<DX::DeviceResources>& deviceResources) :
  17. m_loadingComplete(false),
  18. m_radiansPerSecond(XM_PIDIV4), // rotate 45 degrees per second
  19. m_angle(0),
  20. m_tracking(false),
  21. m_mappedConstantBuffer(nullptr),
  22. m_deviceResources(deviceResources)
  23. {
  24. LoadState();
  25. ZeroMemory(&m_constantBufferData, sizeof(m_constantBufferData));
  26. CreateDeviceDependentResources();
  27. CreateWindowSizeDependentResources();
  28. }
  29. Sample3DSceneRenderer::~Sample3DSceneRenderer()
  30. {
  31. m_constantBuffer->Unmap(0, nullptr);
  32. m_mappedConstantBuffer = nullptr;
  33. }
  34. void Sample3DSceneRenderer::CreateDeviceDependentResources()
  35. {
  36. auto d3dDevice = m_deviceResources->GetD3DDevice();
  37. // Create a root signature with a single constant buffer slot.
  38. {
  39. CD3DX12_DESCRIPTOR_RANGE range;
  40. CD3DX12_ROOT_PARAMETER parameter;
  41. range.Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0);
  42. parameter.InitAsDescriptorTable(1, &range, D3D12_SHADER_VISIBILITY_VERTEX);
  43. D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags =
  44. D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | // Only the input assembler stage needs access to the constant buffer.
  45. D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |
  46. D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS |
  47. D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS |
  48. D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS;
  49. CD3DX12_ROOT_SIGNATURE_DESC descRootSignature;
  50. descRootSignature.Init(1, &parameter, 0, nullptr, rootSignatureFlags);
  51. ComPtr<ID3DBlob> pSignature;
  52. ComPtr<ID3DBlob> pError;
  53. DX::ThrowIfFailed(D3D12SerializeRootSignature(&descRootSignature, D3D_ROOT_SIGNATURE_VERSION_1, pSignature.GetAddressOf(), pError.GetAddressOf()));
  54. DX::ThrowIfFailed(d3dDevice->CreateRootSignature(0, pSignature->GetBufferPointer(), pSignature->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature)));
  55. }
  56. // Load shaders asynchronously.
  57. auto createVSTask = DX::ReadDataAsync(L"SampleVertexShader.cso").then([this](std::vector<byte>& fileData) {
  58. m_vertexShader = fileData;
  59. });
  60. auto createPSTask = DX::ReadDataAsync(L"SamplePixelShader.cso").then([this](std::vector<byte>& fileData) {
  61. m_pixelShader = fileData;
  62. });
  63. // Create the pipeline state once the shaders are loaded.
  64. auto createPipelineStateTask = (createPSTask && createVSTask).then([this]() {
  65. static const D3D12_INPUT_ELEMENT_DESC inputLayout[] =
  66. {
  67. { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  68. { "COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  69. };
  70. D3D12_GRAPHICS_PIPELINE_STATE_DESC state = {};
  71. state.InputLayout = { inputLayout, _countof(inputLayout) };
  72. state.pRootSignature = m_rootSignature.Get();
  73. state.VS = { &m_vertexShader[0], m_vertexShader.size() };
  74. state.PS = { &m_pixelShader[0], m_pixelShader.size() };
  75. state.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
  76. state.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
  77. state.DepthStencilState.DepthEnable = FALSE;
  78. state.DepthStencilState.StencilEnable = FALSE;
  79. state.SampleMask = UINT_MAX;
  80. state.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
  81. state.NumRenderTargets = 1;
  82. state.RTVFormats[0] = DXGI_FORMAT_B8G8R8A8_UNORM;
  83. state.SampleDesc.Count = 1;
  84. DX::ThrowIfFailed(m_deviceResources->GetD3DDevice()->CreateGraphicsPipelineState(&state, IID_PPV_ARGS(&m_pipelineState)));
  85. // Shader data can be deleted once the pipeline state is created.
  86. m_vertexShader.clear();
  87. m_pixelShader.clear();
  88. });
  89. // Create and upload cube geometry resources to the GPU.
  90. auto createAssetsTask = createPipelineStateTask.then([this]() {
  91. auto d3dDevice = m_deviceResources->GetD3DDevice();
  92. // Create a command list.
  93. DX::ThrowIfFailed(d3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_deviceResources->GetCommandAllocator(), m_pipelineState.Get(), IID_PPV_ARGS(&m_commandList)));
  94. // Cube vertices. Each vertex has a position and a color.
  95. VertexPositionColor cubeVertices[] =
  96. {
  97. { XMFLOAT3(-0.5f, -0.5f, -0.5f), XMFLOAT3(0.0f, 0.0f, 0.0f) },
  98. { XMFLOAT3(-0.5f, -0.5f, 0.5f), XMFLOAT3(0.0f, 0.0f, 1.0f) },
  99. { XMFLOAT3(-0.5f, 0.5f, -0.5f), XMFLOAT3(0.0f, 1.0f, 0.0f) },
  100. { XMFLOAT3(-0.5f, 0.5f, 0.5f), XMFLOAT3(0.0f, 1.0f, 1.0f) },
  101. { XMFLOAT3(0.5f, -0.5f, -0.5f), XMFLOAT3(1.0f, 0.0f, 0.0f) },
  102. { XMFLOAT3(0.5f, -0.5f, 0.5f), XMFLOAT3(1.0f, 0.0f, 1.0f) },
  103. { XMFLOAT3(0.5f, 0.5f, -0.5f), XMFLOAT3(1.0f, 1.0f, 0.0f) },
  104. { XMFLOAT3(0.5f, 0.5f, 0.5f), XMFLOAT3(1.0f, 1.0f, 1.0f) },
  105. };
  106. const UINT vertexBufferSize = sizeof(cubeVertices);
  107. // Create the vertex buffer resource in the GPU's default heap and copy vertex data into it using the upload heap.
  108. // The upload resource must not be released until after the GPU has finished using it.
  109. Microsoft::WRL::ComPtr<ID3D12Resource> vertexBufferUpload;
  110. CD3DX12_HEAP_PROPERTIES defaultHeapProperties(D3D12_HEAP_TYPE_DEFAULT);
  111. CD3DX12_RESOURCE_DESC vertexBufferDesc = CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize);
  112. DX::ThrowIfFailed(d3dDevice->CreateCommittedResource(
  113. &defaultHeapProperties,
  114. D3D12_HEAP_FLAG_NONE,
  115. &vertexBufferDesc,
  116. D3D12_RESOURCE_STATE_COPY_DEST,
  117. nullptr,
  118. IID_PPV_ARGS(&m_vertexBuffer)));
  119. CD3DX12_HEAP_PROPERTIES uploadHeapProperties(D3D12_HEAP_TYPE_UPLOAD);
  120. DX::ThrowIfFailed(d3dDevice->CreateCommittedResource(
  121. &uploadHeapProperties,
  122. D3D12_HEAP_FLAG_NONE,
  123. &vertexBufferDesc,
  124. D3D12_RESOURCE_STATE_GENERIC_READ,
  125. nullptr,
  126. IID_PPV_ARGS(&vertexBufferUpload)));
  127. m_vertexBuffer->SetName(L"Vertex Buffer Resource");
  128. vertexBufferUpload->SetName(L"Vertex Buffer Upload Resource");
  129. // Upload the vertex buffer to the GPU.
  130. {
  131. D3D12_SUBRESOURCE_DATA vertexData = {};
  132. vertexData.pData = reinterpret_cast<BYTE*>(cubeVertices);
  133. vertexData.RowPitch = vertexBufferSize;
  134. vertexData.SlicePitch = vertexData.RowPitch;
  135. UpdateSubresources(m_commandList.Get(), m_vertexBuffer.Get(), vertexBufferUpload.Get(), 0, 0, 1, &vertexData);
  136. CD3DX12_RESOURCE_BARRIER vertexBufferResourceBarrier =
  137. CD3DX12_RESOURCE_BARRIER::Transition(m_vertexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
  138. m_commandList->ResourceBarrier(1, &vertexBufferResourceBarrier);
  139. }
  140. // Load mesh indices. Each trio of indices represents a triangle to be rendered on the screen.
  141. // For example: 0,2,1 means that the vertices with indexes 0, 2 and 1 from the vertex buffer compose the
  142. // first triangle of this mesh.
  143. unsigned short cubeIndices[] =
  144. {
  145. 0, 2, 1, // -x
  146. 1, 2, 3,
  147. 4, 5, 6, // +x
  148. 5, 7, 6,
  149. 0, 1, 5, // -y
  150. 0, 5, 4,
  151. 2, 6, 7, // +y
  152. 2, 7, 3,
  153. 0, 4, 6, // -z
  154. 0, 6, 2,
  155. 1, 3, 7, // +z
  156. 1, 7, 5,
  157. };
  158. const UINT indexBufferSize = sizeof(cubeIndices);
  159. // Create the index buffer resource in the GPU's default heap and copy index data into it using the upload heap.
  160. // The upload resource must not be released until after the GPU has finished using it.
  161. Microsoft::WRL::ComPtr<ID3D12Resource> indexBufferUpload;
  162. CD3DX12_RESOURCE_DESC indexBufferDesc = CD3DX12_RESOURCE_DESC::Buffer(indexBufferSize);
  163. DX::ThrowIfFailed(d3dDevice->CreateCommittedResource(
  164. &defaultHeapProperties,
  165. D3D12_HEAP_FLAG_NONE,
  166. &indexBufferDesc,
  167. D3D12_RESOURCE_STATE_COPY_DEST,
  168. nullptr,
  169. IID_PPV_ARGS(&m_indexBuffer)));
  170. DX::ThrowIfFailed(d3dDevice->CreateCommittedResource(
  171. &uploadHeapProperties,
  172. D3D12_HEAP_FLAG_NONE,
  173. &indexBufferDesc,
  174. D3D12_RESOURCE_STATE_GENERIC_READ,
  175. nullptr,
  176. IID_PPV_ARGS(&indexBufferUpload)));
  177. m_indexBuffer->SetName(L"Index Buffer Resource");
  178. indexBufferUpload->SetName(L"Index Buffer Upload Resource");
  179. // Upload the index buffer to the GPU.
  180. {
  181. D3D12_SUBRESOURCE_DATA indexData = {};
  182. indexData.pData = reinterpret_cast<BYTE*>(cubeIndices);
  183. indexData.RowPitch = indexBufferSize;
  184. indexData.SlicePitch = indexData.RowPitch;
  185. UpdateSubresources(m_commandList.Get(), m_indexBuffer.Get(), indexBufferUpload.Get(), 0, 0, 1, &indexData);
  186. CD3DX12_RESOURCE_BARRIER indexBufferResourceBarrier =
  187. CD3DX12_RESOURCE_BARRIER::Transition(m_indexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
  188. m_commandList->ResourceBarrier(1, &indexBufferResourceBarrier);
  189. }
  190. // Create a descriptor heap for the constant buffers.
  191. {
  192. D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};
  193. heapDesc.NumDescriptors = DX::c_frameCount;
  194. heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
  195. // This flag indicates that this descriptor heap can be bound to the pipeline and that descriptors contained in it can be referenced by a root table.
  196. heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
  197. DX::ThrowIfFailed(d3dDevice->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&m_cbvHeap)));
  198. m_cbvHeap->SetName(L"Constant Buffer View Descriptor Heap");
  199. }
  200. CD3DX12_RESOURCE_DESC constantBufferDesc = CD3DX12_RESOURCE_DESC::Buffer(DX::c_frameCount * c_alignedConstantBufferSize);
  201. DX::ThrowIfFailed(d3dDevice->CreateCommittedResource(
  202. &uploadHeapProperties,
  203. D3D12_HEAP_FLAG_NONE,
  204. &constantBufferDesc,
  205. D3D12_RESOURCE_STATE_GENERIC_READ,
  206. nullptr,
  207. IID_PPV_ARGS(&m_constantBuffer)));
  208. m_constantBuffer->SetName(L"Constant Buffer");
  209. // Create constant buffer views to access the upload buffer.
  210. D3D12_GPU_VIRTUAL_ADDRESS cbvGpuAddress = m_constantBuffer->GetGPUVirtualAddress();
  211. CD3DX12_CPU_DESCRIPTOR_HANDLE cbvCpuHandle(m_cbvHeap->GetCPUDescriptorHandleForHeapStart());
  212. m_cbvDescriptorSize = d3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
  213. for (int n = 0; n < DX::c_frameCount; n++)
  214. {
  215. D3D12_CONSTANT_BUFFER_VIEW_DESC desc;
  216. desc.BufferLocation = cbvGpuAddress;
  217. desc.SizeInBytes = c_alignedConstantBufferSize;
  218. d3dDevice->CreateConstantBufferView(&desc, cbvCpuHandle);
  219. cbvGpuAddress += desc.SizeInBytes;
  220. cbvCpuHandle.Offset(m_cbvDescriptorSize);
  221. }
  222. // Map the constant buffers.
  223. DX::ThrowIfFailed(m_constantBuffer->Map(0, nullptr, reinterpret_cast<void**>(&m_mappedConstantBuffer)));
  224. ZeroMemory(m_mappedConstantBuffer, DX::c_frameCount * c_alignedConstantBufferSize);
  225. // We don't unmap this until the app closes. Keeping things mapped for the lifetime of the resource is okay.
  226. // Close the command list and execute it to begin the vertex/index buffer copy into the GPU's default heap.
  227. DX::ThrowIfFailed(m_commandList->Close());
  228. ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() };
  229. m_deviceResources->GetCommandQueue()->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);
  230. // Create vertex/index buffer views.
  231. m_vertexBufferView.BufferLocation = m_vertexBuffer->GetGPUVirtualAddress();
  232. m_vertexBufferView.StrideInBytes = sizeof(VertexPositionColor);
  233. m_vertexBufferView.SizeInBytes = sizeof(cubeVertices);
  234. m_indexBufferView.BufferLocation = m_indexBuffer->GetGPUVirtualAddress();
  235. m_indexBufferView.SizeInBytes = sizeof(cubeIndices);
  236. m_indexBufferView.Format = DXGI_FORMAT_R16_UINT;
  237. // Wait for the command list to finish executing; the vertex/index buffers need to be uploaded to the GPU before the upload resources go out of scope.
  238. m_deviceResources->WaitForGpu();
  239. });
  240. createAssetsTask.then([this]() {
  241. m_loadingComplete = true;
  242. });
  243. }
  244. // Initializes view parameters when the window size changes.
  245. void Sample3DSceneRenderer::CreateWindowSizeDependentResources()
  246. {
  247. Size outputSize = m_deviceResources->GetOutputSize();
  248. float aspectRatio = outputSize.Width / outputSize.Height;
  249. float fovAngleY = 70.0f * XM_PI / 180.0f;
  250. D3D12_VIEWPORT viewport = m_deviceResources->GetScreenViewport();
  251. m_scissorRect = { 0, 0, static_cast<LONG>(viewport.Width), static_cast<LONG>(viewport.Height)};
  252. // This is a simple example of change that can be made when the app is in
  253. // portrait or snapped view.
  254. if (aspectRatio < 1.0f)
  255. {
  256. fovAngleY *= 2.0f;
  257. }
  258. // Note that the OrientationTransform3D matrix is post-multiplied here
  259. // in order to correctly orient the scene to match the display orientation.
  260. // This post-multiplication step is required for any draw calls that are
  261. // made to the swap chain render target. For draw calls to other targets,
  262. // this transform should not be applied.
  263. // This sample makes use of a right-handed coordinate system using row-major matrices.
  264. XMMATRIX perspectiveMatrix = XMMatrixPerspectiveFovRH(
  265. fovAngleY,
  266. aspectRatio,
  267. 0.01f,
  268. 100.0f
  269. );
  270. XMFLOAT4X4 orientation = m_deviceResources->GetOrientationTransform3D();
  271. XMMATRIX orientationMatrix = XMLoadFloat4x4(&orientation);
  272. XMStoreFloat4x4(
  273. &m_constantBufferData.projection,
  274. XMMatrixTranspose(perspectiveMatrix * orientationMatrix)
  275. );
  276. // Eye is at (0,0.7,1.5), looking at point (0,-0.1,0) with the up-vector along the y-axis.
  277. static const XMVECTORF32 eye = { 0.0f, 0.7f, 1.5f, 0.0f };
  278. static const XMVECTORF32 at = { 0.0f, -0.1f, 0.0f, 0.0f };
  279. static const XMVECTORF32 up = { 0.0f, 1.0f, 0.0f, 0.0f };
  280. XMStoreFloat4x4(&m_constantBufferData.view, XMMatrixTranspose(XMMatrixLookAtRH(eye, at, up)));
  281. }
  282. // Called once per frame, rotates the cube and calculates the model and view matrices.
  283. void Sample3DSceneRenderer::Update(DX::StepTimer const& timer)
  284. {
  285. if (m_loadingComplete)
  286. {
  287. if (!m_tracking)
  288. {
  289. // Rotate the cube a small amount.
  290. m_angle += static_cast<float>(timer.GetElapsedSeconds()) * m_radiansPerSecond;
  291. Rotate(m_angle);
  292. }
  293. // Update the constant buffer resource.
  294. UINT8* destination = m_mappedConstantBuffer + (m_deviceResources->GetCurrentFrameIndex() * c_alignedConstantBufferSize);
  295. memcpy(destination, &m_constantBufferData, sizeof(m_constantBufferData));
  296. }
  297. }
  298. // Saves the current state of the renderer.
  299. void Sample3DSceneRenderer::SaveState()
  300. {
  301. auto state = ApplicationData::Current->LocalSettings->Values;
  302. if (state->HasKey(AngleKey))
  303. {
  304. state->Remove(AngleKey);
  305. }
  306. if (state->HasKey(TrackingKey))
  307. {
  308. state->Remove(TrackingKey);
  309. }
  310. state->Insert(AngleKey, PropertyValue::CreateSingle(m_angle));
  311. state->Insert(TrackingKey, PropertyValue::CreateBoolean(m_tracking));
  312. }
  313. // Restores the previous state of the renderer.
  314. void Sample3DSceneRenderer::LoadState()
  315. {
  316. auto state = ApplicationData::Current->LocalSettings->Values;
  317. if (state->HasKey(AngleKey))
  318. {
  319. m_angle = safe_cast<IPropertyValue^>(state->Lookup(AngleKey))->GetSingle();
  320. state->Remove(AngleKey);
  321. }
  322. if (state->HasKey(TrackingKey))
  323. {
  324. m_tracking = safe_cast<IPropertyValue^>(state->Lookup(TrackingKey))->GetBoolean();
  325. state->Remove(TrackingKey);
  326. }
  327. }
  328. // Rotate the 3D cube model a set amount of radians.
  329. void Sample3DSceneRenderer::Rotate(float radians)
  330. {
  331. // Prepare to pass the updated model matrix to the shader.
  332. XMStoreFloat4x4(&m_constantBufferData.model, XMMatrixTranspose(XMMatrixRotationY(radians)));
  333. }
  334. void Sample3DSceneRenderer::StartTracking()
  335. {
  336. m_tracking = true;
  337. }
  338. // When tracking, the 3D cube can be rotated around its Y axis by tracking pointer position relative to the output screen width.
  339. void Sample3DSceneRenderer::TrackingUpdate(float positionX)
  340. {
  341. if (m_tracking)
  342. {
  343. float radians = XM_2PI * 2.0f * positionX / m_deviceResources->GetOutputSize().Width;
  344. Rotate(radians);
  345. }
  346. }
  347. void Sample3DSceneRenderer::StopTracking()
  348. {
  349. m_tracking = false;
  350. }
  351. // Renders one frame using the vertex and pixel shaders.
  352. bool Sample3DSceneRenderer::Render()
  353. {
  354. // Loading is asynchronous. Only draw geometry after it's loaded.
  355. if (!m_loadingComplete)
  356. {
  357. return false;
  358. }
  359. DX::ThrowIfFailed(m_deviceResources->GetCommandAllocator()->Reset());
  360. // The command list can be reset anytime after ExecuteCommandList() is called.
  361. DX::ThrowIfFailed(m_commandList->Reset(m_deviceResources->GetCommandAllocator(), m_pipelineState.Get()));
  362. PIXBeginEvent(m_commandList.Get(), 0, L"Draw the cube");
  363. {
  364. // Set the graphics root signature and descriptor heaps to be used by this frame.
  365. m_commandList->SetGraphicsRootSignature(m_rootSignature.Get());
  366. ID3D12DescriptorHeap* ppHeaps[] = { m_cbvHeap.Get() };
  367. m_commandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps);
  368. // Bind the current frame's constant buffer to the pipeline.
  369. CD3DX12_GPU_DESCRIPTOR_HANDLE gpuHandle(m_cbvHeap->GetGPUDescriptorHandleForHeapStart(), m_deviceResources->GetCurrentFrameIndex(), m_cbvDescriptorSize);
  370. m_commandList->SetGraphicsRootDescriptorTable(0, gpuHandle);
  371. // Set the viewport and scissor rectangle.
  372. D3D12_VIEWPORT viewport = m_deviceResources->GetScreenViewport();
  373. m_commandList->RSSetViewports(1, &viewport);
  374. m_commandList->RSSetScissorRects(1, &m_scissorRect);
  375. // Indicate this resource will be in use as a render target.
  376. CD3DX12_RESOURCE_BARRIER renderTargetResourceBarrier =
  377. CD3DX12_RESOURCE_BARRIER::Transition(m_deviceResources->GetRenderTarget(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
  378. m_commandList->ResourceBarrier(1, &renderTargetResourceBarrier);
  379. // Record drawing commands.
  380. m_commandList->ClearRenderTargetView(m_deviceResources->GetRenderTargetView(), DirectX::Colors::CornflowerBlue, 0, nullptr);
  381. D3D12_CPU_DESCRIPTOR_HANDLE renderTargetView = m_deviceResources->GetRenderTargetView();
  382. m_commandList->OMSetRenderTargets(1, &renderTargetView, false, nullptr);
  383. m_commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
  384. m_commandList->IASetVertexBuffers(0, 1, &m_vertexBufferView);
  385. m_commandList->IASetIndexBuffer(&m_indexBufferView);
  386. m_commandList->DrawIndexedInstanced(36, 1, 0, 0, 0);
  387. // Indicate that the render target will now be used to present when the command list is done executing.
  388. CD3DX12_RESOURCE_BARRIER presentResourceBarrier =
  389. CD3DX12_RESOURCE_BARRIER::Transition(m_deviceResources->GetRenderTarget(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
  390. m_commandList->ResourceBarrier(1, &presentResourceBarrier);
  391. }
  392. PIXEndEvent(m_commandList.Get());
  393. DX::ThrowIfFailed(m_commandList->Close());
  394. // Execute the command list.
  395. ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() };
  396. m_deviceResources->GetCommandQueue()->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);
  397. return true;
  398. }