// Create the resources that will be used every frame. void D3D12DynamicIndexing::CreateFrameResources() { // Initialize each frame resource. CD3DX12_CPU_DESCRIPTOR_HANDLE cbvSrvHandle(m_cbvSrvHeap->GetCPUDescriptorHandleForHeapStart(), CityMaterialCount + 1, m_cbvSrvDescriptorSize); // Move past the SRVs. for (UINT i = 0; i < FrameCount; i++) { FrameResource* pFrameResource = new FrameResource(m_device.Get(), CityRowCount, CityColumnCount, CityMaterialCount, CitySpacingInterval); UINT64 cbOffset = 0; for (UINT j = 0; j < CityRowCount; j++) { for (UINT k = 0; k < CityColumnCount; k++) { // Describe and create a constant buffer view (CBV). D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {}; cbvDesc.BufferLocation = pFrameResource->m_cbvUploadHeap->GetGPUVirtualAddress() + cbOffset; cbvDesc.SizeInBytes = sizeof(FrameResource::SceneConstantBuffer); cbOffset += cbvDesc.SizeInBytes; m_device->CreateConstantBufferView(&cbvDesc, cbvSrvHandle); cbvSrvHandle.Offset(m_cbvSrvDescriptorSize); } } pFrameResource->InitBundle(m_device.Get(), m_pipelineState.Get(), i, m_numIndices, &m_indexBufferView, &m_vertexBufferView, m_cbvSrvHeap.Get(), m_cbvSrvDescriptorSize, m_samplerHeap.Get(), m_rootSignature.Get()); m_frameResources.push_back(pFrameResource); } }
void FrameResource::PopulateCommandList(ID3D12GraphicsCommandList* pCommandList, ID3D12PipelineState* pPso1, ID3D12PipelineState* pPso2, UINT frameResourceIndex, UINT numIndices, D3D12_INDEX_BUFFER_VIEW* pIndexBufferViewDesc, D3D12_VERTEX_BUFFER_VIEW* pVertexBufferViewDesc, ID3D12DescriptorHeap* pCbvSrvDescriptorHeap, UINT cbvSrvDescriptorSize, ID3D12DescriptorHeap* pSamplerDescriptorHeap, ID3D12RootSignature* pRootSignature) { // If the root signature matches the root signature of the caller, then // bindings are inherited, otherwise the bind space is reset. pCommandList->SetGraphicsRootSignature(pRootSignature); ID3D12DescriptorHeap* ppHeaps[] = { pCbvSrvDescriptorHeap, pSamplerDescriptorHeap }; pCommandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); pCommandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); pCommandList->IASetIndexBuffer(pIndexBufferViewDesc); pCommandList->IASetVertexBuffers(0, 1, pVertexBufferViewDesc); pCommandList->SetGraphicsRootDescriptorTable(0, pCbvSrvDescriptorHeap->GetGPUDescriptorHandleForHeapStart()); pCommandList->SetGraphicsRootDescriptorTable(1, pSamplerDescriptorHeap->GetGPUDescriptorHandleForHeapStart()); // Calculate the descriptor offset due to multiple frame resources. // 1 SRV + how many CBVs we have currently. UINT frameResourceDescriptorOffset = 1 + (frameResourceIndex * m_cityRowCount * m_cityColumnCount); CD3DX12_GPU_DESCRIPTOR_HANDLE cbvSrvHandle(pCbvSrvDescriptorHeap->GetGPUDescriptorHandleForHeapStart(), frameResourceDescriptorOffset, cbvSrvDescriptorSize); PIXBeginEvent(pCommandList, 0, L"Draw cities"); BOOL usePso1 = TRUE; for (UINT i = 0; i < m_cityRowCount; i++) { for (UINT j = 0; j < m_cityColumnCount; j++) { // Alternate which PSO to use; the pixel shader is different on // each just as a PSO setting demonstration. pCommandList->SetPipelineState(usePso1 ? pPso1 : pPso2); usePso1 = !usePso1; // Set this city's CBV table and move to the next descriptor. pCommandList->SetGraphicsRootDescriptorTable(2, cbvSrvHandle); cbvSrvHandle.Offset(cbvSrvDescriptorSize); pCommandList->DrawIndexedInstanced(numIndices, 1, 0, 0, 0); } } PIXEndEvent(pCommandList); }
void FrameResource::PopulateCommandList(ID3D12GraphicsCommandList* pCommandList, ID3D12PipelineState* pPso, UINT frameResourceIndex, UINT numIndices, D3D12_INDEX_BUFFER_VIEW* pIndexBufferViewDesc, D3D12_VERTEX_BUFFER_VIEW* pVertexBufferViewDesc, ID3D12DescriptorHeap* pCbvSrvDescriptorHeap, UINT cbvSrvDescriptorSize, ID3D12DescriptorHeap* pSamplerDescriptorHeap, ID3D12RootSignature* pRootSignature) { // If the root signature matches the root signature of the caller, then // bindings are inherited, otherwise the bind space is reset. pCommandList->SetGraphicsRootSignature(pRootSignature); ID3D12DescriptorHeap* ppHeaps[] = { pCbvSrvDescriptorHeap, pSamplerDescriptorHeap }; pCommandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); pCommandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); pCommandList->IASetIndexBuffer(pIndexBufferViewDesc); pCommandList->IASetVertexBuffers(0, 1, pVertexBufferViewDesc); pCommandList->SetGraphicsRootDescriptorTable(0, pCbvSrvDescriptorHeap->GetGPUDescriptorHandleForHeapStart()); pCommandList->SetGraphicsRootDescriptorTable(1, pSamplerDescriptorHeap->GetGPUDescriptorHandleForHeapStart()); // Calculate the descriptor offset due to multiple frame resources. // (m_cityMaterialCount + 1) SRVs + how many CBVs we have currently. UINT frameResourceDescriptorOffset = (m_cityMaterialCount + 1) + (frameResourceIndex * m_cityRowCount * m_cityColumnCount); CD3DX12_GPU_DESCRIPTOR_HANDLE cbvSrvHandle(pCbvSrvDescriptorHeap->GetGPUDescriptorHandleForHeapStart(), frameResourceDescriptorOffset, cbvSrvDescriptorSize); PIXBeginEvent(pCommandList, 0, L"Draw cities"); for (UINT i = 0; i < m_cityRowCount; i++) { for (UINT j = 0; j < m_cityColumnCount; j++) { pCommandList->SetPipelineState(pPso); // Set the city's root constant for dynamically indexing into the material array. pCommandList->SetGraphicsRoot32BitConstant(3, (i * m_cityColumnCount) + j, 0); // Set this city's CBV table and move to the next descriptor. pCommandList->SetGraphicsRootDescriptorTable(2, cbvSrvHandle); cbvSrvHandle.Offset(cbvSrvDescriptorSize); pCommandList->DrawIndexedInstanced(numIndices, 1, 0, 0, 0); } } PIXEndEvent(pCommandList); }
// Create the resources that will be used every frame. void D3D12DynamicIndexing::CreateFrameResources() { ThrowIfFailed(m_commandList->Reset(m_commandAllocator.Get(), m_pipelineState.Get())); // Initialize each frame resource. CD3DX12_CPU_DESCRIPTOR_HANDLE cbvSrvHandle(m_cbvSrvHeap->GetCPUDescriptorHandleForHeapStart(), CityMaterialCount + 1, m_cbvSrvDescriptorSize); // Move past the SRVs. for (UINT i = 0; i < FrameCount; i++) { FrameResource* pFrameResource = new FrameResource(m_device.Get(), CityRowCount, CityColumnCount, CityMaterialCount, CitySpacingInterval); UINT64 cbOffset = 0; for (UINT j = 0; j < CityRowCount; j++) { for (UINT k = 0; k < CityColumnCount; k++) { // Describe and create a constant buffer view (CBV). D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {}; cbvDesc.BufferLocation = pFrameResource->m_cbvUploadHeap->GetGPUVirtualAddress() + cbOffset; cbvDesc.SizeInBytes = sizeof(FrameResource::SceneConstantBuffer); cbOffset += cbvDesc.SizeInBytes; m_device->CreateConstantBufferView(&cbvDesc, cbvSrvHandle); cbvSrvHandle.Offset(m_cbvSrvDescriptorSize); } } pFrameResource->InitBundle(m_device.Get(), m_pipelineState.Get(), i, m_numIndices, &m_indexBufferView, &m_vertexBufferView, m_cbvSrvHeap.Get(), m_cbvSrvDescriptorSize, m_samplerHeap.Get(), m_rootSignature.Get()); m_frameResources.push_back(pFrameResource); } // Close the command list and use it to execute the initial setup. // This places the CBVs in the heap. ThrowIfFailed(m_commandList->Close()); ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() }; m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists); }
//コンスタンスバッファ作成 void CBufferDraw::Impl::CreateConstantBuffer() { auto Dev = App::GetApp()->GetDeviceResources(); ThrowIfFailed(Dev->GetDevice()->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(sizeof(SpriteConstantBuffer)), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_ConstantBufferUploadHeap)), L"コンスタントバッファ用のアップロードヒープ作成に失敗しました", L"Dev->GetDevice()->CreateCommittedResource()", L"TriangleSprite::CreateConstantBuffer()" ); //コンスタントバッファのビューを作成 //TODO : デスクリプタとビューの違いについて D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {}; cbvDesc.BufferLocation = m_ConstantBufferUploadHeap->GetGPUVirtualAddress(); //コンスタントバッファは256バイトにアラインメント cbvDesc.SizeInBytes = (sizeof(SpriteConstantBuffer) + 255) & ~255; //コンスタントバッファビューを作成すべきデスクプリタヒープ上のハンドルを取得 //シェーダリソースがある場合コンスタントバッファはシェーダリソースビューのあとに設置する CD3DX12_CPU_DESCRIPTOR_HANDLE cbvSrvHandle( m_CbvSrvUavDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), 0, 0 ); Dev->GetDevice()->CreateConstantBufferView(&cbvDesc, cbvSrvHandle); //コンスタントバッファのアップロードヒープのマップ CD3DX12_RANGE readRange(0, 0); ThrowIfFailed(m_ConstantBufferUploadHeap->Map(0, &readRange, reinterpret_cast<void**>(&m_pConstantBuffer)), L"コンスタントバッファのマップに失敗しました", L"pImpl->m_ConstantBufferUploadHeap->Map()", L"TriangleSprite::CreateConstantBuffer()" ); }
// 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 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); } }
// Load the sample assets. void D3D12ExecuteIndirect::LoadAssets() { // Create the root signatures. { CD3DX12_ROOT_PARAMETER rootParameters[GraphicsRootParametersCount]; rootParameters[Cbv].InitAsConstantBufferView(0, 0, D3D12_SHADER_VISIBILITY_VERTEX); 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 compute signature. CD3DX12_DESCRIPTOR_RANGE ranges[2]; ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 2, 0); ranges[1].Init(D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 1, 0); CD3DX12_ROOT_PARAMETER computeRootParameters[ComputeRootParametersCount]; computeRootParameters[SrvUavTable].InitAsDescriptorTable(2, ranges); computeRootParameters[RootConstants].InitAsConstants(4, 0); CD3DX12_ROOT_SIGNATURE_DESC computeRootSignatureDesc; computeRootSignatureDesc.Init(_countof(computeRootParameters), computeRootParameters); ThrowIfFailed(D3D12SerializeRootSignature(&computeRootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error)); ThrowIfFailed(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_computeRootSignature))); } // Create the pipeline state, which includes compiling and loading shaders. { ComPtr<ID3DBlob> vertexShader; ComPtr<ID3DBlob> pixelShader; ComPtr<ID3DBlob> computeShader; ComPtr<ID3DBlob> error; #if defined(_DEBUG) // Enable better shader debugging with the graphics debugging tools. UINT compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; #else UINT compileFlags = 0; #endif ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"shaders.hlsl").c_str(), nullptr, nullptr, "VSMain", "vs_5_0", compileFlags, 0, &vertexShader, &error)); ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"shaders.hlsl").c_str(), nullptr, nullptr, "PSMain", "ps_5_0", compileFlags, 0, &pixelShader, &error)); ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"compute.hlsl").c_str(), nullptr, nullptr, "CSMain", "cs_5_0", compileFlags, 0, &computeShader, &error)); // Define the vertex input layout. D3D12_INPUT_ELEMENT_DESC inputElementDescs[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, }; // Describe and create the graphics pipeline state objects (PSO). D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) }; 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 = 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))); // Describe and create the compute pipeline state object (PSO). D3D12_COMPUTE_PIPELINE_STATE_DESC computePsoDesc = {}; computePsoDesc.pRootSignature = m_computeRootSignature.Get(); computePsoDesc.CS = { reinterpret_cast<UINT8*>(computeShader->GetBufferPointer()), computeShader->GetBufferSize() }; ThrowIfFailed(m_device->CreateComputePipelineState(&computePsoDesc, IID_PPV_ARGS(&m_computeState))); } // Create the command list. ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocators[m_frameIndex].Get(), m_pipelineState.Get(), IID_PPV_ARGS(&m_commandList))); ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_COMPUTE, m_computeCommandAllocators[m_frameIndex].Get(), m_computeState.Get(), IID_PPV_ARGS(&m_computeCommandList))); ThrowIfFailed(m_computeCommandList->Close()); // 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> vertexBufferUpload; ComPtr<ID3D12Resource> commandBufferUpload; // Create the vertex buffer. { // Define the geometry for a triangle. Vertex triangleVertices[] = { { { 0.0f, TriangleHalfWidth, TriangleDepth } }, { { TriangleHalfWidth, -TriangleHalfWidth, TriangleDepth } }, { { -TriangleHalfWidth, -TriangleHalfWidth, TriangleDepth } } }; const UINT vertexBufferSize = sizeof(triangleVertices); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize), D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_vertexBuffer))); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&vertexBufferUpload))); // 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 = reinterpret_cast<UINT8*>(triangleVertices); vertexData.RowPitch = vertexBufferSize; vertexData.SlicePitch = vertexData.RowPitch; UpdateSubresources<1>(m_commandList.Get(), m_vertexBuffer.Get(), vertexBufferUpload.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 = sizeof(Vertex); m_vertexBufferView.SizeInBytes = sizeof(triangleVertices); } // 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()); } // Create the constant buffers. { const UINT constantBufferDataSize = TriangleResourceCount * sizeof(ConstantBufferData); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(constantBufferDataSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_constantBuffer))); D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {}; cbvDesc.SizeInBytes = sizeof(ConstantBufferData); // Create constant buffer views to access the upload buffer. for (UINT n = 0; n < TriangleCount; n++) { m_constantBufferData[n].velocity = XMFLOAT4(GetRandomFloat(0.01f, 0.02f), 0.0f, 0.0f, 0.0f); m_constantBufferData[n].offset = XMFLOAT4(GetRandomFloat(-5.0f, -1.5f), GetRandomFloat(-1.0f, 1.0f), GetRandomFloat(0.0f, 2.0f), 0.0f); m_constantBufferData[n].color = XMFLOAT4(GetRandomFloat(0.5f, 1.0f), GetRandomFloat(0.5f, 1.0f), GetRandomFloat(0.5f, 1.0f), 1.0f); XMStoreFloat4x4(&m_constantBufferData[n].projection, XMMatrixTranspose(XMMatrixPerspectiveFovLH(XM_PIDIV4, m_aspectRatio, 0.01f, 20.0f))); } // Map the constant buffers. We don't unmap this until the app closes. // Keeping things mapped for the lifetime of the resource is okay. CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU. ThrowIfFailed(m_constantBuffer->Map(0, &readRange, reinterpret_cast<void**>(&m_pCbvDataBegin))); memcpy(m_pCbvDataBegin, &m_constantBufferData[0], TriangleCount * sizeof(ConstantBufferData)); // Create shader resource views (SRV) of the constant buffers for the // compute shader to read from. D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; srvDesc.Format = DXGI_FORMAT_UNKNOWN; srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; srvDesc.Buffer.NumElements = TriangleCount; srvDesc.Buffer.StructureByteStride = sizeof(ConstantBufferData); srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE; CD3DX12_CPU_DESCRIPTOR_HANDLE cbvSrvHandle(m_cbvSrvUavHeap->GetCPUDescriptorHandleForHeapStart(), CbvSrvOffset, m_cbvSrvUavDescriptorSize); for (UINT frame = 0; frame < FrameCount; frame++) { srvDesc.Buffer.FirstElement = frame * TriangleCount; m_device->CreateShaderResourceView(m_constantBuffer.Get(), &srvDesc, cbvSrvHandle); cbvSrvHandle.Offset(CbvSrvUavDescriptorCountPerFrame, m_cbvSrvUavDescriptorSize); } } // Create the command signature used for indirect drawing. { // Each command consists of a CBV update and a DrawInstanced call. D3D12_INDIRECT_ARGUMENT_DESC argumentDescs[2] = {}; argumentDescs[0].Type = D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT_BUFFER_VIEW; argumentDescs[0].ConstantBufferView.RootParameterIndex = Cbv; argumentDescs[1].Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW; D3D12_COMMAND_SIGNATURE_DESC commandSignatureDesc = {}; commandSignatureDesc.pArgumentDescs = argumentDescs; commandSignatureDesc.NumArgumentDescs = _countof(argumentDescs); commandSignatureDesc.ByteStride = sizeof(IndirectCommand); ThrowIfFailed(m_device->CreateCommandSignature(&commandSignatureDesc, m_rootSignature.Get(), IID_PPV_ARGS(&m_commandSignature))); } // Create the command buffers and UAVs to store the results of the compute work. { std::vector<IndirectCommand> commands; commands.resize(TriangleResourceCount); const UINT commandBufferSize = CommandBufferSizePerFrame * FrameCount; D3D12_RESOURCE_DESC commandBufferDesc = CD3DX12_RESOURCE_DESC::Buffer(commandBufferSize); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &commandBufferDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_commandBuffer))); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(commandBufferSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&commandBufferUpload))); D3D12_GPU_VIRTUAL_ADDRESS gpuAddress = m_constantBuffer->GetGPUVirtualAddress(); UINT commandIndex = 0; for (UINT frame = 0; frame < FrameCount; frame++) { for (UINT n = 0; n < TriangleCount; n++) { commands[commandIndex].cbv = gpuAddress; commands[commandIndex].drawArguments.VertexCountPerInstance = 3; commands[commandIndex].drawArguments.InstanceCount = 1; commands[commandIndex].drawArguments.StartVertexLocation = 0; commands[commandIndex].drawArguments.StartInstanceLocation = 0; commandIndex++; gpuAddress += sizeof(ConstantBufferData); } } // Copy data to the intermediate upload heap and then schedule a copy // from the upload heap to the command buffer. D3D12_SUBRESOURCE_DATA commandData = {}; commandData.pData = reinterpret_cast<UINT8*>(&commands[0]); commandData.RowPitch = commandBufferSize; commandData.SlicePitch = commandData.RowPitch; UpdateSubresources<1>(m_commandList.Get(), m_commandBuffer.Get(), commandBufferUpload.Get(), 0, 0, 1, &commandData); m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_commandBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE)); // Create SRVs for the command buffers. D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; srvDesc.Format = DXGI_FORMAT_UNKNOWN; srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; srvDesc.Buffer.NumElements = TriangleCount; srvDesc.Buffer.StructureByteStride = sizeof(IndirectCommand); srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE; CD3DX12_CPU_DESCRIPTOR_HANDLE commandsHandle(m_cbvSrvUavHeap->GetCPUDescriptorHandleForHeapStart(), CommandsOffset, m_cbvSrvUavDescriptorSize); for (UINT frame = 0; frame < FrameCount; frame++) { srvDesc.Buffer.FirstElement = frame * TriangleCount; m_device->CreateShaderResourceView(m_commandBuffer.Get(), &srvDesc, commandsHandle); commandsHandle.Offset(CbvSrvUavDescriptorCountPerFrame, m_cbvSrvUavDescriptorSize); } // Create the unordered access views (UAVs) that store the results of the compute work. CD3DX12_CPU_DESCRIPTOR_HANDLE processedCommandsHandle(m_cbvSrvUavHeap->GetCPUDescriptorHandleForHeapStart(), ProcessedCommandsOffset, m_cbvSrvUavDescriptorSize); for (UINT frame = 0; frame < FrameCount; frame++) { // Allocate a buffer large enough to hold all of the indirect commands // for a single frame as well as a UAV counter. commandBufferDesc = CD3DX12_RESOURCE_DESC::Buffer(CommandBufferSizePerFrame + sizeof(UINT), D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &commandBufferDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_processedCommandBuffers[frame]))); D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {}; uavDesc.Format = DXGI_FORMAT_UNKNOWN; uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; uavDesc.Buffer.FirstElement = 0; uavDesc.Buffer.NumElements = TriangleCount; uavDesc.Buffer.StructureByteStride = sizeof(IndirectCommand); uavDesc.Buffer.CounterOffsetInBytes = CommandBufferSizePerFrame; uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE; m_device->CreateUnorderedAccessView( m_processedCommandBuffers[frame].Get(), m_processedCommandBuffers[frame].Get(), &uavDesc, processedCommandsHandle); processedCommandsHandle.Offset(CbvSrvUavDescriptorCountPerFrame, m_cbvSrvUavDescriptorSize); } // Allocate a buffer that can be used to reset the UAV counters and initialize // it to 0. ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(sizeof(UINT)), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_processedCommandBufferCounterReset))); UINT8* pMappedCounterReset = nullptr; CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU. ThrowIfFailed(m_processedCommandBufferCounterReset->Map(0, &readRange, reinterpret_cast<void**>(&pMappedCounterReset))); ZeroMemory(pMappedCounterReset, sizeof(UINT)); m_processedCommandBufferCounterReset->Unmap(0, nullptr); } // Close the command list and execute it to begin the vertex buffer copy into // the default heap. ThrowIfFailed(m_commandList->Close()); ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() }; m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists); // Create synchronization objects and wait until assets have been uploaded to the GPU. { ThrowIfFailed(m_device->CreateFence(m_fenceValues[m_frameIndex], D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence))); ThrowIfFailed(m_device->CreateFence(m_fenceValues[m_frameIndex], D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_computeFence))); m_fenceValues[m_frameIndex]++; // 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. WaitForGpu(); } }