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()); }
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); } }
/// <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); }
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()); }
/// <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); }
/// <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); }
/// <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(); }
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()); }
/// <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); }
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); } }
protected virtual void TransitionForPresent() { var barrier = D3D12_RESOURCE_BARRIER.InitTransition(RenderTarget, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT); GraphicsCommandList->ResourceBarrier(1, &barrier); }
/// <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()); }
/// <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); } } }
// 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(); } } }
/// <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); }
/// <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); } } }