void Cloud::Renderer::DebugRenderer::RecordCommandList(ID3D12GraphicsCommandList* commandList) { auto& renderCore = RenderCore::Instance(); std::array<ID3D12DescriptorHeap*, 1> heaps = { renderCore.GetCbvHeap() }; commandList->SetDescriptorHeaps(gsl::narrow_cast<CLuint>(heaps.size()), heaps.data()); commandList->SetGraphicsRootSignature(renderCore.GetRootSignature()); commandList->SetGraphicsRootConstantBufferView(0, renderCore.GetPerSceneConstBuffer().GetCurrentVersionGpuAddress()); commandList->SetGraphicsRootConstantBufferView(1, renderCore.GetPerModelConstBuffer().GetCurrentVersionGpuAddress()); static const auto c_cbvDescriptorSize = renderCore.GetDevice()->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); CD3DX12_GPU_DESCRIPTOR_HANDLE srvHandle(renderCore.GetCbvHeap()->GetGPUDescriptorHandleForHeapStart(), 2, c_cbvDescriptorSize); commandList->SetGraphicsRootDescriptorTable(3, srvHandle); commandList->RSSetViewports(1, &renderCore.GetViewPort()); commandList->RSSetScissorRects(1, &renderCore.GetScissorRect()); auto&& rtvHandle = renderCore.GetCurrentBackBuffer(); auto&& dsvHandle = renderCore.GetDepthStencil()->GetDsv(); commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, &dsvHandle); // clear depth? RenderBoxes(commandList); RenderQuads(commandList); RenderLine2D(); m_boxesToRender = 0; m_quadsToRender = 0; m_line2DsToRender = 0; }
// Fill the command list with all the render commands and dependent state. void D3D12SmallResources::PopulateCommandList() { // Command list allocators can only be reset when the associated // command lists have finished execution on the GPU; apps should use // fences to determine GPU execution progress. ThrowIfFailed(m_commandAllocators[m_frameIndex]->Reset()); // However, when ExecuteCommandList() is called on a particular command // list, that command list can then be reset at any time and must be before // re-recording. ThrowIfFailed(m_commandList->Reset(m_commandAllocators[m_frameIndex].Get(), m_pipelineState.Get())); // Set necessary state. m_commandList->SetGraphicsRootSignature(m_rootSignature.Get()); ID3D12DescriptorHeap* ppHeaps[] = { m_srvHeap.Get() }; m_commandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); m_commandList->RSSetViewports(1, &m_viewport); m_commandList->RSSetScissorRects(1, &m_scissorRect); // Indicate that the back buffer will be used as a render target. m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_frameIndex].Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET)); CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart(), m_frameIndex, m_rtvDescriptorSize); m_commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr); // Record drawing commands. const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f }; m_commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr); // Draw the grid. { m_commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); m_commandList->IASetVertexBuffers(0, 1, &m_vertexBufferView); // Draw the far quad conditionally based on the result of the occlusion query // from the previous frame. PIXBeginEvent(m_commandList.Get(), 0, L"Draw grid"); CD3DX12_GPU_DESCRIPTOR_HANDLE srvHandle(m_srvHeap->GetGPUDescriptorHandleForHeapStart()); for (UINT n = 0; n < TextureCount; n++) { m_commandList->SetGraphicsRootDescriptorTable(0, srvHandle); m_commandList->DrawInstanced(4, 1, n * 4, 0); srvHandle.Offset(m_srvDescriptorSize); } PIXEndEvent(m_commandList.Get()); } // Indicate that the back buffer will now be used to present. m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_frameIndex].Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT)); ThrowIfFailed(m_commandList->Close()); }
// Load resources that are dependent on the size of the main window. void D3D12HDR::LoadSizeDependentResources() { // Create frame resources. { CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart()); // Create a RTV for each frame. for (UINT n = 0; n < FrameCount; n++) { ThrowIfFailed(m_swapChain->GetBuffer(n, IID_PPV_ARGS(&m_renderTargets[n]))); m_device->CreateRenderTargetView(m_renderTargets[n].Get(), nullptr, rtvHandle); rtvHandle.Offset(1, m_rtvDescriptorSize); NAME_D3D12_OBJECT_INDEXED(m_renderTargets, n); } // Create the intermediate render target and an RTV for it. D3D12_RESOURCE_DESC renderTargetDesc = m_renderTargets[0]->GetDesc(); renderTargetDesc.Format = m_intermediateRenderTargetFormat; D3D12_CLEAR_VALUE clearValue = {}; clearValue.Format = m_intermediateRenderTargetFormat; ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &renderTargetDesc, D3D12_RESOURCE_STATE_RENDER_TARGET, &clearValue, IID_PPV_ARGS(&m_intermediateRenderTarget))); NAME_D3D12_OBJECT(m_intermediateRenderTarget); m_device->CreateRenderTargetView(m_intermediateRenderTarget.Get(), nullptr, rtvHandle); rtvHandle.Offset(1, m_rtvDescriptorSize); CD3DX12_CPU_DESCRIPTOR_HANDLE srvHandle(m_srvHeap->GetCPUDescriptorHandleForHeapStart()); m_device->CreateShaderResourceView(m_intermediateRenderTarget.Get(), nullptr, srvHandle); srvHandle.Offset(1, m_srvDescriptorSize); // Create the UI render target and an RTV for it. renderTargetDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; clearValue.Format = renderTargetDesc.Format; ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &renderTargetDesc, D3D12_RESOURCE_STATE_RENDER_TARGET, &clearValue, IID_PPV_ARGS(&m_UIRenderTarget))); NAME_D3D12_OBJECT(m_UIRenderTarget); m_device->CreateRenderTargetView(m_UIRenderTarget.Get(), nullptr, rtvHandle); m_device->CreateShaderResourceView(m_UIRenderTarget.Get(), nullptr, srvHandle); } m_viewport.Width = static_cast<float>(m_width); m_viewport.Height = static_cast<float>(m_height); m_scissorRect.left = 0; m_scissorRect.top = 0; m_scissorRect.right = static_cast<LONG>(m_width); m_scissorRect.bottom = static_cast<LONG>(m_height); // Update the color space triangle vertices when the command list is back in // the recording state. m_updateVertexBuffer = true; if (m_enableUI) { if (!m_uiLayer) { m_uiLayer = std::make_shared<UILayer>(this); } else { m_uiLayer->Resize(); } } }
// Fill the command list with all the render commands and dependent state. void D3D12HeterogeneousMultiadapter::PopulateCommandLists() { // Command list to render target the triangles on the primary adapter. { const GraphicsAdapter adapter = Primary; // Command list allocators can only be reset when the associated // command lists have finished execution on the GPU; apps should use // fences to determine GPU execution progress. ThrowIfFailed(m_directCommandAllocators[adapter][m_frameIndex]->Reset()); // However, when ExecuteCommandList() is called on a particular command // list, that command list can then be reset at any time and must be before // re-recording. ThrowIfFailed(m_directCommandLists[adapter]->Reset(m_directCommandAllocators[adapter][m_frameIndex].Get(), m_pipelineState.Get())); // Get a timestamp at the start of the command list. const UINT timestampHeapIndex = 2 * m_frameIndex; m_directCommandLists[adapter]->EndQuery(m_timestampQueryHeaps[adapter].Get(), D3D12_QUERY_TYPE_TIMESTAMP, timestampHeapIndex); // Set necessary state. m_directCommandLists[adapter]->SetGraphicsRootSignature(m_rootSignature.Get()); m_directCommandLists[adapter]->RSSetViewports(1, &m_viewport); m_directCommandLists[adapter]->RSSetScissorRects(1, &m_scissorRect); // Indicate that the render target will be used as a render target. m_directCommandLists[adapter]->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[adapter][m_frameIndex].Get(), D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET)); CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeaps[adapter]->GetCPUDescriptorHandleForHeapStart(), m_frameIndex, m_rtvDescriptorSizes[adapter]); CD3DX12_CPU_DESCRIPTOR_HANDLE dsvHandle(m_dsvHeap->GetCPUDescriptorHandleForHeapStart()); m_directCommandLists[adapter]->OMSetRenderTargets(1, &rtvHandle, false, &dsvHandle); // Record commands. m_directCommandLists[adapter]->ClearRenderTargetView(rtvHandle, ClearColor, 0, nullptr); m_directCommandLists[adapter]->ClearDepthStencilView(dsvHandle, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr); // Draw the triangles. m_directCommandLists[adapter]->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); m_directCommandLists[adapter]->IASetVertexBuffers(0, 1, &m_vertexBufferView); m_directCommandLists[adapter]->SetGraphicsRootConstantBufferView(1, m_workloadConstantBuffer->GetGPUVirtualAddress() + (m_frameIndex * sizeof(WorkloadConstantBufferData))); const D3D12_GPU_VIRTUAL_ADDRESS cbVirtualAddress = m_constantBuffer->GetGPUVirtualAddress(); for (UINT n = 0; n < m_triangleCount; n++) { const D3D12_GPU_VIRTUAL_ADDRESS cbLocation = cbVirtualAddress + (m_frameIndex * MaxTriangleCount * sizeof(ConstantBufferData)) + (n * sizeof(ConstantBufferData)); m_directCommandLists[adapter]->SetGraphicsRootConstantBufferView(0, cbLocation); m_directCommandLists[adapter]->DrawInstanced(3, 1, 0, 0); } // Indicate that the render target will now be used to copy. m_directCommandLists[adapter]->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[adapter][m_frameIndex].Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE)); // Get a timestamp at the end of the command list and resolve the query data. m_directCommandLists[adapter]->EndQuery(m_timestampQueryHeaps[adapter].Get(), D3D12_QUERY_TYPE_TIMESTAMP, timestampHeapIndex + 1); m_directCommandLists[adapter]->ResolveQueryData(m_timestampQueryHeaps[adapter].Get(), D3D12_QUERY_TYPE_TIMESTAMP, timestampHeapIndex, 2, m_timestampResultBuffers[adapter].Get(), timestampHeapIndex * sizeof(UINT64)); ThrowIfFailed(m_directCommandLists[adapter]->Close()); } // Command list to copy the render target to the shared heap on the primary adapter. { const GraphicsAdapter adapter = Primary; // Reset the copy command allocator and command list. ThrowIfFailed(m_copyCommandAllocators[m_frameIndex]->Reset()); ThrowIfFailed(m_copyCommandList->Reset(m_copyCommandAllocators[m_frameIndex].Get(), nullptr)); // Copy the resource to the cross-adapter shared resource m_copyCommandList->CopyResource(m_crossAdapterResources[adapter][m_frameIndex].Get(), m_renderTargets[adapter][m_frameIndex].Get()); ThrowIfFailed(m_copyCommandList->Close()); } // Command list to blur the render target and present. { const GraphicsAdapter adapter = Secondary; // Command list allocators can only be reset when the associated // command lists have finished execution on the GPU; apps should use // fences to determine GPU execution progress. ThrowIfFailed(m_directCommandAllocators[adapter][m_frameIndex]->Reset()); // However, when ExecuteCommandList() is called on a particular command // list, that command list can then be reset at any time and must be before // re-recording. ThrowIfFailed(m_directCommandLists[adapter]->Reset(m_directCommandAllocators[adapter][m_frameIndex].Get(), m_blurPipelineStates[0].Get())); // Get a timestamp at the start of the command list. const UINT timestampHeapIndex = 2 * m_frameIndex; m_directCommandLists[adapter]->EndQuery(m_timestampQueryHeaps[adapter].Get(), D3D12_QUERY_TYPE_TIMESTAMP, timestampHeapIndex); // Set necessary state. m_directCommandLists[adapter]->SetGraphicsRootSignature(m_blurRootSignature.Get()); ID3D12DescriptorHeap* ppHeaps[] = { m_cbvSrvUavHeap.Get() }; m_directCommandLists[adapter]->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); m_directCommandLists[adapter]->RSSetViewports(1, &m_viewport); m_directCommandLists[adapter]->RSSetScissorRects(1, &m_scissorRect); // Indicate that the intermediate render target will be used as a render target. m_directCommandLists[adapter]->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_intermediateBlurRenderTarget.Get(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET)); // Record commands. m_directCommandLists[adapter]->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); m_directCommandLists[adapter]->IASetVertexBuffers(0, 1, &m_fullscreenQuadVertexBufferView); m_directCommandLists[adapter]->SetGraphicsRootConstantBufferView(0, m_blurConstantBuffer->GetGPUVirtualAddress()); m_directCommandLists[adapter]->SetGraphicsRootConstantBufferView(2, m_blurWorkloadConstantBuffer->GetGPUVirtualAddress() + (m_frameIndex * sizeof(WorkloadConstantBufferData))); // Draw the fullscreen quad - Blur pass #1. { CD3DX12_GPU_DESCRIPTOR_HANDLE srvHandle(m_cbvSrvUavHeap->GetGPUDescriptorHandleForHeapStart(), m_frameIndex, m_srvDescriptorSizes[adapter]); m_directCommandLists[adapter]->SetGraphicsRootDescriptorTable(1, srvHandle); CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeaps[adapter]->GetCPUDescriptorHandleForHeapStart(), FrameCount, m_rtvDescriptorSizes[adapter]); m_directCommandLists[adapter]->OMSetRenderTargets(1, &rtvHandle, false, nullptr); m_directCommandLists[adapter]->DrawInstanced(4, 1, 0, 0); } // Draw the fullscreen quad - Blur pass #2. { m_directCommandLists[adapter]->SetPipelineState(m_blurPipelineStates[1].Get()); // Indicate that the intermediate render target will be used as a shader resource. // Indicate that the back buffer will be used as a render target and the // intermediate render target will be used as a SRV. D3D12_RESOURCE_BARRIER barriers[] = { CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[adapter][m_frameIndex].Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET), CD3DX12_RESOURCE_BARRIER::Transition(m_intermediateBlurRenderTarget.Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE) }; m_directCommandLists[adapter]->ResourceBarrier(_countof(barriers), barriers); CD3DX12_GPU_DESCRIPTOR_HANDLE srvHandle(m_cbvSrvUavHeap->GetGPUDescriptorHandleForHeapStart(), FrameCount, m_srvDescriptorSizes[adapter]); m_directCommandLists[adapter]->SetGraphicsRootDescriptorTable(1, srvHandle); CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeaps[adapter]->GetCPUDescriptorHandleForHeapStart(), m_frameIndex, m_rtvDescriptorSizes[adapter]); m_directCommandLists[adapter]->OMSetRenderTargets(1, &rtvHandle, false, nullptr); m_directCommandLists[adapter]->DrawInstanced(4, 1, 0, 0); } // Indicate that the back buffer will now be used to present. m_directCommandLists[adapter]->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[adapter][m_frameIndex].Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT)); // Get a timestamp at the end of the command list and resolve the query data. m_directCommandLists[adapter]->EndQuery(m_timestampQueryHeaps[adapter].Get(), D3D12_QUERY_TYPE_TIMESTAMP, timestampHeapIndex + 1); m_directCommandLists[adapter]->ResolveQueryData(m_timestampQueryHeaps[adapter].Get(), D3D12_QUERY_TYPE_TIMESTAMP, timestampHeapIndex, 2, m_timestampResultBuffers[adapter].Get(), timestampHeapIndex * sizeof(UINT64)); ThrowIfFailed(m_directCommandLists[adapter]->Close()); } }
// Load the rendering pipeline dependencies. void D3D12HeterogeneousMultiadapter::LoadPipeline() { bool debugLayerEnabled = false; #if defined(_DEBUG) // Enable the D3D12 debug layer. { ComPtr<ID3D12Debug> debugController; if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) { debugController->EnableDebugLayer(); debugLayerEnabled = true; } } #endif ComPtr<IDXGIFactory4> factory; ThrowIfFailed(CreateDXGIFactory1(IID_PPV_ARGS(&factory))); ComPtr<IDXGIAdapter1> primaryAdapter; ComPtr<IDXGIAdapter1> secondaryAdapter; if (m_useWarpDevice) { ThrowIfFailed(factory->EnumWarpAdapter(IID_PPV_ARGS(&primaryAdapter))); ThrowIfFailed(factory->EnumWarpAdapter(IID_PPV_ARGS(&secondaryAdapter))); } else { ThrowIfFailed(GetHardwareAdapters(factory.Get(), &primaryAdapter, &secondaryAdapter)); } IDXGIAdapter1* ppAdapters[] = { primaryAdapter.Get(), secondaryAdapter.Get() }; for (UINT i = 0; i < GraphicsAdaptersCount; i++) { ThrowIfFailed(D3D12CreateDevice(ppAdapters[i], D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_devices[i]))); ThrowIfFailed(ppAdapters[i]->GetDesc1(&m_adapterDescs[i])); if (debugLayerEnabled) { // Set stable power state for reliable timestamp queries. ThrowIfFailed(m_devices[i]->SetStablePowerState(TRUE)); } } // Describe and create the command queues and get their timestamp frequency. D3D12_COMMAND_QUEUE_DESC queueDesc = {}; queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; for (UINT i = 0; i < GraphicsAdaptersCount; i++) { ThrowIfFailed(m_devices[i]->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&m_directCommandQueues[i]))); ThrowIfFailed(m_directCommandQueues[i]->GetTimestampFrequency(&m_directCommandQueueTimestampFrequencies[i])); } queueDesc.Type = D3D12_COMMAND_LIST_TYPE_COPY; ThrowIfFailed(m_devices[Primary]->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&m_copyCommandQueue))); // Describe and create the swap chain on the secondary device because that's where we present from. DXGI_SWAP_CHAIN_DESC swapChainDesc = {}; swapChainDesc.BufferCount = FrameCount; swapChainDesc.BufferDesc.Width = m_width; swapChainDesc.BufferDesc.Height = m_height; swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; swapChainDesc.OutputWindow = Win32Application::GetHwnd(); swapChainDesc.SampleDesc.Count = 1; swapChainDesc.Windowed = TRUE; ComPtr<IDXGISwapChain> swapChain; ThrowIfFailed(factory->CreateSwapChain( m_directCommandQueues[Secondary].Get(), // Swap chain needs the queue so that it can force a flush on it. &swapChainDesc, &swapChain )); ThrowIfFailed(swapChain.As(&m_swapChain)); // This sample does not support fullscreen transitions. ThrowIfFailed(factory->MakeWindowAssociation(Win32Application::GetHwnd(), DXGI_MWA_NO_ALT_ENTER)); // Create descriptor heaps. { // Describe and create a render target view (RTV) descriptor heaps. for (UINT i = 0; i < GraphicsAdaptersCount; i++) { D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {}; rtvHeapDesc.NumDescriptors = FrameCount; if (i == Secondary) { // Add space for the intermediate render target. rtvHeapDesc.NumDescriptors++; } rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; ThrowIfFailed(m_devices[i]->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&m_rtvHeaps[i]))); } // Describe and create a depth stencil view (DSV) descriptor heap. D3D12_DESCRIPTOR_HEAP_DESC dsvHeapDesc = {}; dsvHeapDesc.NumDescriptors = 1; dsvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV; dsvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; ThrowIfFailed(m_devices[Primary]->CreateDescriptorHeap(&dsvHeapDesc, IID_PPV_ARGS(&m_dsvHeap))); // Describe and create a shader resource view (SRV) descriptor heap. D3D12_DESCRIPTOR_HEAP_DESC cbvSrvUavHeapDesc = {}; cbvSrvUavHeapDesc.NumDescriptors = FrameCount + 1; // +1 for the intermediate blur render target. cbvSrvUavHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; cbvSrvUavHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; ThrowIfFailed(m_devices[Secondary]->CreateDescriptorHeap(&cbvSrvUavHeapDesc, IID_PPV_ARGS(&m_cbvSrvUavHeap))); for (UINT i = 0; i < GraphicsAdaptersCount; i++) { m_rtvDescriptorSizes[i] = m_devices[i]->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); m_srvDescriptorSizes[i] = m_devices[i]->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); } } // Create query heaps and result buffers. { // Two timestamps for each frame. const UINT resultCount = 2 * FrameCount; const UINT resultBufferSize = resultCount * sizeof(UINT64); D3D12_QUERY_HEAP_DESC timestampHeapDesc = {}; timestampHeapDesc.Type = D3D12_QUERY_HEAP_TYPE_TIMESTAMP; timestampHeapDesc.Count = resultCount; for (UINT i = 0; i < GraphicsAdaptersCount; i++) { ThrowIfFailed(m_devices[i]->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(resultBufferSize), D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_timestampResultBuffers[i]))); ThrowIfFailed(m_devices[i]->CreateQueryHeap(×tampHeapDesc, IID_PPV_ARGS(&m_timestampQueryHeaps[i]))); } } // Create frame resources. { const CD3DX12_CLEAR_VALUE clearValue(swapChainDesc.BufferDesc.Format, ClearColor); const CD3DX12_RESOURCE_DESC renderTargetDesc = CD3DX12_RESOURCE_DESC::Tex2D( swapChainDesc.BufferDesc.Format, swapChainDesc.BufferDesc.Width, swapChainDesc.BufferDesc.Height, 1u, 1u, swapChainDesc.SampleDesc.Count, swapChainDesc.SampleDesc.Quality, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, D3D12_TEXTURE_LAYOUT_UNKNOWN, 0u); for (UINT i = 0; i < GraphicsAdaptersCount; i++) { CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeaps[i]->GetCPUDescriptorHandleForHeapStart()); // Create a RTV and a command allocator for each frame. for (UINT n = 0; n < FrameCount; n++) { if (i == Secondary) { ThrowIfFailed(m_swapChain->GetBuffer(n, IID_PPV_ARGS(&m_renderTargets[i][n]))); } else { ThrowIfFailed(m_devices[i]->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &renderTargetDesc, D3D12_RESOURCE_STATE_COPY_SOURCE, &clearValue, IID_PPV_ARGS(&m_renderTargets[i][n]))); } m_devices[i]->CreateRenderTargetView(m_renderTargets[i][n].Get(), nullptr, rtvHandle); rtvHandle.Offset(1, m_rtvDescriptorSizes[i]); ThrowIfFailed(m_devices[i]->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_directCommandAllocators[i][n]))); if (i == Primary) { ThrowIfFailed(m_devices[i]->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_COPY, IID_PPV_ARGS(&m_copyCommandAllocators[n]))); } } } // Create cross-adapter shared resources on the primary adapter, and open the shared handles on the secondary adapter. { D3D12_RESOURCE_DESC crossAdapterDesc = m_renderTargets[Primary][0]->GetDesc(); crossAdapterDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER; crossAdapterDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; for (UINT n = 0; n < FrameCount; n++) { ThrowIfFailed(m_devices[Primary]->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_SHARED | D3D12_HEAP_FLAG_SHARED_CROSS_ADAPTER, &crossAdapterDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_crossAdapterResources[Primary][n]))); HANDLE heapHandle = nullptr; ThrowIfFailed(m_devices[Primary]->CreateSharedHandle( m_crossAdapterResources[Primary][n].Get(), nullptr, GENERIC_ALL, nullptr, &heapHandle)); HRESULT openSharedHandleResult = m_devices[Secondary]->OpenSharedHandle(heapHandle, IID_PPV_ARGS(&m_crossAdapterResources[Secondary][n])); // We can close the handle after opening the cross-adapter shared resource. CloseHandle(heapHandle); ThrowIfFailed(openSharedHandleResult); } } // Create an intermediate render target and view on the secondary adapter. { const D3D12_RESOURCE_DESC intermediateRenderTargetDesc = m_renderTargets[Primary][0]->GetDesc(); ThrowIfFailed(m_devices[Secondary]->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &intermediateRenderTargetDesc, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, nullptr, IID_PPV_ARGS(&m_intermediateBlurRenderTarget))); CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeaps[Secondary]->GetCPUDescriptorHandleForHeapStart(), FrameCount, m_rtvDescriptorSizes[Secondary]); m_devices[Secondary]->CreateRenderTargetView(m_intermediateBlurRenderTarget.Get(), nullptr, rtvHandle); } // Create a SRV for the cross-adapter resources and intermediate render target on the secondary adapter. { CD3DX12_CPU_DESCRIPTOR_HANDLE srvHandle(m_cbvSrvUavHeap->GetCPUDescriptorHandleForHeapStart()); for (UINT n = 0; n < FrameCount; n++) { m_devices[Secondary]->CreateShaderResourceView(m_crossAdapterResources[Secondary][n].Get(), nullptr, srvHandle); srvHandle.Offset(m_srvDescriptorSizes[Secondary]); } m_devices[Secondary]->CreateShaderResourceView(m_intermediateBlurRenderTarget.Get(), nullptr, srvHandle); } } }
// Load the sample assets. void D3D12DynamicIndexing::LoadAssets() { // Note: ComPtr's are CPU objects but these resources need to stay in scope until // the command list that references them has finished executing on the GPU. // We will flush the GPU at the end of this method to ensure the resources are not // prematurely destroyed. ComPtr<ID3D12Resource> vertexBufferUploadHeap; ComPtr<ID3D12Resource> indexBufferUploadHeap; ComPtr<ID3D12Resource> textureUploadHeap; ComPtr<ID3D12Resource> materialsUploadHeap; // Create the root signature. { CD3DX12_DESCRIPTOR_RANGE ranges[3]; ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1 + CityMaterialCount, 0); // Diffuse texture + array of materials. ranges[1].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 1, 0); ranges[2].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0); CD3DX12_ROOT_PARAMETER rootParameters[4]; rootParameters[0].InitAsDescriptorTable(1, &ranges[0], D3D12_SHADER_VISIBILITY_PIXEL); rootParameters[1].InitAsDescriptorTable(1, &ranges[1], D3D12_SHADER_VISIBILITY_PIXEL); rootParameters[2].InitAsDescriptorTable(1, &ranges[2], D3D12_SHADER_VISIBILITY_VERTEX); rootParameters[3].InitAsConstants(1, 0, 0, D3D12_SHADER_VISIBILITY_PIXEL); CD3DX12_ROOT_SIGNATURE_DESC rootSignatureDesc; rootSignatureDesc.Init(_countof(rootParameters), rootParameters, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT); ComPtr<ID3DBlob> signature; ComPtr<ID3DBlob> error; ThrowIfFailed(D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error)); ThrowIfFailed(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature))); NAME_D3D12_OBJECT(m_rootSignature); } // Create the pipeline state, which includes loading shaders. { UINT8* pVertexShaderData; UINT8* pPixelShaderData; UINT vertexShaderDataLength; UINT pixelShaderDataLength; ThrowIfFailed(ReadDataFromFile(GetAssetFullPath(L"shader_mesh_simple_vert.cso").c_str(), &pVertexShaderData, &vertexShaderDataLength)); ThrowIfFailed(ReadDataFromFile(GetAssetFullPath(L"shader_mesh_dynamic_indexing_pixel.cso").c_str(), &pPixelShaderData, &pixelShaderDataLength)); CD3DX12_RASTERIZER_DESC rasterizerStateDesc(D3D12_DEFAULT); rasterizerStateDesc.CullMode = D3D12_CULL_MODE_NONE; // Describe and create the graphics pipeline state object (PSO). D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.InputLayout = { SampleAssets::StandardVertexDescription, SampleAssets::StandardVertexDescriptionNumElements }; psoDesc.pRootSignature = m_rootSignature.Get(); psoDesc.VS = CD3DX12_SHADER_BYTECODE(pVertexShaderData, vertexShaderDataLength); psoDesc.PS = CD3DX12_SHADER_BYTECODE(pPixelShaderData, pixelShaderDataLength); psoDesc.RasterizerState = rasterizerStateDesc; psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT); psoDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT); psoDesc.SampleMask = UINT_MAX; psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; psoDesc.NumRenderTargets = 1; psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; psoDesc.DSVFormat = DXGI_FORMAT_D32_FLOAT; psoDesc.SampleDesc.Count = 1; ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineState))); NAME_D3D12_OBJECT(m_pipelineState); delete pVertexShaderData; delete pPixelShaderData; } ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocator.Get(), nullptr, IID_PPV_ARGS(&m_commandList))); NAME_D3D12_OBJECT(m_commandList); // Create render target views (RTVs). CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart()); for (UINT i = 0; i < FrameCount; i++) { ThrowIfFailed(m_swapChain->GetBuffer(i, IID_PPV_ARGS(&m_renderTargets[i]))); m_device->CreateRenderTargetView(m_renderTargets[i].Get(), nullptr, rtvHandle); rtvHandle.Offset(1, m_rtvDescriptorSize); NAME_D3D12_OBJECT_INDEXED(m_renderTargets, i); } // Read in mesh data for vertex/index buffers. UINT8* pMeshData; UINT meshDataLength; ThrowIfFailed(ReadDataFromFile(GetAssetFullPath(SampleAssets::DataFileName).c_str(), &pMeshData, &meshDataLength)); // Create the vertex buffer. { ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(SampleAssets::VertexDataSize), D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_vertexBuffer))); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(SampleAssets::VertexDataSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&vertexBufferUploadHeap))); NAME_D3D12_OBJECT(m_vertexBuffer); // Copy data to the intermediate upload heap and then schedule a copy // from the upload heap to the vertex buffer. D3D12_SUBRESOURCE_DATA vertexData = {}; vertexData.pData = pMeshData + SampleAssets::VertexDataOffset; vertexData.RowPitch = SampleAssets::VertexDataSize; vertexData.SlicePitch = vertexData.RowPitch; UpdateSubresources<1>(m_commandList.Get(), m_vertexBuffer.Get(), vertexBufferUploadHeap.Get(), 0, 0, 1, &vertexData); m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_vertexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER)); // Initialize the vertex buffer view. m_vertexBufferView.BufferLocation = m_vertexBuffer->GetGPUVirtualAddress(); m_vertexBufferView.StrideInBytes = SampleAssets::StandardVertexStride; m_vertexBufferView.SizeInBytes = SampleAssets::VertexDataSize; } // Create the index buffer. { ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(SampleAssets::IndexDataSize), D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_indexBuffer))); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(SampleAssets::IndexDataSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&indexBufferUploadHeap))); NAME_D3D12_OBJECT(m_indexBuffer); // Copy data to the intermediate upload heap and then schedule a copy // from the upload heap to the index buffer. D3D12_SUBRESOURCE_DATA indexData = {}; indexData.pData = pMeshData + SampleAssets::IndexDataOffset; indexData.RowPitch = SampleAssets::IndexDataSize; indexData.SlicePitch = indexData.RowPitch; UpdateSubresources<1>(m_commandList.Get(), m_indexBuffer.Get(), indexBufferUploadHeap.Get(), 0, 0, 1, &indexData); m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_indexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_INDEX_BUFFER)); // Describe the index buffer view. m_indexBufferView.BufferLocation = m_indexBuffer->GetGPUVirtualAddress(); m_indexBufferView.Format = SampleAssets::StandardIndexFormat; m_indexBufferView.SizeInBytes = SampleAssets::IndexDataSize; m_numIndices = SampleAssets::IndexDataSize / 4; // R32_UINT (SampleAssets::StandardIndexFormat) = 4 bytes each. } // Create the textures and sampler. { // Procedurally generate an array of textures to use as city materials. { // All of these materials use the same texture desc. D3D12_RESOURCE_DESC textureDesc = {}; textureDesc.MipLevels = 1; textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; textureDesc.Width = CityMaterialTextureWidth; textureDesc.Height = CityMaterialTextureHeight; textureDesc.Flags = D3D12_RESOURCE_FLAG_NONE; textureDesc.DepthOrArraySize = 1; textureDesc.SampleDesc.Count = 1; textureDesc.SampleDesc.Quality = 0; textureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; // The textures evenly span the color rainbow so that each city gets // a different material. float materialGradStep = (1.0f / static_cast<float>(CityMaterialCount)); // Generate texture data. std::vector<std::vector<unsigned char>> cityTextureData; cityTextureData.resize(CityMaterialCount); for (UINT i = 0; i < CityMaterialCount; ++i) { ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &textureDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_cityMaterialTextures[i]))); NAME_D3D12_OBJECT_INDEXED(m_cityMaterialTextures, i); // Fill the texture. float t = i * materialGradStep; cityTextureData[i].resize(CityMaterialTextureWidth * CityMaterialTextureHeight * CityMaterialTextureChannelCount); for (int x = 0; x < CityMaterialTextureWidth; ++x) { for (int y = 0; y < CityMaterialTextureHeight; ++y) { // Compute the appropriate index into the buffer based on the x/y coordinates. int pixelIndex = (y * CityMaterialTextureChannelCount * CityMaterialTextureWidth) + (x * CityMaterialTextureChannelCount); // Determine this row's position along the rainbow gradient. float tPrime = t + ((static_cast<float>(y) / static_cast<float>(CityMaterialTextureHeight)) * materialGradStep); // Compute the RGB value for this position along the rainbow // and pack the pixel value. XMVECTOR hsl = XMVectorSet(tPrime, 0.5f, 0.5f, 1.0f); XMVECTOR rgb = XMColorHSLToRGB(hsl); cityTextureData[i][pixelIndex + 0] = static_cast<unsigned char>((255 * XMVectorGetX(rgb))); cityTextureData[i][pixelIndex + 1] = static_cast<unsigned char>((255 * XMVectorGetY(rgb))); cityTextureData[i][pixelIndex + 2] = static_cast<unsigned char>((255 * XMVectorGetZ(rgb))); cityTextureData[i][pixelIndex + 3] = 255; } } } // Upload texture data to the default heap resources. { const UINT subresourceCount = textureDesc.DepthOrArraySize * textureDesc.MipLevels; const UINT64 uploadBufferStep = GetRequiredIntermediateSize(m_cityMaterialTextures[0].Get(), 0, subresourceCount); // All of our textures are the same size in this case. const UINT64 uploadBufferSize = uploadBufferStep * CityMaterialCount; ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(uploadBufferSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&materialsUploadHeap))); for (int i = 0; i < CityMaterialCount; ++i) { // Copy data to the intermediate upload heap and then schedule // a copy from the upload heap to the appropriate texture. D3D12_SUBRESOURCE_DATA textureData = {}; textureData.pData = &cityTextureData[i][0]; textureData.RowPitch = static_cast<LONG_PTR>((CityMaterialTextureChannelCount * textureDesc.Width)); textureData.SlicePitch = textureData.RowPitch * textureDesc.Height; UpdateSubresources(m_commandList.Get(), m_cityMaterialTextures[i].Get(), materialsUploadHeap.Get(), i * uploadBufferStep, 0, subresourceCount, &textureData); m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_cityMaterialTextures[i].Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE)); } } } // Load the occcity diffuse texture with baked-in ambient lighting. // This texture will be blended with a texture from the materials // array in the pixel shader. { D3D12_RESOURCE_DESC textureDesc = {}; textureDesc.MipLevels = SampleAssets::Textures[0].MipLevels; textureDesc.Format = SampleAssets::Textures[0].Format; textureDesc.Width = SampleAssets::Textures[0].Width; textureDesc.Height = SampleAssets::Textures[0].Height; textureDesc.Flags = D3D12_RESOURCE_FLAG_NONE; textureDesc.DepthOrArraySize = 1; textureDesc.SampleDesc.Count = 1; textureDesc.SampleDesc.Quality = 0; textureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &textureDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_cityDiffuseTexture))); const UINT subresourceCount = textureDesc.DepthOrArraySize * textureDesc.MipLevels; const UINT64 uploadBufferSize = GetRequiredIntermediateSize(m_cityDiffuseTexture.Get(), 0, subresourceCount); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(uploadBufferSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&textureUploadHeap))); NAME_D3D12_OBJECT(m_cityDiffuseTexture); // Copy data to the intermediate upload heap and then schedule // a copy from the upload heap to the diffuse texture. D3D12_SUBRESOURCE_DATA textureData = {}; textureData.pData = pMeshData + SampleAssets::Textures[0].Data[0].Offset; textureData.RowPitch = SampleAssets::Textures[0].Data[0].Pitch; textureData.SlicePitch = SampleAssets::Textures[0].Data[0].Size; UpdateSubresources(m_commandList.Get(), m_cityDiffuseTexture.Get(), textureUploadHeap.Get(), 0, 0, subresourceCount, &textureData); m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_cityDiffuseTexture.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE)); } // Describe and create a sampler. D3D12_SAMPLER_DESC samplerDesc = {}; samplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR; samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP; samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP; samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP; samplerDesc.MinLOD = 0; samplerDesc.MaxLOD = D3D12_FLOAT32_MAX; samplerDesc.MipLODBias = 0.0f; samplerDesc.MaxAnisotropy = 1; samplerDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS; m_device->CreateSampler(&samplerDesc, m_samplerHeap->GetCPUDescriptorHandleForHeapStart()); // Create SRV for the city's diffuse texture. CD3DX12_CPU_DESCRIPTOR_HANDLE srvHandle(m_cbvSrvHeap->GetCPUDescriptorHandleForHeapStart(), 0, m_cbvSrvDescriptorSize); D3D12_SHADER_RESOURCE_VIEW_DESC diffuseSrvDesc = {}; diffuseSrvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; diffuseSrvDesc.Format = SampleAssets::Textures->Format; diffuseSrvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; diffuseSrvDesc.Texture2D.MipLevels = 1; m_device->CreateShaderResourceView(m_cityDiffuseTexture.Get(), &diffuseSrvDesc, srvHandle); srvHandle.Offset(m_cbvSrvDescriptorSize); // Create SRVs for each city material. for (int i = 0; i < CityMaterialCount; ++i) { D3D12_SHADER_RESOURCE_VIEW_DESC materialSrvDesc = {}; materialSrvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; materialSrvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; materialSrvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; materialSrvDesc.Texture2D.MipLevels = 1; m_device->CreateShaderResourceView(m_cityMaterialTextures[i].Get(), &materialSrvDesc, srvHandle); srvHandle.Offset(m_cbvSrvDescriptorSize); } } delete pMeshData; // Create the depth stencil view. { D3D12_DEPTH_STENCIL_VIEW_DESC depthStencilDesc = {}; depthStencilDesc.Format = DXGI_FORMAT_D32_FLOAT; depthStencilDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; depthStencilDesc.Flags = D3D12_DSV_FLAG_NONE; D3D12_CLEAR_VALUE depthOptimizedClearValue = {}; depthOptimizedClearValue.Format = DXGI_FORMAT_D32_FLOAT; depthOptimizedClearValue.DepthStencil.Depth = 1.0f; depthOptimizedClearValue.DepthStencil.Stencil = 0; ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_D32_FLOAT, m_width, m_height, 1, 0, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL), D3D12_RESOURCE_STATE_DEPTH_WRITE, &depthOptimizedClearValue, IID_PPV_ARGS(&m_depthStencil) )); NAME_D3D12_OBJECT(m_depthStencil); m_device->CreateDepthStencilView(m_depthStencil.Get(), &depthStencilDesc, m_dsvHeap->GetCPUDescriptorHandleForHeapStart()); } // Close the command list and execute it to begin the initial GPU setup. ThrowIfFailed(m_commandList->Close()); ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() }; m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists); CreateFrameResources(); // Create synchronization objects and wait until assets have been uploaded to the GPU. { ThrowIfFailed(m_device->CreateFence(m_fenceValue, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence))); m_fenceValue++; // Create an event handle to use for frame synchronization. m_fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); if (m_fenceEvent == nullptr) { ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError())); } // Wait for the command list to execute; we are reusing the same command // list in our main loop but for now, we just want to wait for setup to // complete before continuing. // Signal and increment the fence value. const UINT64 fenceToWaitFor = m_fenceValue; ThrowIfFailed(m_commandQueue->Signal(m_fence.Get(), fenceToWaitFor)); m_fenceValue++; // Wait until the fence is completed. ThrowIfFailed(m_fence->SetEventOnCompletion(fenceToWaitFor, m_fenceEvent)); WaitForSingleObject(m_fenceEvent, INFINITE); } }
// Load the rendering pipeline dependencies. void D3D12PipelineStateCache::LoadPipeline() { #if defined(_DEBUG) // Enable the D3D12 debug layer. { ComPtr<ID3D12Debug> debugController; if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) { debugController->EnableDebugLayer(); } } #endif ComPtr<IDXGIFactory4> factory; ThrowIfFailed(CreateDXGIFactory1(IID_PPV_ARGS(&factory))); if (m_useWarpDevice) { ComPtr<IDXGIAdapter> warpAdapter; ThrowIfFailed(factory->EnumWarpAdapter(IID_PPV_ARGS(&warpAdapter))); ThrowIfFailed(D3D12CreateDevice( warpAdapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device) )); } else { ComPtr<IDXGIAdapter1> hardwareAdapter; GetHardwareAdapter(factory.Get(), &hardwareAdapter); ThrowIfFailed(D3D12CreateDevice( hardwareAdapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device) )); } // Describe and create the command queue. D3D12_COMMAND_QUEUE_DESC queueDesc = {}; queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; ThrowIfFailed(m_device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&m_commandQueue))); NAME_D3D12_OBJECT(m_commandQueue); // Describe and create the swap chain. DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {}; swapChainDesc.BufferCount = FrameCount; swapChainDesc.Width = m_width; swapChainDesc.Height = m_height; swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; swapChainDesc.SampleDesc.Count = 1; swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; ComPtr<IDXGISwapChain1> swapChain; ThrowIfFailed(factory->CreateSwapChainForCoreWindow( m_commandQueue.Get(), // Swap chain needs the queue so that it can force a flush on it. reinterpret_cast<IUnknown*>(Windows::UI::Core::CoreWindow::GetForCurrentThread()), &swapChainDesc, nullptr, &swapChain )); ThrowIfFailed(swapChain.As(&m_swapChain)); m_frameIndex = m_swapChain->GetCurrentBackBufferIndex(); m_swapChainEvent = m_swapChain->GetFrameLatencyWaitableObject(); // Create descriptor heaps. { // Describe and create a render target view (RTV) descriptor heap. D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {}; rtvHeapDesc.NumDescriptors = FrameCount + 1; // A descriptor for each frame + 1 intermediate render target. rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; ThrowIfFailed(m_device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&m_rtvHeap))); // Describe and create a shader resource view (SRV) descriptor heap. D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {}; srvHeapDesc.NumDescriptors = 1; srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; ThrowIfFailed(m_device->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&m_srvHeap))); NAME_D3D12_OBJECT(m_srvHeap); m_rtvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); m_srvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); } // Create frame resources. { CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart()); // Create RTVs and a command allocator for each frame. for (UINT n = 0; n < FrameCount; n++) { ThrowIfFailed(m_swapChain->GetBuffer(n, IID_PPV_ARGS(&m_renderTargets[n]))); m_device->CreateRenderTargetView(m_renderTargets[n].Get(), nullptr, rtvHandle); rtvHandle.Offset(1, m_rtvDescriptorSize); NAME_D3D12_OBJECT_INDEXED(m_renderTargets, n); ThrowIfFailed(m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_commandAllocators[n]))); } D3D12_RESOURCE_DESC renderTargetDesc = m_renderTargets[0]->GetDesc(); D3D12_CLEAR_VALUE clearValue = {}; memcpy(clearValue.Color, IntermediateClearColor, sizeof(IntermediateClearColor)); clearValue.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // Create an intermediate render target that is the same dimensions as the swap chain. ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &renderTargetDesc, D3D12_RESOURCE_STATE_RENDER_TARGET, &clearValue, IID_PPV_ARGS(&m_intermediateRenderTarget))); NAME_D3D12_OBJECT(m_intermediateRenderTarget); m_device->CreateRenderTargetView(m_intermediateRenderTarget.Get(), nullptr, rtvHandle); rtvHandle.Offset(1, m_rtvDescriptorSize); // Create a SRV of the intermediate render target. D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; srvDesc.Format = renderTargetDesc.Format; srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; srvDesc.Texture2D.MipLevels = 1; CD3DX12_CPU_DESCRIPTOR_HANDLE srvHandle(m_srvHeap->GetCPUDescriptorHandleForHeapStart()); m_device->CreateShaderResourceView(m_intermediateRenderTarget.Get(), &srvDesc, srvHandle); } }
// Fill the command list with all the render commands and dependent state. void D3D12PipelineStateCache::PopulateCommandList() { // Command list allocators can only be reset when the associated // command lists have finished execution on the GPU; apps should use // fences to determine GPU execution progress. ThrowIfFailed(m_commandAllocators[m_frameIndex]->Reset()); // However, when ExecuteCommandList() is called on a particular command // list, that command list can then be reset at any time and must be before // re-recording. ThrowIfFailed(m_commandList->Reset(m_commandAllocators[m_frameIndex].Get(), nullptr)); // Set necessary state. m_commandList->SetGraphicsRootSignature(m_rootSignature.Get()); ID3D12DescriptorHeap* ppHeaps[] = { m_srvHeap.Get() }; m_commandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); m_commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); m_commandList->RSSetViewports(1, &m_viewport); m_commandList->RSSetScissorRects(1, &m_scissorRect); CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart(), m_frameIndex, m_rtvDescriptorSize); CD3DX12_CPU_DESCRIPTOR_HANDLE intermediateRtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart(), FrameCount, m_rtvDescriptorSize); CD3DX12_GPU_DESCRIPTOR_HANDLE srvHandle(m_srvHeap->GetGPUDescriptorHandleForHeapStart()); m_commandList->OMSetRenderTargets(1, &intermediateRtvHandle, FALSE, nullptr); // Record commands. m_commandList->ClearRenderTargetView(intermediateRtvHandle, IntermediateClearColor, 0, nullptr); // Draw the scene as normal into the intermediate buffer. PIXBeginEvent(m_commandList.Get(), 0, L"Draw cube"); { static float rot = 0.0f; DrawConstantBuffer* drawCB = (DrawConstantBuffer*)m_dynamicCB.GetMappedMemory(m_drawIndex, m_frameIndex); drawCB->worldViewProjection = XMMatrixTranspose(XMMatrixRotationY(rot) * XMMatrixRotationX(-rot) * m_camera.GetViewMatrix() * m_projectionMatrix); rot += 0.01f; m_commandList->IASetVertexBuffers(0, 1, &m_cubeVbv); m_commandList->IASetIndexBuffer(&m_cubeIbv); m_psoLibrary.SetPipelineState(m_device.Get(), m_rootSignature.Get(), m_commandList.Get(), BaseNormal3DRender, m_frameIndex); m_commandList->SetGraphicsRootConstantBufferView(RootParameterCB, m_dynamicCB.GetGpuVirtualAddress(m_drawIndex, m_frameIndex)); m_commandList->DrawIndexedInstanced(36, 1, 0, 0, 0); m_drawIndex++; } PIXEndEvent(m_commandList.Get()); // Set up the state for a fullscreen quad. m_commandList->IASetVertexBuffers(0, 1, &m_quadVbv); m_commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); // Indicate that the back buffer will be used as a render target and the // intermediate render target will be used as a SRV. D3D12_RESOURCE_BARRIER barriers[] = { CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_frameIndex].Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET), CD3DX12_RESOURCE_BARRIER::Transition(m_intermediateRenderTarget.Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE) }; m_commandList->ResourceBarrier(_countof(barriers), barriers); m_commandList->SetGraphicsRootDescriptorTable(RootParameterSRV, m_srvHeap->GetGPUDescriptorHandleForHeapStart()); const float black[] = { 0.0f, 0.0f, 0.0f, 0.0f }; m_commandList->ClearRenderTargetView(rtvHandle, black, 0, nullptr); m_commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr); // Draw some quads using the rendered scene with some effect shaders. PIXBeginEvent(m_commandList.Get(), 0, L"Post-processing"); { UINT quadCount = 0; static const UINT quadsX = 3; static const UINT quadsY = 3; // Cycle through all of the effects. for (UINT i = PostBlit; i < EffectPipelineTypeCount; i++) { if (m_enabledEffects[i]) { D3D12_VIEWPORT viewport = {}; viewport.TopLeftX = (quadCount % quadsX) * (m_viewport.Width / quadsX); viewport.TopLeftY = (quadCount / quadsY) * (m_viewport.Height / quadsY); viewport.Width = m_viewport.Width / quadsX; viewport.Height = m_viewport.Height / quadsY; viewport.MinDepth = 0.0f; viewport.MaxDepth = 0.0f; PIXBeginEvent(m_commandList.Get(), 0, g_cEffectNames[i]); m_commandList->RSSetViewports(1, &viewport); m_psoLibrary.SetPipelineState(m_device.Get(), m_rootSignature.Get(), m_commandList.Get(), static_cast<EffectPipelineType>(i), m_frameIndex); m_commandList->DrawInstanced(4, 1, 0, 0); PIXEndEvent(m_commandList.Get()); } quadCount++; } } PIXEndEvent(m_commandList.Get()); // Revert resource states back to original values. barriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; barriers[0].Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; barriers[1].Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; barriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; m_commandList->ResourceBarrier(_countof(barriers), barriers); ThrowIfFailed(m_commandList->Close()); }
void TextureStore::loadTexture(wstring filename, string id) { TextureLoadResult result; TextureInfo initialTexture; // only use to initialize struct in texture store - do not access this after assignment to store vector<byte> file_buffer; initialTexture.id = id; textures[id] = initialTexture; TextureInfo *texture = &textures[id]; // find texture file, look in pak file first: PakEntry *pakFileEntry = nullptr; pakFileEntry = xapp().findFileInPak(filename.c_str()); // try file system if not found in pak: initialTexture.filename = filename; // TODO check: field not needed? only in this method? --> remove if (pakFileEntry == nullptr) { wstring binFile = xapp().findFile(filename.c_str(), XApp::TEXTURE); texture->filename = binFile; //initialTexture.filename = binFile; xapp().readFile(texture->filename.c_str(), file_buffer, XApp::FileCategory::TEXTURE); } else { xapp().readFile(pakFileEntry, file_buffer, XApp::FileCategory::TEXTURE); } ID3D12GraphicsCommandList *commandList = this->commandList.Get(); //D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV // create heap - TODO adjust for one heap for multiple textures // Describe and create a shader resource view (SRV) heap for the texture. D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {}; srvHeapDesc.NumDescriptors = 1; srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; ThrowIfFailed(xapp().device->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&texture->m_srvHeap))); CD3DX12_CPU_DESCRIPTOR_HANDLE srvHandle(texture->m_srvHeap->GetCPUDescriptorHandleForHeapStart()); //CD3DX12_CPU_DESCRIPTOR_HANDLE(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); CreateDDSTextureFromMemory( xapp().device.Get(), &file_buffer[0], file_buffer.size(), 0, true, &texture->texSRV, srvHandle, result ); //CreateDDSTextureFromFile( // xapp().device.Get(), // texture->filename.c_str(), // 0, // true, // &texture->texSRV, // srvHandle, // result // ); // upload texture to GPU: //ID3D12Resource* UploadBuffer; UINT64 uploadBufferSize = GetRequiredIntermediateSize(texture->texSRV.Get(), 0, result.NumSubresources); //CommandContext& InitContext = CommandContext::Begin(); D3D12_HEAP_PROPERTIES HeapProps; HeapProps.Type = D3D12_HEAP_TYPE_UPLOAD; HeapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; HeapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; HeapProps.CreationNodeMask = 1; HeapProps.VisibleNodeMask = 1; D3D12_RESOURCE_DESC BufferDesc; BufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; BufferDesc.Alignment = 0; BufferDesc.Width = uploadBufferSize; BufferDesc.Height = 1; BufferDesc.DepthOrArraySize = 1; BufferDesc.MipLevels = 1; BufferDesc.Format = DXGI_FORMAT_UNKNOWN; BufferDesc.SampleDesc.Count = 1; BufferDesc.SampleDesc.Quality = 0; BufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; BufferDesc.Flags = D3D12_RESOURCE_FLAG_NONE; ThrowIfFailed(xapp().device->CreateCommittedResource(&HeapProps, D3D12_HEAP_FLAG_NONE, &BufferDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&result.UploadBuffer))); // copy data to the intermediate upload heap and then schedule a copy from the upload heap to the default texture //InitContext.TransitionResource(Dest, D3D12_RESOURCE_STATE_COPY_DEST, true); commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(texture->texSRV.Get(), D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_COPY_DEST)); UpdateSubresources(commandList, texture->texSRV.Get(), result.UploadBuffer, 0, 0, result.NumSubresources, result.initData.get()); commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(texture->texSRV.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE)); //InitContext.TransitionResource(Dest, D3D12_RESOURCE_STATE_GENERIC_READ, true); // Execute the command list and wait for it to finish so we can release the upload buffer //InitContext.CloseAndExecute(true); //UploadBuffer->Release(); ThrowIfFailed(commandList->Close()); ID3D12CommandList* ppCommandLists[] = { this->commandList.Get() }; xapp().commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists); // Create synchronization objects and wait until assets have been uploaded to the GPU. //Sleep(300); EffectBase::createSyncPoint(updateFrameData, xapp().commandQueue); EffectBase::waitForSyncPoint(updateFrameData); //auto &f = frameData[frameIndex]; //createSyncPoint(f, xapp().commandQueue); //waitForSyncPoint(f); result.UploadBuffer->Release(); ThrowIfFailed(commandList->Reset(commandAllocator.Get(), pipelineState.Get())); }
void VolumetricAnimation::PopulateGraphicsCommandList() { HRESULT hr; // Command list allocators can only be reset when the associated // command lists have finished execution on the GPU; apps should use // fences to determine GPU execution progress. V( m_graphicCmdAllocator->Reset() ); // However, when ExecuteCommandList() is called on a particular command // list, that command list can then be reset at any time and must be before // re-recording. V( m_graphicCmdList->Reset( m_graphicCmdAllocator.Get(), m_pipelineState.Get() ) ); XMMATRIX view = m_camera.GetViewMatrix(); XMMATRIX proj = m_camera.GetProjMatrix(); XMMATRIX world = XMMatrixRotationY( static_cast< float >( m_timer.GetTotalSeconds() ) ); m_constantBufferData.wvp = XMMatrixMultiply( view, proj ); //m_constantBufferData.wvp = XMMatrixMultiply( XMMatrixMultiply( world, view ), proj ); XMStoreFloat4( &m_constantBufferData.viewPos, m_camera.GetEyePt() ); memcpy( m_pCbvDataBegin, &m_constantBufferData, sizeof( m_constantBufferData ) ); // Set necessary state. m_graphicCmdList->SetGraphicsRootSignature( m_graphicsRootSignature.Get() ); ID3D12DescriptorHeap* ppHeaps[] = { m_cbvsrvuavHeap.Get() }; m_graphicCmdList->SetDescriptorHeaps( _countof( ppHeaps ), ppHeaps ); CD3DX12_GPU_DESCRIPTOR_HANDLE cbvHandle( m_cbvsrvuavHeap->GetGPUDescriptorHandleForHeapStart(), RootParameterCBV, m_cbvsrvuavDescriptorSize ); CD3DX12_GPU_DESCRIPTOR_HANDLE srvHandle( m_cbvsrvuavHeap->GetGPUDescriptorHandleForHeapStart(), RootParameterSRV, m_cbvsrvuavDescriptorSize ); m_graphicCmdList->SetGraphicsRootDescriptorTable( RootParameterCBV, cbvHandle ); m_graphicCmdList->SetGraphicsRootDescriptorTable( RootParameterSRV, srvHandle ); m_graphicCmdList->RSSetViewports( 1, &m_viewport ); m_graphicCmdList->RSSetScissorRects( 1, &m_scissorRect ); // Indicate that the back buffer will be used as a render target. D3D12_RESOURCE_BARRIER resourceBarriersBefore[] = { CD3DX12_RESOURCE_BARRIER::Transition( m_renderTargets[m_frameIndex].Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET ), CD3DX12_RESOURCE_BARRIER::Transition( m_volumeBuffer.Get(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE ) }; m_graphicCmdList->ResourceBarrier( 2, resourceBarriersBefore ); CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle( m_rtvHeap->GetCPUDescriptorHandleForHeapStart(), m_frameIndex, m_rtvDescriptorSize ); m_graphicCmdList->OMSetRenderTargets( 1, &rtvHandle, FALSE, &m_dsvHeap->GetCPUDescriptorHandleForHeapStart() ); // Record commands. const float clearColor[] = { 0.0f, 0.0f, 0.0f, 0.0f }; m_graphicCmdList->ClearRenderTargetView( rtvHandle, clearColor, 0, nullptr ); m_graphicCmdList->ClearDepthStencilView( m_dsvHeap->GetCPUDescriptorHandleForHeapStart(), D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr ); m_graphicCmdList->IASetPrimitiveTopology( D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST ); m_graphicCmdList->IASetVertexBuffers( 0, 1, &m_vertexBufferView ); m_graphicCmdList->IASetIndexBuffer( &m_indexBufferView ); m_graphicCmdList->DrawIndexedInstanced( 36, 1, 0, 0, 0 ); // Indicate that the back buffer will now be used to present. D3D12_RESOURCE_BARRIER resourceBarriersAfter[] = { CD3DX12_RESOURCE_BARRIER::Transition( m_renderTargets[m_frameIndex].Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT ), CD3DX12_RESOURCE_BARRIER::Transition( m_volumeBuffer.Get(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS ) }; m_graphicCmdList->ResourceBarrier( 2, resourceBarriersAfter ); V( m_graphicCmdList->Close() ); }
// Load the assets. HRESULT VolumetricAnimation::LoadAssets() { HRESULT hr; // Create a root signature consisting of a descriptor table with a CBV SRV and a sampler. { CD3DX12_DESCRIPTOR_RANGE ranges[3]; CD3DX12_ROOT_PARAMETER rootParameters[3]; ranges[0].Init( D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0 ); ranges[1].Init( D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0 ); ranges[2].Init( D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 1, 0 ); rootParameters[RootParameterCBV].InitAsDescriptorTable( 1, &ranges[0], D3D12_SHADER_VISIBILITY_ALL ); rootParameters[RootParameterSRV].InitAsDescriptorTable( 1, &ranges[1], D3D12_SHADER_VISIBILITY_PIXEL ); rootParameters[RootParameterUAV].InitAsDescriptorTable( 1, &ranges[2], D3D12_SHADER_VISIBILITY_ALL ); D3D12_STATIC_SAMPLER_DESC sampler = {}; sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT; sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_BORDER; sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_BORDER; sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_BORDER; sampler.MipLODBias = 0; sampler.MaxAnisotropy = 0; sampler.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER; sampler.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK; sampler.MinLOD = 0.0f; sampler.MaxLOD = D3D12_FLOAT32_MAX; sampler.ShaderRegister = 0; sampler.RegisterSpace = 0; sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; // Allow input layout and deny unnecessary access to certain pipeline stages. D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS; CD3DX12_ROOT_SIGNATURE_DESC rootSignatureDesc; rootSignatureDesc.Init( _countof(rootParameters), rootParameters, 1, &sampler, rootSignatureFlags ); ComPtr<ID3DBlob> signature; ComPtr<ID3DBlob> error; V( D3D12SerializeRootSignature( &rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error ) ); if ( error ) PRINTERROR( reinterpret_cast< const char* >( error->GetBufferPointer() ) ); VRET( m_device->CreateRootSignature( 0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS( &m_graphicsRootSignature ) ) ); DXDebugName( m_graphicsRootSignature ); // Create compute signature. Must change visibility for the SRV. rootParameters[RootParameterSRV].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; CD3DX12_ROOT_SIGNATURE_DESC computeRootSignatureDesc( _countof( rootParameters ), rootParameters, 0, nullptr ); VRET( D3D12SerializeRootSignature( &computeRootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error ) ); VRET( m_device->CreateRootSignature( 0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS( &m_computeRootSignature ) ) ); } // Create the pipeline state, which includes compiling and loading shaders. { ComPtr<ID3DBlob> vertexShader; ComPtr<ID3DBlob> pixelShader; ComPtr<ID3DBlob> computeShader; UINT compileFlags = 0; VRET( CompileShaderFromFile( GetAssetFullPath( _T( "VolumetricAnimation_shader.hlsl" ) ).c_str(), nullptr, D3D_COMPILE_STANDARD_FILE_INCLUDE, "vsmain", "vs_5_0", compileFlags, 0, &vertexShader ) ); VRET( CompileShaderFromFile( GetAssetFullPath( _T( "VolumetricAnimation_shader.hlsl" ) ).c_str(), nullptr, D3D_COMPILE_STANDARD_FILE_INCLUDE, "psmain", "ps_5_0", compileFlags, 0, &pixelShader ) ); VRET( CompileShaderFromFile( GetAssetFullPath( _T( "VolumetricAnimation_shader.hlsl" ) ).c_str(), nullptr, D3D_COMPILE_STANDARD_FILE_INCLUDE, "csmain", "cs_5_0", compileFlags, 0, &computeShader ) ); // Define the vertex input layout. D3D12_INPUT_ELEMENT_DESC inputElementDescs[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 } }; CD3DX12_DEPTH_STENCIL_DESC depthStencilDesc( D3D12_DEFAULT ); depthStencilDesc.DepthEnable = true; depthStencilDesc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL; depthStencilDesc.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL; depthStencilDesc.StencilEnable = FALSE; // Describe and create the graphics pipeline state object (PSO). D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.InputLayout = { inputElementDescs, _countof( inputElementDescs ) }; psoDesc.pRootSignature = m_graphicsRootSignature.Get(); psoDesc.VS = { reinterpret_cast< UINT8* >( vertexShader->GetBufferPointer() ), vertexShader->GetBufferSize() }; psoDesc.PS = { reinterpret_cast< UINT8* >( pixelShader->GetBufferPointer() ), pixelShader->GetBufferSize() }; psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC( D3D12_DEFAULT ); psoDesc.BlendState = CD3DX12_BLEND_DESC( D3D12_DEFAULT ); psoDesc.DepthStencilState = depthStencilDesc; psoDesc.SampleMask = UINT_MAX; psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; psoDesc.NumRenderTargets = 1; psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; psoDesc.DSVFormat = DXGI_FORMAT_D32_FLOAT; psoDesc.SampleDesc.Count = 1; VRET( m_device->CreateGraphicsPipelineState( &psoDesc, IID_PPV_ARGS( &m_pipelineState ) ) ); DXDebugName( m_pipelineState ); // Describe and create the compute pipeline state object (PSO). D3D12_COMPUTE_PIPELINE_STATE_DESC computePsoDesc = {}; computePsoDesc.pRootSignature = m_computeRootSignature.Get(); computePsoDesc.CS = { reinterpret_cast< UINT8* >( computeShader->GetBufferPointer() ), computeShader->GetBufferSize() }; VRET( m_device->CreateComputePipelineState( &computePsoDesc, IID_PPV_ARGS( &m_computeState ) ) ); DXDebugName( m_computeState ); } // Create the compute command list. VRET( m_device->CreateCommandList( 0, D3D12_COMMAND_LIST_TYPE_COMPUTE, m_computeCmdAllocator.Get(),m_computeState.Get(), IID_PPV_ARGS( &m_computeCmdList ) ) ); DXDebugName( m_computeCmdList ); VRET( m_computeCmdList->Close() ); // Create the graphics command list. VRET( m_device->CreateCommandList( 0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_graphicCmdAllocator.Get(), m_pipelineState.Get(), IID_PPV_ARGS( &m_graphicCmdList ) ) ); DXDebugName( m_graphicCmdList ); // Note: ComPtr's are CPU objects but this resource needs to stay in scope until // the command list that references it has finished executing on the GPU. // We will flush the GPU at the end of this method to ensure the resource is not // prematurely destroyed. ComPtr<ID3D12Resource> volumeBufferUploadHeap; // Create the volumeBuffer. { UINT volumeBufferSize = m_volumeDepth*m_volumeHeight*m_volumeWidth * 4 * sizeof( UINT8 ); D3D12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer( volumeBufferSize, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS ); D3D12_RESOURCE_DESC uploadBufferDesc = CD3DX12_RESOURCE_DESC::Buffer( volumeBufferSize ); VRET( m_device->CreateCommittedResource(&CD3DX12_HEAP_PROPERTIES( D3D12_HEAP_TYPE_DEFAULT ),D3D12_HEAP_FLAG_NONE, &bufferDesc,D3D12_RESOURCE_STATE_COPY_DEST,nullptr,IID_PPV_ARGS( &m_volumeBuffer ) ) ); const UINT64 uploadBufferSize = GetRequiredIntermediateSize( m_volumeBuffer.Get(), 0, 1 ); // Create the GPU upload buffer. VRET( m_device->CreateCommittedResource(&CD3DX12_HEAP_PROPERTIES( D3D12_HEAP_TYPE_UPLOAD ),D3D12_HEAP_FLAG_NONE, &uploadBufferDesc,D3D12_RESOURCE_STATE_GENERIC_READ, nullptr,IID_PPV_ARGS( &volumeBufferUploadHeap ) ) ); // Copy data to the intermediate upload heap and then schedule a copy // from the upload heap to the Texture2D. UINT8* volumeBuffer = ( UINT8* ) malloc( volumeBufferSize ); memset( volumeBuffer, 64, volumeBufferSize ); //float radius = m_volumeHeight / 2.f; float a = m_volumeWidth / 2.f; float b = m_volumeHeight / 2.f; float c = m_volumeDepth / 2.f; float radius = sqrt( a*a + b*b + c*c ); for ( UINT z = 0; z < m_volumeDepth; z++ ) for ( UINT y = 0; y < m_volumeHeight; y++ ) for ( UINT x = 0; x < m_volumeWidth; x++ ) { float _x = x - m_volumeWidth / 2.f; float _y = y - m_volumeHeight / 2.f; float _z = z - m_volumeDepth / 2.f; //float currentRaidus =abs(_x)+abs(_y)+abs(_z); float currentRaidus = sqrt( _x*_x + _y*_y + _z*_z ); float scale = currentRaidus *3.f / radius; UINT idx = 4 - (UINT)floor( scale ); UINT interm = ( UINT ) ( 192 * scale +0.5f ); UINT8 col = interm % 192+1; volumeBuffer[( x + y*m_volumeWidth + z*m_volumeHeight*m_volumeWidth ) * 4 + 0] += col * m_constantBufferData.colVal[idx].x; volumeBuffer[( x + y*m_volumeWidth + z*m_volumeHeight*m_volumeWidth ) * 4 + 1] += col * m_constantBufferData.colVal[idx].y; volumeBuffer[( x + y*m_volumeWidth + z*m_volumeHeight*m_volumeWidth ) * 4 + 2] += col * m_constantBufferData.colVal[idx].z; volumeBuffer[( x + y*m_volumeWidth + z*m_volumeHeight*m_volumeWidth ) * 4 + 3] = m_constantBufferData.colVal[idx].w; } D3D12_SUBRESOURCE_DATA volumeBufferData = {}; volumeBufferData.pData = &volumeBuffer[0]; volumeBufferData.RowPitch = volumeBufferSize; volumeBufferData.SlicePitch = volumeBufferData.RowPitch; UpdateSubresources( m_graphicCmdList.Get(), m_volumeBuffer.Get(), volumeBufferUploadHeap.Get(), 0, 0, 1, &volumeBufferData ); m_graphicCmdList->ResourceBarrier( 1, &CD3DX12_RESOURCE_BARRIER::Transition( m_volumeBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_UNORDERED_ACCESS ) ); // Describe and create a SRV for the volumeBuffer. D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; srvDesc.Format = DXGI_FORMAT_UNKNOWN; srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; srvDesc.Buffer.FirstElement = 0; srvDesc.Buffer.NumElements = m_volumeDepth*m_volumeHeight*m_volumeWidth; srvDesc.Buffer.StructureByteStride = 4 * sizeof( UINT8 ); srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE; CD3DX12_CPU_DESCRIPTOR_HANDLE srvHandle( m_cbvsrvuavHeap->GetCPUDescriptorHandleForHeapStart(), RootParameterSRV, m_cbvsrvuavDescriptorSize ); m_device->CreateShaderResourceView( m_volumeBuffer.Get(), &srvDesc, srvHandle ); // Describe and create a UAV for the volumeBuffer. D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {}; uavDesc.Format = DXGI_FORMAT_UNKNOWN; uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; uavDesc.Buffer.FirstElement = 0; uavDesc.Buffer.NumElements = m_volumeWidth*m_volumeHeight*m_volumeDepth; uavDesc.Buffer.StructureByteStride = 4 * sizeof( UINT8 ); uavDesc.Buffer.CounterOffsetInBytes = 0; uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE; CD3DX12_CPU_DESCRIPTOR_HANDLE uavHandle( m_cbvsrvuavHeap->GetCPUDescriptorHandleForHeapStart(), RootParameterUAV, m_cbvsrvuavDescriptorSize ); m_device->CreateUnorderedAccessView( m_volumeBuffer.Get(), nullptr, &uavDesc, uavHandle ); free( volumeBuffer ); } // Create the vertex buffer. // Note: ComPtr's are CPU objects but this resource needs to stay in scope until // the command list that references it has finished executing on the GPU. // We will flush the GPU at the end of this method to ensure the resource is not // prematurely destroyed. ComPtr<ID3D12Resource> vertexBufferUpload; { // Define the geometry for a triangle. Vertex cubeVertices[] = { { XMFLOAT3( -128.f, -128.f, -128.f ) }, { XMFLOAT3( -128.f, -128.f, 128.f ) }, { XMFLOAT3( -128.f, 128.f, -128.f ) }, { XMFLOAT3( -128.f, 128.f, 128.f ) }, { XMFLOAT3( 128.f, -128.f, -128.f )}, { XMFLOAT3( 128.f, -128.f, 128.f )}, { XMFLOAT3( 128.f, 128.f, -128.f )}, { XMFLOAT3( 128.f, 128.f, 128.f )}, }; const UINT vertexBufferSize = sizeof( cubeVertices ); VRET( m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES( D3D12_HEAP_TYPE_UPLOAD ), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer( vertexBufferSize ), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS( &vertexBufferUpload ) ) ); VRET( m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES( D3D12_HEAP_TYPE_DEFAULT ), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer( vertexBufferSize ), D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS( &m_vertexBuffer ) ) ); DXDebugName( m_vertexBuffer ); D3D12_SUBRESOURCE_DATA vertexData = {}; vertexData.pData = reinterpret_cast< UINT8* >( cubeVertices ); vertexData.RowPitch = vertexBufferSize; vertexData.SlicePitch = vertexBufferSize; UpdateSubresources<1>( m_graphicCmdList.Get(), m_vertexBuffer.Get(), vertexBufferUpload.Get(), 0, 0, 1, &vertexData ); m_graphicCmdList->ResourceBarrier( 1, &CD3DX12_RESOURCE_BARRIER::Transition( m_vertexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER )); // Initialize the vertex buffer view. m_vertexBufferView.BufferLocation = m_vertexBuffer->GetGPUVirtualAddress(); m_vertexBufferView.StrideInBytes = sizeof( Vertex ); m_vertexBufferView.SizeInBytes = vertexBufferSize; } // Create the index buffer // Note: ComPtr's are CPU objects but this resource needs to stay in scope until // the command list that references it has finished executing on the GPU. // We will flush the GPU at the end of this method to ensure the resource is not // prematurely destroyed. ComPtr<ID3D12Resource> indexBufferUpload; { uint16_t cubeIndices[] = { 0,2,1, 1,2,3, 4,5,6, 5,7,6, 0,1,5, 0,5,4, 2,6,7, 2,7,3, 0,4,6, 0,6,2, 1,3,7, 1,7,5, }; const UINT indexBufferSize = sizeof( cubeIndices ); VRET( m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES( D3D12_HEAP_TYPE_UPLOAD ), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer( indexBufferSize ), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS( &indexBufferUpload ) ) ); VRET( m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES( D3D12_HEAP_TYPE_DEFAULT ), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer( indexBufferSize ), D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS( &m_indexBuffer ) ) ); DXDebugName( m_indexBuffer ); D3D12_SUBRESOURCE_DATA indexData = {}; indexData.pData = reinterpret_cast< UINT8* >( cubeIndices ); indexData.RowPitch = indexBufferSize; indexData.SlicePitch = indexBufferSize; UpdateSubresources<1>( m_graphicCmdList.Get(), m_indexBuffer.Get(), indexBufferUpload.Get(), 0, 0, 1, &indexData ); m_graphicCmdList->ResourceBarrier( 1, &CD3DX12_RESOURCE_BARRIER::Transition( m_indexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_INDEX_BUFFER ) ); m_indexBufferView.BufferLocation = m_indexBuffer->GetGPUVirtualAddress(); m_indexBufferView.SizeInBytes = sizeof( cubeIndices ); m_indexBufferView.Format = DXGI_FORMAT_R16_UINT; } // Create the constant buffer { VRET( m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES( D3D12_HEAP_TYPE_UPLOAD ), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer( 1024 * 64 ), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS( &m_constantBuffer ) ) ); DXDebugName( m_constantBuffer ); // Describe and create a constant buffer view. D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {}; cbvDesc.BufferLocation = m_constantBuffer->GetGPUVirtualAddress(); cbvDesc.SizeInBytes = ( sizeof( ConstantBuffer ) + 255 ) & ~255; // CB size is required to be 256-byte aligned. m_device->CreateConstantBufferView( &cbvDesc, m_cbvsrvuavHeap->GetCPUDescriptorHandleForHeapStart() ); // Initialize and map the constant buffers. We don't unmap this until the // app closes. Keeping things mapped for the lifetime of the resource is okay. CD3DX12_RANGE readRange( 0, 0 ); // We do not intend to read from this resource on the CPU. VRET( m_constantBuffer->Map( 0, &readRange, reinterpret_cast< void** >( &m_pCbvDataBegin ) ) ); memcpy( m_pCbvDataBegin, &m_constantBufferData, sizeof( m_constantBufferData ) ); } // Close the command list and execute it to begin the initial GPU setup. VRET( m_graphicCmdList->Close() ); ID3D12CommandList* ppCommandLists[] = { m_graphicCmdList.Get() }; m_graphicCmdQueue->ExecuteCommandLists( _countof( ppCommandLists ), ppCommandLists ); // Create synchronization objects and wait until assets have been uploaded to the GPU. { VRET( m_device->CreateFence( 0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS( &m_fence ) ) ); DXDebugName( m_fence ); m_fenceValue = 1; // Create an event handle to use for frame synchronization. m_fenceEvent = CreateEvent( nullptr, FALSE, FALSE, nullptr ); if ( m_fenceEvent == nullptr ) { VRET( HRESULT_FROM_WIN32( GetLastError() ) ); } // Wait for the command list to execute; we are reusing the same command // list in our main loop but for now, we just want to wait for setup to // complete before continuing. WaitForGraphicsCmd(); } XMVECTORF32 vecEye = { 500.0f, 500.0f, -500.0f }; XMVECTORF32 vecAt = { 0.0f, 0.0f, 0.0f }; m_camera.SetViewParams( vecEye, vecAt ); m_camera.SetEnablePositionMovement( true ); m_camera.SetButtonMasks( MOUSE_RIGHT_BUTTON, MOUSE_WHEEL, MOUSE_LEFT_BUTTON ); return S_OK; }
/** *************************************************************************************************** * DX12ImageRenderer::CaptureImage * * @brief * Convert a DX12 resource to a CPU-visible linear buffer of pixels. The data is filled * in a user-provided CpuImage struct. * * IMPORTANT: Memory inside pImgOut is allocated on behalf of the caller, so it is their * responsibility to free it. * * @return * S_OK if successful. *************************************************************************************************** */ HRESULT DX12ImageRenderer::CaptureImage( ID3D12Resource* pRes, D3D12_RESOURCE_STATES prevState, UINT newWidth, UINT newHeight, CpuImage* pImgOut, bool bFlipX, bool bFlipY) { HRESULT result = E_FAIL; if ((pRes != nullptr) && (pImgOut != nullptr) && (newWidth > 0) && (newHeight > 0)) { // Create temp assets result = CreateCaptureAssets(pRes, newWidth, newHeight); if (result == S_OK) { result = m_pCmdAllocator->Reset(); } if (result == S_OK) { result = m_pCmdList->Reset(m_pCmdAllocator, m_pPipelineStateGraphics); } // Render work if (result == S_OK) { // Set root sig m_pCmdList->SetGraphicsRootSignature(m_pRootSignatureGraphics); // Set descriptors and tables ID3D12DescriptorHeap* ppHeaps[] = { m_pSrvUavCbHeap }; m_pCmdList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); CD3DX12_GPU_DESCRIPTOR_HANDLE srvHandle(m_pSrvUavCbHeap->GetGPUDescriptorHandleForHeapStart(), RootParameterSRV, m_srvUavCbDescriptorSize); CD3DX12_GPU_DESCRIPTOR_HANDLE uavHandle(m_pSrvUavCbHeap->GetGPUDescriptorHandleForHeapStart(), RootParameterUAV, m_srvUavCbDescriptorSize); CD3DX12_GPU_DESCRIPTOR_HANDLE cbHandle(m_pSrvUavCbHeap->GetGPUDescriptorHandleForHeapStart(), RootParameterCBV, m_srvUavCbDescriptorSize); m_pCmdList->SetGraphicsRootDescriptorTable(RootParameterSRV, srvHandle); m_pCmdList->SetGraphicsRootDescriptorTable(RootParameterUAV, uavHandle); m_pCmdList->SetGraphicsRootDescriptorTable(RootParameterCBV, cbHandle); // Set viewport D3D12_VIEWPORT viewport = {}; viewport.Width = static_cast<float>(newWidth); viewport.Height = static_cast<float>(newHeight); viewport.MaxDepth = 1.0f; m_pCmdList->RSSetViewports(1, &viewport); // Set scissor D3D12_RECT scissorRect = {}; scissorRect.right = static_cast<LONG>(newWidth); scissorRect.bottom = static_cast<LONG>(newHeight); m_pCmdList->RSSetScissorRects(1, &scissorRect); // Update const buf m_constantBufferData.rtWidth = newWidth; m_constantBufferData.flipX = bFlipX ? 1 : 0; m_constantBufferData.flipY = bFlipY ? 1 : 0; CD3DX12_RANGE readRange(0, 0); result = m_pConstantBuffer->Map(0, &readRange, reinterpret_cast<void**>(&m_pCbvDataBegin)); memcpy(m_pCbvDataBegin, &m_constantBufferData, sizeof(m_constantBufferData)); m_pConstantBuffer->Unmap(0, nullptr); // Set RT CD3DX12_CPU_DESCRIPTOR_HANDLE internalRtvHandle(m_pInternalRtvHeap->GetCPUDescriptorHandleForHeapStart()); m_config.pDevice->CreateRenderTargetView(m_pInternalRT, nullptr, internalRtvHandle); m_pCmdList->OMSetRenderTargets(1, &internalRtvHandle, FALSE, nullptr); // Record commands m_pCmdList->ClearRenderTargetView(internalRtvHandle, ClearColor, 0, nullptr); m_pCmdList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); CD3DX12_RESOURCE_BARRIER barrier = {}; // Render full screen quad and write out UAV barrier = CD3DX12_RESOURCE_BARRIER::Transition(pRes, prevState, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); m_pCmdList->ResourceBarrier(1, &barrier); m_pCmdList->DrawInstanced(3, 1, 0, 0); #if OVERWRITE_SRC_RES barrier = CD3DX12_RESOURCE_BARRIER::Transition(pRes, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_COPY_DEST); m_pCmdList->ResourceBarrier(1, &barrier); barrier = CD3DX12_RESOURCE_BARRIER::Transition(m_pInternalRT, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE); m_pCmdList->ResourceBarrier(1, &barrier); m_pCmdList->CopyResource(pRes, m_pInternalRT); barrier = CD3DX12_RESOURCE_BARRIER::Transition(m_pInternalRT, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET); m_pCmdList->ResourceBarrier(1, &barrier); barrier = CD3DX12_RESOURCE_BARRIER::Transition(pRes, D3D12_RESOURCE_STATE_COPY_DEST, prevState); m_pCmdList->ResourceBarrier(1, &barrier); #endif // Copy UAV to CPU-visible buffer barrier = CD3DX12_RESOURCE_BARRIER::Transition(m_pPSWriteBuf, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE); m_pCmdList->ResourceBarrier(1, &barrier); m_pCmdList->CopyResource(m_pPSWriteBufReadBack, m_pPSWriteBuf); barrier = CD3DX12_RESOURCE_BARRIER::Transition(m_pPSWriteBuf, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); m_pCmdList->ResourceBarrier(1, &barrier); // Execute the command list result = m_pCmdList->Close(); ID3D12CommandList* ppCommandLists[] = { m_pCmdList }; m_config.pCmdQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists); WaitCmdListFinish(); // Read back UAV results void* pUavData = nullptr; result = m_pPSWriteBufReadBack->Map(0, &readRange, &pUavData); if (result == S_OK) { const UINT totalBytes = newWidth * newHeight * BytesPerPixel; pImgOut->pitch = newWidth * BytesPerPixel; pImgOut->width = newWidth; pImgOut->height = newHeight; pImgOut->pData = new char[totalBytes]; memcpy(pImgOut->pData, pUavData, totalBytes); m_pPSWriteBufReadBack->Unmap(0, nullptr); } } // Free temp assets FreeCaptureAssets(); } return result; }