// Fill the command list with all the render commands and dependent state. void D3D12Fullscreen::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())); if (m_resizeResources) { // Reload resources that depend on the size of the swap chain. LoadSizeDependentResources(); } // Set necessary state. m_commandList->SetGraphicsRootSignature(m_rootSignature.Get()); ID3D12DescriptorHeap* ppHeaps[] = { m_cbvHeap.Get() }; m_commandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); CD3DX12_GPU_DESCRIPTOR_HANDLE cbvHandle(m_cbvHeap->GetGPUDescriptorHandleForHeapStart(), m_frameIndex, m_cbvDescriptorSize); m_commandList->SetGraphicsRootDescriptorTable(0, cbvHandle); m_commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); 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 commands. const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f }; m_commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr); m_commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); m_commandList->IASetVertexBuffers(0, 1, &m_vertexBufferView); PIXBeginEvent(m_commandList.Get(), 0, L"Draw a thin rectangle"); m_commandList->DrawInstanced(4, 1, 0, 0); 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()); }
void D3D12DynamicIndexing::PopulateCommandList(FrameResource* pFrameResource) { // 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_pCurrentFrameResource->m_commandAllocator->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_pCurrentFrameResource->m_commandAllocator.Get(), m_pipelineState.Get())); // Set necessary state. m_commandList->SetGraphicsRootSignature(m_rootSignature.Get()); ID3D12DescriptorHeap* ppHeaps[] = { m_cbvSrvHeap.Get(), m_samplerHeap.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); CD3DX12_CPU_DESCRIPTOR_HANDLE dsvHandle(m_dsvHeap->GetCPUDescriptorHandleForHeapStart()); m_commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, &dsvHandle); // Record commands. const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f }; m_commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr); m_commandList->ClearDepthStencilView(m_dsvHeap->GetCPUDescriptorHandleForHeapStart(), D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr); if (UseBundles) { // Execute the prebuilt bundle. m_commandList->ExecuteBundle(pFrameResource->m_bundle.Get()); } else { // Populate a new command list. pFrameResource->PopulateCommandList(m_commandList.Get(), m_pipelineState.Get(), m_currentFrameResourceIndex, m_numIndices, &m_indexBufferView, &m_vertexBufferView, m_cbvSrvHeap.Get(), m_cbvSrvDescriptorSize, m_samplerHeap.Get(), m_rootSignature.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()); }
// Assemble the CommandListPre command list. void D3D12Multithreading::BeginFrame() { m_pCurrentFrameResource->Init(); // Indicate that the back buffer will be used as a render target. m_pCurrentFrameResource->m_commandLists[CommandListPre]->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_frameIndex].Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET)); // Clear the render target and depth stencil. const float clearColor[] = { 0.0f, 0.0f, 0.0f, 1.0f }; CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart(), m_frameIndex, m_rtvDescriptorSize); m_pCurrentFrameResource->m_commandLists[CommandListPre]->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr); m_pCurrentFrameResource->m_commandLists[CommandListPre]->ClearDepthStencilView(m_dsvHeap->GetCPUDescriptorHandleForHeapStart(), D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr); ThrowIfFailed(m_pCurrentFrameResource->m_commandLists[CommandListPre]->Close()); }
// Set up appropriate views for the intermediate render target. void D3D12Fullscreen::LoadSceneResolutionDependentResources() { // Update resolutions shown in app title. UpdateTitle(); // Set up the scene viewport and scissor rect to match the current scene rendering resolution. { m_sceneViewport.Width = static_cast<float>(m_resolutionOptions[m_resolutionIndex].Width); m_sceneViewport.Height = static_cast<float>(m_resolutionOptions[m_resolutionIndex].Height); m_sceneViewport.MaxDepth = 1.0f; m_sceneScissorRect.right = static_cast<LONG>(m_resolutionOptions[m_resolutionIndex].Width); m_sceneScissorRect.bottom = static_cast<LONG>(m_resolutionOptions[m_resolutionIndex].Height); } // Update post-process viewport and scissor rectangle. UpdatePostViewAndScissor(); // Create RTV for the intermediate render target. { D3D12_RESOURCE_DESC swapChainDesc = m_renderTargets[m_frameIndex]->GetDesc(); const CD3DX12_CLEAR_VALUE clearValue(swapChainDesc.Format, ClearColor); const CD3DX12_RESOURCE_DESC renderTargetDesc = CD3DX12_RESOURCE_DESC::Tex2D( swapChainDesc.Format, m_resolutionOptions[m_resolutionIndex].Width, m_resolutionOptions[m_resolutionIndex].Height, 1u, 1u, swapChainDesc.SampleDesc.Count, swapChainDesc.SampleDesc.Quality, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, D3D12_TEXTURE_LAYOUT_UNKNOWN, 0u); CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart(), FrameCount, m_rtvDescriptorSize); 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))); m_device->CreateRenderTargetView(m_intermediateRenderTarget.Get(), nullptr, rtvHandle); NAME_D3D12_OBJECT(m_intermediateRenderTarget); } // Create SRV for the intermediate render target. m_device->CreateShaderResourceView(m_intermediateRenderTarget.Get(), nullptr, m_cbvSrvHeap->GetCPUDescriptorHandleForHeapStart()); }
void QD3D12WindowPrivate::setupRenderTargets() { Q_Q(QD3D12Window); D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle(rtvHeap->GetCPUDescriptorHandleForHeapStart()); for (int i = 0; i < swapChainBufferCount; ++i) { if (FAILED(swapChain->GetBuffer(i, IID_PPV_ARGS(&renderTargets[i])))) { qWarning("Failed to get buffer %d from swap chain", i); return; } device->CreateRenderTargetView(renderTargets[i].Get(), Q_NULLPTR, rtvHandle); rtvHandle.ptr += rtvStride; } ID3D12Resource *ds = createDepthStencil(dsvHeap->GetCPUDescriptorHandleForHeapStart(), q->size(), 0); if (ds) depthStencil.Attach(ds); }
// Load size dependent resource HRESULT VolumetricAnimation::LoadSizeDependentResource() { HRESULT hr; // Create render target views (RTVs). CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle( m_rtvHeap->GetCPUDescriptorHandleForHeapStart() ); for ( UINT i = 0; i < FrameCount; i++ ) { VRET( m_swapChain->GetBuffer( i, IID_PPV_ARGS( &m_renderTargets[i] ) ) ); DXDebugName( m_renderTargets[i] ); m_device->CreateRenderTargetView( m_renderTargets[i].Get(), nullptr, rtvHandle ); rtvHandle.Offset( 1, m_rtvDescriptorSize ); } // Create the depth stencil. { CD3DX12_RESOURCE_DESC shadowTextureDesc( D3D12_RESOURCE_DIMENSION_TEXTURE2D, 0, static_cast< UINT >( m_width ), static_cast< UINT >( m_height ), 1, 1, DXGI_FORMAT_D32_FLOAT, 1, 0, D3D12_TEXTURE_LAYOUT_UNKNOWN, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL | D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE ); D3D12_CLEAR_VALUE clearValue; // Performance tip: Tell the runtime at resource creation the desired clear value. clearValue.Format = DXGI_FORMAT_D32_FLOAT; clearValue.DepthStencil.Depth = 1.0f; clearValue.DepthStencil.Stencil = 0; VRET( m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES( D3D12_HEAP_TYPE_DEFAULT ), D3D12_HEAP_FLAG_NONE, &shadowTextureDesc, D3D12_RESOURCE_STATE_DEPTH_WRITE, &clearValue, IID_PPV_ARGS( &m_depthBuffer ) ) ); DXDebugName( m_depthBuffer ); // Create the depth stencil view. m_device->CreateDepthStencilView( m_depthBuffer.Get(), nullptr, m_dsvHeap->GetCPUDescriptorHandleForHeapStart() ); } m_viewport.Width = static_cast< float >( m_width ); m_viewport.Height = static_cast< float >( m_height ); m_viewport.MaxDepth = 1.0f; m_scissorRect.right = static_cast< LONG >( m_width ); m_scissorRect.bottom = static_cast< LONG >( m_height ); float fAspectRatio = m_width / ( FLOAT ) m_height; m_camera.SetProjParams( XM_PI / 4, fAspectRatio, 0.01f, 1250.0f ); m_camera.SetWindow( m_width, m_height ); return S_OK; }
void RenderSysem::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_pCommandAllocator->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. auto pPipelineState = m_Triangle.GetPipelineState(); ThrowIfFailed(m_pCommandList->Reset(m_pCommandAllocator.Get(), pPipelineState.Get())); auto pRootSignature = m_Triangle.GetRootSignature(); m_pCommandList->SetGraphicsRootSignature(pRootSignature.Get()); // ThrowIfFailed(m_pBundleList->Reset(m_pBundleAllocator.Get(), pPipelineState.Get())); auto pCBVHeap = m_Triangle.GetCBVHeap(); ID3D12DescriptorHeap* ppHeaps[] ={ pCBVHeap.Get() }; m_pCommandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); m_pCommandList->RSSetViewports(1, &m_Viewport); m_pCommandList->RSSetScissorRects(1, &m_ScissorRect); m_pCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_pRenderTargets[m_FrameIndex].Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET)); CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_pRTVHeap->GetCPUDescriptorHandleForHeapStart(), m_FrameIndex, m_RTVDescriptorSize); m_pCommandList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr); // Record commands. const float clearColor[] ={ 0.0f, 0.2f, 0.4f, 1.0f }; m_pCommandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr); m_pCommandList->ExecuteBundle(m_pBundleList.Get()); //pCIndicate that the back buffer will now be used to present. m_pCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_pRenderTargets[m_FrameIndex].Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT)); ThrowIfFailed(m_pCommandList->Close()); }
void D3D1211on12::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()); 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 commands. const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f }; m_commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr); m_commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); m_commandList->IASetVertexBuffers(0, 1, &m_vertexBufferView); m_commandList->DrawInstanced(3, 1, 0, 0); // Note: do not transition the render target to present here. // the transition will occur when the wrapped 11On12 render // target resource is released. ThrowIfFailed(m_commandList->Close()); }
CD3DX12_CPU_DESCRIPTOR_HANDLE VR::getRTVHandle(int frameIndex) { UINT rtvDescriptorSize; rtvDescriptorSize = xapp->device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(rtvVRHeap->GetCPUDescriptorHandleForHeapStart(), frameIndex, rtvDescriptorSize); return rtvHandle; };
// Load the sample assets. void D3D12Multithreading::LoadAssets() { // Create the root signature. { CD3DX12_DESCRIPTOR_RANGE ranges[4]; // Perfomance TIP: Order from most frequent to least frequent. ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 2, 1); // 2 frequently changed diffuse + normal textures - using registers t1 and t2. ranges[1].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0); // 1 frequently changed constant buffer. ranges[2].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0); // 1 infrequently changed shadow texture - starting in register t0. ranges[3].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 2, 0); // 2 static samplers. CD3DX12_ROOT_PARAMETER rootParameters[4]; rootParameters[0].InitAsDescriptorTable(1, &ranges[0], D3D12_SHADER_VISIBILITY_PIXEL); rootParameters[1].InitAsDescriptorTable(1, &ranges[1], D3D12_SHADER_VISIBILITY_ALL); rootParameters[2].InitAsDescriptorTable(1, &ranges[2], D3D12_SHADER_VISIBILITY_PIXEL); rootParameters[3].InitAsDescriptorTable(1, &ranges[3], 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))); } // Create the pipeline state, which includes loading shaders. { ComPtr<ID3DBlob> vertexShader; ComPtr<ID3DBlob> pixelShader; #ifdef _DEBUG // Enable better shader debugging with the graphics debugging tools. UINT compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; #else UINT compileFlags = D3DCOMPILE_OPTIMIZATION_LEVEL3; #endif ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"shaders.hlsl").c_str(), nullptr, nullptr, "VSMain", "vs_5_0", compileFlags, 0, &vertexShader, nullptr)); ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"shaders.hlsl").c_str(), nullptr, nullptr, "PSMain", "ps_5_0", compileFlags, 0, &pixelShader, nullptr)); D3D12_INPUT_LAYOUT_DESC inputLayoutDesc; inputLayoutDesc.pInputElementDescs = SampleAssets::StandardVertexDescription; inputLayoutDesc.NumElements = _countof(SampleAssets::StandardVertexDescription); 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 PSO for rendering the scene. D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.InputLayout = inputLayoutDesc; psoDesc.pRootSignature = m_rootSignature.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; ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineState))); // Alter the description and create the PSO for rendering // the shadow map. The shadow map does not use a pixel // shader or render targets. psoDesc.PS.pShaderBytecode = 0; psoDesc.PS.BytecodeLength = 0; psoDesc.RTVFormats[0] = DXGI_FORMAT_UNKNOWN; psoDesc.NumRenderTargets = 0; ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineStateShadowMap))); } // Create temporary command list for initial GPU setup. ComPtr<ID3D12GraphicsCommandList> commandList; ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocator.Get(), m_pipelineState.Get(), IID_PPV_ARGS(&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); } // Create the depth stencil. { CD3DX12_RESOURCE_DESC shadowTextureDesc( D3D12_RESOURCE_DIMENSION_TEXTURE2D, 0, static_cast<UINT>(m_viewport.Width), static_cast<UINT>(m_viewport.Height), 1, 1, DXGI_FORMAT_D32_FLOAT, 1, 0, D3D12_TEXTURE_LAYOUT_UNKNOWN, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL | D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE); D3D12_CLEAR_VALUE clearValue; // Performance tip: Tell the runtime at resource creation the desired clear value. clearValue.Format = DXGI_FORMAT_D32_FLOAT; clearValue.DepthStencil.Depth = 1.0f; clearValue.DepthStencil.Stencil = 0; ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &shadowTextureDesc, D3D12_RESOURCE_STATE_DEPTH_WRITE, &clearValue, IID_PPV_ARGS(&m_depthStencil))); // Create the depth stencil view. m_device->CreateDepthStencilView(m_depthStencil.Get(), nullptr, m_dsvHeap->GetCPUDescriptorHandleForHeapStart()); } // Load scene assets. UINT fileSize = 0; UINT8* pAssetData; ThrowIfFailed(ReadDataFromFile(GetAssetFullPath(SampleAssets::DataFileName).c_str(), &pAssetData, &fileSize)); // 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(&m_vertexBufferUpload))); // Copy data to the upload heap and then schedule a copy // from the upload heap to the vertex buffer. D3D12_SUBRESOURCE_DATA vertexData = {}; vertexData.pData = pAssetData + SampleAssets::VertexDataOffset; vertexData.RowPitch = SampleAssets::VertexDataSize; vertexData.SlicePitch = vertexData.RowPitch; PIXBeginEvent(commandList.Get(), 0, L"Copy vertex buffer data to default resource..."); UpdateSubresources<1>(commandList.Get(), m_vertexBuffer.Get(), m_vertexBufferUpload.Get(), 0, 0, 1, &vertexData); commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_vertexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER)); PIXEndEvent(commandList.Get()); } // Initialize the vertex buffer view. m_vertexBufferView.BufferLocation = m_vertexBuffer->GetGPUVirtualAddress(); m_vertexBufferView.SizeInBytes = SampleAssets::VertexDataSize; m_vertexBufferView.StrideInBytes = SampleAssets::StandardVertexStride; } // 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(&m_indexBufferUpload))); // Copy data to the upload heap and then schedule a copy // from the upload heap to the index buffer. D3D12_SUBRESOURCE_DATA indexData = {}; indexData.pData = pAssetData + SampleAssets::IndexDataOffset; indexData.RowPitch = SampleAssets::IndexDataSize; indexData.SlicePitch = indexData.RowPitch; PIXBeginEvent(commandList.Get(), 0, L"Copy index buffer data to default resource..."); UpdateSubresources<1>(commandList.Get(), m_indexBuffer.Get(), m_indexBufferUpload.Get(), 0, 0, 1, &indexData); commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_indexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_INDEX_BUFFER)); PIXEndEvent(commandList.Get()); } // Initialize the index buffer view. m_indexBufferView.BufferLocation = m_indexBuffer->GetGPUVirtualAddress(); m_indexBufferView.SizeInBytes = SampleAssets::IndexDataSize; m_indexBufferView.Format = SampleAssets::StandardIndexFormat; } // Create shader resources. { // Get the CBV SRV descriptor size for the current device. const UINT cbvSrvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); // Get a handle to the start of the descriptor heap. CD3DX12_CPU_DESCRIPTOR_HANDLE cbvSrvHandle(m_cbvSrvHeap->GetCPUDescriptorHandleForHeapStart()); { // Describe and create 2 null SRVs. Null descriptors are needed in order // to achieve the effect of an "unbound" resource. D3D12_SHADER_RESOURCE_VIEW_DESC nullSrvDesc = {}; nullSrvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; nullSrvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; nullSrvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; nullSrvDesc.Texture2D.MipLevels = 1; nullSrvDesc.Texture2D.MostDetailedMip = 0; nullSrvDesc.Texture2D.ResourceMinLODClamp = 0.0f; m_device->CreateShaderResourceView(nullptr, &nullSrvDesc, cbvSrvHandle); cbvSrvHandle.Offset(cbvSrvDescriptorSize); m_device->CreateShaderResourceView(nullptr, &nullSrvDesc, cbvSrvHandle); cbvSrvHandle.Offset(cbvSrvDescriptorSize); } // Create each texture and SRV descriptor. const UINT srvCount = _countof(SampleAssets::Textures); PIXBeginEvent(commandList.Get(), 0, L"Copy diffuse and normal texture data to default resources..."); for (int i = 0; i < srvCount; i++) { // Describe and create a Texture2D. const SampleAssets::TextureResource &tex = SampleAssets::Textures[i]; CD3DX12_RESOURCE_DESC texDesc( D3D12_RESOURCE_DIMENSION_TEXTURE2D, 0, tex.Width, tex.Height, 1, static_cast<UINT16>(tex.MipLevels), tex.Format, 1, 0, D3D12_TEXTURE_LAYOUT_UNKNOWN, D3D12_RESOURCE_FLAG_NONE); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &texDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_textures[i]))); { const UINT subresourceCount = texDesc.DepthOrArraySize * texDesc.MipLevels; UINT64 uploadBufferSize = GetRequiredIntermediateSize(m_textures[i].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(&m_textureUploads[i]))); // Copy data to the intermediate upload heap and then schedule a copy // from the upload heap to the Texture2D. D3D12_SUBRESOURCE_DATA textureData = {}; textureData.pData = pAssetData + tex.Data->Offset; textureData.RowPitch = tex.Data->Pitch; textureData.SlicePitch = tex.Data->Size; UpdateSubresources(commandList.Get(), m_textures[i].Get(), m_textureUploads[i].Get(), 0, 0, subresourceCount, &textureData); commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_textures[i].Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE)); } // Describe and create an SRV. D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; srvDesc.Format = tex.Format; srvDesc.Texture2D.MipLevels = tex.MipLevels; srvDesc.Texture2D.MostDetailedMip = 0; srvDesc.Texture2D.ResourceMinLODClamp = 0.0f; m_device->CreateShaderResourceView(m_textures[i].Get(), &srvDesc, cbvSrvHandle); // Move to the next descriptor slot. cbvSrvHandle.Offset(cbvSrvDescriptorSize); } PIXEndEvent(commandList.Get()); } free(pAssetData); // Create the samplers. { // Get the sampler descriptor size for the current device. const UINT samplerDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); // Get a handle to the start of the descriptor heap. CD3DX12_CPU_DESCRIPTOR_HANDLE samplerHandle(m_samplerHeap->GetCPUDescriptorHandleForHeapStart()); // Describe and create the wrapping sampler, which is used for // sampling diffuse/normal maps. D3D12_SAMPLER_DESC wrapSamplerDesc = {}; wrapSamplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR; wrapSamplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP; wrapSamplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP; wrapSamplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP; wrapSamplerDesc.MinLOD = 0; wrapSamplerDesc.MaxLOD = D3D12_FLOAT32_MAX; wrapSamplerDesc.MipLODBias = 0.0f; wrapSamplerDesc.MaxAnisotropy = 1; wrapSamplerDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS; wrapSamplerDesc.BorderColor[0] = wrapSamplerDesc.BorderColor[1] = wrapSamplerDesc.BorderColor[2] = wrapSamplerDesc.BorderColor[3] = 0; m_device->CreateSampler(&wrapSamplerDesc, samplerHandle); // Move the handle to the next slot in the descriptor heap. samplerHandle.Offset(samplerDescriptorSize); // Describe and create the point clamping sampler, which is // used for the shadow map. D3D12_SAMPLER_DESC clampSamplerDesc = {}; clampSamplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT; clampSamplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; clampSamplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; clampSamplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; clampSamplerDesc.MipLODBias = 0.0f; clampSamplerDesc.MaxAnisotropy = 1; clampSamplerDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS; clampSamplerDesc.BorderColor[0] = clampSamplerDesc.BorderColor[1] = clampSamplerDesc.BorderColor[2] = clampSamplerDesc.BorderColor[3] = 0; clampSamplerDesc.MinLOD = 0; clampSamplerDesc.MaxLOD = D3D12_FLOAT32_MAX; m_device->CreateSampler(&clampSamplerDesc, samplerHandle); } // Create lights. for (int i = 0; i < NumLights; i++) { // Set up each of the light positions and directions (they all start // in the same place). m_lights[i].position = { 0.0f, 15.0f, -30.0f, 1.0f }; m_lights[i].direction = { 0.0, 0.0f, 1.0f, 0.0f }; m_lights[i].falloff = { 800.0f, 1.0f, 0.0f, 1.0f }; m_lights[i].color = { 0.7f, 0.7f, 0.7f, 1.0f }; XMVECTOR eye = XMLoadFloat4(&m_lights[i].position); XMVECTOR at = XMVectorAdd(eye, XMLoadFloat4(&m_lights[i].direction)); XMVECTOR up = { 0, 1, 0 }; m_lightCameras[i].Set(eye, at, up); } // Close the command list and use it to execute the initial GPU setup. ThrowIfFailed(commandList->Close()); ID3D12CommandList* ppCommandLists[] = { commandList.Get() }; m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists); // Create frame resources. for (int i = 0; i < FrameCount; i++) { m_frameResources[i] = new FrameResource(m_device.Get(), m_pipelineState.Get(), m_pipelineStateShadowMap.Get(), m_dsvHeap.Get(), m_cbvSrvHeap.Get(), &m_viewport, i); m_frameResources[i]->WriteConstantBuffers(&m_viewport, &m_camera, m_lightCameras, m_lights); } m_currentFrameResourceIndex = 0; m_pCurrentFrameResource = m_frameResources[m_currentFrameResourceIndex]; // 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 = CreateEventEx(nullptr, FALSE, FALSE, EVENT_ALL_ACCESS); 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); } }
// 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 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()); }
// Load the rendering pipeline dependencies. void D3D12HelloConstBuffers::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))); // 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; 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(); // Create descriptor heaps. { // Describe and create a render target view (RTV) descriptor heap. D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {}; rtvHeapDesc.NumDescriptors = FrameCount; rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; ThrowIfFailed(m_device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&m_rtvHeap))); m_rtvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); // Describe and create a constant buffer view (CBV) descriptor heap. // Flags indicate that this descriptor heap can be bound to the pipeline // and that descriptors contained in it can be referenced by a root table. D3D12_DESCRIPTOR_HEAP_DESC cbvHeapDesc = {}; cbvHeapDesc.NumDescriptors = 1; cbvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; cbvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; ThrowIfFailed(m_device->CreateDescriptorHeap(&cbvHeapDesc, IID_PPV_ARGS(&m_cbvHeap))); } // 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); } } ThrowIfFailed(m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_commandAllocator))); }
// Fill the command list with all the render commands and dependent state. void D3D12Fullscreen::PopulateCommandLists() { // 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_sceneCommandAllocators[m_frameIndex]->Reset()); ThrowIfFailed(m_postCommandAllocators[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_sceneCommandList->Reset(m_sceneCommandAllocators[m_frameIndex].Get(), m_scenePipelineState.Get())); ThrowIfFailed(m_postCommandList->Reset(m_postCommandAllocators[m_frameIndex].Get(), m_postPipelineState.Get())); // Populate m_sceneCommandList to render scene to intermediate render target. { // Set necessary state. m_sceneCommandList->SetGraphicsRootSignature(m_sceneRootSignature.Get()); ID3D12DescriptorHeap* ppHeaps[] = { m_cbvSrvHeap.Get() }; m_sceneCommandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); CD3DX12_GPU_DESCRIPTOR_HANDLE cbvHandle(m_cbvSrvHeap->GetGPUDescriptorHandleForHeapStart(), m_frameIndex + 1, m_cbvSrvDescriptorSize); m_sceneCommandList->SetGraphicsRootDescriptorTable(0, cbvHandle); m_sceneCommandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); m_sceneCommandList->RSSetViewports(1, &m_sceneViewport); m_sceneCommandList->RSSetScissorRects(1, &m_sceneScissorRect); CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart(), FrameCount, m_rtvDescriptorSize); m_sceneCommandList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr); // Record commands. m_sceneCommandList->ClearRenderTargetView(rtvHandle, ClearColor, 0, nullptr); m_sceneCommandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); m_sceneCommandList->IASetVertexBuffers(0, 1, &m_sceneVertexBufferView); PIXBeginEvent(m_sceneCommandList.Get(), 0, L"Draw a thin rectangle"); m_sceneCommandList->DrawInstanced(4, 1, 0, 0); PIXEndEvent(m_sceneCommandList.Get()); } ThrowIfFailed(m_sceneCommandList->Close()); // Populate m_postCommandList to scale intermediate render target to screen. { // Set necessary state. m_postCommandList->SetGraphicsRootSignature(m_postRootSignature.Get()); ID3D12DescriptorHeap* ppHeaps[] = { m_cbvSrvHeap.Get() }; m_postCommandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); // 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_postCommandList->ResourceBarrier(_countof(barriers), barriers); m_postCommandList->SetGraphicsRootDescriptorTable(0, m_cbvSrvHeap->GetGPUDescriptorHandleForHeapStart()); m_postCommandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); m_postCommandList->RSSetViewports(1, &m_postViewport); m_postCommandList->RSSetScissorRects(1, &m_postScissorRect); CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart(), m_frameIndex, m_rtvDescriptorSize); m_postCommandList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr); // Record commands. m_postCommandList->ClearRenderTargetView(rtvHandle, LetterboxColor, 0, nullptr); m_postCommandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); m_postCommandList->IASetVertexBuffers(0, 1, &m_postVertexBufferView); PIXBeginEvent(m_postCommandList.Get(), 0, L"Draw texture to screen."); m_postCommandList->DrawInstanced(4, 1, 0, 0); PIXEndEvent(m_postCommandList.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_postCommandList->ResourceBarrier(_countof(barriers), barriers); } ThrowIfFailed(m_postCommandList->Close()); }
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() ); }
void VR::initD3D() { #if defined(_OVR_) Sizei bufferSize; bufferSize.w = buffersize_width; bufferSize.h = buffersize_height; // xapp->d3d11Device.Get() will not work, we need a real D3D11 device //for (int i = 0; i < xapp->FrameCount; i++) { // ID3D12Resource *resource = xapp->renderTargets[i].Get(); // D3D12_RESOURCE_DESC rDesc = resource->GetDesc(); // D3D11_RESOURCE_FLAGS d3d11Flags = { D3D11_BIND_RENDER_TARGET }; // ThrowIfFailed(xapp->d3d11On12Device->CreateWrappedResource( // resource, // &d3d11Flags, // D3D12_RESOURCE_STATE_RENDER_TARGET, // D3D12_RESOURCE_STATE_PRESENT, // IID_PPV_ARGS(&xapp->wrappedBackBuffers[i]) // )); // //xapp->d3d11On12Device->AcquireWrappedResources(xapp->wrappedBackBuffers[i].GetAddressOf(), 1); //} ovrTextureSwapChainDesc dsDesc = {}; dsDesc.Type = ovrTexture_2D; dsDesc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; dsDesc.ArraySize = 1; dsDesc.Width = bufferSize.w; dsDesc.Height = bufferSize.h; dsDesc.MipLevels = 1; dsDesc.SampleCount = 1; dsDesc.StaticImage = ovrFalse; dsDesc.MiscFlags = ovrTextureMisc_DX_Typeless;//ovrTextureMisc_None; dsDesc.BindFlags = ovrTextureBind_DX_RenderTarget; /* D3D11_TEXTURE2D_DESC dsDesc; dsDesc.Width = bufferSize.w; dsDesc.Height = bufferSize.h; dsDesc.MipLevels = 1; dsDesc.ArraySize = 1; dsDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;//DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; dsDesc.SampleDesc.Count = 1; dsDesc.SampleDesc.Quality = 0; dsDesc.Usage = D3D11_USAGE_DEFAULT; dsDesc.CPUAccessFlags = 0; dsDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED; dsDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; */ if (ovr_CreateTextureSwapChainDX(session, xapp->commandQueue.Get()/*xapp->reald3d11Device.Get()*/, &dsDesc, &textureSwapChain) == ovrSuccess) { int count = 0; ovr_GetTextureSwapChainLength(session, textureSwapChain, &count); texRtv.resize(count); texResource.resize(count); // Create descriptor heaps. UINT rtvDescriptorSize; { // Describe and create a render target view (RTV) descriptor heap. D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {}; rtvHeapDesc.NumDescriptors = count; rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; ThrowIfFailed(xapp->device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&rtvVRHeap))); rtvVRHeap->SetName(L"rtVRHeap_xapp"); rtvDescriptorSize = xapp->device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); } for (int i = 0; i < count; ++i) { ID3D11Texture2D* tex = nullptr; ovr_GetTextureSwapChainBufferDX(session, textureSwapChain, i, IID_PPV_ARGS(&texResource[i])); //xapp->reald3d11Device.Get()->CreateRenderTargetView(tex, nullptr, &texRtv[i]); D3D12_RENDER_TARGET_VIEW_DESC rtvd = {}; rtvd.Format = DXGI_FORMAT_R8G8B8A8_UNORM; rtvd.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(rtvVRHeap->GetCPUDescriptorHandleForHeapStart(), i, rtvDescriptorSize); texRtv[i] = rtvHandle; xapp->device->CreateRenderTargetView(texResource[i], /*nullptr*/&rtvd, texRtv[i]); //ComPtr<IDXGIResource> dxgires; //tex->QueryInterface<IDXGIResource>(&dxgires); ////Log("dxgires = " << dxgires.GetAddressOf() << endl); //HANDLE shHandle; //dxgires->GetSharedHandle(&shHandle); ////Log("shared handle = " << shHandle << endl); //xapp->d3d11Device->OpenSharedResource(shHandle, IID_PPV_ARGS(&xapp->wrappedTextures[i])); //tex->Release(); } } // Initialize our single full screen Fov layer. layer.Header.Type = ovrLayerType_EyeFov; layer.Header.Flags = 0; layer.ColorTexture[0] = textureSwapChain; layer.ColorTexture[1] = nullptr;//textureSwapChain; layer.Fov[0] = eyeRenderDesc[0].Fov; layer.Fov[1] = eyeRenderDesc[1].Fov; layer.Viewport[0] = Recti(0, 0, bufferSize.w / 2, bufferSize.h); layer.Viewport[1] = Recti(bufferSize.w / 2, 0, bufferSize.w / 2, bufferSize.h); // ld.RenderPose and ld.SensorSampleTime are updated later per frame. #endif #if defined(_DEBUG) // SetStablePowerState requires Win10 to be in developer mode: // start settings app, then search for 'for developers settings', // then enable it under developer features, developer mode //xapp->device->SetStablePowerState(true); #endif }
void D3D12Render::loadPipeline() { HRESULT res; #ifdef _DEBUG //Enable the D3D12 debug layer ComPtr<ID3D12Debug> pDebugController; if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&pDebugController)))) { pDebugController->EnableDebugLayer(); } #endif ComPtr<IDXGIFactory4> pFactory; CreateDXGIFactory1(IID_PPV_ARGS(&pFactory)); bool UseWarpDevice = false; if (UseWarpDevice) { ComPtr<IDXGIAdapter> pWarpAdapter; res = pFactory->EnumWarpAdapter(IID_PPV_ARGS(&pWarpAdapter)); assert(res == S_OK); res = D3D12CreateDevice(pWarpAdapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_pD3D12Device)); assert(res == S_OK); } else { res = D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_pD3D12Device)); assert(res == S_OK); } /////////////////////// //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; res = m_pD3D12Device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&m_pCommandQueue)); assert(res == S_OK); //Describe and Create the swap chain DXGI_SWAP_CHAIN_DESC swapChainDesc ={}; swapChainDesc.BufferCount = FrameCount; swapChainDesc.BufferDesc.Width = getClientWidth(); swapChainDesc.BufferDesc.Height = getClientHeight(); swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; swapChainDesc.OutputWindow = getHwnd(); swapChainDesc.SampleDesc.Count = 1; swapChainDesc.Windowed = TRUE; ComPtr<IDXGISwapChain> pSwapChain; res = pFactory->CreateSwapChain( m_pCommandQueue.Get(), // Swap chain needs the queue so that it can force a flush on it. &swapChainDesc, &pSwapChain ); assert(res == S_OK); res = pSwapChain.As(&m_pSwapChain); assert(res == S_OK); m_frameIndex = m_pSwapChain->GetCurrentBackBufferIndex(); ///////////////////////// Create Decriptor heaps ///////////////////////////////////////////// { D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc ={}; rtvHeapDesc.NumDescriptors = FrameCount; rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; res = m_pD3D12Device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&m_pRTVHeap)); assert(res == S_OK); m_rtvDescSize = m_pD3D12Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); } //Create frame resources { CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_pRTVHeap->GetCPUDescriptorHandleForHeapStart()); // Create a RTV for each frame. for (UINT n = 0; n < FrameCount; n++) { res = m_pSwapChain->GetBuffer(n, IID_PPV_ARGS(&m_pRenderTargets[n])); assert(res == S_OK); m_pD3D12Device->CreateRenderTargetView(m_pRenderTargets[n].Get(), nullptr, rtvHandle); rtvHandle.Offset(1, m_rtvDescSize); } } //The command allocator is going to be used for allocating memory for the list of commands that we send to the GPU each frame to render graphics. res = m_pD3D12Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_pCommandAllocator)); assert(res == S_OK); res = m_pD3D12Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_BUNDLE, IID_PPV_ARGS(&m_pBundleAllocator)); assert(res == S_OK); }
// 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 D3D12Bundles::LoadAssets() { // These upload heaps are only needed during loading. ComPtr<ID3D12Resource> vertexBufferUploadHeap; ComPtr<ID3D12Resource> indexBufferUploadHeap; ComPtr<ID3D12Resource> textureUploadHeap; // Create the root signature. { CD3DX12_DESCRIPTOR_RANGE ranges[3]; ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0); ranges[1].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 1, 0); ranges[2].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0); CD3DX12_ROOT_PARAMETER rootParameters[3]; 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_ALL); 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))); } // Create the pipeline state, which includes loading shaders. { UINT8* pVertexShaderData; UINT8* pPixelShaderData1; UINT8* pPixelShaderData2; UINT vertexShaderDataLength; UINT pixelShaderDataLength1; UINT pixelShaderDataLength2; // Load pre-compiled shaders. ThrowIfFailed(ReadDataFromFile(GetAssetFullPath(L"shader_mesh_simple_vert.cso").c_str(), &pVertexShaderData, &vertexShaderDataLength)); ThrowIfFailed(ReadDataFromFile(GetAssetFullPath(L"shader_mesh_simple_pixel.cso").c_str(), &pPixelShaderData1, &pixelShaderDataLength1)); ThrowIfFailed(ReadDataFromFile(GetAssetFullPath(L"shader_mesh_alt_pixel.cso").c_str(), &pPixelShaderData2, &pixelShaderDataLength2)); CD3DX12_RASTERIZER_DESC rasterizerStateDesc(D3D12_DEFAULT); rasterizerStateDesc.CullMode = D3D12_CULL_MODE_NONE; // Describe and create the graphics pipeline state objects (PSO). D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.InputLayout = { SampleAssets::StandardVertexDescription, SampleAssets::StandardVertexDescriptionNumElements }; psoDesc.pRootSignature = m_rootSignature.Get(); psoDesc.VS = { pVertexShaderData, vertexShaderDataLength }; psoDesc.PS = { pPixelShaderData1, pixelShaderDataLength1 }; 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_pipelineState1))); // Modify the description to use an alternate pixel shader and create // a second PSO. psoDesc.PS = { pPixelShaderData2, pixelShaderDataLength2 }; ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineState2))); delete pVertexShaderData; delete pPixelShaderData1; delete pPixelShaderData2; } ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocator.Get(), nullptr, IID_PPV_ARGS(&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); } // 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))); // 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))); // 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 texture and sampler. { // Describe and create a Texture2D. 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_texture))); const UINT subresourceCount = textureDesc.DepthOrArraySize * textureDesc.MipLevels; const UINT64 uploadBufferSize = GetRequiredIntermediateSize(m_texture.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))); // Copy data to the intermediate upload heap and then schedule a copy // from the upload heap to the Texture2D. 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_texture.Get(), textureUploadHeap.Get(), 0, 0, subresourceCount, &textureData); m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_texture.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()); // Describe and create a SRV for the texture. D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; srvDesc.Format = SampleAssets::Textures->Format; srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; srvDesc.Texture2D.MipLevels = 1; m_device->CreateShaderResourceView(m_texture.Get(), &srvDesc, m_cbvSrvHeap->GetCPUDescriptorHandleForHeapStart()); } 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) )); 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 D3D1211on12::LoadPipeline() { UINT d3d11DeviceFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; D2D1_FACTORY_OPTIONS d2dFactoryOptions = {}; #ifdef _DEBUG // Enable the D2D debug layer. d2dFactoryOptions.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION; // Enable the D3D11 debug layer. d3d11DeviceFlags |= D3D11_CREATE_DEVICE_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_d3d12Device) )); } else { ThrowIfFailed(D3D12CreateDevice( nullptr, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_d3d12Device) )); } // 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_d3d12Device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&m_commandQueue))); // Describe the swap chain. 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 = m_hwnd; swapChainDesc.SampleDesc.Count = 1; swapChainDesc.Windowed = TRUE; ComPtr<IDXGISwapChain> swapChain; ThrowIfFailed(factory->CreateSwapChain( m_commandQueue.Get(), // Swap chain needs the queue so that it can force a flush on it. &swapChainDesc, &swapChain )); ThrowIfFailed(swapChain.As(&m_swapChain)); m_frameIndex = m_swapChain->GetCurrentBackBufferIndex(); // Create an 11 device wrapped around the 12 device and share // 12's command queue. ComPtr<ID3D11Device> d3d11Device; ThrowIfFailed(D3D11On12CreateDevice( m_d3d12Device.Get(), d3d11DeviceFlags, nullptr, 0, reinterpret_cast<IUnknown**>(m_commandQueue.GetAddressOf()), 1, 0, &d3d11Device, &m_d3d11DeviceContext, nullptr )); // Query the 11On12 device from the 11 device. ThrowIfFailed(d3d11Device.As(&m_d3d11On12Device)); // Create D2D/DWrite components. { D2D1_DEVICE_CONTEXT_OPTIONS deviceOptions = D2D1_DEVICE_CONTEXT_OPTIONS_NONE; ThrowIfFailed(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory3), &d2dFactoryOptions, &m_d2dFactory)); ComPtr<IDXGIDevice> dxgiDevice; ThrowIfFailed(m_d3d11On12Device.As(&dxgiDevice)); ThrowIfFailed(m_d2dFactory->CreateDevice(dxgiDevice.Get(), &m_d2dDevice)); ThrowIfFailed(m_d2dDevice->CreateDeviceContext(deviceOptions, &m_d2dDeviceContext)); ThrowIfFailed(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &m_dWriteFactory)); } // Query the desktop's dpi settings, which will be used to create // D2D's render targets. float dpiX; float dpiY; m_d2dFactory->GetDesktopDpi(&dpiX, &dpiY); D2D1_BITMAP_PROPERTIES1 bitmapProperties = D2D1::BitmapProperties1( D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW, D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED), dpiX, dpiY ); // Create descriptor heaps. { // Describe and create a render target view (RTV) descriptor heap. D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {}; rtvHeapDesc.NumDescriptors = FrameCount; rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; ThrowIfFailed(m_d3d12Device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&m_rtvHeap))); m_rtvDescriptorSize = m_d3d12Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); } // Create frame resources. { CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart()); // Create a RTV, D2D render target, 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_d3d12Device->CreateRenderTargetView(m_renderTargets[n].Get(), nullptr, rtvHandle); // Create a wrapped 11On12 resource of this back buffer. Since we are // rendering all D3D12 content first and then all D2D content, we specify // the In resource state as RENDER_TARGET - because D3D12 will have last // used it in this state - and the Out resource state as PRESENT. When // ReleaseWrappedResources() is called on the 11On12 device, the resource // will be transitioned to the PRESENT state. D3D11_RESOURCE_FLAGS d3d11Flags = { D3D11_BIND_RENDER_TARGET }; ThrowIfFailed(m_d3d11On12Device->CreateWrappedResource( m_renderTargets[n].Get(), &d3d11Flags, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT, IID_PPV_ARGS(&m_wrappedBackBuffers[n]) )); // Create a render target for D2D to draw directly to this back buffer. ComPtr<IDXGISurface> surface; ThrowIfFailed(m_wrappedBackBuffers[n].As(&surface)); ThrowIfFailed(m_d2dDeviceContext->CreateBitmapFromDxgiSurface( surface.Get(), &bitmapProperties, &m_d2dRenderTargets[n] )); rtvHandle.Offset(1, m_rtvDescriptorSize); ThrowIfFailed(m_d3d12Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_commandAllocators[n]))); } } }
// Worker thread body. workerIndex is an integer from 0 to NumContexts // describing the worker's thread index. void D3D12Multithreading::WorkerThread(LPVOID workerIndex) { int threadIndex = reinterpret_cast<int>(workerIndex); assert(threadIndex >= 0); assert(threadIndex < NumContexts); #if !SINGLETHREADED while (threadIndex >= 0 && threadIndex < NumContexts) { // Wait for main thread to tell us to draw. WaitForSingleObject(m_workerBeginRenderFrame[threadIndex], INFINITE); #endif ID3D12GraphicsCommandList* pShadowCommandList = m_pCurrentFrameResource->m_shadowCommandLists[threadIndex].Get(); ID3D12GraphicsCommandList* pSceneCommandList = m_pCurrentFrameResource->m_sceneCommandLists[threadIndex].Get(); // // Shadow pass // // Populate the command list. SetCommonPipelineState(pShadowCommandList); m_pCurrentFrameResource->Bind(pShadowCommandList, FALSE, nullptr, nullptr); // No need to pass RTV or DSV descriptor heap. // Set null SRVs for the diffuse/normal textures. pShadowCommandList->SetGraphicsRootDescriptorTable(0, m_cbvSrvHeap->GetGPUDescriptorHandleForHeapStart()); // Distribute objects over threads by drawing only 1/NumContexts // objects per worker (i.e. every object such that objectnum % // NumContexts == threadIndex). PIXBeginEvent(pShadowCommandList, 0, L"Worker drawing shadow pass..."); for (int j = threadIndex; j < _countof(SampleAssets::Draws); j += NumContexts) { SampleAssets::DrawParameters drawArgs = SampleAssets::Draws[j]; pShadowCommandList->DrawIndexedInstanced(drawArgs.IndexCount, 1, drawArgs.IndexStart, drawArgs.VertexBase, 0); } PIXEndEvent(pShadowCommandList); ThrowIfFailed(pShadowCommandList->Close()); #if !SINGLETHREADED // Submit shadow pass. SetEvent(m_workerFinishShadowPass[threadIndex]); #endif // // Scene pass // // Populate the command list. These can only be sent after the shadow // passes for this frame have been submitted. SetCommonPipelineState(pSceneCommandList); CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart(), m_frameIndex, m_rtvDescriptorSize); CD3DX12_CPU_DESCRIPTOR_HANDLE dsvHandle(m_dsvHeap->GetCPUDescriptorHandleForHeapStart()); m_pCurrentFrameResource->Bind(pSceneCommandList, TRUE, &rtvHandle, &dsvHandle); PIXBeginEvent(pSceneCommandList, 0, L"Worker drawing scene pass..."); D3D12_GPU_DESCRIPTOR_HANDLE cbvSrvHeapStart = m_cbvSrvHeap->GetGPUDescriptorHandleForHeapStart(); const UINT cbvSrvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); const UINT nullSrvCount = 2; for (int j = threadIndex; j < _countof(SampleAssets::Draws); j += NumContexts) { SampleAssets::DrawParameters drawArgs = SampleAssets::Draws[j]; // Set the diffuse and normal textures for the current object. CD3DX12_GPU_DESCRIPTOR_HANDLE cbvSrvHandle(cbvSrvHeapStart, nullSrvCount + drawArgs.DiffuseTextureIndex, cbvSrvDescriptorSize); pSceneCommandList->SetGraphicsRootDescriptorTable(0, cbvSrvHandle); pSceneCommandList->DrawIndexedInstanced(drawArgs.IndexCount, 1, drawArgs.IndexStart, drawArgs.VertexBase, 0); } PIXEndEvent(pSceneCommandList); ThrowIfFailed(pSceneCommandList->Close()); #if !SINGLETHREADED // Tell main thread that we are done. SetEvent(m_workerFinishedRenderFrame[threadIndex]); } #endif }
// Load the rendering pipeline dependencies. void D3D12HelloTexture::LoadPipeline() { #ifdef _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 { ThrowIfFailed(D3D12CreateDevice( nullptr, 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))); // Describe and create the swap chain. 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 = m_hwnd; swapChainDesc.SampleDesc.Count = 1; swapChainDesc.Windowed = TRUE; ComPtr<IDXGISwapChain> swapChain; ThrowIfFailed(factory->CreateSwapChain( m_commandQueue.Get(), // Swap chain needs the queue so that it can force a flush on it. &swapChainDesc, &swapChain )); ThrowIfFailed(swapChain.As(&m_swapChain)); m_frameIndex = m_swapChain->GetCurrentBackBufferIndex(); // Create descriptor heaps. { // Describe and create a render target view (RTV) descriptor heap. D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {}; rtvHeapDesc.NumDescriptors = FrameCount; 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) 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(m_device->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&m_srvHeap))); m_rtvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); } // 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); } } ThrowIfFailed(m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_commandAllocator))); }
// 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(); } } }
// Load the rendering pipeline dependencies. void D3D12PredicationQueries::LoadPipeline() { UINT dxgiFactoryFlags = 0; #if defined(_DEBUG) // Enable the debug layer (requires the Graphics Tools "optional feature"). // NOTE: Enabling the debug layer after device creation will invalidate the active device. { ComPtr<ID3D12Debug> debugController; if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) { debugController->EnableDebugLayer(); // Enable additional debug layers. dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG; } } #endif ComPtr<IDXGIFactory4> factory; ThrowIfFailed(CreateDXGIFactory2(dxgiFactoryFlags, 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; ComPtr<IDXGISwapChain1> swapChain; ThrowIfFailed(factory->CreateSwapChainForHwnd( m_commandQueue.Get(), // Swap chain needs the queue so that it can force a flush on it. Win32Application::GetHwnd(), &swapChainDesc, nullptr, nullptr, &swapChain )); // This sample does not support fullscreen transitions. ThrowIfFailed(factory->MakeWindowAssociation(Win32Application::GetHwnd(), DXGI_MWA_NO_ALT_ENTER)); ThrowIfFailed(swapChain.As(&m_swapChain)); m_frameIndex = m_swapChain->GetCurrentBackBufferIndex(); // Create descriptor heaps. { // Describe and create a render target view (RTV) descriptor heap. D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {}; rtvHeapDesc.NumDescriptors = FrameCount; 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 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_device->CreateDescriptorHeap(&dsvHeapDesc, IID_PPV_ARGS(&m_dsvHeap))); // Describe and create a constant buffer view (CBV) descriptor heap. D3D12_DESCRIPTOR_HEAP_DESC cbvHeapDesc = {}; cbvHeapDesc.NumDescriptors = CbvCountPerFrame * FrameCount; cbvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; cbvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; ThrowIfFailed(m_device->CreateDescriptorHeap(&cbvHeapDesc, IID_PPV_ARGS(&m_cbvHeap))); NAME_D3D12_OBJECT(m_cbvHeap); // Describe and create a heap for occlusion queries. D3D12_QUERY_HEAP_DESC queryHeapDesc = {}; queryHeapDesc.Count = 1; queryHeapDesc.Type = D3D12_QUERY_HEAP_TYPE_OCCLUSION; ThrowIfFailed(m_device->CreateQueryHeap(&queryHeapDesc, IID_PPV_ARGS(&m_queryHeap))); m_rtvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); m_cbvSrvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); } // Create frame resources. { CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart()); // Create a RTV 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]))); } } }
// Fill the command list with all the render commands and dependent state. void D3D12ExecuteIndirect::PopulateCommandLists() { // 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_computeCommandAllocators[m_frameIndex]->Reset()); 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_computeCommandList->Reset(m_computeCommandAllocators[m_frameIndex].Get(), m_computeState.Get())); ThrowIfFailed(m_commandList->Reset(m_commandAllocators[m_frameIndex].Get(), m_pipelineState.Get())); // Record the compute commands that will cull triangles and prevent them from being processed by the vertex shader. if (m_enableCulling) { UINT frameDescriptorOffset = m_frameIndex * CbvSrvUavDescriptorCountPerFrame; D3D12_GPU_DESCRIPTOR_HANDLE cbvSrvUavHandle = m_cbvSrvUavHeap->GetGPUDescriptorHandleForHeapStart(); m_computeCommandList->SetComputeRootSignature(m_computeRootSignature.Get()); ID3D12DescriptorHeap* ppHeaps[] = { m_cbvSrvUavHeap.Get() }; m_computeCommandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); m_computeCommandList->SetComputeRootDescriptorTable( SrvUavTable, CD3DX12_GPU_DESCRIPTOR_HANDLE(cbvSrvUavHandle, CbvSrvOffset + frameDescriptorOffset, m_cbvSrvUavDescriptorSize)); m_computeCommandList->SetComputeRoot32BitConstants(RootConstants, 4, reinterpret_cast<void*>(&m_csRootConstants), 0); // Reset the UAV counter for this frame. m_computeCommandList->CopyBufferRegion(m_processedCommandBuffers[m_frameIndex].Get(), CommandBufferSizePerFrame, m_processedCommandBufferCounterReset.Get(), 0, sizeof(UINT)); D3D12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(m_processedCommandBuffers[m_frameIndex].Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); m_computeCommandList->ResourceBarrier(1, &barrier); m_computeCommandList->Dispatch(static_cast<UINT>(ceil(TriangleCount / float(ComputeThreadBlockSize))), 1, 1); } ThrowIfFailed(m_computeCommandList->Close()); // Record the rendering commands. { // Set necessary state. m_commandList->SetGraphicsRootSignature(m_rootSignature.Get()); ID3D12DescriptorHeap* ppHeaps[] = { m_cbvSrvUavHeap.Get() }; m_commandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); m_commandList->RSSetViewports(1, &m_viewport); m_commandList->RSSetScissorRects(1, m_enableCulling ? &m_cullingScissorRect : &m_scissorRect); // Indicate that the command buffer will be used for indirect drawing // and that the back buffer will be used as a render target. D3D12_RESOURCE_BARRIER barriers[2] = { CD3DX12_RESOURCE_BARRIER::Transition( m_enableCulling ? m_processedCommandBuffers[m_frameIndex].Get() : m_commandBuffer.Get(), m_enableCulling ? D3D12_RESOURCE_STATE_UNORDERED_ACCESS : D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT), CD3DX12_RESOURCE_BARRIER::Transition( m_renderTargets[m_frameIndex].Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET) }; m_commandList->ResourceBarrier(_countof(barriers), barriers); CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart(), m_frameIndex, m_rtvDescriptorSize); CD3DX12_CPU_DESCRIPTOR_HANDLE dsvHandle(m_dsvHeap->GetCPUDescriptorHandleForHeapStart()); m_commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, &dsvHandle); // Record commands. const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f }; m_commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr); m_commandList->ClearDepthStencilView(dsvHandle, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr); m_commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); m_commandList->IASetVertexBuffers(0, 1, &m_vertexBufferView); if (m_enableCulling) { // Draw the triangles that have not been culled. m_commandList->ExecuteIndirect( m_commandSignature.Get(), TriangleCount, m_processedCommandBuffers[m_frameIndex].Get(), 0, m_processedCommandBuffers[m_frameIndex].Get(), CommandBufferSizePerFrame); } else { // Draw all of the triangles. m_commandList->ExecuteIndirect( m_commandSignature.Get(), TriangleCount, m_commandBuffer.Get(), CommandBufferSizePerFrame * m_frameIndex, nullptr, 0); } // Indicate that the command buffer may be used by the compute shader // and that the back buffer will now be used to present. barriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT; barriers[0].Transition.StateAfter = m_enableCulling ? D3D12_RESOURCE_STATE_COPY_DEST : D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; barriers[1].Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; barriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; m_commandList->ResourceBarrier(_countof(barriers), barriers); ThrowIfFailed(m_commandList->Close()); } }
// Load the rendering pipeline dependencies. void D3D12HelloWindow::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))); // 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; ComPtr<IDXGISwapChain1> swapChain; ThrowIfFailed(factory->CreateSwapChainForHwnd( m_commandQueue.Get(), // Swap chain needs the queue so that it can force a flush on it. Win32Application::GetHwnd(), &swapChainDesc, nullptr, nullptr, &swapChain )); // This sample does not support fullscreen transitions. ThrowIfFailed(factory->MakeWindowAssociation(Win32Application::GetHwnd(), DXGI_MWA_NO_ALT_ENTER)); ThrowIfFailed(swapChain.As(&m_swapChain)); m_frameIndex = m_swapChain->GetCurrentBackBufferIndex(); // Create descriptor heaps. { // Describe and create a render target view (RTV) descriptor heap. D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {}; rtvHeapDesc.NumDescriptors = FrameCount; rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; ThrowIfFailed(m_device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&m_rtvHeap))); m_rtvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); } // 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); } } ThrowIfFailed(m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_commandAllocator))); }
// Fill the command list with all the render commands and dependent state. void D3D12PredicationQueries::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_cbvHeap.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); CD3DX12_CPU_DESCRIPTOR_HANDLE dsvHandle(m_dsvHeap->GetCPUDescriptorHandleForHeapStart()); m_commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, &dsvHandle); // Record commands. const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f }; m_commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr); m_commandList->ClearDepthStencilView(dsvHandle, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr); // Draw the quads and perform the occlusion query. { CD3DX12_GPU_DESCRIPTOR_HANDLE cbvFarQuad(m_cbvHeap->GetGPUDescriptorHandleForHeapStart(), m_frameIndex * CbvCountPerFrame, m_cbvSrvDescriptorSize); CD3DX12_GPU_DESCRIPTOR_HANDLE cbvNearQuad(cbvFarQuad, m_cbvSrvDescriptorSize); 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 potentially occluded geometry"); m_commandList->SetGraphicsRootDescriptorTable(0, cbvFarQuad); m_commandList->SetPredication(m_queryResult.Get(), 0, D3D12_PREDICATION_OP_EQUAL_ZERO); m_commandList->DrawInstanced(4, 1, 0, 0); PIXEndEvent(m_commandList.Get()); // Disable predication and always draw the near quad. PIXBeginEvent(m_commandList.Get(), 0, L"Draw animating geometry"); m_commandList->SetPredication(nullptr, 0, D3D12_PREDICATION_OP_EQUAL_ZERO); m_commandList->SetGraphicsRootDescriptorTable(0, cbvNearQuad); m_commandList->DrawInstanced(4, 1, 4, 0); PIXEndEvent(m_commandList.Get()); // Run the occlusion query with the bounding box quad. PIXBeginEvent(m_commandList.Get(), 0, L"Execute occlusion query"); m_commandList->SetGraphicsRootDescriptorTable(0, cbvFarQuad); m_commandList->SetPipelineState(m_queryState.Get()); m_commandList->BeginQuery(m_queryHeap.Get(), D3D12_QUERY_TYPE_BINARY_OCCLUSION, 0); m_commandList->DrawInstanced(4, 1, 8, 0); m_commandList->EndQuery(m_queryHeap.Get(), D3D12_QUERY_TYPE_BINARY_OCCLUSION, 0); PIXEndEvent(m_commandList.Get()); // Resolve the occlusion query and store the results in the query result buffer // to be used on the subsequent frame. m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_queryResult.Get(), D3D12_RESOURCE_STATE_PREDICATION, D3D12_RESOURCE_STATE_COPY_DEST)); m_commandList->ResolveQueryData(m_queryHeap.Get(), D3D12_QUERY_TYPE_BINARY_OCCLUSION, 0, 1, m_queryResult.Get(), 0); m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_queryResult.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PREDICATION)); } // 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()); }
// Fill the command list with all the render commands and dependent state and // submit it to the command queue. void D3D12HDR::RenderScene() { // 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_pipelineStates[GradientPSO].Get())); if (m_updateVertexBuffer) { UpdateVertexBuffer(); m_updateVertexBuffer = false; } // 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_TRIANGLESTRIP); m_commandList->RSSetViewports(1, &m_viewport); m_commandList->RSSetScissorRects(1, &m_scissorRect); // Bind the root constants and the SRV table to the pipeline. m_rootConstantsF[ReferenceWhiteNits] = m_referenceWhiteNits; m_commandList->SetGraphicsRoot32BitConstants(0, RootConstantsCount, m_rootConstants, 0); m_commandList->SetGraphicsRootDescriptorTable(1, m_srvHeap->GetGPUDescriptorHandleForHeapStart()); // Draw the scene into the intermediate render target. { PIXBeginEvent(m_commandList.Get(), 0, L"Draw scene content"); CD3DX12_CPU_DESCRIPTOR_HANDLE intermediateRtv(m_rtvHeap->GetCPUDescriptorHandleForHeapStart(), FrameCount, m_rtvDescriptorSize); m_commandList->OMSetRenderTargets(1, &intermediateRtv, FALSE, nullptr); const float clearColor[] = { 0.0f, 0.0f, 0.0f, 0.0f }; m_commandList->ClearRenderTargetView(intermediateRtv, clearColor, 0, nullptr); m_commandList->IASetVertexBuffers(0, 1, &m_gradientVertexBufferView); PIXBeginEvent(m_commandList.Get(), 0, L"Standard Gradient"); m_commandList->DrawInstanced(4, 1, 0, 0); PIXEndEvent(m_commandList.Get()); PIXBeginEvent(m_commandList.Get(), 0, L"Bright Gradient"); m_commandList->DrawInstanced(4, 1, 4, 0); PIXEndEvent(m_commandList.Get()); m_commandList->SetPipelineState(m_pipelineStates[PalettePSO].Get()); m_commandList->IASetVertexBuffers(0, 1, &m_trianglesVertexBufferView); m_commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); PIXBeginEvent(m_commandList.Get(), 0, L"Rec709 Triangles"); m_commandList->DrawInstanced(3, 1, 0, 0); m_commandList->DrawInstanced(3, 1, 3, 0); m_commandList->DrawInstanced(3, 1, 6, 0); PIXEndEvent(m_commandList.Get()); m_commandList->SetPipelineState(m_pipelineStates[PalettePSO].Get()); PIXBeginEvent(m_commandList.Get(), 0, L"Rec2020 Triangles"); m_commandList->DrawInstanced(3, 1, 9, 0); m_commandList->DrawInstanced(3, 1, 12, 0); m_commandList->DrawInstanced(3, 1, 15, 0); PIXEndEvent(m_commandList.Get()); PIXEndEvent(m_commandList.Get()); if (!m_enableUI) { intermediateRtv.Offset(1, m_rtvDescriptorSize); m_commandList->OMSetRenderTargets(1, &intermediateRtv, FALSE, nullptr); m_commandList->ClearRenderTargetView(intermediateRtv, clearColor, 0, nullptr); } } // Indicate that the intermediates will be used as SRVs in the pixel shader // and the back buffer will be used as a render target. D3D12_RESOURCE_BARRIER barriers[] = { CD3DX12_RESOURCE_BARRIER::Transition(m_intermediateRenderTarget.Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE), CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_frameIndex].Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET), CD3DX12_RESOURCE_BARRIER::Transition(m_UIRenderTarget.Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE), }; // Process the intermediate and draw into the swap chain render target. { PIXBeginEvent(m_commandList.Get(), 0, L"Apply HDR"); // If the UI is enabled, the 11on12 layer will do the state transition for us. UINT barrierCount = m_enableUI ? 2 : _countof(barriers); m_commandList->ResourceBarrier(barrierCount, barriers); m_commandList->SetPipelineState(m_pipelineStates[Present8bitPSO + m_currentSwapChainBitDepth].Get()); CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart(), m_frameIndex, m_rtvDescriptorSize); m_commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr); m_commandList->ClearRenderTargetView(rtvHandle, ClearColor, 0, nullptr); m_commandList->IASetVertexBuffers(0, 1, &m_presentVertexBufferView); m_commandList->DrawInstanced(3, 1, 0, 0); PIXEndEvent(m_commandList.Get()); } // Indicate that the intermediates will be used as render targets and the swap chain // back buffer will be used for presentation. barriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; barriers[0].Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; barriers[1].Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; barriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; barriers[2].Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; barriers[2].Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; m_commandList->ResourceBarrier(_countof(barriers), barriers); ThrowIfFailed(m_commandList->Close()); // Execute the command list. ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() }; m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists); }
// 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); } }