Exemplo n.º 1
0
        /// <summary>
        /// Creates and initializes a new <see cref="IDXGIFactory4As6Backcompat"/> instance.
        /// </summary>
        /// <param name="dxgiFactory4">The <see cref="IDXGIFactory4"/> instance to wrap.</param>
        /// <param name="dxgiFactory6">The resulting <see cref="IDXGIFactory6"/> instance.</param>
        public static void Create(IDXGIFactory4 *dxgiFactory4, IDXGIFactory6 **dxgiFactory6)
        {
            IDXGIFactory4As6Backcompat * @this = (IDXGIFactory4As6Backcompat *)NativeMemory.Alloc((nuint)sizeof(IDXGIFactory4As6Backcompat));

            @this->lpVtbl       = Vtbl;
            @this->dxgiFactory4 = dxgiFactory4;

            _ = dxgiFactory4->AddRef();

            *dxgiFactory6 = (IDXGIFactory6 *)@this;
        }
Exemplo n.º 2
0
        // Load the rendering pipeline dependencies.
        private void LoadPipeline()
        {
            Guid             iid;
            ID3D12Debug *    debugController = null;
            IDXGIFactory4 *  factory         = null;
            IDXGIAdapter *   adapter         = null;
            IDXGISwapChain1 *swapChain       = null;

            try
            {
                var dxgiFactoryFlags = 0u;

#if DEBUG
                // Enable the debug layer (requires the Graphics Tools "optional feature").
                // NOTE: Enabling the debug layer after device creation will invalidate the active device.
                {
                    iid = IID_ID3D12Debug;
                    if (SUCCEEDED(D3D12GetDebugInterface(&iid, (void **)&debugController)))
                    {
                        debugController->EnableDebugLayer();

                        // Enable additional debug layers.
                        dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
                    }
                }
#endif

                iid = IID_IDXGIFactory4;
                ThrowIfFailed(nameof(CreateDXGIFactory2), CreateDXGIFactory2(dxgiFactoryFlags, &iid, (void **)&factory));

                if (UseWarpDevice)
                {
                    iid = IID_IDXGIAdapter;
                    ThrowIfFailed(nameof(IDXGIFactory4.EnumWarpAdapter), factory->EnumWarpAdapter(&iid, (void **)&adapter));
                }
                else
                {
                    adapter = GetHardwareAdapter((IDXGIFactory1 *)factory);
                }

                fixed(ID3D12Device **device = &_device)
                {
                    iid = IID_ID3D12Device;
                    ThrowIfFailed(nameof(D3D12CreateDevice), D3D12CreateDevice((IUnknown *)adapter, D3D_FEATURE_LEVEL_11_0, &iid, (void **)device));
                }

                // Describe and create the command queue.
                var queueDesc = new D3D12_COMMAND_QUEUE_DESC();

                fixed(ID3D12CommandQueue **commandQueue = &_commandQueue)
                {
                    iid = IID_ID3D12CommandQueue;
                    ThrowIfFailed(nameof(ID3D12Device.CreateCommandQueue), _device->CreateCommandQueue(&queueDesc, &iid, (void **)commandQueue));
                }

                // Describe and create the swap chain.
                var swapChainDesc = new DXGI_SWAP_CHAIN_DESC1 {
                    BufferCount = FrameCount,
                    Width       = Width,
                    Height      = Height,
                    Format      = DXGI_FORMAT_R8G8B8A8_UNORM,
                    BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT,
                    SwapEffect  = DXGI_SWAP_EFFECT_FLIP_DISCARD,
                    SampleDesc  = new DXGI_SAMPLE_DESC(count: 1, quality: 0),
                };

                ThrowIfFailed(nameof(IDXGIFactory4.CreateSwapChainForHwnd), factory->CreateSwapChainForHwnd(
                                  (IUnknown *)_commandQueue, // Swap chain needs the queue so that it can force a flush on it.
                                  Win32Application.Hwnd,
                                  &swapChainDesc,
                                  pFullscreenDesc: null,
                                  pRestrictToOutput: null,
                                  &swapChain
                                  ));

                // This sample does not support fullscreen transitions.
                ThrowIfFailed(nameof(IDXGIFactory4.MakeWindowAssociation), factory->MakeWindowAssociation(Win32Application.Hwnd, DXGI_MWA_NO_ALT_ENTER));

                fixed(IDXGISwapChain3 **swapChain3 = &_swapChain)
                {
                    iid = IID_IDXGISwapChain3;
                    ThrowIfFailed(nameof(IDXGISwapChain1.QueryInterface), swapChain->QueryInterface(&iid, (void **)swapChain3));
                    _frameIndex = _swapChain->GetCurrentBackBufferIndex();
                }

                // Create descriptor heaps.
                {
                    // Describe and create a render target view (RTV) descriptor heap.
                    var rtvHeapDesc = new D3D12_DESCRIPTOR_HEAP_DESC {
                        NumDescriptors = FrameCount,
                        Type           = D3D12_DESCRIPTOR_HEAP_TYPE_RTV,
                    };

                    fixed(ID3D12DescriptorHeap **rtvHeap = &_rtvHeap)
                    {
                        iid = IID_ID3D12DescriptorHeap;
                        ThrowIfFailed(nameof(ID3D12Device.CreateDescriptorHeap), _device->CreateDescriptorHeap(&rtvHeapDesc, &iid, (void **)rtvHeap));
                    }

                    _rtvDescriptorSize = _device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
                }

                // Create frame resources.
                {
                    var rtvHandle = _rtvHeap->GetCPUDescriptorHandleForHeapStart();

                    // Create a RTV for each frame.
                    iid = IID_ID3D12Resource;

                    for (var n = 0u; n < FrameCount; n++)
                    {
                        ID3D12Resource *renderTarget;
                        {
                            ThrowIfFailed(nameof(IDXGISwapChain3.GetBuffer), _swapChain->GetBuffer(n, &iid, (void **)&renderTarget));
                            _device->CreateRenderTargetView(renderTarget, pDesc: null, rtvHandle);
                            rtvHandle.Offset(1, _rtvDescriptorSize);
                        }
                        _renderTargets[unchecked ((int)n)] = renderTarget;
                    }
                }

                fixed(ID3D12CommandAllocator **commandAllocator = &_commandAllocator)
                {
                    iid = IID_ID3D12CommandAllocator;
                    ThrowIfFailed(nameof(ID3D12Device.CreateRenderTargetView), _device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, &iid, (void **)commandAllocator));
                }

                fixed(ID3D12CommandAllocator **bundleAllocator = &_bundleAllocator)
                {
                    iid = IID_ID3D12CommandAllocator;
                    ThrowIfFailed(nameof(ID3D12Device.CreateRenderTargetView), _device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_BUNDLE, &iid, (void **)bundleAllocator));
                }
            }
            finally
            {
                if (debugController != null)
                {
                    debugController->Release();
                }

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

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

                if (swapChain != null)
                {
                    swapChain->Release();
                }
            }
        }
Exemplo n.º 3
0
        protected override void DestroyDeviceDependentResources()
        {
            DestroyAssets();

            DestroyGraphicsCommandLists();
            DestroyPipelineState();
            DestroyRootSignature();

            DestroyFenceEvent();
            DestroyFence();

            DestroyCommandAllocators();

            DestroyDescriptorHeaps();

            DestroyCommandQueue();
            DestroyD3DDevice();
            DestroyDxgiAdapter();
            DestroyDxgiFactory();

            void DestroyCommandAllocators()
            {
                for (var i = 0; i < _commandAllocators.Length; i++)
                {
                    var commandAllocator = _commandAllocators[i];

                    if (commandAllocator != null)
                    {
                        _commandAllocators[i] = null;
                        _ = commandAllocator->Release();
                    }
                }
            }

            void DestroyCommandQueue()
            {
                var commandQueue = _commandQueue;

                if (commandQueue != null)
                {
                    _commandQueue = null;
                    _             = commandQueue->Release();
                }
            }

            void DestroyD3DDevice()
            {
                var d3dDevice = _d3dDevice;

                if (d3dDevice != null)
                {
                    _d3dDevice = null;
                    _          = d3dDevice->Release();
                }
            }

            void DestroyDxgiAdapter()
            {
                var dxgiAdapter = _dxgiAdapter;

                if (dxgiAdapter != null)
                {
                    _dxgiAdapter = null;
                    _            = dxgiAdapter->Release();
                }
            }

            void DestroyDxgiFactory()
            {
                var dxgiFactory = _dxgiFactory;

                if (dxgiFactory != null)
                {
                    _dxgiFactory = null;
                    _            = dxgiFactory->Release();
                }
            }

            void DestroyFence()
            {
                var fence = _fence;

                if (fence != null)
                {
                    _fence = null;
                    _      = fence->Release();
                }
            }

            void DestroyFenceEvent()
            {
                var fenceEvent = _fenceEvent;

                if (fenceEvent != IntPtr.Zero)
                {
                    _fenceEvent = IntPtr.Zero;
                    _           = CloseHandle(_fenceEvent);
                }
            }

            void DestroyGraphicsCommandLists()
            {
                for (var i = 0; i < _graphicsCommandLists.Length; i++)
                {
                    var graphicsCommandList = _graphicsCommandLists[i];

                    if (graphicsCommandList != null)
                    {
                        _graphicsCommandLists[i] = null;
                        _ = graphicsCommandList->Release();
                    }
                }
            }

            void DestroyPipelineState()
            {
                var pipelineState = _pipelineState;

                if (pipelineState != null)
                {
                    _pipelineState = null;
                    _ = pipelineState->Release();
                }
            }

            void DestroyRootSignature()
            {
                var rootSignature = _rootSignature;

                if (rootSignature != null)
                {
                    _rootSignature = null;
                    _ = rootSignature->Release();
                }
            }
        }
Exemplo n.º 4
0
        protected override void CreateDeviceDependentResources()
        {
            _dxgiFactory  = CreateDxgiFactory();
            _dxgiAdapter  = GetDxgiAdapter();
            _d3dDevice    = CreateD3DDevice();
            _commandQueue = CreateCommandQueue();

            CreateDescriptorHeaps();

            for (int i = 0; i < FrameCount; i++)
            {
                _commandAllocators[i] = CreateCommandAllocator();
            }

            _fence       = CreateFence();
            _fenceValues = CreateFenceValues();
            _fenceEvent  = CreateFenceEvent();

            _rootSignature        = CreateRootSignature();
            _pipelineState        = CreatePipelineState();
            _graphicsCommandLists = CreateGraphicsCommandLists();

            ThrowIfFailed(nameof(ID3D12CommandAllocator.Reset), CommandAllocator->Reset());
            ThrowIfFailed(nameof(ID3D12GraphicsCommandList.Reset), GraphicsCommandList->Reset(CommandAllocator, PipelineState));

            CreateAssets();

            ID3D12CommandAllocator *CreateCommandAllocator()
            {
                ID3D12CommandAllocator *commandAllocator;

                var iid = IID_ID3D12CommandAllocator;

                ThrowIfFailed(nameof(ID3D12Device.CreateCommandAllocator), D3DDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, &iid, (void **)&commandAllocator));

                return(commandAllocator);
            }

            ID3D12CommandQueue *CreateCommandQueue()
            {
                var queueDesc = new D3D12_COMMAND_QUEUE_DESC();

                ID3D12CommandQueue *commandQueue;

                var iid = IID_ID3D12CommandQueue;

                ThrowIfFailed(nameof(ID3D12Device.CreateCommandQueue), D3DDevice->CreateCommandQueue(&queueDesc, &iid, (void **)&commandQueue));

                return(commandQueue);
            }

            ID3D12Device *CreateD3DDevice()
            {
                ID3D12Device *d3dDevice;

                var iid = IID_ID3D12Device;

                ThrowIfFailed(nameof(D3D12CreateDevice), D3D12CreateDevice((IUnknown *)_dxgiAdapter, D3D_FEATURE_LEVEL_11_0, &iid, (void **)&d3dDevice));

                return(d3dDevice);
            }

            IDXGIFactory4 *CreateDxgiFactory()
            {
                var dxgiFactoryFlags = TryEnableDebugLayer() ? DXGI_CREATE_FACTORY_DEBUG : 0u;

                IDXGIFactory4 *dxgiFactory;

                var iid = IID_IDXGIFactory4;

                ThrowIfFailed(nameof(CreateDXGIFactory2), CreateDXGIFactory2(dxgiFactoryFlags, &iid, (void **)&dxgiFactory));

                return(dxgiFactory);
            }

            ID3D12Fence *CreateFence()
            {
                ID3D12Fence *fence;

                var iid = IID_ID3D12Fence;

                ThrowIfFailed(nameof(ID3D12Device.CreateFence), D3DDevice->CreateFence(InitialValue: 0, D3D12_FENCE_FLAG_NONE, &iid, (void **)&fence));

                return(fence);
            }

            IntPtr CreateFenceEvent()
            {
                var fenceEvent = CreateEventW(lpEventAttributes: null, bManualReset: FALSE, bInitialState: FALSE, lpName: null);

                if (fenceEvent == IntPtr.Zero)
                {
                    var hr = Marshal.GetHRForLastWin32Error();
                    Marshal.ThrowExceptionForHR(hr);
                }

                return(fenceEvent);
            }

            ulong[] CreateFenceValues()
            {
                var fenceValues = new ulong[FrameCount];

                fenceValues[0] = 1;
                return(fenceValues);
            }

            ID3D12GraphicsCommandList *[] CreateGraphicsCommandLists()
            {
                var graphicsCommandLists = new ID3D12GraphicsCommandList *[FrameCount];

                for (uint i = 0u; i < FrameCount; i++)
                {
                    ID3D12GraphicsCommandList *graphicsCommandList;

                    var iid = IID_ID3D12GraphicsCommandList;
                    ThrowIfFailed(nameof(ID3D12Device.CreateCommandList), D3DDevice->CreateCommandList(nodeMask: 0, D3D12_COMMAND_LIST_TYPE_DIRECT, _commandAllocators[i], PipelineState, &iid, (void **)&graphicsCommandList));

                    ThrowIfFailed(nameof(ID3D12GraphicsCommandList.Close), graphicsCommandList->Close());
                    graphicsCommandLists[i] = graphicsCommandList;
                }

                return(graphicsCommandLists);
            }

            IDXGIAdapter1 *GetDxgiAdapter()
            {
                if (UseWarpDevice)
                {
                    IDXGIAdapter1 *adapter;

                    var iid = IID_IDXGIAdapter;
                    ThrowIfFailed(nameof(IDXGIFactory4.EnumWarpAdapter), _dxgiFactory->EnumWarpAdapter(&iid, (void **)&adapter));

                    return(adapter);
                }
                else
                {
                    return(GetHardwareAdapter((IDXGIFactory1 *)_dxgiFactory));
                }
            }

            bool TryEnableDebugLayer()
            {
#if DEBUG
                // Enable the debug layer (requires the Graphics Tools "optional feature").
                // NOTE: Enabling the debug layer after device creation will invalidate the active device.

                using ComPtr <ID3D12Debug> debugController = null;
                var iid = IID_ID3D12Debug;

                if (SUCCEEDED(D3D12GetDebugInterface(&iid, (void **)&debugController)))
                {
                    debugController.Get()->EnableDebugLayer();
                    return(true);
                }
#endif

                return(false);
            }
        }
        // Load the rendering pipeline dependencies.
        private void LoadPipeline()
        {
            Guid             iid;
            ID3D12Debug *    debugController = null;
            IDXGIFactory4 *  factory         = null;
            IDXGIAdapter *   adapter         = null;
            IDXGISwapChain1 *swapChain       = null;

            try
            {
                var dxgiFactoryFlags = 0u;

#if DEBUG
                // Enable the debug layer (requires the Graphics Tools "optional feature").
                // NOTE: Enabling the debug layer after device creation will invalidate the active device.
                {
                    iid = IID_ID3D12Debug;
                    if (SUCCEEDED(D3D12GetDebugInterface(&iid, (void **)&debugController)))
                    {
                        debugController->EnableDebugLayer();

                        // Enable additional debug layers.
                        dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
                    }
                }
#endif

                iid = IID_IDXGIFactory4;
                ThrowIfFailed(nameof(CreateDXGIFactory2), CreateDXGIFactory2(dxgiFactoryFlags, &iid, (void **)&factory));

                if (UseWarpDevice)
                {
                    iid = IID_IDXGIAdapter;
                    ThrowIfFailed(nameof(IDXGIFactory4.EnumWarpAdapter), factory->EnumWarpAdapter(&iid, (void **)&adapter));
                }
                else
                {
                    adapter = GetHardwareAdapter((IDXGIFactory1 *)factory);
                }

                fixed(ID3D12Device **device = &_device)
                {
                    iid = IID_ID3D12Device;
                    ThrowIfFailed(nameof(D3D12CreateDevice), D3D12CreateDevice((IUnknown *)adapter, D3D_FEATURE_LEVEL_11_0, &iid, (void **)device));
                }

                // Describe and create the command queue.
                var queueDesc = new D3D12_COMMAND_QUEUE_DESC();

                fixed(ID3D12CommandQueue **commandQueue = &_commandQueue)
                {
                    iid = IID_ID3D12CommandQueue;
                    ThrowIfFailed(nameof(ID3D12Device.CreateCommandQueue), _device->CreateCommandQueue(&queueDesc, &iid, (void **)commandQueue));
                }

                // Describe and create the swap chain.
                var swapChainDesc = new DXGI_SWAP_CHAIN_DESC1 {
                    BufferCount = FrameCount,
                    Width       = Width,
                    Height      = Height,
                    Format      = DXGI_FORMAT_B8G8R8A8_UNORM,
                    BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT,
                    SwapEffect  = DXGI_SWAP_EFFECT_FLIP_DISCARD,

                    // The swap chain could do multisampling for you in older versions of Direct3D
                    // You might see this in tutorials for D3D11
                    // This is no longer supported, so the swapchain has no multisampling itself
                    SampleDesc = new DXGI_SAMPLE_DESC(count: 1, quality: 0),
                };

                ThrowIfFailed(nameof(IDXGIFactory4.CreateSwapChainForHwnd), factory->CreateSwapChainForHwnd(
                                  (IUnknown *)_commandQueue, // Swap chain needs the queue so that it can force a flush on it.
                                  Win32Application.Hwnd,
                                  &swapChainDesc,
                                  pFullscreenDesc: null,
                                  pRestrictToOutput: null,
                                  &swapChain
                                  ));

                // This sample does not support fullscreen transitions.
                ThrowIfFailed(nameof(IDXGIFactory4.MakeWindowAssociation), factory->MakeWindowAssociation(Win32Application.Hwnd, DXGI_MWA_NO_ALT_ENTER));

                fixed(IDXGISwapChain3 **swapChain3 = &_swapChain)
                {
                    iid = IID_IDXGISwapChain3;
                    ThrowIfFailed(nameof(IDXGISwapChain1.QueryInterface), swapChain->QueryInterface(&iid, (void **)swapChain3));
                    _frameIndex = _swapChain->GetCurrentBackBufferIndex();
                }

                // Check MSAA support
                CheckMultiSamplingSupport();

                // Create descriptor heaps.
                {
                    // Describe and create a render target view (RTV) descriptor heap.
                    var rtvHeapDesc = new D3D12_DESCRIPTOR_HEAP_DESC {
                        NumDescriptors = 1, // We only have 1 render target
                        Type           = D3D12_DESCRIPTOR_HEAP_TYPE_RTV,
                    };

                    fixed(ID3D12DescriptorHeap **rtvHeap = &_rtvHeap)
                    {
                        iid = IID_ID3D12DescriptorHeap;
                        ThrowIfFailed(nameof(ID3D12Device.CreateDescriptorHeap), _device->CreateDescriptorHeap(&rtvHeapDesc, &iid, (void **)rtvHeap));
                    }

                    _rtvDescriptorSize = _device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
                }

                // Create the render target
                // We do not use the back buffer as that cannot be multisampled
                {
                    var desc = new D3D12_RESOURCE_DESC {
                        Height           = Height,
                        Width            = Width,
                        DepthOrArraySize = 1,
                        Alignment        = 0,
                        SampleDesc       = _msaaDesc,
                        Dimension        = D3D12_RESOURCE_DIMENSION_TEXTURE2D,
                        Flags            = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET,
                        Format           = DXGI_FORMAT_B8G8R8A8_UNORM,
                        Layout           = D3D12_TEXTURE_LAYOUT_UNKNOWN,
                        MipLevels        = 1
                    };

                    var heapProperties = new D3D12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT);

                    var clearColor = stackalloc float[4] {
                        0.0f, 0.2f, 0.4f, 1.0f
                    };
                    var clearVal = new D3D12_CLEAR_VALUE(DXGI_FORMAT_B8G8R8A8_UNORM, clearColor);

                    ID3D12Resource *multisampledRenderTarget;
                    iid = IID_ID3D12Resource;
                    ThrowIfFailed(nameof(ID3D12Device.CreateCommittedResource), _device->CreateCommittedResource(&heapProperties, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_RENDER_TARGET, &clearVal, &iid, (void **)&multisampledRenderTarget));
                    _multiSampledRenderTarget = multisampledRenderTarget;
                }

                // Create the render target for the multisampled render target
                {
                    var rtvHandle = _rtvHeap->GetCPUDescriptorHandleForHeapStart();
                    _device->CreateRenderTargetView(_multiSampledRenderTarget, pDesc: null, rtvHandle);
                }

                // Create frame resources.
                {
                    iid = IID_ID3D12Resource;

                    for (var n = 0u; n < FrameCount; n++)
                    {
                        ID3D12Resource *renderTarget;
                        {
                            ThrowIfFailed(nameof(IDXGISwapChain3.GetBuffer), _swapChain->GetBuffer(n, &iid, (void **)&renderTarget));
                        }
                        _renderTargets[unchecked ((int)n)] = renderTarget;
                    }
                }

                fixed(ID3D12CommandAllocator **commandAllocator = &_commandAllocator)
                {
                    iid = IID_ID3D12CommandAllocator;
                    ThrowIfFailed(nameof(ID3D12Device.CreateRenderTargetView), _device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, &iid, (void **)commandAllocator));
                }
            }
            finally
            {
                if (debugController != null)
                {
                    debugController->Release();
                }

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

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

                if (swapChain != null)
                {
                    swapChain->Release();
                }
            }
        }
Exemplo n.º 6
0
        protected override void CreateDeviceDependentResources()
        {
            _dxgiFactory = CreateDxgiFactory();
            _dxgiAdapter = GetDxgiAdapter();
            _d3dDevice   = CreateD3DDevice();
            StartInfoPump();
            _commandQueue = CreateCommandQueue();

            CreateDescriptorHeaps();

            for (int i = 0; i < FrameCount; i++)
            {
                _commandAllocators[i] = CreateCommandAllocator();
            }

            _fence       = CreateFence();
            _fenceValues = CreateFenceValues();
            _fenceEvent  = CreateFenceEvent();

            _rootSignature        = CreateRootSignature();
            _pipelineState        = CreatePipelineState();
            _graphicsCommandLists = CreateGraphicsCommandLists();

            SilkMarshal.ThrowHResult(CommandAllocator->Reset());
            SilkMarshal.ThrowHResult(GraphicsCommandList->Reset(CommandAllocator, PipelineState));

            CreateAssets();

            ID3D12CommandAllocator *CreateCommandAllocator()
            {
                ID3D12CommandAllocator *commandAllocator;

                var iid = ID3D12CommandAllocator.Guid;

                SilkMarshal.ThrowHResult
                (
                    D3DDevice->CreateCommandAllocator
                        (CommandListType.CommandListTypeDirect, &iid, (void **)&commandAllocator)
                );

                return(commandAllocator);
            }

            ID3D12CommandQueue *CreateCommandQueue()
            {
                var queueDesc = new CommandQueueDesc();

                ID3D12CommandQueue *commandQueue;

                var iid = ID3D12CommandQueue.Guid;

                SilkMarshal.ThrowHResult(D3DDevice->CreateCommandQueue(&queueDesc, &iid, (void **)&commandQueue));

                return(commandQueue);
            }

            ID3D12Device *CreateD3DDevice()
            {
                ID3D12Device *d3dDevice;

                var iid = ID3D12Device.Guid;

                SilkMarshal.ThrowHResult
                (
                    D3D12.CreateDevice
                        ((IUnknown *)_dxgiAdapter, D3DFeatureLevel.D3DFeatureLevel110, &iid, (void **)&d3dDevice)
                );

                return(d3dDevice);
            }

            IDXGIFactory4 *CreateDxgiFactory()
            {
                var dxgiFactoryFlags = TryEnableDebugLayer() ? 0x01 : 0u;

                IDXGIFactory4 *dxgiFactory;

                var iid = IDXGIFactory4.Guid;

                SilkMarshal.ThrowHResult(Dxgi.CreateDXGIFactory2(dxgiFactoryFlags, &iid, (void **)&dxgiFactory));

                return(dxgiFactory);
            }

            ID3D12Fence *CreateFence()
            {
                ID3D12Fence *fence;

                var iid = ID3D12Fence.Guid;

                SilkMarshal.ThrowHResult
                    (D3DDevice->CreateFence(InitialValue: 0, FenceFlags.FenceFlagNone, &iid, (void **)&fence));

                return(fence);
            }

            IntPtr CreateFenceEvent()
            {
                var fenceEvent = SilkMarshal.CreateWindowsEvent(null, false, false, null);

                if (fenceEvent == IntPtr.Zero)
                {
                    var hr = Marshal.GetHRForLastWin32Error();
                    Marshal.ThrowExceptionForHR(hr);
                }

                return(fenceEvent);
            }

            ulong[] CreateFenceValues()
            {
                var fenceValues = new ulong[FrameCount];

                fenceValues[0] = 1;
                return(fenceValues);
            }

            ID3D12GraphicsCommandList *[] CreateGraphicsCommandLists()
            {
                var graphicsCommandLists = new ID3D12GraphicsCommandList *[FrameCount];

                for (uint i = 0u; i < FrameCount; i++)
                {
                    ID3D12GraphicsCommandList *graphicsCommandList;

                    var iid = ID3D12GraphicsCommandList.Guid;
                    SilkMarshal.ThrowHResult
                    (
                        D3DDevice->CreateCommandList
                        (
                            nodeMask: 0, CommandListType.CommandListTypeDirect, _commandAllocators[i], PipelineState,
                            &iid, (void **)&graphicsCommandList
                        )
                    );

                    SilkMarshal.ThrowHResult(graphicsCommandList->Close());
                    graphicsCommandLists[i] = graphicsCommandList;
                }

                return(graphicsCommandLists);
            }

            IDXGIAdapter1 *GetDxgiAdapter()
            {
                if (UseWarpDevice)
                {
                    IDXGIAdapter1 *adapter;

                    var iid = IDXGIAdapter.Guid;
                    SilkMarshal.ThrowHResult(_dxgiFactory->EnumWarpAdapter(&iid, (void **)&adapter));

                    return(adapter);
                }
                else
                {
                    return(GetHardwareAdapter((IDXGIFactory1 *)_dxgiFactory));
                }
            }

            bool TryEnableDebugLayer()
            {
#if DEBUG
                // Enable the debug layer (requires the Graphics Tools "optional feature").
                // NOTE: Enabling the debug layer after device creation will invalidate the active device.

                using ComPtr <ID3D12Debug> debugController = null;
                var iid = ID3D12Debug.Guid;
                var hr  = D3D12.GetDebugInterface(&iid, (void **)&debugController);

                if (HResult.IndicatesSuccess(hr))
                {
                    debugController.Get().EnableDebugLayer();
                    Log.LogInformation("Debug layer enabled");
                    return(_debug = true);
                }
                else
                {
                    Log.LogWarning
                    (
                        Marshal.GetExceptionForHR(hr),
                        $"Failed to enable debug layer, failed with result {hr} (0x{hr:x8})"
                    );
                }
#endif

                return(false);
            }

            void StartInfoPump()
            {
#if DEBUG
                if (!_debug)
                {
                    Log.LogInformation("Skipped creation of info pump due to the debug layer not being enabled.");
                    return;
                }

                var iid = ID3D12InfoQueue.Guid;
                fixed(ID3D12InfoQueue ** @out = &_infoQueue)
                {
                    SilkMarshal.ThrowHResult(D3DDevice->QueryInterface(&iid, (void **)@out));
                }

                _infoPumpCancellationToken = new();
                _infoPump = Task.Run
                            (
                    () =>
                {
                    Log.LogInformation("Info queue pump started");
                    while (!_infoPumpCancellationToken.Token.IsCancellationRequested)
                    {
                        var numMessages = _infoQueue->GetNumStoredMessages();
                        if (numMessages == 0)
                        {
                            continue;
                        }

                        for (var i = 0ul; i < numMessages; i++)
                        {
                            nuint msgByteLength;
                            SilkMarshal.ThrowHResult(_infoQueue->GetMessageA(i, null, &msgByteLength));
                            using var memory = GlobalMemory.Allocate((int)msgByteLength);
                            SilkMarshal.ThrowHResult
                            (
                                _infoQueue->GetMessageA(i, memory.AsPtr <Message>(), &msgByteLength)
                            );

                            ref var msg   = ref memory.AsRef <Message>();
                            var descBytes = new Span <byte>(msg.PDescription, (int)msg.DescriptionByteLength);
                            var desc      = Encoding.UTF8.GetString(descBytes[..^ 1]);
                            var eid       = new EventId((int)msg.ID, msg.ID.ToString()["MessageID".Length..]);