// Load the sample assets. void D3D12PredicationQueries::LoadAssets() { // Create a root signature consisting of a single CBV parameter. { D3D12_FEATURE_DATA_ROOT_SIGNATURE featureData = {}; // This is the highest version the sample supports. If CheckFeatureSupport succeeds, the HighestVersion returned will not be greater than this. featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_1; if (FAILED(m_device->CheckFeatureSupport(D3D12_FEATURE_ROOT_SIGNATURE, &featureData, sizeof(featureData)))) { featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_0; } CD3DX12_DESCRIPTOR_RANGE1 ranges[1]; CD3DX12_ROOT_PARAMETER1 rootParameters[1]; ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC); rootParameters[0].InitAsDescriptorTable(1, &ranges[0], D3D12_SHADER_VISIBILITY_VERTEX); // Allow input layout and deny uneccessary access to certain pipeline stages. D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS; CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC rootSignatureDesc; rootSignatureDesc.Init_1_1(_countof(rootParameters), rootParameters, 0, nullptr, rootSignatureFlags); ComPtr<ID3DBlob> signature; ComPtr<ID3DBlob> error; ThrowIfFailed(D3DX12SerializeVersionedRootSignature(&rootSignatureDesc, featureData.HighestVersion, &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 compiling and loading shaders. { ComPtr<ID3DBlob> vertexShader; ComPtr<ID3DBlob> pixelShader; #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, nullptr)); ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"shaders.hlsl").c_str(), nullptr, nullptr, "PSMain", "ps_5_0", compileFlags, 0, &pixelShader, nullptr)); // 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 }, { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 } }; // Enable alpha blending so we can visualize the occlusion query results. CD3DX12_BLEND_DESC blendDesc(D3D12_DEFAULT); blendDesc.RenderTarget[0] = { TRUE, FALSE, D3D12_BLEND_SRC_ALPHA, D3D12_BLEND_INV_SRC_ALPHA, D3D12_BLEND_OP_ADD, D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, D3D12_LOGIC_OP_NOOP, D3D12_COLOR_WRITE_ENABLE_ALL, }; // 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 = CD3DX12_SHADER_BYTECODE(vertexShader.Get()); psoDesc.PS = CD3DX12_SHADER_BYTECODE(pixelShader.Get()); psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT); psoDesc.BlendState = blendDesc; 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); // Disable color writes and depth writes for the occlusion query's state. psoDesc.BlendState.RenderTarget[0].RenderTargetWriteMask = 0; psoDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO; ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_queryState))); NAME_D3D12_OBJECT(m_queryState); } // 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))); NAME_D3D12_OBJECT(m_commandList); // Note: ComPtr's are CPU objects but this resource needs to stay in scope until // the command list that references it has finished executing on the GPU. // We will flush the GPU at the end of this method to ensure the resource is not // prematurely destroyed. ComPtr<ID3D12Resource> vertexBufferUpload; // Create the vertex buffer. { // Create geometry for two quads and a bounding box for the occlusion query. // Geometry will be rendered back-to-front to support transparency in the scene. Vertex quadVertices[] = { // Far quad - in practice this would be a complex geometry. { { -0.25f, -0.25f * m_aspectRatio, 0.5f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, { { -0.25f, 0.25f * m_aspectRatio, 0.5f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, { { 0.25f, -0.25f * m_aspectRatio, 0.5f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, { { 0.25f, 0.25f * m_aspectRatio, 0.5f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, // Near quad. { { -0.5f, -0.35f * m_aspectRatio, 0.0f }, { 1.0f, 0.0f, 0.0f, 0.65f } }, { { -0.5f, 0.35f * m_aspectRatio, 0.0f }, { 1.0f, 0.0f, 0.0f, 0.65f } }, { { 0.5f, -0.35f * m_aspectRatio, 0.0f }, { 1.0f, 1.0f, 0.0f, 0.65f } }, { { 0.5f, 0.35f * m_aspectRatio, 0.0f }, { 1.0f, 1.0f, 0.0f, 0.65f } }, // Far quad bounding box used for occlusion query (offset slightly to avoid z-fighting). { { -0.25f, -0.25f * m_aspectRatio, 0.4999f }, { 0.0f, 0.0f, 0.0f, 1.0f } }, { { -0.25f, 0.25f * m_aspectRatio, 0.4999f }, { 0.0f, 0.0f, 0.0f, 1.0f } }, { { 0.25f, -0.25f * m_aspectRatio, 0.4999f }, { 0.0f, 0.0f, 0.0f, 1.0f } }, { { 0.25f, 0.25f * m_aspectRatio, 0.4999f }, { 0.0f, 0.0f, 0.0f, 1.0f } }, }; const UINT vertexBufferSize = sizeof(quadVertices); 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))); 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 = reinterpret_cast<UINT8*>(quadVertices); 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(quadVertices); } // Create the constant buffers. { ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(FrameCount * sizeof(m_constantBufferData)), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_constantBuffer))); NAME_D3D12_OBJECT(m_constantBuffer); // Map and initialize the constant buffer. 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))); ZeroMemory(m_pCbvDataBegin, FrameCount * sizeof(m_constantBufferData)); // Create constant buffer views to access the upload buffer. CD3DX12_CPU_DESCRIPTOR_HANDLE cpuHandle(m_cbvHeap->GetCPUDescriptorHandleForHeapStart()); D3D12_GPU_VIRTUAL_ADDRESS gpuAddress = m_constantBuffer->GetGPUVirtualAddress(); D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {}; cbvDesc.SizeInBytes = sizeof(SceneConstantBuffer); for (UINT n = 0; n < FrameCount; n++) { cbvDesc.BufferLocation = gpuAddress; m_device->CreateConstantBufferView(&cbvDesc, cpuHandle); cpuHandle.Offset(m_cbvSrvDescriptorSize); gpuAddress += cbvDesc.SizeInBytes; cbvDesc.BufferLocation = gpuAddress; m_device->CreateConstantBufferView(&cbvDesc, cpuHandle); cpuHandle.Offset(m_cbvSrvDescriptorSize); gpuAddress += cbvDesc.SizeInBytes; } } // 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()); } // Create the query result buffer. { D3D12_RESOURCE_DESC queryResultDesc = CD3DX12_RESOURCE_DESC::Buffer(8); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &queryResultDesc, D3D12_RESOURCE_STATE_PREDICATION, nullptr, IID_PPV_ARGS(&m_queryResult) )); NAME_D3D12_OBJECT(m_queryResult); } // 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))); 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(); } }
void D3D12PipelineStateCache::LoadAssets() { // Create the root signature. { D3D12_FEATURE_DATA_ROOT_SIGNATURE featureData = {}; // This is the highest version the sample supports. If CheckFeatureSupport succeeds, the HighestVersion returned will not be greater than this. featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_1; if (FAILED(m_device->CheckFeatureSupport(D3D12_FEATURE_ROOT_SIGNATURE, &featureData, sizeof(featureData)))) { featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_0; } CD3DX12_DESCRIPTOR_RANGE1 ranges[RootParametersCount]; ranges[RootParameterSRV].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC); CD3DX12_ROOT_PARAMETER1 rootParameters[RootParametersCount]; rootParameters[RootParameterUberShaderCB].InitAsConstantBufferView(0, 0, D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC, D3D12_SHADER_VISIBILITY_ALL); rootParameters[RootParameterCB].InitAsConstantBufferView(1, 0, D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC, D3D12_SHADER_VISIBILITY_ALL); rootParameters[RootParameterSRV].InitAsDescriptorTable(1, &ranges[RootParameterSRV]); D3D12_STATIC_SAMPLER_DESC sampler = {}; sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT; sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_BORDER; sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_BORDER; sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_BORDER; sampler.MipLODBias = 0; sampler.MaxAnisotropy = 0; sampler.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER; sampler.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK; sampler.MinLOD = 0.0f; sampler.MaxLOD = 9999.0f; sampler.ShaderRegister = 0; sampler.RegisterSpace = 0; sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC rootSignatureDesc; rootSignatureDesc.Init_1_1(_countof(rootParameters), rootParameters, 1, &sampler, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT); ComPtr<ID3DBlob> signature; ComPtr<ID3DBlob> error; ThrowIfFailed(D3DX12SerializeVersionedRootSignature(&rootSignatureDesc, featureData.HighestVersion, &signature, &error)); ThrowIfFailed(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature))); NAME_D3D12_OBJECT(m_rootSignature); } // Create the command list. ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocators[m_frameIndex].Get(), nullptr, IID_PPV_ARGS(&m_commandList))); NAME_D3D12_OBJECT(m_commandList); // Note: ComPtr's are CPU objects but this resource needs to stay in scope until // the command list that references it has finished executing on the GPU. // We will flush the GPU at the end of this method to ensure the resource is not // prematurely destroyed. ComPtr<ID3D12Resource> vertexIndexBufferUpload; // Vertex and Index Buffer. { const VertexPositionColor cubeVertices[] = { { { -1.0f, 1.0f, -1.0f, 1.0f }, { GetRandomColor(),GetRandomColor(), GetRandomColor() } }, // Back Top Left { { 1.0f, 1.0f, -1.0f, 1.0f }, { GetRandomColor(), GetRandomColor(), GetRandomColor() } }, // Back Top Right { { 1.0f, 1.0f, 1.0f, 1.0f }, { GetRandomColor(), GetRandomColor(), GetRandomColor() } }, // Front Top Right { { -1.0f, 1.0f, 1.0f, 1.0f }, { GetRandomColor(), GetRandomColor(), GetRandomColor() } }, // Front Top Left { { -1.0f, -1.0f, -1.0f, 1.0f }, { GetRandomColor(),GetRandomColor(), GetRandomColor() } }, // Back Bottom Left { { 1.0f, -1.0f, -1.0f, 1.0f }, { GetRandomColor(),GetRandomColor(), GetRandomColor() } }, // Back Bottom Right { { 1.0f, -1.0f, 1.0f, 1.0f }, { GetRandomColor(),GetRandomColor(), GetRandomColor() } }, // Front Bottom Right { { -1.0f, -1.0f, 1.0f, 1.0f }, { GetRandomColor(),GetRandomColor(), GetRandomColor() } }, // Front Bottom Left }; const UINT cubeIndices[] = { 0, 1, 3, 1, 2, 3, 3, 2, 7, 6, 7, 2, 2, 1, 6, 5, 6, 1, 1, 0, 5, 4, 5, 0, 0, 3, 4, 7, 4, 3, 7, 6, 4, 5, 4, 6, }; static const VertexPositionUV quadVertices[] = { { { -1.0f, -1.0f, 0.0f, 1.0f }, { 0.0f, 1.0f } }, // Bottom Left { { -1.0f, 1.0f, 0.0f, 1.0f }, { 0.0f, 0.0f } }, // Top Left { { 1.0f, -1.0f, 0.0f, 1.0f }, { 1.0f, 1.0f } }, // Bottom Right { { 1.0f, 1.0f, 0.0f, 1.0f }, { 1.0f, 0.0f } }, // Top Right }; const UINT vertexIndexBufferSize = sizeof(cubeIndices) + sizeof(cubeVertices) + sizeof(quadVertices); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(vertexIndexBufferSize), D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_vertexIndexBuffer))); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(vertexIndexBufferSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&vertexIndexBufferUpload))); NAME_D3D12_OBJECT(m_vertexIndexBuffer); UINT8* mappedUploadHeap = nullptr; CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU. ThrowIfFailed(vertexIndexBufferUpload->Map(0, &readRange, reinterpret_cast<void**>(&mappedUploadHeap))); // Fill in part of the upload heap with our index and vertex data. UINT8* heapLocation = static_cast<UINT8*>(mappedUploadHeap); memcpy(heapLocation, cubeVertices, sizeof(cubeVertices)); heapLocation += sizeof(cubeVertices); memcpy(heapLocation, cubeIndices, sizeof(cubeIndices)); heapLocation += sizeof(cubeIndices); memcpy(heapLocation, quadVertices, sizeof(quadVertices)); // Pack the vertices and indices into their destination by copying from the upload heap. m_commandList->CopyBufferRegion(m_vertexIndexBuffer.Get(), 0, vertexIndexBufferUpload.Get(), 0, vertexIndexBufferSize); m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_vertexIndexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER | D3D12_RESOURCE_STATE_INDEX_BUFFER)); // Create the index and vertex buffer views. m_cubeVbv.BufferLocation = m_vertexIndexBuffer.Get()->GetGPUVirtualAddress(); m_cubeVbv.SizeInBytes = sizeof(cubeVertices); m_cubeVbv.StrideInBytes = sizeof(VertexPositionColor); m_cubeIbv.BufferLocation = m_cubeVbv.BufferLocation + sizeof(cubeVertices); m_cubeIbv.SizeInBytes = sizeof(cubeIndices); m_cubeIbv.Format = DXGI_FORMAT_R32_UINT; m_quadVbv.BufferLocation = m_cubeIbv.BufferLocation + sizeof(cubeIndices); m_quadVbv.SizeInBytes = sizeof(quadVertices); m_quadVbv.StrideInBytes = sizeof(VertexPositionUV); } // Create the constant buffer. m_dynamicCB.Init(m_device.Get()); // Close the command list and execute it to begin the vertex/index 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))); 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(); } m_psoLibrary.Build(m_device.Get(), m_rootSignature.Get()); UpdateWindowTextPso(); }
void CrossNodeResources::LoadAssets() { // Create the root signatures. // Root signatures may be shared across GPU nodes. { D3D12_FEATURE_DATA_ROOT_SIGNATURE featureData = {}; // This is the highest version the sample supports. If CheckFeatureSupport succeeds, the HighestVersion returned will not be greater than this. featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_1; if (FAILED(m_device->CheckFeatureSupport(D3D12_FEATURE_ROOT_SIGNATURE, &featureData, sizeof(featureData)))) { featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_0; } // Create a root signature for rendering the triangle scene. { CD3DX12_DESCRIPTOR_RANGE1 sceneRanges[1]; sceneRanges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC); CD3DX12_ROOT_PARAMETER1 sceneRootParameters[2]; sceneRootParameters[0].InitAsDescriptorTable(1, &sceneRanges[0], D3D12_SHADER_VISIBILITY_VERTEX); sceneRootParameters[1].InitAsConstants(1, 1, 0, D3D12_SHADER_VISIBILITY_VERTEX); CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC sceneRootSignatureDesc; sceneRootSignatureDesc.Init_1_1(_countof(sceneRootParameters), sceneRootParameters, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT); ComPtr<ID3DBlob> signature; ComPtr<ID3DBlob> error; ThrowIfFailed(D3DX12SerializeVersionedRootSignature(&sceneRootSignatureDesc, featureData.HighestVersion, &signature, &error)); ThrowIfFailed(m_device->CreateRootSignature(Settings::SharedNodeMask, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_sceneRootSignature))); } // Create a root signature for the post-process pass. { CD3DX12_DESCRIPTOR_RANGE1 postRanges[2]; postRanges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, Settings::SceneHistoryCount, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE); postRanges[1].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 1, 0); CD3DX12_ROOT_PARAMETER1 postRootParameters[3]; postRootParameters[0].InitAsDescriptorTable(1, &postRanges[0], D3D12_SHADER_VISIBILITY_PIXEL); postRootParameters[1].InitAsDescriptorTable(1, &postRanges[1], D3D12_SHADER_VISIBILITY_PIXEL); postRootParameters[2].InitAsConstants(2, 0, 0, D3D12_SHADER_VISIBILITY_PIXEL); CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC postRootSignatureDesc; postRootSignatureDesc.Init_1_1(_countof(postRootParameters), postRootParameters, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT); ComPtr<ID3DBlob> signature; ComPtr<ID3DBlob> error; ThrowIfFailed(D3DX12SerializeVersionedRootSignature(&postRootSignatureDesc, featureData.HighestVersion, &signature, &error)); ThrowIfFailed(m_device->CreateRootSignature(Settings::SharedNodeMask, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_postRootSignature))); } } // Create the pipeline state, which includes compiling and loading shaders. // Pipeline states may be shared across GPU nodes. { // Define the vertex input layout for the triangle scene. 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_sceneRootSignature.Get(); psoDesc.VS = { g_SceneVS, sizeof(g_SceneVS) }; psoDesc.PS = { g_ScenePS, sizeof(g_ScenePS) }; 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; psoDesc.NodeMask = Settings::SharedNodeMask; ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_scenePipelineState))); // Define the vertex input layout for the post-process fullscreen quad. D3D12_INPUT_ELEMENT_DESC postInputElementDescs[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, }; // Describe and create the PSO for the post-process pass. D3D12_GRAPHICS_PIPELINE_STATE_DESC postPsoDesc = {}; postPsoDesc.InputLayout = { postInputElementDescs, _countof(postInputElementDescs) }; postPsoDesc.pRootSignature = m_postRootSignature.Get(); postPsoDesc.VS = { g_PostVS, sizeof(g_PostVS) }; postPsoDesc.PS = { g_PostPS, sizeof(g_PostPS) }; postPsoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT); postPsoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT); postPsoDesc.DepthStencilState.DepthEnable = FALSE; postPsoDesc.DepthStencilState.StencilEnable = FALSE; postPsoDesc.SampleMask = UINT_MAX; postPsoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; postPsoDesc.NumRenderTargets = 1; postPsoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; postPsoDesc.SampleDesc.Count = 1; postPsoDesc.NodeMask = Settings::SharedNodeMask; ThrowIfFailed(m_device->CreateGraphicsPipelineState(&postPsoDesc, IID_PPV_ARGS(&m_postPipelineState))); } // Create and map the constant buffers. // Upload heaps live in system memory and can be made visible to all GPU nodes. { const UINT constantBufferDataSize = Settings::TriangleCount * Settings::SceneConstantBufferFrames * sizeof(SceneConstantBuffer); D3D12_HEAP_PROPERTIES uploadHeapProps = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD); uploadHeapProps.VisibleNodeMask = Settings::SharedNodeMask; ThrowIfFailed(m_device->CreateCommittedResource( &uploadHeapProps, D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(constantBufferDataSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_sceneConstantBuffer))); // Map the constant buffers. We don't unmap this until the app closes. // Keeping things mapped for the lifetime of the resource is okay. ThrowIfFailed(m_sceneConstantBuffer->Map(0, nullptr, reinterpret_cast<void**>(&m_mappedConstantBuffer))); ZeroMemory(m_mappedConstantBuffer, constantBufferDataSize); } }
// Load the sample assets. void D3D12Fullscreen::LoadAssets() { D3D12_FEATURE_DATA_ROOT_SIGNATURE featureData = {}; // This is the highest version the sample supports. If CheckFeatureSupport succeeds, the HighestVersion returned will not be greater than this. featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_1; if (FAILED(m_device->CheckFeatureSupport(D3D12_FEATURE_ROOT_SIGNATURE, &featureData, sizeof(featureData)))) { featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_0; } // Create a root signature consisting of a descriptor table with a single CBV. { CD3DX12_DESCRIPTOR_RANGE1 ranges[1]; CD3DX12_ROOT_PARAMETER1 rootParameters[1]; ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC); rootParameters[0].InitAsDescriptorTable(1, &ranges[0], D3D12_SHADER_VISIBILITY_VERTEX); // Allow input layout and deny uneccessary access to certain pipeline stages. D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS; CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC rootSignatureDesc; rootSignatureDesc.Init_1_1(_countof(rootParameters), rootParameters, 0, nullptr, rootSignatureFlags); ComPtr<ID3DBlob> signature; ComPtr<ID3DBlob> error; ThrowIfFailed(D3DX12SerializeVersionedRootSignature(&rootSignatureDesc, featureData.HighestVersion, &signature, &error)); ThrowIfFailed(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_sceneRootSignature))); NAME_D3D12_OBJECT(m_sceneRootSignature); } // Create a root signature consisting of a descriptor table with a SRV and a sampler. { CD3DX12_DESCRIPTOR_RANGE1 ranges[1]; CD3DX12_ROOT_PARAMETER1 rootParameters[1]; // We don't modify the SRV in the post-processing command list after // SetGraphicsRootDescriptorTable is executed on the GPU so we can use the default // range behavior: D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0); rootParameters[0].InitAsDescriptorTable(1, &ranges[0], D3D12_SHADER_VISIBILITY_PIXEL); // Allow input layout and pixel shader access and deny uneccessary access to certain pipeline stages. D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS; // Create a sampler. D3D12_STATIC_SAMPLER_DESC sampler = {}; sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR; sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_BORDER; sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_BORDER; sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_BORDER; sampler.MipLODBias = 0; sampler.MaxAnisotropy = 0; sampler.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER; sampler.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK; sampler.MinLOD = 0.0f; sampler.MaxLOD = D3D12_FLOAT32_MAX; sampler.ShaderRegister = 0; sampler.RegisterSpace = 0; sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC rootSignatureDesc; rootSignatureDesc.Init_1_1(_countof(rootParameters), rootParameters, 1, &sampler, rootSignatureFlags); ComPtr<ID3DBlob> signature; ComPtr<ID3DBlob> error; ThrowIfFailed(D3DX12SerializeVersionedRootSignature(&rootSignatureDesc, featureData.HighestVersion, &signature, &error)); ThrowIfFailed(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_postRootSignature))); NAME_D3D12_OBJECT(m_postRootSignature); } // Create the pipeline state, which includes compiling and loading shaders. { ComPtr<ID3DBlob> sceneVertexShader; ComPtr<ID3DBlob> scenePixelShader; ComPtr<ID3DBlob> postVertexShader; ComPtr<ID3DBlob> postPixelShader; 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"sceneShaders.hlsl").c_str(), nullptr, nullptr, "VSMain", "vs_5_0", compileFlags, 0, &sceneVertexShader, &error)); ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"sceneShaders.hlsl").c_str(), nullptr, nullptr, "PSMain", "ps_5_0", compileFlags, 0, &scenePixelShader, &error)); ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"postShaders.hlsl").c_str(), nullptr, nullptr, "VSMain", "vs_5_0", compileFlags, 0, &postVertexShader, &error)); ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"postShaders.hlsl").c_str(), nullptr, nullptr, "PSMain", "ps_5_0", compileFlags, 0, &postPixelShader, &error)); // Define the vertex input layouts. D3D12_INPUT_ELEMENT_DESC inputElementDescs[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 } }; D3D12_INPUT_ELEMENT_DESC scaleInputElementDescs[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 } }; // Describe and create the graphics pipeline state objects (PSOs). D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) }; psoDesc.pRootSignature = m_sceneRootSignature.Get(); psoDesc.VS = CD3DX12_SHADER_BYTECODE(sceneVertexShader.Get()); psoDesc.PS = CD3DX12_SHADER_BYTECODE(scenePixelShader.Get()); psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT); psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT); psoDesc.DepthStencilState.DepthEnable = FALSE; psoDesc.DepthStencilState.StencilEnable = FALSE; psoDesc.SampleMask = UINT_MAX; psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; psoDesc.NumRenderTargets = 1; psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; psoDesc.SampleDesc.Count = 1; ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_scenePipelineState))); NAME_D3D12_OBJECT(m_scenePipelineState); psoDesc.InputLayout = { scaleInputElementDescs, _countof(scaleInputElementDescs) }; psoDesc.pRootSignature = m_postRootSignature.Get(); psoDesc.VS = CD3DX12_SHADER_BYTECODE(postVertexShader.Get()); psoDesc.PS = CD3DX12_SHADER_BYTECODE(postPixelShader.Get()); ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_postPipelineState))); NAME_D3D12_OBJECT(m_postPipelineState); } // Single-use command allocator and command list for creating resources. ComPtr<ID3D12CommandAllocator> commandAllocator; ComPtr<ID3D12GraphicsCommandList> commandList; ThrowIfFailed(m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&commandAllocator))); ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAllocator.Get(), nullptr, IID_PPV_ARGS(&commandList))); // Create the command lists. { ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_sceneCommandAllocators[m_frameIndex].Get(), m_scenePipelineState.Get(), IID_PPV_ARGS(&m_sceneCommandList))); NAME_D3D12_OBJECT(m_sceneCommandList); ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_postCommandAllocators[m_frameIndex].Get(), m_postPipelineState.Get(), IID_PPV_ARGS(&m_postCommandList))); NAME_D3D12_OBJECT(m_postCommandList); // Close the command lists. ThrowIfFailed(m_sceneCommandList->Close()); ThrowIfFailed(m_postCommandList->Close()); } LoadSizeDependentResources(); LoadSceneResolutionDependentResources(); // Create/update the vertex buffer. ComPtr<ID3D12Resource> sceneVertexBufferUpload; { // Define the geometry for a thin quad that will animate across the screen. const float x = QuadWidth / 2.0f; const float y = QuadHeight / 2.0f; SceneVertex quadVertices[] = { { { -x, -y, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, { { -x, y, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, { { x, -y, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, { { x, y, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } } }; const UINT vertexBufferSize = sizeof(quadVertices); 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_sceneVertexBuffer))); 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(&sceneVertexBufferUpload))); NAME_D3D12_OBJECT(m_sceneVertexBuffer); // Copy data to the intermediate upload heap and then schedule a copy // from the upload heap to the vertex buffer. UINT8* pVertexDataBegin; CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU. ThrowIfFailed(sceneVertexBufferUpload->Map(0, &readRange, reinterpret_cast<void**>(&pVertexDataBegin))); memcpy(pVertexDataBegin, quadVertices, sizeof(quadVertices)); sceneVertexBufferUpload->Unmap(0, nullptr); commandList->CopyBufferRegion(m_sceneVertexBuffer.Get(), 0, sceneVertexBufferUpload.Get(), 0, vertexBufferSize); commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_sceneVertexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER)); // Initialize the vertex buffer views. m_sceneVertexBufferView.BufferLocation = m_sceneVertexBuffer->GetGPUVirtualAddress(); m_sceneVertexBufferView.StrideInBytes = sizeof(SceneVertex); m_sceneVertexBufferView.SizeInBytes = vertexBufferSize; } // Create/update the fullscreen quad vertex buffer. ComPtr<ID3D12Resource> postVertexBufferUpload; { // Define the geometry for a fullscreen quad. PostVertex quadVertices[] = { { { -1.0f, -1.0f, 0.0f, 1.0f }, { 0.0f, 0.0f } }, // Bottom left. { { -1.0f, 1.0f, 0.0f, 1.0f }, { 0.0f, 1.0f } }, // Top left. { { 1.0f, -1.0f, 0.0f, 1.0f }, { 1.0f, 0.0f } }, // Bottom right. { { 1.0f, 1.0f, 0.0f, 1.0f }, { 1.0f, 1.0f } } // Top right. }; const UINT vertexBufferSize = sizeof(quadVertices); 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_postVertexBuffer))); 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(&postVertexBufferUpload))); NAME_D3D12_OBJECT(m_postVertexBuffer); // Copy data to the intermediate upload heap and then schedule a copy // from the upload heap to the vertex buffer. UINT8* pVertexDataBegin; CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU. ThrowIfFailed(postVertexBufferUpload->Map(0, &readRange, reinterpret_cast<void**>(&pVertexDataBegin))); memcpy(pVertexDataBegin, quadVertices, sizeof(quadVertices)); postVertexBufferUpload->Unmap(0, nullptr); commandList->CopyBufferRegion(m_postVertexBuffer.Get(), 0, postVertexBufferUpload.Get(), 0, vertexBufferSize); commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_postVertexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER)); // Initialize the vertex buffer views. m_postVertexBufferView.BufferLocation = m_postVertexBuffer->GetGPUVirtualAddress(); m_postVertexBufferView.StrideInBytes = sizeof(PostVertex); m_postVertexBufferView.SizeInBytes = vertexBufferSize; } // Create the constant buffer. { ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(sizeof(SceneConstantBuffer) * FrameCount), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_sceneConstantBuffer))); NAME_D3D12_OBJECT(m_sceneConstantBuffer); // Describe and create constant buffer views. D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {}; cbvDesc.BufferLocation = m_sceneConstantBuffer->GetGPUVirtualAddress(); cbvDesc.SizeInBytes = sizeof(SceneConstantBuffer); CD3DX12_CPU_DESCRIPTOR_HANDLE cpuHandle(m_cbvSrvHeap->GetCPUDescriptorHandleForHeapStart(), 1, m_cbvSrvDescriptorSize); for (UINT n = 0; n < FrameCount; n++) { m_device->CreateConstantBufferView(&cbvDesc, cpuHandle); cbvDesc.BufferLocation += sizeof(SceneConstantBuffer); cpuHandle.Offset(m_cbvSrvDescriptorSize); } // Map and initialize the constant buffer. 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_sceneConstantBuffer->Map(0, &readRange, reinterpret_cast<void**>(&m_pCbvDataBegin))); memcpy(m_pCbvDataBegin, &m_sceneConstantBufferData, sizeof(m_sceneConstantBufferData)); } // Close the resource creation command list and execute it to begin the vertex buffer copy into // the default heap. ThrowIfFailed(commandList->Close()); ID3D12CommandList* ppCommandLists[] = { 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))); 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 before continuing. WaitForGpu(); } }
// 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. { D3D12_FEATURE_DATA_ROOT_SIGNATURE featureData = {}; // This is the highest version the sample supports. If CheckFeatureSupport succeeds, the HighestVersion returned will not be greater than this. featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_1; if (FAILED(m_device->CheckFeatureSupport(D3D12_FEATURE_ROOT_SIGNATURE, &featureData, sizeof(featureData)))) { featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_0; } CD3DX12_DESCRIPTOR_RANGE1 ranges[3]; ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1 + CityMaterialCount, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC); // 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, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC); CD3DX12_ROOT_PARAMETER1 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_VERSIONED_ROOT_SIGNATURE_DESC rootSignatureDesc; rootSignatureDesc.Init_1_1(_countof(rootParameters), rootParameters, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT); ComPtr<ID3DBlob> signature; ComPtr<ID3DBlob> error; ThrowIfFailed(D3DX12SerializeVersionedRootSignature(&rootSignatureDesc, featureData.HighestVersion, &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); // 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); } CreateFrameResources(); }
// Load the sample assets. void D3D12Multithreading::LoadAssets() { // Create the root signature. { D3D12_FEATURE_DATA_ROOT_SIGNATURE featureData = {}; // This is the highest version the sample supports. If CheckFeatureSupport succeeds, the HighestVersion returned will not be greater than this. featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_1; if (FAILED(m_device->CheckFeatureSupport(D3D12_FEATURE_ROOT_SIGNATURE, &featureData, sizeof(featureData)))) { featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_0; } CD3DX12_DESCRIPTOR_RANGE1 ranges[4]; // Perfomance TIP: Order from most frequent to least frequent. ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 2, 1, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC); // 2 frequently changed diffuse + normal textures - using registers t1 and t2. ranges[1].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC); // 1 frequently changed constant buffer. ranges[2].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE);// 1 infrequently changed shadow texture - starting in register t0. ranges[3].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 2, 0); // 2 static samplers. CD3DX12_ROOT_PARAMETER1 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_VERSIONED_ROOT_SIGNATURE_DESC rootSignatureDesc; rootSignatureDesc.Init_1_1(_countof(rootParameters), rootParameters, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT); ComPtr<ID3DBlob> signature; ComPtr<ID3DBlob> error; ThrowIfFailed(D3DX12SerializeVersionedRootSignature(&rootSignatureDesc, featureData.HighestVersion, &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. { ComPtr<ID3DBlob> vertexShader; ComPtr<ID3DBlob> pixelShader; #if defined(_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 = CD3DX12_SHADER_BYTECODE(vertexShader.Get()); psoDesc.PS = CD3DX12_SHADER_BYTECODE(pixelShader.Get()); 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))); NAME_D3D12_OBJECT(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 = CD3DX12_SHADER_BYTECODE(0, 0); psoDesc.RTVFormats[0] = DXGI_FORMAT_UNKNOWN; psoDesc.NumRenderTargets = 0; ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineStateShadowMap))); NAME_D3D12_OBJECT(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); NAME_D3D12_OBJECT_INDEXED(m_renderTargets, i); } // 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))); NAME_D3D12_OBJECT(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))); NAME_D3D12_OBJECT(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))); NAME_D3D12_OBJECT(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 (UINT 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]))); NAME_D3D12_OBJECT_INDEXED(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 = 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 sample assets. void D3D12HelloTexture::LoadAssets() { // Create the root signature. { D3D12_FEATURE_DATA_ROOT_SIGNATURE featureData = {}; // This is the highest version the sample supports. If CheckFeatureSupport succeeds, the HighestVersion returned will not be greater than this. featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_1; if (FAILED(m_device->CheckFeatureSupport(D3D12_FEATURE_ROOT_SIGNATURE, &featureData, sizeof(featureData)))) { featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_0; } CD3DX12_DESCRIPTOR_RANGE1 ranges[1]; ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC); CD3DX12_ROOT_PARAMETER1 rootParameters[1]; rootParameters[0].InitAsDescriptorTable(1, &ranges[0], D3D12_SHADER_VISIBILITY_PIXEL); D3D12_STATIC_SAMPLER_DESC sampler = {}; sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT; sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_BORDER; sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_BORDER; sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_BORDER; sampler.MipLODBias = 0; sampler.MaxAnisotropy = 0; sampler.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER; sampler.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK; sampler.MinLOD = 0.0f; sampler.MaxLOD = D3D12_FLOAT32_MAX; sampler.ShaderRegister = 0; sampler.RegisterSpace = 0; sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC rootSignatureDesc; rootSignatureDesc.Init_1_1(_countof(rootParameters), rootParameters, 1, &sampler, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT); ComPtr<ID3DBlob> signature; ComPtr<ID3DBlob> error; ThrowIfFailed(D3DX12SerializeVersionedRootSignature(&rootSignatureDesc, featureData.HighestVersion, &signature, &error)); ThrowIfFailed(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature))); } // Create the pipeline state, which includes compiling and loading shaders. { ComPtr<ID3DBlob> vertexShader; ComPtr<ID3DBlob> pixelShader; #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, nullptr)); ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"shaders.hlsl").c_str(), nullptr, nullptr, "PSMain", "ps_5_0", compileFlags, 0, &pixelShader, nullptr)); // 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 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 } }; // Describe and create the graphics pipeline state object (PSO). D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) }; psoDesc.pRootSignature = m_rootSignature.Get(); psoDesc.VS = CD3DX12_SHADER_BYTECODE(vertexShader.Get()); psoDesc.PS = CD3DX12_SHADER_BYTECODE(pixelShader.Get()); psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT); psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT); psoDesc.DepthStencilState.DepthEnable = FALSE; psoDesc.DepthStencilState.StencilEnable = FALSE; psoDesc.SampleMask = UINT_MAX; psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; psoDesc.NumRenderTargets = 1; psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; psoDesc.SampleDesc.Count = 1; ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineState))); } // Create the command list. ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocator.Get(), m_pipelineState.Get(), IID_PPV_ARGS(&m_commandList))); // Create the vertex buffer. { // Define the geometry for a triangle. Vertex triangleVertices[] = { { { 0.0f, 0.25f * m_aspectRatio, 0.0f }, { 0.5f, 0.0f } }, { { 0.25f, -0.25f * m_aspectRatio, 0.0f }, { 1.0f, 1.0f } }, { { -0.25f, -0.25f * m_aspectRatio, 0.0f }, { 0.0f, 1.0f } } }; const UINT vertexBufferSize = sizeof(triangleVertices); // Note: using upload heaps to transfer static data like vert buffers is not // recommended. Every time the GPU needs it, the upload heap will be marshalled // over. Please read up on Default Heap usage. An upload heap is used here for // code simplicity and because there are very few verts to actually transfer. 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(&m_vertexBuffer))); // Copy the triangle data to the vertex buffer. UINT8* pVertexDataBegin; CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU. ThrowIfFailed(m_vertexBuffer->Map(0, &readRange, reinterpret_cast<void**>(&pVertexDataBegin))); memcpy(pVertexDataBegin, triangleVertices, sizeof(triangleVertices)); m_vertexBuffer->Unmap(0, nullptr); // Initialize the vertex buffer view. m_vertexBufferView.BufferLocation = m_vertexBuffer->GetGPUVirtualAddress(); m_vertexBufferView.StrideInBytes = sizeof(Vertex); m_vertexBufferView.SizeInBytes = vertexBufferSize; } // Note: ComPtr's are CPU objects but this resource needs to stay in scope until // the command list that references it has finished executing on the GPU. // We will flush the GPU at the end of this method to ensure the resource is not // prematurely destroyed. ComPtr<ID3D12Resource> textureUploadHeap; // Create the texture. { // Describe and create a Texture2D. D3D12_RESOURCE_DESC textureDesc = {}; textureDesc.MipLevels = 1; textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; textureDesc.Width = TextureWidth; textureDesc.Height = TextureHeight; 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 UINT64 uploadBufferSize = GetRequiredIntermediateSize(m_texture.Get(), 0, 1); // Create the GPU upload buffer. 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. std::vector<UINT8> texture = GenerateTextureData(); D3D12_SUBRESOURCE_DATA textureData = {}; textureData.pData = &texture[0]; textureData.RowPitch = TextureWidth * TexturePixelSize; textureData.SlicePitch = textureData.RowPitch * TextureHeight; UpdateSubresources(m_commandList.Get(), m_texture.Get(), textureUploadHeap.Get(), 0, 0, 1, &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 SRV for the texture. D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; srvDesc.Format = textureDesc.Format; srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; srvDesc.Texture2D.MipLevels = 1; m_device->CreateShaderResourceView(m_texture.Get(), &srvDesc, m_srvHeap->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); // Create synchronization objects and wait until assets have been uploaded to the GPU. { ThrowIfFailed(m_device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence))); m_fenceValue = 1; // Create an event handle to use for frame synchronization. m_fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); if (m_fenceEvent == nullptr) { 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. WaitForPreviousFrame(); } }
// Load the sample assets. void D3D12HelloConstBuffers::LoadAssets() { // Create a root signature consisting of a descriptor table with a single CBV. { D3D12_FEATURE_DATA_ROOT_SIGNATURE featureData = {}; // This is the highest version the sample supports. If CheckFeatureSupport succeeds, the HighestVersion returned will not be greater than this. featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_1; if (FAILED(m_device->CheckFeatureSupport(D3D12_FEATURE_ROOT_SIGNATURE, &featureData, sizeof(featureData)))) { featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_0; } CD3DX12_DESCRIPTOR_RANGE1 ranges[1]; CD3DX12_ROOT_PARAMETER1 rootParameters[1]; ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC); rootParameters[0].InitAsDescriptorTable(1, &ranges[0], D3D12_SHADER_VISIBILITY_VERTEX); // Allow input layout and deny uneccessary access to certain pipeline stages. D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS; CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC rootSignatureDesc; rootSignatureDesc.Init_1_1(_countof(rootParameters), rootParameters, 0, nullptr, rootSignatureFlags); ComPtr<ID3DBlob> signature; ComPtr<ID3DBlob> error; ThrowIfFailed(D3DX12SerializeVersionedRootSignature(&rootSignatureDesc, featureData.HighestVersion, &signature, &error)); ThrowIfFailed(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature))); } // Create the pipeline state, which includes compiling and loading shaders. { ComPtr<ID3DBlob> vertexShader; ComPtr<ID3DBlob> pixelShader; #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, nullptr)); ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"shaders.hlsl").c_str(), nullptr, nullptr, "PSMain", "ps_5_0", compileFlags, 0, &pixelShader, nullptr)); // 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 }, { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 } }; // Describe and create the graphics pipeline state object (PSO). D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) }; psoDesc.pRootSignature = m_rootSignature.Get(); psoDesc.VS = CD3DX12_SHADER_BYTECODE(vertexShader.Get()); psoDesc.PS = CD3DX12_SHADER_BYTECODE(pixelShader.Get()); psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT); psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT); psoDesc.DepthStencilState.DepthEnable = FALSE; psoDesc.DepthStencilState.StencilEnable = FALSE; psoDesc.SampleMask = UINT_MAX; psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; psoDesc.NumRenderTargets = 1; psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; psoDesc.SampleDesc.Count = 1; ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineState))); } // Create the command list. ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocator.Get(), m_pipelineState.Get(), IID_PPV_ARGS(&m_commandList))); // Command lists are created in the recording state, but there is nothing // to record yet. The main loop expects it to be closed, so close it now. ThrowIfFailed(m_commandList->Close()); // Create the vertex buffer. { // Define the geometry for a triangle. Vertex triangleVertices[] = { { { 0.0f, 0.25f * m_aspectRatio, 0.0f }, { 1.0f, 0.0f, 0.0f, 1.0f } }, { { 0.25f, -0.25f * m_aspectRatio, 0.0f }, { 0.0f, 1.0f, 0.0f, 1.0f } }, { { -0.25f, -0.25f * m_aspectRatio, 0.0f }, { 0.0f, 0.0f, 1.0f, 1.0f } } }; const UINT vertexBufferSize = sizeof(triangleVertices); // Note: using upload heaps to transfer static data like vert buffers is not // recommended. Every time the GPU needs it, the upload heap will be marshalled // over. Please read up on Default Heap usage. An upload heap is used here for // code simplicity and because there are very few verts to actually transfer. 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(&m_vertexBuffer))); // Copy the triangle data to the vertex buffer. UINT8* pVertexDataBegin; CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU. ThrowIfFailed(m_vertexBuffer->Map(0, &readRange, reinterpret_cast<void**>(&pVertexDataBegin))); memcpy(pVertexDataBegin, triangleVertices, sizeof(triangleVertices)); m_vertexBuffer->Unmap(0, nullptr); // Initialize the vertex buffer view. m_vertexBufferView.BufferLocation = m_vertexBuffer->GetGPUVirtualAddress(); m_vertexBufferView.StrideInBytes = sizeof(Vertex); m_vertexBufferView.SizeInBytes = vertexBufferSize; } // Create the constant buffer. { ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(1024 * 64), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_constantBuffer))); // Describe and create a constant buffer view. D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {}; cbvDesc.BufferLocation = m_constantBuffer->GetGPUVirtualAddress(); cbvDesc.SizeInBytes = (sizeof(SceneConstantBuffer) + 255) & ~255; // CB size is required to be 256-byte aligned. m_device->CreateConstantBufferView(&cbvDesc, m_cbvHeap->GetCPUDescriptorHandleForHeapStart()); // Map and initialize the constant buffer. 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, sizeof(m_constantBufferData)); } // Create synchronization objects and wait until assets have been uploaded to the GPU. { ThrowIfFailed(m_device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence))); m_fenceValue = 1; // Create an event handle to use for frame synchronization. m_fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); if (m_fenceEvent == nullptr) { 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. WaitForPreviousFrame(); } }