protected override void TransitionForPresent()
    {
        if (MSAACount > 1)
        {
            var barriers = stackalloc D3D12_RESOURCE_BARRIER[2];

            barriers[0] = D3D12_RESOURCE_BARRIER.InitTransition(MSAARenderTarget, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
            barriers[1] = D3D12_RESOURCE_BARRIER.InitTransition(RenderTarget, D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RESOLVE_DEST);

            GraphicsCommandList->ResourceBarrier(2, barriers);
            GraphicsCommandList->ResolveSubresource(RenderTarget, 0, MSAARenderTarget, 0, BackBufferFormat);

            barriers[0] = D3D12_RESOURCE_BARRIER.InitTransition(MSAARenderTarget, D3D12_RESOURCE_STATE_RESOLVE_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
            barriers[1] = D3D12_RESOURCE_BARRIER.InitTransition(RenderTarget, D3D12_RESOURCE_STATE_RESOLVE_DEST, D3D12_RESOURCE_STATE_PRESENT);
            GraphicsCommandList->ResourceBarrier(2, barriers);
        }
        else
        {
            var barriers = stackalloc D3D12_RESOURCE_BARRIER[2];

            barriers[0] = D3D12_RESOURCE_BARRIER.InitTransition(MSAARenderTarget, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
            barriers[1] = D3D12_RESOURCE_BARRIER.InitTransition(RenderTarget, D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_COPY_DEST);

            GraphicsCommandList->ResourceBarrier(2, barriers);
            GraphicsCommandList->CopyResource(RenderTarget, MSAARenderTarget);

            barriers[0] = D3D12_RESOURCE_BARRIER.InitTransition(MSAARenderTarget, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
            barriers[1] = D3D12_RESOURCE_BARRIER.InitTransition(RenderTarget, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PRESENT);
            GraphicsCommandList->ResourceBarrier(2, barriers);
        }
    }
Ejemplo n.º 2
0
        private void PopulateCommandList()
        {
            // Command list allocators can only be reset when the associated
            // command lists have finished execution on the GPU; apps should use
            // fences to determine GPU execution progress.
            ThrowIfFailed(nameof(ID3D12CommandAllocator.Reset), _commandAllocator->Reset());

            // However, when ExecuteCommandList() is called on a particular command
            // list, that command list can then be reset at any time and must be before
            // re-recording.
            ThrowIfFailed(nameof(ID3D12GraphicsCommandList.Reset), _commandList->Reset(_commandAllocator, _pipelineState));

            // Set necessary state.
            _commandList->SetGraphicsRootSignature(_rootSignature);

            fixed(D3D12_VIEWPORT *viewport = &_viewport)
            {
                _commandList->RSSetViewports(1, viewport);
            }

            fixed(RECT *scissorRect = &_scissorRect)
            {
                _commandList->RSSetScissorRects(1, scissorRect);
            }

            // Indicate that the back buffer will be used as a render target.
            var barrier = D3D12_RESOURCE_BARRIER.InitTransition(_renderTargets[unchecked ((int)_frameIndex)], D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);

            _commandList->ResourceBarrier(1, &barrier);

            var rtvHandle = _rtvHeap->GetCPUDescriptorHandleForHeapStart();

            rtvHandle.ptr = (UIntPtr)((byte *)rtvHandle.ptr + (_frameIndex * _rtvDescriptorSize));
            _commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, null);

            // Record commands.
            _isOnColorToggle = !_isOnColorToggle;
            var r          = 0f;
            var g          = _isOnColorToggle ? 25 / 255f : 54 / 255f;
            var b          = _isOnColorToggle ? 70 / 255f : 52 / 255f;
            var clearColor = stackalloc float[4] {
                r, g, b, 1f
            };

            _commandList->ClearRenderTargetView(rtvHandle, clearColor, NumRects: 0, null);
            _commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

            fixed(D3D12_VERTEX_BUFFER_VIEW *vertexBufferView = &_vertexBufferView)
            {
                _commandList->IASetVertexBuffers(StartSlot: 0, 1, vertexBufferView);
            }

            _commandList->DrawInstanced(VertexCountPerInstance: 3, InstanceCount: 1, StartVertexLocation: 0, StartInstanceLocation: 0);

            // Indicate that the back buffer will now be used to present.
            barrier = D3D12_RESOURCE_BARRIER.InitTransition(_renderTargets[unchecked ((int)_frameIndex)], D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
            _commandList->ResourceBarrier(1, &barrier);

            ThrowIfFailed(nameof(ID3D12GraphicsCommandList.Close), _commandList->Close());
        }
Ejemplo n.º 3
0
    public static D3D12_RESOURCE_BARRIER InitUAV(ID3D12Resource *pResource)
    {
        D3D12_RESOURCE_BARRIER result = default;

        result.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV;
        result.Anonymous.UAV.pResource = pResource;
        return(result);
    }
Ejemplo n.º 4
0
        /// <summary>Begins a new frame for rendering.</summary>
        /// <param name="backgroundColor">A color to which the background should be cleared.</param>
        public void BeginFrame(ColorRgba backgroundColor)
        {
            var frameIndex = SwapChain->GetCurrentBackBufferIndex();

            _frameIndex = frameIndex;
            WaitForFence(Fences[frameIndex], FenceEvents[frameIndex], FenceValues[frameIndex]);

            var commandAllocator = CommandAllocators[frameIndex];

            ThrowExternalExceptionIfFailed(nameof(ID3D12CommandAllocator.Reset), commandAllocator->Reset());

            var graphicsCommandList = GraphicsCommandLists[frameIndex];

            ThrowExternalExceptionIfFailed(nameof(ID3D12GraphicsCommandList.Reset), graphicsCommandList->Reset(commandAllocator, pInitialState: null));

            var renderTargetDescriptorSize = Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
            var renderTargetHandle         = RenderTargetsHeap->GetCPUDescriptorHandleForHeapStart();

            _ = renderTargetHandle.Offset((int)frameIndex, renderTargetDescriptorSize);
            graphicsCommandList->OMSetRenderTargets(1, &renderTargetHandle, RTsSingleHandleToDescriptorRange: TRUE, pDepthStencilDescriptor: null);

            var viewport = new D3D12_VIEWPORT {
                TopLeftX = 0.0f,
                TopLeftY = 0.0f,
                Width    = _graphicsSurface.Width,
                Height   = _graphicsSurface.Height,
                MinDepth = 0.0f,
                MaxDepth = 1.0f,
            };

            graphicsCommandList->RSSetViewports(1, &viewport);

            var scissorRect = new RECT {
                left   = 0,
                top    = 0,
                right  = (int)_graphicsSurface.Width,
                bottom = (int)_graphicsSurface.Height,
            };

            graphicsCommandList->RSSetScissorRects(1, &scissorRect);

            var barrier = new D3D12_RESOURCE_BARRIER {
                Type      = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION,
                Flags     = D3D12_RESOURCE_BARRIER_FLAG_NONE,
                Anonymous = new D3D12_RESOURCE_BARRIER._Anonymous_e__Union {
                    Transition = new D3D12_RESOURCE_TRANSITION_BARRIER {
                        pResource   = RenderTargets[frameIndex],
                        Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
                        StateBefore = D3D12_RESOURCE_STATE_PRESENT,
                        StateAfter  = D3D12_RESOURCE_STATE_RENDER_TARGET,
                    },
                },
            };

            graphicsCommandList->ResourceBarrier(1, &barrier);

            graphicsCommandList->ClearRenderTargetView(renderTargetHandle, (float *)&backgroundColor, NumRects: 0, pRects: null);
        }
Ejemplo n.º 5
0
    public static D3D12_RESOURCE_BARRIER InitAliasing(ID3D12Resource *pResourceBefore, ID3D12Resource *pResourceAfter)
    {
        D3D12_RESOURCE_BARRIER result = default;

        result.Type = D3D12_RESOURCE_BARRIER_TYPE_ALIASING;
        result.Anonymous.Aliasing.pResourceBefore = pResourceBefore;
        result.Anonymous.Aliasing.pResourceAfter  = pResourceAfter;
        return(result);
    }
Ejemplo n.º 6
0
    public static D3D12_RESOURCE_BARRIER InitTransition(ID3D12Resource *pResource, D3D12_RESOURCE_STATES stateBefore, D3D12_RESOURCE_STATES stateAfter, uint subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, D3D12_RESOURCE_BARRIER_FLAGS flags = D3D12_RESOURCE_BARRIER_FLAG_NONE)
    {
        D3D12_RESOURCE_BARRIER result = default;

        result.Type  = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
        result.Flags = flags;
        result.Anonymous.Transition.pResource   = pResource;
        result.Anonymous.Transition.StateBefore = stateBefore;
        result.Anonymous.Transition.StateAfter  = stateAfter;
        result.Anonymous.Transition.Subresource = subresource;
        return(result);
    }
Ejemplo n.º 7
0
    /// <summary>Ends a render pass.</summary>
    /// <exception cref="InvalidOperationException">A render pass is not active.</exception>
    /// <exception cref="ObjectDisposedException">The context has been disposed.</exception>
    public void EndRenderPass()
    {
        var renderPass = Interlocked.Exchange(ref _renderPass, null);

        if (renderPass is null)
        {
            ThrowForInvalidState(nameof(RenderPass));
        }

        var d3d12RtvResourceBarrier = D3D12_RESOURCE_BARRIER.InitTransition(renderPass.Swapchain.CurrentRenderTarget.D3D12RtvResource, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);

        D3D12GraphicsCommandList->ResourceBarrier(1, &d3d12RtvResourceBarrier);
    }
Ejemplo n.º 8
0
        private void PopulateCommandList()
        {
            // Command list allocators can only be reset when the associated
            // command lists have finished execution on the GPU; apps should use
            // fences to determine GPU execution progress.
            ThrowIfFailed(nameof(ID3D12CommandAllocator.Reset), _commandAllocator->Reset());

            // However, when ExecuteCommandList() is called on a particular command
            // list, that command list can then be reset at any time and must be before
            // re-recording.
            ThrowIfFailed(nameof(ID3D12GraphicsCommandList.Reset), _commandList->Reset(_commandAllocator, _pipelineState));

            // Set necessary state.
            _commandList->SetGraphicsRootSignature(_rootSignature);

            fixed(D3D12_VIEWPORT *viewport = &_viewport)
            {
                _commandList->RSSetViewports(1, viewport);
            }

            fixed(RECT *scissorRect = &_scissorRect)
            {
                _commandList->RSSetScissorRects(1, scissorRect);
            }

            // Indicate that the back buffer will be used as a render target.
            var barrier = D3D12_RESOURCE_BARRIER.InitTransition(_renderTargets[unchecked ((int)_frameIndex)], D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);

            _commandList->ResourceBarrier(1, &barrier);

            var rtvHandle = _rtvHeap->GetCPUDescriptorHandleForHeapStart();

            rtvHandle.ptr = (UIntPtr)((byte *)rtvHandle.ptr + (_frameIndex * _rtvDescriptorSize));
            _commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, null);

            // Record commands.
            var clearColor = stackalloc float[4] {
                0.0f, 0.2f, 0.4f, 1.0f
            };

            _commandList->ClearRenderTargetView(rtvHandle, clearColor, NumRects: 0, null);

            // Execute the commands stored in the bundle.
            _commandList->ExecuteBundle(_bundle);

            // Indicate that the back buffer will now be used to present.
            barrier = D3D12_RESOURCE_BARRIER.InitTransition(_renderTargets[unchecked ((int)_frameIndex)], D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
            _commandList->ResourceBarrier(1, &barrier);

            ThrowIfFailed(nameof(ID3D12GraphicsCommandList.Close), _commandList->Close());
        }
Ejemplo n.º 9
0
        public virtual void ResourceBarrier(
            uint NumBarriers,
            ref D3D12_RESOURCE_BARRIER pBarriers
            )
        {
            var fp = GetFunctionPointer(26);

            if (m_ResourceBarrierFunc == null)
            {
                m_ResourceBarrierFunc = (ResourceBarrierFunc)Marshal.GetDelegateForFunctionPointer(fp, typeof(ResourceBarrierFunc));
            }

            m_ResourceBarrierFunc(m_ptr, NumBarriers, ref pBarriers);
        }
Ejemplo n.º 10
0
        /// <inheritdoc />
        public override void BeginFrame(ColorRgba backgroundColor)
        {
            var graphicsFence = D3D12GraphicsFence;

            graphicsFence.Wait();
            graphicsFence.Reset();

            var commandAllocator = D3D12CommandAllocator;

            ThrowExternalExceptionIfFailed(nameof(ID3D12CommandAllocator.Reset), commandAllocator->Reset());

            var graphicsCommandList = D3D12GraphicsCommandList;

            ThrowExternalExceptionIfFailed(nameof(ID3D12GraphicsCommandList.Reset), graphicsCommandList->Reset(commandAllocator, pInitialState: null));

            var renderTargetResourceBarrier = D3D12_RESOURCE_BARRIER.InitTransition(D3D12RenderTargetResource, D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);

            graphicsCommandList->ResourceBarrier(1, &renderTargetResourceBarrier);

            var renderTargetView = D3D12RenderTargetView;

            graphicsCommandList->OMSetRenderTargets(1, &renderTargetView, RTsSingleHandleToDescriptorRange: TRUE, pDepthStencilDescriptor: null);

            var graphicsSurface = D3D12GraphicsDevice.GraphicsSurface;

            var graphicsSurfaceWidth  = graphicsSurface.Width;
            var graphicsSurfaceHeight = graphicsSurface.Height;

            var viewport = new D3D12_VIEWPORT {
                Width    = graphicsSurfaceWidth,
                Height   = graphicsSurfaceHeight,
                MinDepth = D3D12_MIN_DEPTH,
                MaxDepth = D3D12_MAX_DEPTH,
            };

            graphicsCommandList->RSSetViewports(1, &viewport);

            var scissorRect = new RECT {
                right  = (int)graphicsSurfaceWidth,
                bottom = (int)graphicsSurfaceHeight,
            };

            graphicsCommandList->RSSetScissorRects(1, &scissorRect);

            graphicsCommandList->ClearRenderTargetView(renderTargetView, (float *)&backgroundColor, NumRects: 0, pRects: null);
            graphicsCommandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
        }
Ejemplo n.º 11
0
        /// <inheritdoc />
        public override void BeginDrawing(ColorRgba backgroundColor)
        {
            var graphicsCommandList = D3D12GraphicsCommandList;

            var renderTargetResourceBarrier = D3D12_RESOURCE_BARRIER.InitTransition(D3D12RenderTargetResource, D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);

            graphicsCommandList->ResourceBarrier(1, &renderTargetResourceBarrier);

            var renderTargetView = D3D12RenderTargetView;

            graphicsCommandList->OMSetRenderTargets(1, &renderTargetView, RTsSingleHandleToDescriptorRange: TRUE, pDepthStencilDescriptor: null);

            var graphicsSurface = D3D12GraphicsDevice.GraphicsSurface;

            var graphicsSurfaceWidth  = graphicsSurface.Width;
            var graphicsSurfaceHeight = graphicsSurface.Height;

            var viewport = new D3D12_VIEWPORT {
                Width    = graphicsSurfaceWidth,
                Height   = graphicsSurfaceHeight,
                MinDepth = D3D12_MIN_DEPTH,
                MaxDepth = D3D12_MAX_DEPTH,
            };

            graphicsCommandList->RSSetViewports(1, &viewport);

            var scissorRect = new RECT {
                right  = (int)graphicsSurfaceWidth,
                bottom = (int)graphicsSurfaceHeight,
            };

            graphicsCommandList->RSSetScissorRects(1, &scissorRect);

            graphicsCommandList->ClearRenderTargetView(renderTargetView, (float *)&backgroundColor, NumRects: 0, pRects: null);
            graphicsCommandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

            var descriptorHeaps = stackalloc ID3D12DescriptorHeap *[1] {
                D3D12GraphicsDevice.D3D12ShaderResourceDescriptorHeap,
            };

            graphicsCommandList->SetDescriptorHeaps(1, descriptorHeaps);
        }
Ejemplo n.º 12
0
        /// <inheritdoc />
        public override void EndFrame()
        {
            var graphicsCommandList = D3D12GraphicsCommandList;

            var renderTargetResourceBarrier = D3D12_RESOURCE_BARRIER.InitTransition(D3D12RenderTargetResource, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);

            graphicsCommandList->ResourceBarrier(1, &renderTargetResourceBarrier);

            var commandQueue = D3D12GraphicsDevice.D3D12CommandQueue;

            ThrowExternalExceptionIfFailed(nameof(ID3D12GraphicsCommandList.Close), graphicsCommandList->Close());
            commandQueue->ExecuteCommandLists(1, (ID3D12CommandList **)&graphicsCommandList);

            var executeGraphicsFence = WaitForExecuteCompletionGraphicsFence;

            ThrowExternalExceptionIfFailed(nameof(ID3D12CommandQueue.Signal), commandQueue->Signal(executeGraphicsFence.D3D12Fence, executeGraphicsFence.D3D12FenceSignalValue));

            executeGraphicsFence.Wait();
            executeGraphicsFence.Reset();
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Mark a resource barrier on the command list
        /// </summary>
        /// <param name="resource">The resource to transition</param>
        /// <param name="transition">The transition</param>
        public void ResourceTransition(GpuResource resource, ResourceTransition transition)
        {
            // don't do unnecessary work
            if (resource.State == transition.NewState)
            {
                return;
            }

            var barrier = new D3D12_RESOURCE_BARRIER
            {
                Type      = D3D12_RESOURCE_BARRIER_TYPE.D3D12_RESOURCE_BARRIER_TYPE_TRANSITION,
                Flags     = D3D12_RESOURCE_BARRIER_FLAGS.D3D12_RESOURCE_BARRIER_FLAG_NONE,
                Anonymous = new D3D12_RESOURCE_BARRIER._Anonymous_e__Union
                {
                    Transition = CreateD3D12Transition(resource, transition)
                }
            };

            resource.State = transition.NewState;
            _list.Get()->ResourceBarrier(1, &barrier);
        }
        private void PopulateCommandList()
        {
            // Command list allocators can only be reset when the associated
            // command lists have finished execution on the GPU; apps should use
            // fences to determine GPU execution progress.
            ThrowIfFailed(nameof(ID3D12CommandAllocator.Reset), _commandAllocator->Reset());

            // However, when ExecuteCommandList() is called on a particular command
            // list, that command list can then be reset at any time and must be before
            // re-recording.
            ThrowIfFailed(nameof(ID3D12GraphicsCommandList.Reset), _commandList->Reset(_commandAllocator, _pipelineState));

            // Indicate that the back buffer will be used as a render target.
            var barrier = D3D12_RESOURCE_BARRIER.InitTransition(_renderTargets[unchecked ((int)_frameIndex)], D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);

            _commandList->ResourceBarrier(1, &barrier);

            var rtvHandle = _rtvHeap->GetCPUDescriptorHandleForHeapStart();

            rtvHandle.ptr = (UIntPtr)((byte *)rtvHandle.ptr + (_frameIndex * _rtvDescriptorSize));

            // Record commands.
            var clearColor = stackalloc float[4];

            {
                clearColor[0] = 0.0f;
                clearColor[1] = 0.2f;
                clearColor[2] = 0.4f;
                clearColor[3] = 1.0f;
            }
            _commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, null);

            // Indicate that the back buffer will now be used to present.
            barrier = D3D12_RESOURCE_BARRIER.InitTransition(_renderTargets[unchecked ((int)_frameIndex)], D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
            _commandList->ResourceBarrier(1, &barrier);

            ThrowIfFailed(nameof(ID3D12GraphicsCommandList.Close), _commandList->Close());
        }
Ejemplo n.º 15
0
    /// <summary>Begins a render pass.</summary>
    /// <param name="renderPass">The render pass to begin.</param>
    /// <param name="renderTargetClearColor">The color to which the render target should be cleared.</param>
    /// <exception cref="ArgumentNullException"><paramref name="renderPass" /> is <c>null</c>.</exception>
    /// <exception cref="InvalidOperationException">A render pass is already active.</exception>
    /// <exception cref="ObjectDisposedException">The context has been disposed.</exception>
    public void BeginRenderPass(GraphicsRenderPass renderPass, ColorRgba renderTargetClearColor)
    {
        ThrowIfNull(renderPass);

        if (Interlocked.CompareExchange(ref _renderPass, renderPass, null) is not null)
        {
            ThrowForInvalidState(nameof(RenderPass));
        }

        var d3d12GraphicsCommandList = D3D12GraphicsCommandList;
        var renderTarget             = renderPass.Swapchain.CurrentRenderTarget;

        var d3d12RtvResourceBarrier = D3D12_RESOURCE_BARRIER.InitTransition(renderTarget.D3D12RtvResource, D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);

        d3d12GraphicsCommandList->ResourceBarrier(1, &d3d12RtvResourceBarrier);

        var d3d12RtvDescriptorHandle = renderTarget.D3D12RtvDescriptorHandle;

        d3d12GraphicsCommandList->OMSetRenderTargets(1, &d3d12RtvDescriptorHandle, RTsSingleHandleToDescriptorRange: TRUE, pDepthStencilDescriptor: null);

        d3d12GraphicsCommandList->ClearRenderTargetView(d3d12RtvDescriptorHandle, (float *)&renderTargetClearColor, NumRects: 0, pRects: null);
        d3d12GraphicsCommandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
    }
Ejemplo n.º 16
0
        /// <summary>Ends the frame currently be rendered.</summary>
        public void EndFrame()
        {
            var frameIndex = _frameIndex;

            var barrier = new D3D12_RESOURCE_BARRIER {
                Type      = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION,
                Flags     = D3D12_RESOURCE_BARRIER_FLAG_NONE,
                Anonymous = new D3D12_RESOURCE_BARRIER._Anonymous_e__Union {
                    Transition = new D3D12_RESOURCE_TRANSITION_BARRIER {
                        pResource   = RenderTargets[frameIndex],
                        Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
                        StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET,
                        StateAfter  = D3D12_RESOURCE_STATE_PRESENT,
                    },
                },
            };

            var graphicsCommandList = GraphicsCommandLists[frameIndex];

            graphicsCommandList->ResourceBarrier(1, &barrier);

            ThrowExternalExceptionIfFailed(nameof(ID3D12GraphicsCommandList.Close), graphicsCommandList->Close());
            CommandQueue->ExecuteCommandLists(1, (ID3D12CommandList **)&graphicsCommandList);
        }
Ejemplo n.º 17
0
        public unsafe bool Render()
        {
            if (!_loadingComplete)
            {
                return(false);
            }

            ThrowIfFailed(_deviceResources.CommandAllocator->Reset());

            ThrowIfFailed(_commandList.Ptr->Reset(_deviceResources.CommandAllocator, _pipelineState.Ptr));

            {
                _commandList.Ptr->SetGraphicsRootSignature(_rootSignature.Ptr);
                const uint             ppHeapsCount = 1;
                ID3D12DescriptorHeap **ppHeaps      = stackalloc ID3D12DescriptorHeap *[(int)ppHeapsCount] {
                    _cbvHeap.Ptr
                };

                _commandList.Ptr->SetDescriptorHeaps(ppHeapsCount, ppHeaps);

                D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle;
                _cbvHeap.Ptr->GetGPUDescriptorHandleForHeapStart(&gpuHandle);
                gpuHandle.ptr += _deviceResources.CurrentFrameIndex * _cbvDescriptorSize;
                _commandList.Ptr->SetGraphicsRootDescriptorTable(0, gpuHandle);

                D3D12_VIEWPORT viewport = _deviceResources.ScreenViewport;
                _commandList.Ptr->RSSetViewports(1, &viewport);
                D3D12_RECT rect = _scissorRect;
                _commandList.Ptr->RSSetScissorRects(1, &rect);

                D3D12_RESOURCE_BARRIER renderTargetResourceBarrier =
                    CD3DX12_RESOURCE_BARRIER.Transition(
                        _deviceResources.RenderTarget,
                        D3D12_RESOURCE_STATE_PRESENT,
                        D3D12_RESOURCE_STATE_RENDER_TARGET
                        );
                _commandList.Ptr->ResourceBarrier(1, &renderTargetResourceBarrier);

                D3D12_CPU_DESCRIPTOR_HANDLE renderTargetView = _deviceResources.RenderTargetView;
                D3D12_CPU_DESCRIPTOR_HANDLE depthStencilView = _deviceResources.DepthStencilView;


                _commandList.Ptr->ClearRenderTargetView(renderTargetView, CornflowerBlue, 0, null);
                _commandList.Ptr->ClearDepthStencilView(depthStencilView, D3D12_CLEAR_FLAG_DEPTH,
                                                        1, 0, 0, null);

                _commandList.Ptr->OMSetRenderTargets(1, &renderTargetView, FALSE, &depthStencilView);

                _commandList.Ptr->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

                D3D12_VERTEX_BUFFER_VIEW vertexBufferView = _vertexBufferView;
                D3D12_INDEX_BUFFER_VIEW  indexBufferView  = _indexBufferView;
                _commandList.Ptr->IASetVertexBuffers(0, 1, &vertexBufferView);
                _commandList.Ptr->IASetIndexBuffer(&indexBufferView);

                _commandList.Ptr->DrawIndexedInstanced(36, 1, 0, 0, 0);

                D3D12_RESOURCE_BARRIER presentResourceBarrier =
                    CD3DX12_RESOURCE_BARRIER.Transition(
                        _deviceResources.RenderTarget,
                        D3D12_RESOURCE_STATE_RENDER_TARGET,
                        D3D12_RESOURCE_STATE_PRESENT);

                _commandList.Ptr->ResourceBarrier(1, &presentResourceBarrier);
            }

            ThrowIfFailed(_commandList.Ptr->Close());

            const uint          ppCommandListsCount = 1;
            ID3D12CommandList **ppCommandLists      = stackalloc ID3D12CommandList *[(int)ppCommandListsCount]
            {
                (ID3D12CommandList *)_commandList.Ptr
            };

            _deviceResources.CommandQueue->ExecuteCommandLists(ppCommandListsCount, ppCommandLists);

            return(true);
        }
Ejemplo n.º 18
0
    protected override void CreateAssets()
    {
        using ComPtr <ID3D12Resource> textureUploadHeap = null;

        _texture = CreateTexture();
        base.CreateAssets();

        ID3D12Resource *CreateTexture()
        {
            // Describe and create a Texture2D.
            var textureDesc = new D3D12_RESOURCE_DESC {
                MipLevels        = 1,
                Format           = DXGI_FORMAT_R8G8B8A8_UNORM,
                Width            = TextureWidth,
                Height           = TextureHeight,
                Flags            = D3D12_RESOURCE_FLAG_NONE,
                DepthOrArraySize = 1,
                SampleDesc       = new DXGI_SAMPLE_DESC {
                    Count   = 1,
                    Quality = 0,
                },
                Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D,
            };

            ID3D12Resource *texture;
            var             iid = __uuidof <ID3D12Resource>();

            var heapProperties = new D3D12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT);

            ThrowIfFailed(D3DDevice->CreateCommittedResource(
                              &heapProperties,
                              D3D12_HEAP_FLAG_NONE,
                              &textureDesc,
                              D3D12_RESOURCE_STATE_COPY_DEST,
                              pOptimizedClearValue: null,
                              iid,
                              (void **)&texture
                              ));

            var uploadBufferSize = GetRequiredIntermediateSize(texture, 0, 1);

            // Create the GPU upload buffer.
            heapProperties = new D3D12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD);
            var bufferDesc = D3D12_RESOURCE_DESC.Buffer(uploadBufferSize);

            ThrowIfFailed(D3DDevice->CreateCommittedResource(
                              &heapProperties,
                              D3D12_HEAP_FLAG_NONE,
                              &bufferDesc,
                              D3D12_RESOURCE_STATE_GENERIC_READ,
                              pOptimizedClearValue: null,
                              iid,
                              (void **)textureUploadHeap.GetAddressOf()
                              ));

            // Copy data to the intermediate upload heap and then schedule a copy
            // from the upload heap to the Texture2D.
            var textureData = GenerateTextureData();
            var rowPitch    = TextureWidth * TexturePixelSize;
            var slicePitch  = rowPitch * TextureHeight;
            D3D12_SUBRESOURCE_DATA textureSubresourceData;

            fixed(byte *pTextureData = &textureData[0])
            {
                textureSubresourceData = new D3D12_SUBRESOURCE_DATA {
                    pData      = (void *)pTextureData,
                    RowPitch   = (nint)rowPitch,
                    SlicePitch = (nint)slicePitch,
                };
            }

            _ = UpdateSubresources(GraphicsCommandList, texture, textureUploadHeap, 0, 0, 1, &textureSubresourceData);
            var barrier = D3D12_RESOURCE_BARRIER.InitTransition(texture, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);

            GraphicsCommandList->ResourceBarrier(1, &barrier);

            // Describe and create a SRV for the texture.
            var srvDesc = new D3D12_SHADER_RESOURCE_VIEW_DESC {
                Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING,
                Format        = textureDesc.Format,
                ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D,
            };

            srvDesc.Anonymous.Texture2D.MipLevels = 1;

            D3DDevice->CreateShaderResourceView(texture, &srvDesc, _srvHeap->GetCPUDescriptorHandleForHeapStart());

            return(texture);
        }

        byte[] GenerateTextureData()
        {
            const uint RowPitch    = TextureWidth * TexturePixelSize;
            const uint CellPitch   = RowPitch >> 3;      // The width of a cell in the checkboard texture.
            const uint CellHeight  = TextureWidth >> 3;  // The height of a cell in the checkerboard texture.
            const uint TextureSize = RowPitch * TextureHeight;

            var data = new byte[TextureSize];

            fixed(byte *pData = &data[0])
            {
                for (uint n = 0; n < TextureSize; n += TexturePixelSize)
                {
                    var x = n % RowPitch;
                    var y = n / RowPitch;
                    var i = x / CellPitch;
                    var j = y / CellHeight;

                    if (i % 2 == j % 2)
                    {
                        pData[n]     = 0x00;    // R
                        pData[n + 1] = 0x00;    // G
                        pData[n + 2] = 0x00;    // B
                        pData[n + 3] = 0xff;    // A
                    }
                    else
                    {
                        pData[n]     = 0xff;    // R
                        pData[n + 1] = 0xff;    // G
                        pData[n + 2] = 0xff;    // B
                        pData[n + 3] = 0xff;    // A
                    }
                }
            }

            return(data);
        }
    }
Ejemplo n.º 19
0
        protected virtual void TransitionForPresent()
        {
            var barrier = D3D12_RESOURCE_BARRIER.InitTransition(RenderTarget, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);

            GraphicsCommandList->ResourceBarrier(1, &barrier);
        }
Ejemplo n.º 20
0
    /// <inheritdoc/>
    public override unsafe void OnUpdate(TimeSpan time)
    {
        if (this.isResizePending)
        {
            ApplyResize();

            this.isResizePending = false;
        }

        // Generate the new frame
        GraphicsDevice.Default.ForEach(this.texture !, this.shaderFactory(time));

        using ComPtr <ID3D12Resource> d3D12Resource = default;

        // Get the underlying ID3D12Resource pointer for the texture
        _ = InteropServices.TryGetID3D12Resource(this.texture !, Windows.__uuidof <ID3D12Resource>(), (void **)d3D12Resource.GetAddressOf());

        // Get the target back buffer to update
        ID3D12Resource *d3D12ResourceBackBuffer = this.currentBufferIndex switch
        {
            0 => this.d3D12Resource0.Get(),
            1 => this.d3D12Resource1.Get(),
            _ => null
        };

        this.currentBufferIndex ^= 1;

        // Reset the command list and command allocator
        this.d3D12CommandAllocator.Get()->Reset();
        this.d3D12GraphicsCommandList.Get()->Reset(this.d3D12CommandAllocator.Get(), null);

        D3D12_RESOURCE_BARRIER *d3D12ResourceBarriers = stackalloc D3D12_RESOURCE_BARRIER[]
        {
            D3D12_RESOURCE_BARRIER.InitTransition(
                d3D12Resource.Get(),
                D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
                D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_COPY_SOURCE),
            D3D12_RESOURCE_BARRIER.InitTransition(
                d3D12ResourceBackBuffer,
                D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_COMMON,
                D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_COPY_DEST)
        };

        // Transition the resources to COPY_DEST and COPY_SOURCE respectively
        d3D12GraphicsCommandList.Get()->ResourceBarrier(2, d3D12ResourceBarriers);

        // Copy the generated frame to the target back buffer
        d3D12GraphicsCommandList.Get()->CopyResource(d3D12ResourceBackBuffer, d3D12Resource.Get());

        d3D12ResourceBarriers[0] = D3D12_RESOURCE_BARRIER.InitTransition(
            d3D12Resource.Get(),
            D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_COPY_SOURCE,
            D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_UNORDERED_ACCESS);

        d3D12ResourceBarriers[1] = D3D12_RESOURCE_BARRIER.InitTransition(
            d3D12ResourceBackBuffer,
            D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_COPY_DEST,
            D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_COMMON);

        // Transition the resources back to COMMON and UNORDERED_ACCESS respectively
        d3D12GraphicsCommandList.Get()->ResourceBarrier(2, d3D12ResourceBarriers);

        d3D12GraphicsCommandList.Get()->Close();

        // Execute the command list to perform the copy
        this.d3D12CommandQueue.Get()->ExecuteCommandLists(1, (ID3D12CommandList **)d3D12GraphicsCommandList.GetAddressOf());
        this.d3D12CommandQueue.Get()->Signal(this.d3D12Fence.Get(), this.nextD3D12FenceValue);

        // Present the new frame
        this.dxgiSwapChain1.Get()->Present(0, 0);

        if (this.nextD3D12FenceValue > this.d3D12Fence.Get()->GetCompletedValue())
        {
            this.d3D12Fence.Get()->SetEventOnCompletion(this.nextD3D12FenceValue, default);
        }

        this.nextD3D12FenceValue++;
    }
}
        private void PopulateCommandList()
        {
            // Command list allocators can only be reset when the associated
            // command lists have finished execution on the GPU; apps should use
            // fences to determine GPU execution progress.
            ThrowIfFailed(nameof(ID3D12CommandAllocator.Reset), _commandAllocator->Reset());

            // However, when ExecuteCommandList() is called on a particular command
            // list, that command list can then be reset at any time and must be before
            // re-recording.
            ThrowIfFailed(nameof(ID3D12GraphicsCommandList.Reset), _commandList->Reset(_commandAllocator, _pipelineState));

            // Set necessary state.
            _commandList->SetGraphicsRootSignature(_rootSignature);

            fixed(D3D12_VIEWPORT *viewport = &_viewport)
            {
                _commandList->RSSetViewports(1, viewport);
            }

            fixed(RECT *scissorRect = &_scissorRect)
            {
                _commandList->RSSetScissorRects(1, scissorRect);
            }

            var rtvHandle = _rtvHeap->GetCPUDescriptorHandleForHeapStart();

            _commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, null);

            // Record commands.
            var clearColor = stackalloc float[4] {
                0.0f, 0.2f, 0.4f, 1.0f
            };

            _commandList->ClearRenderTargetView(rtvHandle, clearColor, NumRects: 0, null);
            _commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

            fixed(D3D12_VERTEX_BUFFER_VIEW *vertexBufferView = &_vertexBufferView)
            {
                _commandList->IASetVertexBuffers(StartSlot: 0, 1, vertexBufferView);
            }

            _commandList->DrawInstanced(VertexCountPerInstance: 3, InstanceCount: 1, StartVertexLocation: 0, StartInstanceLocation: 0);

            // If MSAA is enabled, we need to resolve the resource from the multi-sampled render target to the single-sampled back buffer
            if (_msaaDesc.Count > 1)
            {
                var barriers = stackalloc D3D12_RESOURCE_BARRIER[2];

                barriers[0] = D3D12_RESOURCE_BARRIER.InitTransition(_multiSampledRenderTarget, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
                barriers[1] = D3D12_RESOURCE_BARRIER.InitTransition(_renderTargets[_frameIndex], D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RESOLVE_DEST);

                _commandList->ResourceBarrier(2, barriers);
                _commandList->ResolveSubresource(_renderTargets[_frameIndex], 0, _multiSampledRenderTarget, 0, DXGI_FORMAT_B8G8R8A8_UNORM);

                barriers[0] = D3D12_RESOURCE_BARRIER.InitTransition(_multiSampledRenderTarget, D3D12_RESOURCE_STATE_RESOLVE_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
                barriers[1] = D3D12_RESOURCE_BARRIER.InitTransition(_renderTargets[unchecked ((int)_frameIndex)], D3D12_RESOURCE_STATE_RESOLVE_DEST, D3D12_RESOURCE_STATE_PRESENT);
                _commandList->ResourceBarrier(2, barriers);
            }
            else
            {
                var barriers = stackalloc D3D12_RESOURCE_BARRIER[2];

                barriers[0] = D3D12_RESOURCE_BARRIER.InitTransition(_multiSampledRenderTarget, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
                barriers[1] = D3D12_RESOURCE_BARRIER.InitTransition(_renderTargets[_frameIndex], D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_COPY_DEST);

                _commandList->ResourceBarrier(2, barriers);
                _commandList->CopyResource(_renderTargets[_frameIndex], _multiSampledRenderTarget);

                barriers[0] = D3D12_RESOURCE_BARRIER.InitTransition(_multiSampledRenderTarget, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
                barriers[1] = D3D12_RESOURCE_BARRIER.InitTransition(_renderTargets[unchecked ((int)_frameIndex)], D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PRESENT);
                _commandList->ResourceBarrier(2, barriers);
            }

            // Indicate that the back buffer will now be used to present.

            ThrowIfFailed(nameof(ID3D12GraphicsCommandList.Close), _commandList->Close());
        }
        private unsafe void CreateAssets()
        {
            ID3D12Device *d3dDevice = _deviceResources.D3DDevice;

            Guid iid;

            {
                iid = D3D12.IID_ID3D12GraphicsCommandList;
                ID3D12GraphicsCommandList *commandList;
                ThrowIfFailed(d3dDevice->CreateCommandList(
                                  0,
                                  D3D12_COMMAND_LIST_TYPE.D3D12_COMMAND_LIST_TYPE_DIRECT,
                                  _deviceResources.CommandAllocator,
                                  _pipelineState.Ptr,
                                  &iid,
                                  (void **)&commandList));

                _commandList = commandList;
                DX.NameD3D12Object(_commandList.Ptr, nameof(_commandList));
            }

            // Cube vertices. Each vertex has a position and a color.
            const uint           vertexPositionColorCount = 8;
            VertexPositionColor *cubeVertices             = stackalloc VertexPositionColor[(int)vertexPositionColorCount]
            {
                new VertexPositionColor {
                    pos = new Vector3(-0.5f, -0.5f, -0.5f), color = new Vector3(0.0f, 0.0f, 0.0f)
                },
                new VertexPositionColor {
                    pos = new Vector3(-0.5f, -0.5f, 0.5f), color = new Vector3(0.0f, 0.0f, 1.0f)
                },
                new VertexPositionColor {
                    pos = new Vector3(-0.5f, 0.5f, -0.5f), color = new Vector3(0.0f, 1.0f, 0.0f)
                },
                new VertexPositionColor {
                    pos = new Vector3(-0.5f, 0.5f, 0.5f), color = new Vector3(0.0f, 1.0f, 1.0f)
                },
                new VertexPositionColor {
                    pos = new Vector3(0.5f, -0.5f, -0.5f), color = new Vector3(1.0f, 0.0f, 0.0f)
                },
                new VertexPositionColor {
                    pos = new Vector3(0.5f, -0.5f, 0.5f), color = new Vector3(1.0f, 0.0f, 1.0f)
                },
                new VertexPositionColor {
                    pos = new Vector3(0.5f, 0.5f, -0.5f), color = new Vector3(1.0f, 1.0f, 0.0f)
                },
                new VertexPositionColor {
                    pos = new Vector3(0.5f, 0.5f, 0.5f), color = new Vector3(1.0f, 1.0f, 1.0f)
                }
            };

            Debug.Assert(sizeof(VertexPositionColor) == Marshal.SizeOf <VertexPositionColor>());
            uint vertexBufferSize = (uint)sizeof(VertexPositionColor) * vertexPositionColorCount;

            using ComPtr <ID3D12Resource> vertexBufferUpload = default;

            D3D12_HEAP_PROPERTIES defaultHeapProperties =
                CD3DX12_HEAP_PROPERTIES.Create(D3D12_HEAP_TYPE.D3D12_HEAP_TYPE_DEFAULT);

            D3D12_RESOURCE_DESC vertexBufferDesc = CD3DX12_RESOURCE_DESC.Buffer(vertexBufferSize);

            {
                iid = D3D12.IID_ID3D12Resource;
                ID3D12Resource *vertexBuffer;
                ThrowIfFailed(d3dDevice->CreateCommittedResource(
                                  &defaultHeapProperties,
                                  D3D12_HEAP_FLAGS.D3D12_HEAP_FLAG_NONE,
                                  &vertexBufferDesc,
                                  D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_COPY_DEST,
                                  null,
                                  &iid,
                                  (void **)&vertexBuffer));

                _vertexBuffer = vertexBuffer;
            }

            iid = D3D12.IID_ID3D12Resource;
            D3D12_HEAP_PROPERTIES uploadHeapProperties =
                CD3DX12_HEAP_PROPERTIES.Create(D3D12_HEAP_TYPE.D3D12_HEAP_TYPE_UPLOAD);

            ThrowIfFailed(d3dDevice->CreateCommittedResource(
                              &uploadHeapProperties,
                              D3D12_HEAP_FLAGS.D3D12_HEAP_FLAG_NONE,
                              &vertexBufferDesc,
                              D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_GENERIC_READ,
                              null,
                              &iid,
                              (void **)vertexBufferUpload.GetAddressOf()));

            DX.NameD3D12Object(_vertexBuffer.Ptr, nameof(_vertexBuffer));

            {
                D3D12_SUBRESOURCE_DATA vertexData;
                vertexData.pData      = (byte *)cubeVertices;
                vertexData.RowPitch   = (IntPtr)vertexBufferSize;
                vertexData.SlicePitch = vertexData.RowPitch;

                Functions.UpdateSubresources(
                    _commandList.Ptr,
                    _vertexBuffer.Ptr,
                    vertexBufferUpload.Ptr,
                    0, 0, 1,
                    &vertexData);

                D3D12_RESOURCE_BARRIER vertexBufferResourceBarrier =
                    CD3DX12_RESOURCE_BARRIER.Transition(_vertexBuffer.Ptr,
                                                        D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_COPY_DEST,
                                                        D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);

                _commandList.Ptr->ResourceBarrier(1, &vertexBufferResourceBarrier);
            }

            const int cubeIndicesCount = 36;
            ushort *  cubeIndices      = stackalloc ushort[cubeIndicesCount]
            {
                0,
                2,
                1, // -x
                1,
                2,
                3,

                4,
                5,
                6, // +x
                5,
                7,
                6,

                0,
                1,
                5, // -y
                0,
                5,
                4,

                2,
                6,
                7, // +y
                2,
                7,
                3,

                0,
                4,
                6, // -z
                0,
                6,
                2,

                1,
                3,
                7, // +z
                1,
                7,
                5,
            };
            const uint indexBufferSize = sizeof(ushort) * cubeIndicesCount;

            using var indexBufferUpload = new ComPtr <ID3D12Resource>();

            D3D12_RESOURCE_DESC indexBufferDesc = CD3DX12_RESOURCE_DESC.Buffer(indexBufferSize);

            {
                iid = D3D12.IID_ID3D12Resource;
                ID3D12Resource *indexBuffer;
                ThrowIfFailed(d3dDevice->CreateCommittedResource(
                                  &defaultHeapProperties,
                                  D3D12_HEAP_FLAGS.D3D12_HEAP_FLAG_NONE,
                                  &indexBufferDesc,
                                  D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_COPY_DEST,
                                  null,
                                  &iid,
                                  (void **)&indexBuffer));
                _indexBuffer = indexBuffer;
            }

            iid = D3D12.IID_ID3D12Resource;
            ThrowIfFailed(d3dDevice->CreateCommittedResource(
                              &uploadHeapProperties,
                              D3D12_HEAP_FLAGS.D3D12_HEAP_FLAG_NONE,
                              &indexBufferDesc,
                              D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_GENERIC_READ,
                              null,
                              &iid,
                              (void **)indexBufferUpload.GetAddressOf()));

            DX.NameD3D12Object(_indexBuffer.Ptr, nameof(_indexBuffer));

            {
                D3D12_SUBRESOURCE_DATA indexData;
                indexData.pData      = (byte *)cubeIndices;
                indexData.RowPitch   = (IntPtr)indexBufferSize;
                indexData.SlicePitch = indexData.RowPitch;

                Functions.UpdateSubresources(
                    _commandList.Ptr,
                    _indexBuffer.Ptr,
                    indexBufferUpload.Ptr,
                    0, 0, 1,
                    &indexData);

                D3D12_RESOURCE_BARRIER indexBufferResourceBarrier =
                    CD3DX12_RESOURCE_BARRIER.Transition(_indexBuffer.Ptr,
                                                        D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_COPY_DEST,
                                                        D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_INDEX_BUFFER);

                _commandList.Ptr->ResourceBarrier(1, &indexBufferResourceBarrier);
            }

            {
                D3D12_DESCRIPTOR_HEAP_DESC heapDesc;
                heapDesc.NumDescriptors = DeviceResources.FrameCount;
                heapDesc.Type           = D3D12_DESCRIPTOR_HEAP_TYPE.D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
                heapDesc.Flags          = D3D12_DESCRIPTOR_HEAP_FLAGS.D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;

                {
                    ID3D12DescriptorHeap *cbvHeap;
                    iid = D3D12.IID_ID3D12DescriptorHeap;
                    ThrowIfFailed(d3dDevice->CreateDescriptorHeap(&heapDesc, &iid, (void **)&cbvHeap));
                    _cbvHeap = cbvHeap;
                    DX.NameD3D12Object(_cbvHeap.Ptr, nameof(_cbvHeap));
                }
            }

            D3D12_RESOURCE_DESC constantBufferDesc = CD3DX12_RESOURCE_DESC.Buffer(
                DeviceResources.FrameCount * AlignedConstantBufferSize);

            {
                iid = D3D12.IID_ID3D12Resource;
                ID3D12Resource *constantBuffer;
                ThrowIfFailed(d3dDevice->CreateCommittedResource(
                                  &uploadHeapProperties,
                                  D3D12_HEAP_FLAGS.D3D12_HEAP_FLAG_NONE,
                                  &constantBufferDesc,
                                  D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_GENERIC_READ,
                                  null,
                                  &iid,
                                  (void **)&constantBuffer));
                _constantBuffer = constantBuffer;

                DX.NameD3D12Object(_constantBuffer.Ptr, nameof(_constantBuffer));
            }

            D3D12_GPU_VIRTUAL_ADDRESS   cbvGpuAddress = _constantBuffer.Ptr->GetGPUVirtualAddress();
            D3D12_CPU_DESCRIPTOR_HANDLE cbvCpuHandle  = _cbvHeap.Ptr->GetCPUDescriptorHandleForHeapStart();

            _cbvDescriptorSize =
                d3dDevice->GetDescriptorHandleIncrementSize(
                    D3D12_DESCRIPTOR_HEAP_TYPE.D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);

            for (var i = 0; i < DeviceResources.FrameCount; i++)
            {
                D3D12_CONSTANT_BUFFER_VIEW_DESC desc;
                desc.BufferLocation = cbvGpuAddress;
                desc.SizeInBytes    = AlignedConstantBufferSize;
                d3dDevice->CreateConstantBufferView(&desc, cbvCpuHandle);
                cbvGpuAddress += desc.SizeInBytes;
                cbvCpuHandle.Offset((int)_cbvDescriptorSize);
            }

            D3D12_RANGE readRange = CD3DX12_RANGE.Create((UIntPtr)0, (UIntPtr)0);

            fixed(byte **p = &_mappedConstantBuffer)
            {
                ThrowIfFailed(_constantBuffer.Ptr->Map(0, &readRange, (void **)p));
                Unsafe.InitBlockUnaligned(_mappedConstantBuffer, 0, DeviceResources.FrameCount * AlignedConstantBufferSize);
            }

            ThrowIfFailed(_commandList.Ptr->Close());
            const int           ppCommandListCount = 1;
            ID3D12CommandList **ppCommandLists     = stackalloc ID3D12CommandList *[ppCommandListCount]
            {
                (ID3D12CommandList *)_commandList.Ptr
            };

            _deviceResources.CommandQueue->ExecuteCommandLists(ppCommandListCount, ppCommandLists);

            _vertexBufferView.BufferLocation = _vertexBuffer.Ptr->GetGPUVirtualAddress();
            _vertexBufferView.StrideInBytes  = (uint)sizeof(VertexPositionColor);
            _vertexBufferView.SizeInBytes    = vertexBufferSize;

            _indexBufferView.BufferLocation = _indexBuffer.Ptr->GetGPUVirtualAddress();
            _indexBufferView.SizeInBytes    = indexBufferSize;
            _indexBufferView.Format         = DXGI_FORMAT.DXGI_FORMAT_R16_UINT;

            _deviceResources.WaitForGpu();
        }

        #endregion
    }
}
Ejemplo n.º 23
0
        /// <inheritdoc cref="Copy(GraphicsBuffer, GraphicsBuffer)" />
        public void Copy(D3D12GraphicsBuffer destination, D3D12GraphicsBuffer source)
        {
            ThrowIfNull(destination, nameof(destination));
            ThrowIfNull(source, nameof(source));

            var graphicsCommandList = D3D12GraphicsCommandList;

            var destinationCpuAccess = destination.GraphicsHeap.CpuAccess;
            var sourceCpuAccess      = source.GraphicsHeap.CpuAccess;

            var d3d12DestinationResource = destination.D3D12Resource;
            var d3d12SourceResource      = source.D3D12Resource;

            var d3d12DestinationResourceState = destination.D3D12ResourceState;
            var d3d12SourceResourceState      = source.D3D12ResourceState;

            BeginCopy();

            graphicsCommandList->CopyResource(d3d12DestinationResource, d3d12SourceResource);

            EndCopy();

            void BeginCopy()
            {
                var resourceBarriers    = stackalloc D3D12_RESOURCE_BARRIER[2];
                var numResourceBarriers = 0u;

                if (destinationCpuAccess == GraphicsHeapCpuAccess.None)
                {
                    resourceBarriers[numResourceBarriers] = D3D12_RESOURCE_BARRIER.InitTransition(
                        d3d12DestinationResource,
                        stateBefore: d3d12DestinationResourceState,
                        stateAfter: D3D12_RESOURCE_STATE_COPY_DEST
                        );
                    numResourceBarriers++;
                }

                if (sourceCpuAccess == GraphicsHeapCpuAccess.None)
                {
                    resourceBarriers[numResourceBarriers] = D3D12_RESOURCE_BARRIER.InitTransition(
                        d3d12SourceResource,
                        stateBefore: d3d12SourceResourceState,
                        stateAfter: D3D12_RESOURCE_STATE_COPY_SOURCE
                        );
                    numResourceBarriers++;
                }

                if (numResourceBarriers != 0)
                {
                    graphicsCommandList->ResourceBarrier(numResourceBarriers, resourceBarriers);
                }
            }

            void EndCopy()
            {
                var resourceBarriers    = stackalloc D3D12_RESOURCE_BARRIER[2];
                var numResourceBarriers = 0u;

                if (sourceCpuAccess == GraphicsHeapCpuAccess.None)
                {
                    resourceBarriers[numResourceBarriers] = D3D12_RESOURCE_BARRIER.InitTransition(
                        d3d12SourceResource,
                        stateBefore: D3D12_RESOURCE_STATE_COPY_SOURCE,
                        stateAfter: d3d12SourceResourceState
                        );
                    numResourceBarriers++;
                }

                if (destinationCpuAccess == GraphicsHeapCpuAccess.None)
                {
                    resourceBarriers[numResourceBarriers] = D3D12_RESOURCE_BARRIER.InitTransition(
                        d3d12DestinationResource,
                        stateBefore: D3D12_RESOURCE_STATE_COPY_DEST,
                        stateAfter: d3d12DestinationResourceState
                        );
                    numResourceBarriers++;
                }

                if (numResourceBarriers != 0)
                {
                    graphicsCommandList->ResourceBarrier(numResourceBarriers, resourceBarriers);
                }
            }
        }
Ejemplo n.º 24
0
        /// <inheritdoc cref="Copy(GraphicsTexture, GraphicsBuffer)" />
        public void Copy(D3D12GraphicsTexture destination, D3D12GraphicsBuffer source)
        {
            ThrowIfNull(destination, nameof(destination));
            ThrowIfNull(source, nameof(source));

            var graphicsDevice      = D3D12GraphicsDevice.D3D12Device;
            var graphicsCommandList = D3D12GraphicsCommandList;

            var destinationCpuAccess = destination.GraphicsHeap.CpuAccess;
            var sourceCpuAccess      = source.GraphicsHeap.CpuAccess;

            var d3d12DestinationResource = destination.D3D12Resource;
            var d3d12SourceResource      = source.D3D12Resource;

            var d3d12DestinationResourceState = destination.D3D12ResourceState;
            var d3d12SourceResourceState      = source.D3D12ResourceState;

            BeginCopy();

            D3D12_PLACED_SUBRESOURCE_FOOTPRINT sourceFootprint;

            var destinationDesc = d3d12DestinationResource->GetDesc();

            graphicsDevice->GetCopyableFootprints(&destinationDesc, FirstSubresource: 0, NumSubresources: 1, BaseOffset: 0, &sourceFootprint, pNumRows: null, pRowSizeInBytes: null, pTotalBytes: null);

            var d3d12DestinationTextureCopyLocation = new D3D12_TEXTURE_COPY_LOCATION(d3d12DestinationResource, Sub: 0);
            var d3d12SourceTextureCopyLocation      = new D3D12_TEXTURE_COPY_LOCATION(d3d12SourceResource, in sourceFootprint);

            graphicsCommandList->CopyTextureRegion(&d3d12DestinationTextureCopyLocation, DstX: 0, DstY: 0, DstZ: 0, &d3d12SourceTextureCopyLocation, pSrcBox: null);

            EndCopy();

            void BeginCopy()
            {
                var resourceBarriers    = stackalloc D3D12_RESOURCE_BARRIER[2];
                var numResourceBarriers = 0u;

                if (destinationCpuAccess == GraphicsHeapCpuAccess.None)
                {
                    resourceBarriers[numResourceBarriers] = D3D12_RESOURCE_BARRIER.InitTransition(
                        d3d12DestinationResource,
                        stateBefore: d3d12DestinationResourceState,
                        stateAfter: D3D12_RESOURCE_STATE_COPY_DEST
                        );
                    numResourceBarriers++;
                }

                if (sourceCpuAccess == GraphicsHeapCpuAccess.None)
                {
                    resourceBarriers[numResourceBarriers] = D3D12_RESOURCE_BARRIER.InitTransition(
                        d3d12SourceResource,
                        stateBefore: d3d12SourceResourceState,
                        stateAfter: D3D12_RESOURCE_STATE_COPY_SOURCE
                        );
                    numResourceBarriers++;
                }

                if (numResourceBarriers != 0)
                {
                    graphicsCommandList->ResourceBarrier(numResourceBarriers, resourceBarriers);
                }
            }

            void EndCopy()
            {
                var resourceBarriers    = stackalloc D3D12_RESOURCE_BARRIER[2];
                var numResourceBarriers = 0u;

                if (sourceCpuAccess == GraphicsHeapCpuAccess.None)
                {
                    resourceBarriers[numResourceBarriers] = D3D12_RESOURCE_BARRIER.InitTransition(
                        d3d12SourceResource,
                        stateBefore: D3D12_RESOURCE_STATE_COPY_SOURCE,
                        stateAfter: d3d12SourceResourceState
                        );
                    numResourceBarriers++;
                }

                if (destinationCpuAccess == GraphicsHeapCpuAccess.None)
                {
                    resourceBarriers[numResourceBarriers] = D3D12_RESOURCE_BARRIER.InitTransition(
                        d3d12DestinationResource,
                        stateBefore: D3D12_RESOURCE_STATE_COPY_DEST,
                        stateAfter: d3d12DestinationResourceState
                        );
                    numResourceBarriers++;
                }

                if (numResourceBarriers != 0)
                {
                    graphicsCommandList->ResourceBarrier(numResourceBarriers, resourceBarriers);
                }
            }
        }
Ejemplo n.º 25
0
        /// <inheritdoc />
        public override void EndDrawing()
        {
            var renderTargetResourceBarrier = D3D12_RESOURCE_BARRIER.InitTransition(D3D12RenderTargetResource, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);

            D3D12GraphicsCommandList->ResourceBarrier(1, &renderTargetResourceBarrier);
        }
Ejemplo n.º 26
0
        // Load the sample assets.
        private void LoadAssets()
        {
            Guid      iid;
            ID3DBlob *signature    = null;
            ID3DBlob *error        = null;
            ID3DBlob *vertexShader = null;
            ID3DBlob *pixelShader  = null;

            try
            {
                // Create the root signature.
                {
                    var featureData = new D3D12_FEATURE_DATA_ROOT_SIGNATURE {
                        // This is the highest version the sample supports. If CheckFeatureSupport succeeds, the HighestVersion returned will not be greater than this.
                        HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_1
                    };

                    if (FAILED(_device->CheckFeatureSupport(D3D12_FEATURE_ROOT_SIGNATURE, &featureData, (uint)sizeof(D3D12_FEATURE))))
                    {
                        featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_0;
                    }

                    const int RangesCount = 1;
                    var       ranges      = stackalloc D3D12_DESCRIPTOR_RANGE1[RangesCount];
                    ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC);

                    const int RootParametersCount = 1;
                    var       rootParameters      = stackalloc D3D12_ROOT_PARAMETER1[RootParametersCount];
                    rootParameters[0].InitAsDescriptorTable(1, ranges, D3D12_SHADER_VISIBILITY_PIXEL);

                    var sampler = new D3D12_STATIC_SAMPLER_DESC {
                        Filter           = D3D12_FILTER.D3D12_FILTER_MIN_MAG_MIP_POINT,
                        AddressU         = D3D12_TEXTURE_ADDRESS_MODE_BORDER,
                        AddressV         = D3D12_TEXTURE_ADDRESS_MODE_BORDER,
                        AddressW         = D3D12_TEXTURE_ADDRESS_MODE_BORDER,
                        MipLODBias       = 0,
                        MaxAnisotropy    = 0,
                        ComparisonFunc   = D3D12_COMPARISON_FUNC_NEVER,
                        BorderColor      = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK,
                        MinLOD           = 0.0f,
                        MaxLOD           = D3D12_FLOAT32_MAX,
                        ShaderRegister   = 0,
                        RegisterSpace    = 0,
                        ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL,
                    };

                    var rootSignatureDesc = new D3D12_VERSIONED_ROOT_SIGNATURE_DESC();
                    rootSignatureDesc.Init_1_1(RootParametersCount, rootParameters, 1, &sampler, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);

                    ThrowIfFailed(nameof(D3D12SerializeVersionedRootSignature), D3D12SerializeVersionedRootSignature(
                                      &rootSignatureDesc, featureData.HighestVersion, &signature, &error));

                    fixed(ID3D12RootSignature **rootSignature = &_rootSignature)
                    {
                        iid = IID_ID3D12RootSignature;
                        ThrowIfFailed(nameof(ID3D12Device.CreateRootSignature), _device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), &iid, (void **)rootSignature));
                    }
                }

                // Create the pipeline state, which includes compiling and loading shaders.
                {
                    var compileFlags = 0u;

#if DEBUG
                    // Enable better shader debugging with the graphics debugging tools.
                    compileFlags |= D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
#endif
                    fixed(char *fileName = GetAssetFullPath(@"D3D12\Assets\Shaders\HelloTexture.hlsl"))
                    {
                        var entryPoint = 0x00006E69614D5356;    // VSMain
                        var target     = 0x0000305F355F7376;    // vs_5_0

                        ThrowIfFailed(nameof(D3DCompileFromFile), D3DCompileFromFile((ushort *)fileName, pDefines: null, pInclude: null, (sbyte *)&entryPoint, (sbyte *)&target, compileFlags, Flags2: 0, &vertexShader, ppErrorMsgs: null));

                        entryPoint = 0x00006E69614D5350;        // PSMain
                        target     = 0x0000305F355F7370;        // ps_5_0
                        ThrowIfFailed(nameof(D3DCompileFromFile), D3DCompileFromFile((ushort *)fileName, pDefines: null, pInclude: null, (sbyte *)&entryPoint, (sbyte *)&target, compileFlags, Flags2: 0, &pixelShader, ppErrorMsgs: null));
                    }

                    // Define the vertex input layout.
                    const int InputElementDescsCount = 2;

                    var semanticName0 = stackalloc ulong[2] {
                        0x4E4F495449534F50,     // POSITION
                        0x0000000000000000,
                    };

                    var semanticName1 = stackalloc ulong[2] {
                        0x44524F4F43584554,     // TEXCOORD
                        0x0000000000000000,
                    };

                    var inputElementDescs = stackalloc D3D12_INPUT_ELEMENT_DESC[InputElementDescsCount] {
                        new D3D12_INPUT_ELEMENT_DESC {
                            SemanticName   = (sbyte *)semanticName0,
                            Format         = DXGI_FORMAT_R32G32B32_FLOAT,
                            InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,
                        },
                        new D3D12_INPUT_ELEMENT_DESC {
                            SemanticName      = (sbyte *)semanticName1,
                            Format            = DXGI_FORMAT_R32G32_FLOAT,
                            AlignedByteOffset = 12,
                            InputSlotClass    = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,
                        },
                    };

                    // Describe and create the graphics pipeline state object (PSO).
                    var psoDesc = new D3D12_GRAPHICS_PIPELINE_STATE_DESC {
                        InputLayout = new D3D12_INPUT_LAYOUT_DESC {
                            pInputElementDescs = inputElementDescs,
                            NumElements        = InputElementDescsCount,
                        },
                        pRootSignature    = _rootSignature,
                        VS                = new D3D12_SHADER_BYTECODE(vertexShader),
                        PS                = new D3D12_SHADER_BYTECODE(pixelShader),
                        RasterizerState   = D3D12_RASTERIZER_DESC.DEFAULT,
                        BlendState        = D3D12_BLEND_DESC.DEFAULT,
                        DepthStencilState = new D3D12_DEPTH_STENCIL_DESC {
                            DepthEnable   = FALSE,
                            StencilEnable = FALSE,
                        },
                        SampleMask            = uint.MaxValue,
                        PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
                        NumRenderTargets      = 1,
                        SampleDesc            = new DXGI_SAMPLE_DESC(count: 1, quality: 0),
                    };
                    psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;

                    fixed(ID3D12PipelineState **pipelineState = &_pipelineState)
                    {
                        iid = IID_ID3D12PipelineState;
                        ThrowIfFailed(nameof(ID3D12Device.CreateGraphicsPipelineState), _device->CreateGraphicsPipelineState(&psoDesc, &iid, (void **)pipelineState));
                    }
                }

                // Create the command list.
                fixed(ID3D12GraphicsCommandList **commandList = &_commandList)
                {
                    iid = IID_ID3D12GraphicsCommandList;
                    ThrowIfFailed(nameof(ID3D12Device.CreateCommandList), _device->CreateCommandList(nodeMask: 0, D3D12_COMMAND_LIST_TYPE_DIRECT, _commandAllocator, _pipelineState, &iid, (void **)commandList));
                }

                // Create the vertex buffer.
                {
                    // Define the geometry for a triangle.
                    const int TriangleVerticesCount = 3;
                    var       triangleVertices      = stackalloc Vertex[TriangleVerticesCount] {
                        new Vertex {
                            Position = new Vector3(0.0f, 0.25f * AspectRatio, 0.0f),
                            UV       = new Vector2(0.5f, 0.0f)
                        },
                        new Vertex {
                            Position = new Vector3(0.25f, -0.25f * AspectRatio, 0.0f),
                            UV       = new Vector2(1.0f, 1.0f)
                        },
                        new Vertex {
                            Position = new Vector3(-0.25f, -0.25f * AspectRatio, 0.0f),
                            UV       = new Vector2(0.0f, 1.0f)
                        },
                    };

                    var vertexBufferSize = (uint)sizeof(Vertex) * TriangleVerticesCount;

                    // 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.
                    fixed(ID3D12Resource **vertexBuffer = &_vertexBuffer)
                    {
                        var heapProperties = new D3D12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD);
                        var bufferDesc     = D3D12_RESOURCE_DESC.Buffer(vertexBufferSize);

                        iid = IID_ID3D12Resource;
                        ThrowIfFailed(nameof(ID3D12Device.CreateCommittedResource), _device->CreateCommittedResource(
                                          &heapProperties,
                                          D3D12_HEAP_FLAG_NONE,
                                          &bufferDesc,
                                          D3D12_RESOURCE_STATE_GENERIC_READ,
                                          pOptimizedClearValue: null,
                                          &iid,
                                          (void **)vertexBuffer
                                          ));
                    }

                    // Copy the triangle data to the vertex buffer.
                    var   readRange = new D3D12_RANGE();
                    byte *pVertexDataBegin;
                    ThrowIfFailed(nameof(ID3D12Resource.Map), _vertexBuffer->Map(Subresource: 0, &readRange, (void **)&pVertexDataBegin));
                    Unsafe.CopyBlock(pVertexDataBegin, triangleVertices, vertexBufferSize);
                    _vertexBuffer->Unmap(0, null);

                    // Initialize the vertex buffer view.
                    _vertexBufferView.BufferLocation = _vertexBuffer->GetGPUVirtualAddress();
                    _vertexBufferView.StrideInBytes  = (uint)sizeof(Vertex);
                    _vertexBufferView.SizeInBytes    = vertexBufferSize;
                }

                // Note: textureUploadHeap needs to stay in scope until
                // the command list that references it has finished executing on the GPU.
                // We will flush the GPU at the end of this method to ensure the resource is not
                // prematurely destroyed.
                ID3D12Resource *textureUploadHeap;

                // Create the texture.
                {
                    // Describe and create a Texture2D.
                    var textureDesc = new D3D12_RESOURCE_DESC {
                        MipLevels        = 1,
                        Format           = DXGI_FORMAT_R8G8B8A8_UNORM,
                        Width            = TextureWidth,
                        Height           = TextureHeight,
                        Flags            = D3D12_RESOURCE_FLAG_NONE,
                        DepthOrArraySize = 1,
                        SampleDesc       = new DXGI_SAMPLE_DESC {
                            Count   = 1,
                            Quality = 0,
                        },
                        Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D,
                    };

                    fixed(ID3D12Resource **pTexture = &_texture)
                    {
                        var heapProperties = new D3D12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT);

                        iid = IID_ID3D12Resource;
                        ThrowIfFailed(nameof(ID3D12Device.CreateCommittedResource), _device->CreateCommittedResource(
                                          &heapProperties,
                                          D3D12_HEAP_FLAG_NONE,
                                          &textureDesc,
                                          D3D12_RESOURCE_STATE_COPY_DEST,
                                          pOptimizedClearValue: null,
                                          &iid,
                                          (void **)pTexture
                                          ));

                        var uploadBufferSize = GetRequiredIntermediateSize(_texture, 0, 1);

                        // Create the GPU upload buffer.
                        heapProperties = new D3D12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD);
                        var bufferDesc = D3D12_RESOURCE_DESC.Buffer(uploadBufferSize);

                        ThrowIfFailed(nameof(ID3D12Device.CreateCommittedResource), _device->CreateCommittedResource(
                                          &heapProperties,
                                          D3D12_HEAP_FLAG_NONE,
                                          &bufferDesc,
                                          D3D12_RESOURCE_STATE_GENERIC_READ,
                                          pOptimizedClearValue: null,
                                          &iid,
                                          (void **)&textureUploadHeap
                                          ));
                    }

                    // Copy data to the intermediate upload heap and then schedule a copy
                    // from the upload heap to the Texture2D.
                    var texture    = GenerateTextureData();
                    var rowPitch   = TextureWidth * TexturePixelSize;
                    var slicePitch = rowPitch * TextureHeight;
                    D3D12_SUBRESOURCE_DATA textureData;
                    fixed(byte *pTexture = &texture[0])
                    {
                        textureData = new D3D12_SUBRESOURCE_DATA {
                            pData      = (void *)pTexture,
                            RowPitch   = (nint)rowPitch,
                            SlicePitch = (nint)slicePitch,
                        };
                    }
                    UpdateSubresources(_commandList, _texture, textureUploadHeap, 0, 0, 1, &textureData);
                    var barrier = D3D12_RESOURCE_BARRIER.InitTransition(_texture, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
                    _commandList->ResourceBarrier(1, &barrier);

                    // Describe and create a SRV for the texture.
                    var srvDesc = new D3D12_SHADER_RESOURCE_VIEW_DESC {
                        Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING,
                        Format        = textureDesc.Format,
                        ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D,
                    };
                    srvDesc.Anonymous.Texture2D.MipLevels = 1;

                    _device->CreateShaderResourceView(_texture, &srvDesc, _srvHeap->GetCPUDescriptorHandleForHeapStart());
                }

                // Close the command list and execute it to begin the initial GPU setup.
                ThrowIfFailed(nameof(ID3D12GraphicsCommandList.Close), _commandList->Close());

                const int CommandListsCount = 1;
                var       ppCommandLists    = stackalloc ID3D12CommandList *[CommandListsCount] {
                    (ID3D12CommandList *)_commandList,
                };
                _commandQueue->ExecuteCommandLists(CommandListsCount, ppCommandLists);

                // Create synchronization objects and wait until assets have been uploaded to the GPU.
                {
                    fixed(ID3D12Fence **fence = &_fence)
                    {
                        iid = IID_ID3D12Fence;
                        ThrowIfFailed(nameof(ID3D12Device.CreateFence), _device->CreateFence(0, D3D12_FENCE_FLAG_NONE, &iid, (void **)fence));
                        _fenceValue = 1;
                    }

                    // Create an event handle to use for frame synchronization.
                    _fenceEvent = CreateEventW(lpEventAttributes: null, bManualReset: FALSE, bInitialState: FALSE, lpName: null);
                    if (_fenceEvent == null)
                    {
                        var hr = Marshal.GetHRForLastWin32Error();
                        Marshal.ThrowExceptionForHR(hr);
                    }

                    // 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();
                }
            }
            finally
            {
                if (signature != null)
                {
                    signature->Release();
                }

                if (error != null)
                {
                    error->Release();
                }

                if (vertexShader != null)
                {
                    vertexShader->Release();
                }

                if (pixelShader != null)
                {
                    pixelShader->Release();
                }
            }
        }