IFACEMETHODIMP ImageControlMixIn::MeasureOverride( Size availableSize, Size* returnValue) { UNREFERENCED_PARAMETER(availableSize); return ExceptionBoundary( [&] { Size zeroSize{ 0, 0 }; // // Call Measure on our children (in this case just the image control). // ThrowIfFailed(As<IUIElement>(m_imageControl)->Measure(zeroSize)); // // Reply that we're happy to be sized however the layout engine wants to size us. // *returnValue = zeroSize; }); }
// Render the scene. void D3D1211on12::OnRender() { PIXBeginEvent(m_commandQueue.Get(), 0, L"Render 3D"); // Record all the commands we need to render the scene into the command list. PopulateCommandList(); // Execute the command list. ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() }; m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists); PIXEndEvent(m_commandQueue.Get()); PIXBeginEvent(m_commandQueue.Get(), 0, L"Render UI"); RenderUI(); PIXEndEvent(m_commandQueue.Get()); // Present the frame. ThrowIfFailed(m_swapChain->Present(1, 0)); MoveToNextFrame(); }
void D3D12HDR::UpdateSwapChainBuffer(UINT width, UINT height, DXGI_FORMAT format) { if (!m_swapChain) { return; } // Flush all current GPU commands. WaitForGpu(); // Release the resources holding references to the swap chain (requirement of // IDXGISwapChain::ResizeBuffers) and reset the frame fence values to the // current fence value. for (UINT n = 0; n < FrameCount; n++) { m_renderTargets[n].Reset(); m_fenceValues[n] = m_fenceValues[m_frameIndex]; } if (m_enableUI) { m_uiLayer->ReleaseResources(); } // Resize the swap chain to the desired dimensions. DXGI_SWAP_CHAIN_DESC1 desc = {}; m_swapChain->GetDesc1(&desc); ThrowIfFailed(m_swapChain->ResizeBuffers(FrameCount, width, height, format, desc.Flags)); EnsureSwapChainColorSpace(m_currentSwapChainBitDepth, m_enableST2084); // Reset the frame index to the current back buffer index. m_frameIndex = m_swapChain->GetCurrentBackBufferIndex(); // Update the width, height, and aspect ratio member variables. UpdateForSizeChange(width, height); LoadSizeDependentResources(); }
UINT64 GpuTimer::getTimeSpanInMs( const UINT frameNum, const char* timeSpanName ) { // Get the timestamp values for the given frame and time span from the result buffers. const D3D12_RANGE emptyRange = {}; D3D12_RANGE readRange = {}; readRange.Begin = getStartTimerIndx( frameNum, timeSpanName ) * sizeof( UINT64 ); readRange.End = readRange.Begin + 2 * sizeof( UINT64 ); void* pData = nullptr; ThrowIfFailed( m_timestampResultBuffer->Map( 0, &readRange, &pData ) ); const UINT64* pTimestamps = reinterpret_cast<UINT64*>( static_cast<UINT8*>( pData ) + readRange.Begin ); const UINT64 timeStampDelta = pTimestamps[ 1 ] - pTimestamps[ 0 ]; // Unmap with an empty range (written range). m_timestampResultBuffer->Unmap( 0, &emptyRange ); // Compute the duration of the given time span in microseconds. m_timeSpans[ timeSpanName ].duration = ( timeStampDelta * 1000000 ) / m_timestampFrequency; return m_timeSpans[ timeSpanName ].duration; }
VertexBuffer::VertexBuffer(RenderDevice* renderDevice, u32 vertexSize, u32 vertexCount, BufferUsage bufferUsage, void* initialData) : RenderDeviceChild(renderDevice) , m_vertexSize(vertexSize) , m_vertexCount(vertexCount) , m_bufferUsage(bufferUsage) , m_pImpl(make_unique<Impl>()) { TALON_ASSERT((initialData != nullptr || bufferUsage == BufferUsage::Dynamic) && "Initial data is required, unless the buffer is writable!"); D3D11_BUFFER_DESC bufferDesc = {0}; bufferDesc.ByteWidth = vertexSize * vertexCount; bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; bufferDesc.CPUAccessFlags = bufferUsage == BufferUsage::Dynamic ? D3D11_CPU_ACCESS_WRITE : 0; bufferDesc.MiscFlags = 0; bufferDesc.StructureByteStride = 0; switch(bufferUsage) { case BufferUsage::Default: bufferDesc.Usage = D3D11_USAGE_DEFAULT; break; case BufferUsage::Dynamic: bufferDesc.Usage = D3D11_USAGE_DYNAMIC; break; case BufferUsage::Immutable: bufferDesc.Usage = D3D11_USAGE_IMMUTABLE; break; } D3D11_SUBRESOURCE_DATA bufferData = {0}; bufferData.pSysMem = initialData; bufferData.SysMemPitch = 0; bufferData.SysMemSlicePitch = 0; ThrowIfFailed(renderDevice->GetDevice()->CreateBuffer(&bufferDesc, initialData == nullptr ? nullptr : &bufferData, &m_pImpl->vertexBuffer)); D3D11::SetDebugName(m_pImpl->vertexBuffer, "VertexBuffer"); }
void CanvasSwapChain::ResizeBuffersImpl( D2DResourceLock const& lock, float newWidth, float newHeight, float newDpi, DirectXPixelFormat newFormat, int32_t bufferCount) { auto swapChain = As<IDXGISwapChain2>(GetResource()); int widthInPixels = SizeDipsToPixels(newWidth, newDpi); int heightInPixels = SizeDipsToPixels(newHeight, newDpi); ThrowIfNegative(bufferCount); ThrowIfNegative(widthInPixels); ThrowIfNegative(heightInPixels); ThrowIfFailed(swapChain->ResizeBuffers( bufferCount, widthInPixels, heightInPixels, static_cast<DXGI_FORMAT>(newFormat), 0)); if (m_isCoreWindowSwapChain) { // CoreWindow swap chains can't get or set the transform matrix. m_dpi = newDpi; } else { // Update the transform matrix to account for any DPI changes DXGI_MATRIX_3X2_F dpiIndependentTransform = GetMatrixInternal(lock, swapChain); m_dpi = newDpi; SetMatrixInternal(lock, swapChain, &dpiIndependentTransform); } }
void SpecularLightingDemo::CreateVertexBuffer(ID3D11Device* device, const Mesh& mesh, ID3D11Buffer** vertexBuffer) const { const std::vector < XMFLOAT3 >& sourceVertices = mesh.Vertices(); const std::vector < XMFLOAT3 >& sourceNormals = mesh.Normals(); const auto& sourceUVs = mesh.TextureCoordinates().at(0); std::vector <VertexPositionTextureNormal> vertices; vertices.reserve(sourceVertices.size()); for (UINT i = 0; i < sourceVertices.size(); i++) { const XMFLOAT3& position = sourceVertices.at(i); const XMFLOAT3& uv = sourceUVs->at(i); const XMFLOAT3& normal = sourceNormals.at(i); vertices.push_back(VertexPositionTextureNormal(XMFLOAT4(position.x, position.y, position.z, 1.0f), XMFLOAT2(uv.x, uv.y), normal)); } //Vertex Buffer D3D11_BUFFER_DESC vertexBufferDesc = { 0 }; vertexBufferDesc.ByteWidth = sizeof(VertexPositionTextureNormal) * static_cast<UINT>(vertices.size()); vertexBufferDesc.Usage = D3D11_USAGE_IMMUTABLE; vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; D3D11_SUBRESOURCE_DATA vertexSubResourceData = { 0 }; vertexSubResourceData.pSysMem = &vertices[0]; ThrowIfFailed(device->CreateBuffer(&vertexBufferDesc, &vertexSubResourceData, vertexBuffer), "ID3D11Device::CreateBuffer() failed."); }
IFACEMETHODIMP CanvasCommandList::CreateDrawingSession( ICanvasDrawingSession** drawingSession) { return ExceptionBoundary( [&] { CheckAndClearOutPointer(drawingSession); if (m_d2dCommandListIsClosed) ThrowHR(E_INVALIDARG, Strings::CommandListCannotBeDrawnToAfterItHasBeenUsed); auto& d2dCommandList = GetResource(); auto& device = m_device.EnsureNotClosed(); auto deviceContext = As<ICanvasDeviceInternal>(device)->CreateDeviceContextForDrawingSession(); deviceContext->SetTarget(d2dCommandList.Get()); auto adapter = std::make_shared<SimpleCanvasDrawingSessionAdapter>(deviceContext.Get()); auto ds = CanvasDrawingSession::CreateNew(deviceContext.Get(), adapter, device.Get()); ThrowIfFailed(ds.CopyTo(drawingSession)); }); }
void FrameResource::Init() { // Reset the command allocators and lists for the main thread. for (int i = 0; i < CommandListCount; i++) { ThrowIfFailed(m_commandAllocators[i]->Reset()); ThrowIfFailed(m_commandLists[i]->Reset(m_commandAllocators[i].Get(), m_pipelineState.Get())); } // Clear the depth stencil buffer in preparation for rendering the shadow map. m_commandLists[CommandListPre]->ClearDepthStencilView(m_shadowDepthView, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr); // Reset the worker command allocators and lists. for (int i = 0; i < NumContexts; i++) { ThrowIfFailed(m_shadowCommandAllocators[i]->Reset()); ThrowIfFailed(m_shadowCommandLists[i]->Reset(m_shadowCommandAllocators[i].Get(), m_pipelineStateShadowMap.Get())); ThrowIfFailed(m_sceneCommandAllocators[i]->Reset()); ThrowIfFailed(m_sceneCommandLists[i]->Reset(m_sceneCommandAllocators[i].Get(), m_pipelineState.Get())); } }
void RenderSysem::LoadAssets() { // Create the command list. ThrowIfFailed(m_pD3D12Device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_pCommandAllocator.Get(), nullptr, IID_PPV_ARGS(&m_pCommandList))); // 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_pCommandList->Close()); // Create and record the bundle. { auto pPipelineState = m_Triangle.GetPipelineState(); ThrowIfFailed(m_pD3D12Device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_BUNDLE, m_pBundleAllocator.Get(), pPipelineState.Get(), IID_PPV_ARGS(&m_pBundleList))); m_Triangle.Render(m_pBundleList); ThrowIfFailed(m_pBundleList->Close()); } // Create synchronization objects. { ThrowIfFailed(m_pD3D12Device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_pD3D12Fence))); m_FenceValue = 1; // 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. WaitForPreviousFrame(); } }
// Load the rendering pipeline dependencies. void D3D12HDR::LoadPipeline() { #if defined(_DEBUG) // Enable the debug layer (requires the Graphics Tools "optional feature"). // NOTE: Enabling the debug layer after device creation will invalidate the active device. { ComPtr<ID3D12Debug> debugController; if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) { debugController->EnableDebugLayer(); // Enable additional debug layers. m_dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG; } } #endif ThrowIfFailed(CreateDXGIFactory2(m_dxgiFactoryFlags, IID_PPV_ARGS(&m_dxgiFactory))); if (m_useWarpDevice) { ComPtr<IDXGIAdapter> warpAdapter; ThrowIfFailed(m_dxgiFactory->EnumWarpAdapter(IID_PPV_ARGS(&warpAdapter))); ThrowIfFailed(D3D12CreateDevice( warpAdapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device) )); } else { ComPtr<IDXGIAdapter1> hardwareAdapter; GetHardwareAdapter(m_dxgiFactory.Get(), &hardwareAdapter); ThrowIfFailed(D3D12CreateDevice( hardwareAdapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device) )); } // Describe and create the command queue. D3D12_COMMAND_QUEUE_DESC queueDesc = {}; queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; ThrowIfFailed(m_device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&m_commandQueue))); NAME_D3D12_OBJECT(m_commandQueue); // Describe and create the swap chain. DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {}; swapChainDesc.BufferCount = FrameCount; swapChainDesc.Width = m_width; swapChainDesc.Height = m_height; swapChainDesc.Format = m_swapChainFormats[m_currentSwapChainBitDepth]; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; swapChainDesc.SampleDesc.Count = 1; // It is recommended to always use the tearing flag when it is available. swapChainDesc.Flags = m_tearingSupport ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0; ComPtr<IDXGISwapChain1> swapChain; ThrowIfFailed(m_dxgiFactory->CreateSwapChainForHwnd( m_commandQueue.Get(), // Swap chain needs the queue so that it can force a flush on it. Win32Application::GetHwnd(), &swapChainDesc, nullptr, nullptr, &swapChain )); if (m_tearingSupport) { // When tearing support is enabled we will handle ALT+Enter key presses in the // window message loop rather than let DXGI handle it by calling SetFullscreenState. m_dxgiFactory->MakeWindowAssociation(Win32Application::GetHwnd(), DXGI_MWA_NO_ALT_ENTER); } ThrowIfFailed(swapChain.As(&m_swapChain)); // Check display HDR support and initialize ST.2084 support to match the display's support. CheckDisplayHDRSupport(); m_enableST2084 = m_hdrSupport; EnsureSwapChainColorSpace(m_currentSwapChainBitDepth, m_enableST2084); SetHDRMetaData(HDRMetaDataPool[m_hdrMetaDataPoolIdx][0], HDRMetaDataPool[m_hdrMetaDataPoolIdx][1], HDRMetaDataPool[m_hdrMetaDataPoolIdx][2], HDRMetaDataPool[m_hdrMetaDataPoolIdx][3]); m_frameIndex = m_swapChain->GetCurrentBackBufferIndex(); // Create descriptor heaps. { // Describe and create a render target view (RTV) descriptor heap. D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {}; rtvHeapDesc.NumDescriptors = FrameCount + 2; // A descriptor for each frame + 2 intermediate render targets. rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; ThrowIfFailed(m_device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&m_rtvHeap))); // Describe and create a shader resource view (SRV) descriptor heap. D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {}; srvHeapDesc.NumDescriptors = 2; // A descriptor for each of the 2 intermediate render targets. srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; ThrowIfFailed(m_device->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&m_srvHeap))); m_rtvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); m_srvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); } // Create a command allocator for each frame. for (UINT n = 0; n < FrameCount; n++) { ThrowIfFailed(m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_commandAllocators[n]))); } }
// Recalculate vertex positions for the color space triangles and then update the vertex buffer. // The scene's command list must be in the recording state when this method is called. void D3D12HDR::UpdateVertexBuffer() { const XMFLOAT2 primaries709[] = { { 0.64f, 0.33f }, { 0.30f, 0.60f }, { 0.15f, 0.06f }, { 0.3127f, 0.3290f } }; const XMFLOAT2 primaries2020[] = { { 0.708f, 0.292f }, { 0.170f, 0.797f }, { 0.131f, 0.046f }, { 0.3127f, 0.3290f } }; const XMFLOAT2 offset1 = { 0.2f, 0.0f }; const XMFLOAT2 offset2 = { 0.2f, -1.0f }; const XMFLOAT3 triangle709[] = { TransformVertex(primaries709[0], offset1), // R TransformVertex(primaries709[1], offset1), // G TransformVertex(primaries709[2], offset1), // B TransformVertex(primaries709[3], offset1) // White }; const XMFLOAT3 triangle2020[] = { TransformVertex(primaries2020[0], offset2), // R TransformVertex(primaries2020[1], offset2), // G TransformVertex(primaries2020[2], offset2), // B TransformVertex(primaries2020[3], offset2) // White }; TrianglesVertex triangleVertices[] = { // Upper triangles. Rec 709 primaries. { triangle709[2], primaries709[2] }, { triangle709[1], primaries709[1] }, { triangle709[3], primaries709[3] }, { triangle709[1], primaries709[1] }, { triangle709[0], primaries709[0] }, { triangle709[3], primaries709[3] }, { triangle709[0], primaries709[0] }, { triangle709[2], primaries709[2] }, { triangle709[3], primaries709[3] }, // Lower triangles. Rec 2020 primaries. { triangle2020[2], primaries2020[2] }, { triangle2020[1], primaries2020[1] }, { triangle2020[3], primaries2020[3] }, { triangle2020[1], primaries2020[1] }, { triangle2020[0], primaries2020[0] }, { triangle2020[3], primaries2020[3] }, { triangle2020[0], primaries2020[0] }, { triangle2020[2], primaries2020[2] }, { triangle2020[3], primaries2020[3] }, }; // Copy data to the intermediate upload heap and then schedule a copy // from the upload heap to the vertex buffer. UINT8* mappedUploadHeap = nullptr; ThrowIfFailed(m_vertexBufferUpload->Map(0, &CD3DX12_RANGE(0, 0), reinterpret_cast<void**>(&mappedUploadHeap))); mappedUploadHeap += m_gradientVertexBufferView.SizeInBytes; memcpy(mappedUploadHeap, triangleVertices, sizeof(triangleVertices)); m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_vertexBuffer.Get(), D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER, D3D12_RESOURCE_STATE_COPY_DEST)); m_commandList->CopyBufferRegion(m_vertexBuffer.Get(), 0, m_vertexBufferUpload.Get(), 0, m_vertexBuffer->GetDesc().Width); m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_vertexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER)); }
// Load the sample assets. void D3D12HDR::LoadAssets() { // Create a root signature containing root constants for brightness information // and the desired output curve as well as a SRV descriptor table pointing to the // intermediate render targets. { CD3DX12_DESCRIPTOR_RANGE ranges[1]; ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 2, 0); CD3DX12_ROOT_PARAMETER rootParameters[2]; rootParameters[0].InitAsConstants(4, 0); rootParameters[1].InitAsDescriptorTable(1, &ranges[0]); 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.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER; sampler.MaxLOD = D3D12_FLOAT32_MAX; sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; // 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; CD3DX12_ROOT_SIGNATURE_DESC rootSignatureDesc; rootSignatureDesc.Init(_countof(rootParameters), rootParameters, 1, &sampler, rootSignatureFlags); 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 objects for the different views and render target formats // as well as the intermediate blend step. { // Create the pipeline state for the scene geometry. D3D12_INPUT_ELEMENT_DESC gradientElementDescs[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, { "COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, }; // Describe and create the graphics pipeline state objects (PSO). D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.InputLayout = { gradientElementDescs, _countof(gradientElementDescs) }; psoDesc.pRootSignature = m_rootSignature.Get(); psoDesc.VS = CD3DX12_SHADER_BYTECODE(g_gradientVS, sizeof(g_gradientVS)); psoDesc.PS = CD3DX12_SHADER_BYTECODE(g_gradientPS, sizeof(g_gradientPS)); 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] = m_intermediateRenderTargetFormat; psoDesc.SampleDesc.Count = 1; ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineStates[GradientPSO]))); // Create pipeline state for the color space triangles. D3D12_INPUT_ELEMENT_DESC colorElementDescs[] = { { "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 }, }; psoDesc.InputLayout = { colorElementDescs, _countof(colorElementDescs) }; psoDesc.VS = CD3DX12_SHADER_BYTECODE(g_paletteVS, sizeof(g_paletteVS)); psoDesc.PS = CD3DX12_SHADER_BYTECODE(g_palettePS, sizeof(g_palettePS)); psoDesc.RTVFormats[0] = m_intermediateRenderTargetFormat; ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineStates[PalettePSO]))); // Create pipeline states for the final blend step. // There will be one for each swap chain format the sample supports. D3D12_INPUT_ELEMENT_DESC quadElementDescs[] = { { "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 }, }; psoDesc.InputLayout = { quadElementDescs, _countof(quadElementDescs) }; psoDesc.VS = CD3DX12_SHADER_BYTECODE(g_presentVS, sizeof(g_presentVS)); psoDesc.PS = CD3DX12_SHADER_BYTECODE(g_presentPS, sizeof(g_presentPS)); psoDesc.RTVFormats[0] = m_swapChainFormats[_8]; ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineStates[Present8bitPSO]))); psoDesc.RTVFormats[0] = m_swapChainFormats[_10]; ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineStates[Present10bitPSO]))); psoDesc.RTVFormats[0] = m_swapChainFormats[_16]; ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineStates[Present16bitPSO]))); } // 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))); // Create the vertex buffer. { // Create geometry for the different sections of the render target. GradientVertex gradientVertices[] = { // Upper strip. SDR Gradient from [0,1]. { { -1.0f, 0.45f, 0.0f }, { 0.0f, 0.0f, 0.0f } }, { { -1.0f, 0.55f, 0.0f }, { 0.0f, 0.0f, 0.0f } }, { { 0.0f, 0.45f, 0.0f }, { 1.0f, 1.0f, 1.0f } }, { { 0.0f, 0.55f, 0.0f }, { 1.0f, 1.0f, 1.0f } }, // Lower strip. HDR Gradient from [0,9]. Perceptually, 9.0 is about 3 times as bright as 1.0. (See gradientPS.hlsl.) { { -1.0f, -0.55f, 0.0f }, { 0.0f, 0.0f, 0.0f } }, { { -1.0f, -0.45f, 0.0f }, { 0.0f, 0.0f, 0.0f } }, { { 0.0f, -0.55f, 0.0f }, { 3.0f, 3.0f, 3.0f } }, { { 0.0f, -0.45f, 0.0f }, { 3.0f, 3.0f, 3.0f } }, }; // The vertices for the color space triangles are dependent on the size of the // render target and will not be loaded at this time. We'll leave a gap in the // buffer that will be filled in later. const UINT triangleVerticesSize = sizeof(TrianglesVertex) * TrianglesVertexCount; m_updateVertexBuffer = true; PresentVertex presentVertices[] = { // 1 triangle that fills the entire render target. { { -1.0f, -3.0f, 0.0f }, { 0.0f, 2.0f } }, // Bottom left { { -1.0f, 1.0f, 0.0f }, { 0.0f, 0.0f } }, // Top left { { 3.0f, 1.0f, 0.0f }, { 2.0f, 0.0f } }, // Top right }; const UINT vertexBufferSize = sizeof(gradientVertices) + triangleVerticesSize + sizeof(presentVertices); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize), D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER, 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(&m_vertexBufferUpload))); // Copy data to the intermediate upload heap. It will be uploaded to the // DEFAULT buffer when the color space triangle vertices are updated. UINT8* mappedUploadHeap = nullptr; ThrowIfFailed(m_vertexBufferUpload->Map(0, &CD3DX12_RANGE(0, 0), reinterpret_cast<void**>(&mappedUploadHeap))); memcpy(mappedUploadHeap, gradientVertices, sizeof(gradientVertices)); mappedUploadHeap += sizeof(gradientVertices) + triangleVerticesSize; memcpy(mappedUploadHeap, presentVertices, sizeof(presentVertices)); m_vertexBufferUpload->Unmap(0, &CD3DX12_RANGE(0, 0)); // Initialize the vertex buffer views. m_gradientVertexBufferView.BufferLocation = m_vertexBuffer->GetGPUVirtualAddress(); m_gradientVertexBufferView.StrideInBytes = sizeof(GradientVertex); m_gradientVertexBufferView.SizeInBytes = sizeof(gradientVertices); m_trianglesVertexBufferView.BufferLocation = m_gradientVertexBufferView.BufferLocation + m_gradientVertexBufferView.SizeInBytes; m_trianglesVertexBufferView.StrideInBytes = sizeof(TrianglesVertex); m_trianglesVertexBufferView.SizeInBytes = triangleVerticesSize; m_presentVertexBufferView.BufferLocation = m_trianglesVertexBufferView.BufferLocation + m_trianglesVertexBufferView.SizeInBytes; m_presentVertexBufferView.StrideInBytes = sizeof(PresentVertex); m_presentVertexBufferView.SizeInBytes = sizeof(presentVertices); } LoadSizeDependentResources(); // 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(); } }
// Load the rendering pipeline dependencies. void D3D12HelloWindow::LoadPipeline() { #if defined(_DEBUG) // Enable the D3D12 debug layer. { ComPtr<ID3D12Debug> debugController; if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) { debugController->EnableDebugLayer(); } } #endif ComPtr<IDXGIFactory4> factory; ThrowIfFailed(CreateDXGIFactory1(IID_PPV_ARGS(&factory))); if (m_useWarpDevice) { ComPtr<IDXGIAdapter> warpAdapter; ThrowIfFailed(factory->EnumWarpAdapter(IID_PPV_ARGS(&warpAdapter))); ThrowIfFailed(D3D12CreateDevice( warpAdapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device) )); } else { ComPtr<IDXGIAdapter1> hardwareAdapter; GetHardwareAdapter(factory.Get(), &hardwareAdapter); ThrowIfFailed(D3D12CreateDevice( hardwareAdapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device) )); } // Describe and create the command queue. D3D12_COMMAND_QUEUE_DESC queueDesc = {}; queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; ThrowIfFailed(m_device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&m_commandQueue))); // Describe and create the swap chain. DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {}; swapChainDesc.BufferCount = FrameCount; swapChainDesc.Width = m_width; swapChainDesc.Height = m_height; swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; swapChainDesc.SampleDesc.Count = 1; ComPtr<IDXGISwapChain1> swapChain; ThrowIfFailed(factory->CreateSwapChainForHwnd( m_commandQueue.Get(), // Swap chain needs the queue so that it can force a flush on it. Win32Application::GetHwnd(), &swapChainDesc, nullptr, nullptr, &swapChain )); // This sample does not support fullscreen transitions. ThrowIfFailed(factory->MakeWindowAssociation(Win32Application::GetHwnd(), DXGI_MWA_NO_ALT_ENTER)); ThrowIfFailed(swapChain.As(&m_swapChain)); m_frameIndex = m_swapChain->GetCurrentBackBufferIndex(); // Create descriptor heaps. { // Describe and create a render target view (RTV) descriptor heap. D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {}; rtvHeapDesc.NumDescriptors = FrameCount; rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; ThrowIfFailed(m_device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&m_rtvHeap))); m_rtvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); } // Create frame resources. { CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart()); // Create a RTV for each frame. for (UINT n = 0; n < FrameCount; n++) { ThrowIfFailed(m_swapChain->GetBuffer(n, IID_PPV_ARGS(&m_renderTargets[n]))); m_device->CreateRenderTargetView(m_renderTargets[n].Get(), nullptr, rtvHandle); rtvHandle.Offset(1, m_rtvDescriptorSize); } } ThrowIfFailed(m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_commandAllocator))); }
// Render the scene. void D3D12Multithreading::OnRender() { BeginFrame(); #if SINGLETHREADED for (int i = 0; i < NumContexts; i++) { WorkerThread(reinterpret_cast<LPVOID>(i)); } MidFrame(); EndFrame(); m_commandQueue->ExecuteCommandLists(_countof(m_pCurrentFrameResource->m_batchSubmit), m_pCurrentFrameResource->m_batchSubmit); #else for (int i = 0; i < NumContexts; i++) { SetEvent(m_workerBeginRenderFrame[i]); // Tell each worker to start drawing. } MidFrame(); EndFrame(); WaitForMultipleObjects(NumContexts, m_workerFinishShadowPass, TRUE, INFINITE); // You can execute command lists on any thread. Depending on the work // load, apps can choose between using ExecuteCommandLists on one thread // vs ExecuteCommandList from multiple threads. m_commandQueue->ExecuteCommandLists(NumContexts + 2, m_pCurrentFrameResource->m_batchSubmit); // Submit PRE, MID and shadows. WaitForMultipleObjects(NumContexts, m_workerFinishedRenderFrame, TRUE, INFINITE); // Submit remaining command lists. m_commandQueue->ExecuteCommandLists(_countof(m_pCurrentFrameResource->m_batchSubmit) - NumContexts - 2, m_pCurrentFrameResource->m_batchSubmit + NumContexts + 2); #endif m_cpuTimer.Tick(NULL); if (m_titleCount == TitleThrottle) { WCHAR cpu[64]; swprintf_s(cpu, L"%.4f CPU", m_cpuTime / m_titleCount); SetCustomWindowText(cpu); m_titleCount = 0; m_cpuTime = 0; } else { m_titleCount++; m_cpuTime += m_cpuTimer.GetElapsedSeconds() * 1000; m_cpuTimer.ResetElapsedTime(); } // Present and update the frame index for the next frame. PIXBeginEvent(m_commandQueue.Get(), 0, L"Presenting to screen"); ThrowIfFailed(m_swapChain->Present(0, 0)); PIXEndEvent(m_commandQueue.Get()); m_frameIndex = m_swapChain->GetCurrentBackBufferIndex(); // Signal and increment the fence value. m_pCurrentFrameResource->m_fenceValue = m_fenceValue; ThrowIfFailed(m_commandQueue->Signal(m_fence.Get(), m_fenceValue)); m_fenceValue++; }
// 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 rendering pipeline dependencies. void D3D12Multithreading::LoadPipeline() { #ifdef _DEBUG // Enable the D3D12 debug layer. { ComPtr<ID3D12Debug> debugController; if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) { debugController->EnableDebugLayer(); } } #endif ComPtr<IDXGIFactory4> factory; ThrowIfFailed(CreateDXGIFactory1(IID_PPV_ARGS(&factory))); if (m_useWarpDevice) { ComPtr<IDXGIAdapter> warpAdapter; ThrowIfFailed(factory->EnumWarpAdapter(IID_PPV_ARGS(&warpAdapter))); ThrowIfFailed(D3D12CreateDevice( warpAdapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device) )); } else { ThrowIfFailed(D3D12CreateDevice( nullptr, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device) )); } // Describe and create the command queue. D3D12_COMMAND_QUEUE_DESC queueDesc = {}; queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; ThrowIfFailed(m_device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&m_commandQueue))); // Describe and create the swap chain. DXGI_SWAP_CHAIN_DESC swapChainDesc = {}; swapChainDesc.BufferCount = FrameCount; swapChainDesc.BufferDesc.Width = m_width; swapChainDesc.BufferDesc.Height = m_height; swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; swapChainDesc.OutputWindow = m_hwnd; swapChainDesc.SampleDesc.Count = 1; swapChainDesc.Windowed = TRUE; ComPtr<IDXGISwapChain> swapChain; ThrowIfFailed(factory->CreateSwapChain( m_commandQueue.Get(), // Swap chain needs the queue so that it can force a flush on it. &swapChainDesc, &swapChain )); ThrowIfFailed(swapChain.As(&m_swapChain)); m_frameIndex = m_swapChain->GetCurrentBackBufferIndex(); // Create descriptor heaps. { // Describe and create a render target view (RTV) descriptor heap. D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {}; rtvHeapDesc.NumDescriptors = FrameCount; rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; ThrowIfFailed(m_device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&m_rtvHeap))); // Describe and create a depth stencil view (DSV) descriptor heap. // Each frame has its own depth stencils (to write shadows onto) // and then there is one for the scene itself. D3D12_DESCRIPTOR_HEAP_DESC dsvHeapDesc = {}; dsvHeapDesc.NumDescriptors = 1 + FrameCount * 1; dsvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV; dsvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; ThrowIfFailed(m_device->CreateDescriptorHeap(&dsvHeapDesc, IID_PPV_ARGS(&m_dsvHeap))); // Describe and create a shader resource view (SRV) and constant // buffer view (CBV) descriptor heap. Heap layout: null views, // object diffuse + normal textures views, frame 1's shadow buffer, // frame 1's 2x constant buffer, frame 2's shadow buffer, frame 2's // 2x constant buffers, etc... const UINT nullSrvCount = 2; // Null descriptors are needed for out of bounds behavior reads. const UINT cbvCount = FrameCount * 2; const UINT srvCount = _countof(SampleAssets::Textures) + (FrameCount * 1); D3D12_DESCRIPTOR_HEAP_DESC cbvSrvHeapDesc = {}; cbvSrvHeapDesc.NumDescriptors = nullSrvCount + cbvCount + srvCount; cbvSrvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; cbvSrvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; ThrowIfFailed(m_device->CreateDescriptorHeap(&cbvSrvHeapDesc, IID_PPV_ARGS(&m_cbvSrvHeap))); // Describe and create a sampler descriptor heap. D3D12_DESCRIPTOR_HEAP_DESC samplerHeapDesc = {}; samplerHeapDesc.NumDescriptors = 2; // One clamp and one wrap sampler. samplerHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; samplerHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; ThrowIfFailed(m_device->CreateDescriptorHeap(&samplerHeapDesc, IID_PPV_ARGS(&m_samplerHeap))); m_rtvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); } ThrowIfFailed(m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_commandAllocator))); }
// Load the sample assets. void D3D12HelloTriangle::LoadAssets() { // Create an empty root signature. { CD3DX12_ROOT_SIGNATURE_DESC rootSignatureDesc; rootSignatureDesc.Init(0, nullptr, 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 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 = { 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.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 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(); } }
// 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 }
void SpecularLightingDemo::Initialize() { // Load a compiled vertex shader vector<char> compiledVertexShader; Utility::LoadBinaryFile(L"Content\\Shaders\\SpecularLightingDemoVS.cso", compiledVertexShader); ThrowIfFailed(mGame->Direct3DDevice()->CreateVertexShader(&compiledVertexShader[0], compiledVertexShader.size(), nullptr, mVertexShader.ReleaseAndGetAddressOf()), "ID3D11Device::CreatedVertexShader() failed."); // Load a compiled pixel shader vector<char> compiledPixelShader; Utility::LoadBinaryFile(L"Content\\Shaders\\SpecularLightingDemoPS.cso", compiledPixelShader); ThrowIfFailed(mGame->Direct3DDevice()->CreatePixelShader(&compiledPixelShader[0], compiledPixelShader.size(), nullptr, mPixelShader.ReleaseAndGetAddressOf()), "ID3D11Device::CreatedPixelShader() failed."); // Create an input layout D3D11_INPUT_ELEMENT_DESC inputElementDescriptions[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, }; ThrowIfFailed(mGame->Direct3DDevice()->CreateInputLayout(inputElementDescriptions, ARRAYSIZE(inputElementDescriptions), &compiledVertexShader[0], compiledVertexShader.size(), mInputLayout.ReleaseAndGetAddressOf()), "ID3D11Device::CreateInputLayout() failed."); // Load the model unique_ptr<Library::Model> model = make_unique<Library::Model>("Content\\Models\\Sphere.obj.bin"); // Create vertex and index buffers for the model Mesh* mesh = model->Meshes().at(0).get(); CreateVertexBuffer(*mesh, mVertexBuffer.ReleaseAndGetAddressOf()); mesh->CreateIndexBuffer(*mGame->Direct3DDevice(), mIndexBuffer.ReleaseAndGetAddressOf()); mIndexCount = static_cast<UINT>(mesh->Indices().size()); D3D11_BUFFER_DESC constantBufferDesc = { 0 }; constantBufferDesc.ByteWidth = sizeof(VertexCBufferPerObject); constantBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; ThrowIfFailed(mGame->Direct3DDevice()->CreateBuffer(&constantBufferDesc, nullptr, mVSConstantBufferPO.ReleaseAndGetAddressOf()), "ID3D11Device::CreateBuffer() failed."); constantBufferDesc.ByteWidth = sizeof(VertexCBufferPerFrame); ThrowIfFailed(mGame->Direct3DDevice()->CreateBuffer(&constantBufferDesc, nullptr, mVSConstantBufferPF.ReleaseAndGetAddressOf()), "ID3D11Device::CreateBuffer() failed."); constantBufferDesc.ByteWidth = sizeof(PixelCBufferPerFrame); ThrowIfFailed(mGame->Direct3DDevice()->CreateBuffer(&constantBufferDesc, nullptr, mPSConstantBufferPF.ReleaseAndGetAddressOf()), "ID3D11Device::CreateBuffer() failed."); constantBufferDesc.ByteWidth = sizeof(PixelCBufferPerObject); ThrowIfFailed(mGame->Direct3DDevice()->CreateBuffer(&constantBufferDesc, nullptr, mPSConstantBufferPO.ReleaseAndGetAddressOf()), "ID3D11Device::CreateBuffer() failed."); // Load a texture wstring textureName = L"Content\\Textures\\Earthatday.dds"; ThrowIfFailed(CreateDDSTextureFromFile(mGame->Direct3DDevice(), textureName.c_str(), nullptr, mColorTexture.ReleaseAndGetAddressOf()), "CreateDDSTextureFromFile() failed."); mSpriteBatch = std::make_unique<SpriteBatch>(mGame->Direct3DDeviceContext()); mSpriteFont = std::make_unique<SpriteFont>(mGame->Direct3DDevice(), L"Content\\Fonts\\Arial_14_Regular.spritefont"); //Create DirectionalLight mDirectionalLight = std::make_unique<DirectionalLight>(*mGame); mPSCBufferPerFrame.LightDirection = mDirectionalLight->DirectionToLight(); mPSCBufferPerObject.SpecularPower = 25.0f; XMStoreFloat3(&mPSCBufferPerObject.SpecularColor, DirectX::Colors::White); XMStoreFloat4(&mPSCBufferPerFrame.AmbientColor, DirectX::Colors::Black); XMStoreFloat4(&mPSCBufferPerFrame.LightColor, DirectX::Colors::White); // Load a proxy model for the directional light mProxyModel = make_unique<ProxyModel>(*mGame, mCamera, "Content\\Models\\DirectionalLightProxy.obj.bin", 0.5f); mProxyModel->Initialize(); mProxyModel->SetPosition(10.0f, 0.0, 0.0f); mProxyModel->ApplyRotation(XMMatrixRotationY(XM_PIDIV2)); // Locate possible input devices mKeyboard = static_cast<KeyboardComponent*>(mGame->Services().GetService(KeyboardComponent::TypeIdClass())); mGamePad = static_cast<GamePadComponent*>(mGame->Services().GetService(GamePadComponent::TypeIdClass())); }
void D3D12HDR::CheckDisplayHDRSupport() { // If the display's advanced color state has changed (e.g. HDR display plug/unplug, or OS HDR setting on/off), // then this app's DXGI factory is invalidated and must be created anew in order to retrieve up-to-date display information. if (m_dxgiFactory->IsCurrent() == false) { ThrowIfFailed( CreateDXGIFactory2(0, IID_PPV_ARGS(&m_dxgiFactory)) ); } // First, the method must determine the app's current display. // We don't recommend using IDXGISwapChain::GetContainingOutput method to do that because of two reasons: // 1. Swap chains created with CreateSwapChainForComposition do not support this method. // 2. Swap chains will return a stale dxgi output once DXGIFactory::IsCurrent() is false. In addition, // we don't recommend re-creating swapchain to resolve the stale dxgi output because it will cause a short // period of black screen. // Instead, we suggest enumerating through the bounds of all dxgi outputs and determine which one has the greatest // intersection with the app window bounds. Then, use the DXGI output found in previous step to determine if the // app is on a HDR capable display. // Retrieve the current default adapter. ComPtr<IDXGIAdapter1> dxgiAdapter; ThrowIfFailed(m_dxgiFactory->EnumAdapters1(0, &dxgiAdapter)); // Iterate through the DXGI outputs associated with the DXGI adapter, // and find the output whose bounds have the greatest overlap with the // app window (i.e. the output for which the intersection area is the // greatest). UINT i = 0; ComPtr<IDXGIOutput> currentOutput; ComPtr<IDXGIOutput> bestOutput; float bestIntersectArea = -1; while (dxgiAdapter->EnumOutputs(i, ¤tOutput) != DXGI_ERROR_NOT_FOUND) { // Get the retangle bounds of the app window int ax1 = m_windowBounds.left; int ay1 = m_windowBounds.top; int ax2 = m_windowBounds.right; int ay2 = m_windowBounds.bottom; // Get the rectangle bounds of current output DXGI_OUTPUT_DESC desc; ThrowIfFailed(currentOutput->GetDesc(&desc)); RECT r = desc.DesktopCoordinates; int bx1 = r.left; int by1 = r.top; int bx2 = r.right; int by2 = r.bottom; // Compute the intersection int intersectArea = ComputeIntersectionArea(ax1, ay1, ax2, ay2, bx1, by1, bx2, by2); if (intersectArea > bestIntersectArea) { bestOutput = currentOutput; bestIntersectArea = static_cast<float>(intersectArea); } i++; } // Having determined the output (display) upon which the app is primarily being // rendered, retrieve the HDR capabilities of that display by checking the color space. ComPtr<IDXGIOutput6> output6; ThrowIfFailed(bestOutput.As(&output6)); DXGI_OUTPUT_DESC1 desc1; ThrowIfFailed(output6->GetDesc1(&desc1)); m_hdrSupport = (desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020); }
// Load the sample assets. void D3D12HelloConstBuffers::LoadAssets() { // Create a root signature consisting of a single CBV parameter. { CD3DX12_DESCRIPTOR_RANGE ranges[1]; CD3DX12_ROOT_PARAMETER rootParameters[1]; ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0); 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_ROOT_SIGNATURE_DESC rootSignatureDesc; rootSignatureDesc.Init(_countof(rootParameters), rootParameters, 0, nullptr, rootSignatureFlags); 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 compiling and loading shaders. { ComPtr<ID3DBlob> vertexShader; ComPtr<ID3DBlob> pixelShader; #if 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 = { 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.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; ThrowIfFailed(m_vertexBuffer->Map(0, nullptr, 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(ConstantBuffer) + 255) & ~255; // CB size is required to be 256-byte aligned. m_device->CreateConstantBufferView(&cbvDesc, m_cbvHeap->GetCPUDescriptorHandleForHeapStart()); // Initialize and map the constant buffers. We don't unmap this until the // app closes. Keeping things mapped for the lifetime of the resource is okay. ZeroMemory(&m_constantBufferData, sizeof(m_constantBufferData)); ThrowIfFailed(m_constantBuffer->Map(0, nullptr, reinterpret_cast<void**>(&m_pCbvDataBegin))); memcpy(m_pCbvDataBegin, &m_constantBufferData, sizeof(m_constantBufferData)); } // Create and record the bundle. { ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_BUNDLE, m_bundleAllocator.Get(), m_pipelineState.Get(), IID_PPV_ARGS(&m_bundle))); m_bundle->SetDescriptorHeaps(1, m_cbvHeap.GetAddressOf()); m_bundle->SetGraphicsRootSignature(m_rootSignature.Get()); m_bundle->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); m_bundle->IASetVertexBuffers(0, 1, &m_vertexBufferView); m_bundle->SetGraphicsRootDescriptorTable(0, m_cbvHeap->GetGPUDescriptorHandleForHeapStart()); m_bundle->DrawInstanced(3, 1, 0, 0); ThrowIfFailed(m_bundle->Close()); } // 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 = 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. WaitForPreviousFrame(); } }
// Load resources that are dependent on the size of the main window. void D3D12HDR::LoadSizeDependentResources() { // Create frame resources. { CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart()); // Create a RTV for each frame. for (UINT n = 0; n < FrameCount; n++) { ThrowIfFailed(m_swapChain->GetBuffer(n, IID_PPV_ARGS(&m_renderTargets[n]))); m_device->CreateRenderTargetView(m_renderTargets[n].Get(), nullptr, rtvHandle); rtvHandle.Offset(1, m_rtvDescriptorSize); NAME_D3D12_OBJECT_INDEXED(m_renderTargets, n); } // Create the intermediate render target and an RTV for it. D3D12_RESOURCE_DESC renderTargetDesc = m_renderTargets[0]->GetDesc(); renderTargetDesc.Format = m_intermediateRenderTargetFormat; D3D12_CLEAR_VALUE clearValue = {}; clearValue.Format = m_intermediateRenderTargetFormat; ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &renderTargetDesc, D3D12_RESOURCE_STATE_RENDER_TARGET, &clearValue, IID_PPV_ARGS(&m_intermediateRenderTarget))); NAME_D3D12_OBJECT(m_intermediateRenderTarget); m_device->CreateRenderTargetView(m_intermediateRenderTarget.Get(), nullptr, rtvHandle); rtvHandle.Offset(1, m_rtvDescriptorSize); CD3DX12_CPU_DESCRIPTOR_HANDLE srvHandle(m_srvHeap->GetCPUDescriptorHandleForHeapStart()); m_device->CreateShaderResourceView(m_intermediateRenderTarget.Get(), nullptr, srvHandle); srvHandle.Offset(1, m_srvDescriptorSize); // Create the UI render target and an RTV for it. renderTargetDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; clearValue.Format = renderTargetDesc.Format; ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &renderTargetDesc, D3D12_RESOURCE_STATE_RENDER_TARGET, &clearValue, IID_PPV_ARGS(&m_UIRenderTarget))); NAME_D3D12_OBJECT(m_UIRenderTarget); m_device->CreateRenderTargetView(m_UIRenderTarget.Get(), nullptr, rtvHandle); m_device->CreateShaderResourceView(m_UIRenderTarget.Get(), nullptr, srvHandle); } m_viewport.Width = static_cast<float>(m_width); m_viewport.Height = static_cast<float>(m_height); m_scissorRect.left = 0; m_scissorRect.top = 0; m_scissorRect.right = static_cast<LONG>(m_width); m_scissorRect.bottom = static_cast<LONG>(m_height); // Update the color space triangle vertices when the command list is back in // the recording state. m_updateVertexBuffer = true; if (m_enableUI) { if (!m_uiLayer) { m_uiLayer = std::make_shared<UILayer>(this); } else { m_uiLayer->Resize(); } } }
void FogDemo::Initialize() { #if (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP) SetCurrentDirectory(Utility::ExecutableDirectory().c_str()); #endif // Load a compiled vertex shader std::string compiledVertexShader = Utility::LoadBinaryFile("Content\\Shaders\\FogDemoVS.cso"); ThrowIfFailed(mGame.GetDirectXDevice()->CreateVertexShader(&compiledVertexShader[0], compiledVertexShader.size(), nullptr, mVertexShader.ReleaseAndGetAddressOf()), "CreateVertexShader() : Failed"); // Load a compiled pixel shader std::string compiledPixelShader = Utility::LoadBinaryFile("Content\\Shaders\\FogDemoPS.cso"); ThrowIfFailed(mGame.GetDirectXDevice()->CreatePixelShader(&compiledPixelShader[0], compiledPixelShader.size(), nullptr, mPixelShader.ReleaseAndGetAddressOf()), "CreatePixelShader() : Failed"); // Create an input layout D3D11_INPUT_ELEMENT_DESC inputElementDescriptions[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 } }; ThrowIfFailed(mGame.GetDirectXDevice()->CreateInputLayout(inputElementDescriptions, ARRAYSIZE(inputElementDescriptions), &compiledVertexShader[0], compiledVertexShader.size(), &mInputLayout), "ID3D11Device::CreateInputLayout() failed."); // Load the model std::unique_ptr<Model> model = std::make_unique<Model>(mGame, "Content\\Models\\Sphere.bin", true); // Create vertex and index buffers for the model std::shared_ptr<Mesh> mesh = model->Meshes().at(0); CreateVertexBuffer(mGame.GetDirectXDevice().Get(), mesh, mVertexBuffer.GetAddressOf()); mesh->CreateIndexBuffer(mIndexBuffer.GetAddressOf()); mIndexCount = (UINT)mesh->Indices().size(); // Create constant buffers D3D11_BUFFER_DESC constantBufferDesc; ZeroMemory(&constantBufferDesc, sizeof(constantBufferDesc)); constantBufferDesc.ByteWidth = sizeof(mVertexCBufferPerObjectData); constantBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; ThrowIfFailed(mGame.GetDirectXDevice()->CreateBuffer(&constantBufferDesc, nullptr, mVertexCBufferPerObject.GetAddressOf()), "ID3D11Device::CreateBuffer() failed."); constantBufferDesc.ByteWidth = sizeof(mVertexCBufferPerFrameData); ThrowIfFailed(mGame.GetDirectXDevice()->CreateBuffer(&constantBufferDesc, nullptr, mVertexCBufferPerFrame.GetAddressOf()), "ID3D11Device::CreateBuffer() failed."); constantBufferDesc.ByteWidth = sizeof(mPixelCBufferPerObjectData); ThrowIfFailed(mGame.GetDirectXDevice()->CreateBuffer(&constantBufferDesc, nullptr, mPixelCBufferPerObject.GetAddressOf()), "ID3D11Device::CreateBuffer() failed."); constantBufferDesc.ByteWidth = sizeof(mPixelCBufferPerFrameData); ThrowIfFailed(mGame.GetDirectXDevice()->CreateBuffer(&constantBufferDesc, nullptr, mPixelCBufferPerFrame.GetAddressOf()), "ID3D11Device::CreateBuffer() failed."); // Load a texture std::wstring textureName = L"Content\\Textures\\Earthatday.dds"; ThrowIfFailed(DirectX::CreateDDSTextureFromFile(mGame.GetDirectXDevice().Get(), textureName.c_str(), nullptr, mColorTexture.GetAddressOf()), "CreateDDSTextureFromFile() failed."); // Create a texture sampler D3D11_SAMPLER_DESC samplerDesc; ZeroMemory(&samplerDesc, sizeof(samplerDesc)); samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; ThrowIfFailed(mGame.GetDirectXDevice()->CreateSamplerState(&samplerDesc, mColorSampler.GetAddressOf()), "ID3D11Device::CreateSamplerState() failed."); // Create text rendering helpers mSpriteBatch = std::make_unique<SpriteBatch>(mGame.GetDirectXContext().Get()); mSpriteFont = std::make_unique<SpriteFont>(mGame.GetDirectXDevice().Get(), L"Content\\Fonts\\Arial_14_Regular.spritefont"); // Retrieve the keyboard service mGamePad = (GamePadComponent*)mGame.Services().GetService(GamePadComponent::TypeIdClass()); assert(mGamePad!= nullptr); mProxyModel = std::make_unique<ProxyModel>(mGame, mCamera, "Content\\Models\\DirectionalLightProxy.bin", 0.5f); mProxyModel->Initialize(); mProxyModel->SetPosition(10.0f, 0.0, 0.0f); mProxyModel->ApplyRotation(XMMatrixRotationY(XM_PIDIV2)); mDirectionalLight = std::make_unique<DirectionalLight>(mGame); const XMFLOAT3& lightdirection = mDirectionalLight->Direction(); mVertexCBufferPerFrameData.LightDirection = XMFLOAT4(lightdirection.x, lightdirection.y, lightdirection.z, 0.0f); const XMFLOAT3& cameraPosition = mCamera->Position(); mVertexCBufferPerFrameData.CameraPosition = XMFLOAT4(cameraPosition.x, cameraPosition.y, cameraPosition.z, 1.0f); mPixelCBufferPerFrameData.CameraPosition = mVertexCBufferPerFrameData.CameraPosition; mVertexCBufferPerFrameData.FogStart = mFogStart; mVertexCBufferPerFrameData.FogRange = mFogRange; mPixelCBufferPerFrameData.FogColor = FogColor; }
// Fill the command list with all the render commands and dependent state and // submit it to the command queue. void D3D12HDR::RenderScene() { // Command list allocators can only be reset when the associated // command lists have finished execution on the GPU; apps should use // fences to determine GPU execution progress. ThrowIfFailed(m_commandAllocators[m_frameIndex]->Reset()); // However, when ExecuteCommandList() is called on a particular command // list, that command list can then be reset at any time and must be before // re-recording. ThrowIfFailed(m_commandList->Reset(m_commandAllocators[m_frameIndex].Get(), m_pipelineStates[GradientPSO].Get())); if (m_updateVertexBuffer) { UpdateVertexBuffer(); m_updateVertexBuffer = false; } // Set necessary state. m_commandList->SetGraphicsRootSignature(m_rootSignature.Get()); ID3D12DescriptorHeap* ppHeaps[] = { m_srvHeap.Get() }; m_commandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); m_commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); m_commandList->RSSetViewports(1, &m_viewport); m_commandList->RSSetScissorRects(1, &m_scissorRect); // Bind the root constants and the SRV table to the pipeline. m_rootConstantsF[ReferenceWhiteNits] = m_referenceWhiteNits; m_commandList->SetGraphicsRoot32BitConstants(0, RootConstantsCount, m_rootConstants, 0); m_commandList->SetGraphicsRootDescriptorTable(1, m_srvHeap->GetGPUDescriptorHandleForHeapStart()); // Draw the scene into the intermediate render target. { PIXBeginEvent(m_commandList.Get(), 0, L"Draw scene content"); CD3DX12_CPU_DESCRIPTOR_HANDLE intermediateRtv(m_rtvHeap->GetCPUDescriptorHandleForHeapStart(), FrameCount, m_rtvDescriptorSize); m_commandList->OMSetRenderTargets(1, &intermediateRtv, FALSE, nullptr); const float clearColor[] = { 0.0f, 0.0f, 0.0f, 0.0f }; m_commandList->ClearRenderTargetView(intermediateRtv, clearColor, 0, nullptr); m_commandList->IASetVertexBuffers(0, 1, &m_gradientVertexBufferView); PIXBeginEvent(m_commandList.Get(), 0, L"Standard Gradient"); m_commandList->DrawInstanced(4, 1, 0, 0); PIXEndEvent(m_commandList.Get()); PIXBeginEvent(m_commandList.Get(), 0, L"Bright Gradient"); m_commandList->DrawInstanced(4, 1, 4, 0); PIXEndEvent(m_commandList.Get()); m_commandList->SetPipelineState(m_pipelineStates[PalettePSO].Get()); m_commandList->IASetVertexBuffers(0, 1, &m_trianglesVertexBufferView); m_commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); PIXBeginEvent(m_commandList.Get(), 0, L"Rec709 Triangles"); m_commandList->DrawInstanced(3, 1, 0, 0); m_commandList->DrawInstanced(3, 1, 3, 0); m_commandList->DrawInstanced(3, 1, 6, 0); PIXEndEvent(m_commandList.Get()); m_commandList->SetPipelineState(m_pipelineStates[PalettePSO].Get()); PIXBeginEvent(m_commandList.Get(), 0, L"Rec2020 Triangles"); m_commandList->DrawInstanced(3, 1, 9, 0); m_commandList->DrawInstanced(3, 1, 12, 0); m_commandList->DrawInstanced(3, 1, 15, 0); PIXEndEvent(m_commandList.Get()); PIXEndEvent(m_commandList.Get()); if (!m_enableUI) { intermediateRtv.Offset(1, m_rtvDescriptorSize); m_commandList->OMSetRenderTargets(1, &intermediateRtv, FALSE, nullptr); m_commandList->ClearRenderTargetView(intermediateRtv, clearColor, 0, nullptr); } } // Indicate that the intermediates will be used as SRVs in the pixel shader // and the back buffer will be used as a render target. D3D12_RESOURCE_BARRIER barriers[] = { CD3DX12_RESOURCE_BARRIER::Transition(m_intermediateRenderTarget.Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE), CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_frameIndex].Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET), CD3DX12_RESOURCE_BARRIER::Transition(m_UIRenderTarget.Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE), }; // Process the intermediate and draw into the swap chain render target. { PIXBeginEvent(m_commandList.Get(), 0, L"Apply HDR"); // If the UI is enabled, the 11on12 layer will do the state transition for us. UINT barrierCount = m_enableUI ? 2 : _countof(barriers); m_commandList->ResourceBarrier(barrierCount, barriers); m_commandList->SetPipelineState(m_pipelineStates[Present8bitPSO + m_currentSwapChainBitDepth].Get()); CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart(), m_frameIndex, m_rtvDescriptorSize); m_commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr); m_commandList->ClearRenderTargetView(rtvHandle, ClearColor, 0, nullptr); m_commandList->IASetVertexBuffers(0, 1, &m_presentVertexBufferView); m_commandList->DrawInstanced(3, 1, 0, 0); PIXEndEvent(m_commandList.Get()); } // Indicate that the intermediates will be used as render targets and the swap chain // back buffer will be used for presentation. barriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; barriers[0].Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; barriers[1].Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; barriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; barriers[2].Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; barriers[2].Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; m_commandList->ResourceBarrier(_countof(barriers), barriers); ThrowIfFailed(m_commandList->Close()); // Execute the command list. ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() }; m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists); }
// Load the sample assets. void D3D12HelloTexture::LoadAssets() { // Create the root signature. { CD3DX12_DESCRIPTOR_RANGE ranges[1]; ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0); CD3DX12_ROOT_PARAMETER 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_ROOT_SIGNATURE_DESC rootSignatureDesc; rootSignatureDesc.Init(_countof(rootParameters), rootParameters, 1, &sampler, 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 compiling and 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 = 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 = { 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.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; ThrowIfFailed(m_vertexBuffer->Map(0, nullptr, 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 an upload heap to load the texture onto the GPU. ComPtr's are CPU objects // but this heap needs to stay in scope until the GPU work is complete. We will // synchronize with the GPU at the end of this method before the ComPtr is 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 = 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. WaitForPreviousFrame(); } }
void D3D12HDR::OnKeyDown(UINT8 key) { switch (key) { // Instrument the Space Bar to toggle between fullscreen states. // The window message loop callback will receive a WM_SIZE message once the // window is in the fullscreen state. At that point, the IDXGISwapChain should // be resized to match the new window size. // // NOTE: ALT+Enter will perform a similar operation; the code below is not // required to enable that key combination. case VK_SPACE: { if (m_tearingSupport) { Win32Application::ToggleFullscreenWindow(); } else { BOOL fullscreenState; ThrowIfFailed(m_swapChain->GetFullscreenState(&fullscreenState, nullptr)); if (FAILED(m_swapChain->SetFullscreenState(!fullscreenState, nullptr))) { // Transitions to fullscreen mode can fail when running apps over // terminal services or for some other unexpected reason. Consider // notifying the user in some way when this happens. OutputDebugString(L"Fullscreen transition failed"); assert(false); } } break; } case VK_PRIOR: // Page Up { m_currentSwapChainBitDepth = static_cast<SwapChainBitDepth>((m_currentSwapChainBitDepth - 1 + SwapChainBitDepthCount) % SwapChainBitDepthCount); DXGI_FORMAT newFormat = m_swapChainFormats[m_currentSwapChainBitDepth]; UpdateSwapChainBuffer(m_width, m_height, newFormat); SetHDRMetaData(HDRMetaDataPool[m_hdrMetaDataPoolIdx][0], HDRMetaDataPool[m_hdrMetaDataPoolIdx][1], HDRMetaDataPool[m_hdrMetaDataPoolIdx][2], HDRMetaDataPool[m_hdrMetaDataPoolIdx][3]); break; } case VK_NEXT: // Page Down { m_currentSwapChainBitDepth = static_cast<SwapChainBitDepth>((m_currentSwapChainBitDepth + 1) % SwapChainBitDepthCount); DXGI_FORMAT newFormat = m_swapChainFormats[m_currentSwapChainBitDepth]; UpdateSwapChainBuffer(m_width, m_height, newFormat); SetHDRMetaData(HDRMetaDataPool[m_hdrMetaDataPoolIdx][0], HDRMetaDataPool[m_hdrMetaDataPoolIdx][1], HDRMetaDataPool[m_hdrMetaDataPoolIdx][2], HDRMetaDataPool[m_hdrMetaDataPoolIdx][3]); break; } case 'H': { m_enableST2084 = !m_enableST2084; if (m_currentSwapChainBitDepth == _10) { EnsureSwapChainColorSpace(m_currentSwapChainBitDepth, m_enableST2084); SetHDRMetaData(HDRMetaDataPool[m_hdrMetaDataPoolIdx][0], HDRMetaDataPool[m_hdrMetaDataPoolIdx][1], HDRMetaDataPool[m_hdrMetaDataPoolIdx][2], HDRMetaDataPool[m_hdrMetaDataPoolIdx][3]); } break; } case 'U': { m_enableUI = !m_enableUI; if (m_enableUI) { m_uiLayer = std::make_shared<UILayer>(this); } else { m_uiLayer.reset(); } break; } case 'M': { // Switch meta data value for testing. TV should adjust the content based on the metadata we sent. m_hdrMetaDataPoolIdx = (m_hdrMetaDataPoolIdx + 1) % 4; SetHDRMetaData(HDRMetaDataPool[m_hdrMetaDataPoolIdx][0], HDRMetaDataPool[m_hdrMetaDataPoolIdx][1], HDRMetaDataPool[m_hdrMetaDataPoolIdx][2], HDRMetaDataPool[m_hdrMetaDataPoolIdx][3]); break; } } }
// Load the rendering pipeline dependencies. void D3D12HelloTexture::LoadPipeline() { #ifdef _DEBUG // Enable the D3D12 debug layer. { ComPtr<ID3D12Debug> debugController; if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) { debugController->EnableDebugLayer(); } } #endif ComPtr<IDXGIFactory4> factory; ThrowIfFailed(CreateDXGIFactory1(IID_PPV_ARGS(&factory))); if (m_useWarpDevice) { ComPtr<IDXGIAdapter> warpAdapter; ThrowIfFailed(factory->EnumWarpAdapter(IID_PPV_ARGS(&warpAdapter))); ThrowIfFailed(D3D12CreateDevice( warpAdapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device) )); } else { ThrowIfFailed(D3D12CreateDevice( nullptr, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device) )); } // Describe and create the command queue. D3D12_COMMAND_QUEUE_DESC queueDesc = {}; queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; ThrowIfFailed(m_device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&m_commandQueue))); // Describe and create the swap chain. DXGI_SWAP_CHAIN_DESC swapChainDesc = {}; swapChainDesc.BufferCount = FrameCount; swapChainDesc.BufferDesc.Width = m_width; swapChainDesc.BufferDesc.Height = m_height; swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; swapChainDesc.OutputWindow = m_hwnd; swapChainDesc.SampleDesc.Count = 1; swapChainDesc.Windowed = TRUE; ComPtr<IDXGISwapChain> swapChain; ThrowIfFailed(factory->CreateSwapChain( m_commandQueue.Get(), // Swap chain needs the queue so that it can force a flush on it. &swapChainDesc, &swapChain )); ThrowIfFailed(swapChain.As(&m_swapChain)); m_frameIndex = m_swapChain->GetCurrentBackBufferIndex(); // Create descriptor heaps. { // Describe and create a render target view (RTV) descriptor heap. D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {}; rtvHeapDesc.NumDescriptors = FrameCount; rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; ThrowIfFailed(m_device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&m_rtvHeap))); // Describe and create a shader resource view (SRV) heap for the texture. D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {}; srvHeapDesc.NumDescriptors = 1; srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; ThrowIfFailed(m_device->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&m_srvHeap))); m_rtvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); } // Create frame resources. { CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart()); // Create a RTV for each frame. for (UINT n = 0; n < FrameCount; n++) { ThrowIfFailed(m_swapChain->GetBuffer(n, IID_PPV_ARGS(&m_renderTargets[n]))); m_device->CreateRenderTargetView(m_renderTargets[n].Get(), nullptr, rtvHandle); rtvHandle.Offset(1, m_rtvDescriptorSize); } } ThrowIfFailed(m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_commandAllocator))); }
void Audio::PreloadSoundEffect(const char* pszFilePath, bool isMusic) { if (m_engineExperiencedCriticalError) { return; } int sound = Hash(pszFilePath); if (m_soundEffects.end() != m_soundEffects.find(sound)) { return; } MediaStreamer mediaStreamer; mediaStreamer.Initialize(CCUtf8ToUnicode(pszFilePath, -1).c_str()); m_soundEffects[sound].m_soundID = sound; uint32 bufferLength = mediaStreamer.GetMaxStreamLengthInBytes(); if (m_soundEffects.find(sound) != m_soundEffects.end()) { if (m_soundEffects[sound].m_soundEffectBufferData) { delete[] m_soundEffects[sound].m_soundEffectBufferData; m_soundEffects[sound].m_soundEffectBufferData = NULL; } } else { m_soundEffects[sound].m_soundEffectBufferData = NULL; } m_soundEffects[sound].m_soundEffectBufferData = new byte[bufferLength]; mediaStreamer.ReadAll(m_soundEffects[sound].m_soundEffectBufferData, bufferLength, &m_soundEffects[sound].m_soundEffectBufferLength); if (isMusic) { XAUDIO2_SEND_DESCRIPTOR descriptors[1]; descriptors[0].pOutputVoice = m_musicMasteringVoice; descriptors[0].Flags = 0; XAUDIO2_VOICE_SENDS sends = {0}; sends.SendCount = 1; sends.pSends = descriptors; ThrowIfFailed( m_musicEngine->CreateSourceVoice(&m_soundEffects[sound].m_soundEffectSourceVoice, &(mediaStreamer.GetOutputWaveFormatEx()), 0, 1.0f, &m_voiceContext, &sends) ); //fix bug: set a initial volume m_soundEffects[sound].m_soundEffectSourceVoice->SetVolume(m_backgroundMusicVolume); } else { XAUDIO2_SEND_DESCRIPTOR descriptors[1]; descriptors[0].pOutputVoice = m_soundEffectMasteringVoice; descriptors[0].Flags = 0; XAUDIO2_VOICE_SENDS sends = {0}; sends.SendCount = 1; sends.pSends = descriptors; ThrowIfFailed( m_soundEffectEngine->CreateSourceVoice(&m_soundEffects[sound].m_soundEffectSourceVoice, &(mediaStreamer.GetOutputWaveFormatEx()), 0, 1.0f, &m_voiceContext, &sends, nullptr) ); //fix bug: set a initial volume m_soundEffects[sound].m_soundEffectSourceVoice->SetVolume(m_soundEffctVolume); } m_soundEffects[sound].m_soundEffectSampleRate = mediaStreamer.GetOutputWaveFormatEx().nSamplesPerSec; // Queue in-memory buffer for playback ZeroMemory(&m_soundEffects[sound].m_audioBuffer, sizeof(m_soundEffects[sound].m_audioBuffer)); m_soundEffects[sound].m_audioBuffer.AudioBytes = m_soundEffects[sound].m_soundEffectBufferLength; m_soundEffects[sound].m_audioBuffer.pAudioData = m_soundEffects[sound].m_soundEffectBufferData; m_soundEffects[sound].m_audioBuffer.pContext = &m_soundEffects[sound]; m_soundEffects[sound].m_audioBuffer.Flags = XAUDIO2_END_OF_STREAM; m_soundEffects[sound].m_audioBuffer.LoopCount = 0; }
void CommandAllocator::Reset() { ThrowIfFailed(m_native->Reset()); }