public void ResourceFromTexture3D(Device device, Type bufferType) { using Texture3D <float> buffer = device.Get().AllocateTexture3D <float>(bufferType, 16, 16, 4); using ComPtr <ID3D12Resource> d3D12Resource = default; InteropServices.GetID3D12Resource(buffer, FX.__uuidof <ID3D12Resource>(), (void **)d3D12Resource.GetAddressOf()); Assert.IsTrue(d3D12Resource.Get() != null); Assert.AreEqual(d3D12Resource.Get()->GetDesc().Dimension, D3D12_RESOURCE_DIMENSION_TEXTURE3D); d3D12Resource.Dispose(); int hResult = InteropServices.TryGetID3D12Resource(buffer, FX.__uuidof <ID3D12Resource>(), (void **)d3D12Resource.GetAddressOf()); Assert.AreEqual(hResult, FX.S_OK); Assert.IsTrue(d3D12Resource.Get() != null); Assert.AreEqual(d3D12Resource.Get()->GetDesc().Dimension, D3D12_RESOURCE_DIMENSION_TEXTURE3D); }
/// <summary> /// Applies the actual resize logic that was scheduled from <see cref="OnResize"/>. /// </summary> private unsafe void ApplyResize() { this.d3D12CommandQueue.Get()->Signal(this.d3D12Fence.Get(), this.nextD3D12FenceValue); // Wait for the fence again to ensure there are no pending operations this.d3D12Fence.Get()->SetEventOnCompletion(this.nextD3D12FenceValue, default); this.nextD3D12FenceValue++; // Dispose the old buffers before resizing the buffer this.d3D12Resource0.Dispose(); this.d3D12Resource1.Dispose(); // Resize the swap chain buffers this.dxgiSwapChain1.Get()->ResizeBuffers(0, 0, 0, DXGI_FORMAT.DXGI_FORMAT_UNKNOWN, 0); // Get the index of the initial back buffer using (ComPtr <IDXGISwapChain3> dxgiSwapChain3 = default) { _ = this.dxgiSwapChain1.CopyTo(dxgiSwapChain3.GetAddressOf()); this.currentBufferIndex = dxgiSwapChain3.Get()->GetCurrentBackBufferIndex(); } // Retrieve the back buffers for the swap chain fixed(ID3D12Resource **d3D12Resource0 = this.d3D12Resource0) fixed(ID3D12Resource **d3D12Resource1 = this.d3D12Resource1) { _ = dxgiSwapChain1.Get()->GetBuffer(0, FX.__uuidof <ID3D12Resource>(), (void **)d3D12Resource0); _ = dxgiSwapChain1.Get()->GetBuffer(1, FX.__uuidof <ID3D12Resource>(), (void **)d3D12Resource1); } this.texture?.Dispose(); D3D12_RESOURCE_DESC d3D12Resource0Description = this.d3D12Resource0.Get()->GetDesc(); // Create the 2D texture to use to generate frames to display this.texture = Gpu.Default.AllocateReadWriteTexture2D <Rgba32, Float4>( (int)d3D12Resource0Description.Width, (int)d3D12Resource0Description.Height); }
/// <summary> /// Creates a new <see cref="ID3D12InfoQueue"/> for a given device. /// </summary> /// <param name="d3D12Device">The target <see cref="ID3D12Device"/> to use to create the info queue.</param> /// <returns>A pointer to the newly created <see cref="ID3D12InfoQueue"/> instance.</returns> /// <exception cref="Exception">Thrown when the creation of the info queue fails.</exception> public static ComPtr <ID3D12InfoQueue> CreateInfoQueue(this ref ID3D12Device d3D12Device) { ComPtr <ID3D12InfoQueue> d3D12InfoQueue = default; d3D12Device.QueryInterface(FX.__uuidof <ID3D12InfoQueue>(), d3D12InfoQueue.GetVoidAddressOf()).Assert(); D3D12_MESSAGE_ID *d3D12MessageIds = stackalloc D3D12_MESSAGE_ID[3] { D3D12_MESSAGE_ID_CREATEDEVICE_DEBUG_LAYER_STARTUP_OPTIONS, D3D12_MESSAGE_ID_MAP_INVALID_NULLRANGE, D3D12_MESSAGE_ID_UNMAP_INVALID_NULLRANGE }; D3D12_INFO_QUEUE_FILTER d3D12InfoQueueFilter = default; d3D12InfoQueueFilter.DenyList.NumIDs = 3; d3D12InfoQueueFilter.DenyList.pIDList = d3D12MessageIds; d3D12InfoQueue.Get()->PushRetrievalFilter(&d3D12InfoQueueFilter).Assert(); return(d3D12InfoQueue.Move()); }
/// <summary> /// Creates a new <see cref="ShaderCompiler"/> instance. /// </summary> private ShaderCompiler() { lock (this) { InitializeDxcLibrariesLoading(); } using ComPtr <IDxcCompiler> dxcCompiler = default; using ComPtr <IDxcLibrary> dxcLibrary = default; using ComPtr <IDxcIncludeHandler> dxcIncludeHandler = default; Guid dxcCompilerCLGuid = FX.CLSID_DxcCompiler; Guid dxcLibraryCLGuid = FX.CLSID_DxcLibrary; FX.DxcCreateInstance(&dxcCompilerCLGuid, FX.__uuidof <IDxcCompiler>(), dxcCompiler.GetVoidAddressOf()).Assert(); FX.DxcCreateInstance(&dxcLibraryCLGuid, FX.__uuidof <IDxcLibrary>(), dxcLibrary.GetVoidAddressOf()).Assert(); dxcLibrary.Get()->CreateIncludeHandler(dxcIncludeHandler.GetAddressOf()).Assert(); DxcCompiler = dxcCompiler.Move(); DxcLibrary = dxcLibrary.Move(); DxcIncludeHandler = dxcIncludeHandler.Move(); }
public void GetDevice(Device device) { using ComPtr <ID3D12Device> d3D12Device = default; InteropServices.GetID3D12Device(device.Get(), FX.__uuidof <ID3D12Device>(), (void **)d3D12Device.GetAddressOf()); Assert.IsTrue(d3D12Device.Get() != null); LUID luid = d3D12Device.Get()->GetAdapterLuid(); Assert.IsTrue(*(ulong *)&luid != 0); d3D12Device.Dispose(); int hResult = InteropServices.TryGetID3D12Device(device.Get(), FX.__uuidof <ID3D12Device>(), (void **)d3D12Device.GetAddressOf()); Assert.AreEqual(hResult, FX.S_OK); Assert.IsTrue(d3D12Device.Get() != null); luid = d3D12Device.Get()->GetAdapterLuid(); Assert.IsTrue(*(ulong *)&luid != 0); }
/// <summary> /// Tries to check or create a warp <see cref="ID3D12Device"/> object. /// </summary> /// <param name="d3D12Device">A pointer to the <see cref="ID3D12Device"/> object to create, or <see langword="null"/>.</param> /// <param name="dxgiAdapter">A pointer to the <see cref="IDXGIAdapter"/> object used to create <paramref name="d3D12Device"/>, or <see langword="null"/>.</param> /// <param name="dxgiDescription1">A pointer to the <see cref="DXGI_ADAPTER_DESC1"/> value for the device found.</param> /// <returns>Whether a warp device was created successfully.</returns> private static unsafe bool TryGetWarpDevice(ID3D12Device **d3D12Device, IDXGIAdapter **dxgiAdapter, DXGI_ADAPTER_DESC1 *dxgiDescription1) { using ComPtr <IDXGIFactory4> dxgiFactory4 = default; EnableDebugMode(); FX.CreateDXGIFactory2(IDXGIFactoryCreationFlags, FX.__uuidof <IDXGIFactory4>(), dxgiFactory4.GetVoidAddressOf()).Assert(); using ComPtr <IDXGIAdapter1> dxgiAdapter1 = default; dxgiFactory4.Get()->EnumWarpAdapter(FX.__uuidof <IDXGIAdapter1>(), dxgiAdapter1.GetVoidAddressOf()).Assert(); dxgiAdapter1.Get()->GetDesc1(dxgiDescription1).Assert(); HRESULT createDeviceResult = FX.D3D12CreateDevice( dxgiAdapter1.AsIUnknown().Get(), D3D_FEATURE_LEVEL_11_0, FX.__uuidof <ID3D12Device>(), (void **)d3D12Device); dxgiAdapter1.CopyTo(dxgiAdapter); return(FX.SUCCEEDED(createDeviceResult)); }
/// <inheritdoc/> public override unsafe void OnInitialize(HWND hwnd) { // Get the underlying ID3D12Device in use fixed(ID3D12Device **d3D12Device = this.d3D12Device) { _ = InteropServices.TryGetID3D12Device(Gpu.Default, FX.__uuidof <ID3D12Device>(), (void **)d3D12Device); } // Create the direct command queue to use fixed(ID3D12CommandQueue **d3D12CommandQueue = this.d3D12CommandQueue) { D3D12_COMMAND_QUEUE_DESC d3D12CommandQueueDesc; d3D12CommandQueueDesc.Type = D3D12_COMMAND_LIST_TYPE.D3D12_COMMAND_LIST_TYPE_DIRECT; d3D12CommandQueueDesc.Priority = (int)D3D12_COMMAND_QUEUE_PRIORITY.D3D12_COMMAND_QUEUE_PRIORITY_NORMAL; d3D12CommandQueueDesc.Flags = D3D12_COMMAND_QUEUE_FLAGS.D3D12_COMMAND_QUEUE_FLAG_NONE; d3D12CommandQueueDesc.NodeMask = 0; _ = d3D12Device.Get()->CreateCommandQueue( &d3D12CommandQueueDesc, FX.__uuidof <ID3D12CommandQueue>(), (void **)d3D12CommandQueue); } // Create the direct fence fixed(ID3D12Fence **d3D12Fence = this.d3D12Fence) { _ = this.d3D12Device.Get()->CreateFence( 0, D3D12_FENCE_FLAGS.D3D12_FENCE_FLAG_NONE, FX.__uuidof <ID3D12Fence>(), (void **)d3D12Fence); } // Create the swap chain to display frames fixed(IDXGISwapChain1 **dxgiSwapChain1 = this.dxgiSwapChain1) { using ComPtr <IDXGIFactory2> dxgiFactory2 = default; _ = FX.CreateDXGIFactory2(FX.DXGI_CREATE_FACTORY_DEBUG, FX.__uuidof <IDXGIFactory2>(), (void **)dxgiFactory2.GetAddressOf()); DXGI_SWAP_CHAIN_DESC1 dxgiSwapChainDesc1 = default; dxgiSwapChainDesc1.AlphaMode = DXGI_ALPHA_MODE.DXGI_ALPHA_MODE_IGNORE; dxgiSwapChainDesc1.BufferCount = 2; dxgiSwapChainDesc1.Flags = 0; dxgiSwapChainDesc1.Format = DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_UNORM; dxgiSwapChainDesc1.Width = 0; dxgiSwapChainDesc1.Height = 0; dxgiSwapChainDesc1.SampleDesc = new DXGI_SAMPLE_DESC(count: 1, quality: 0); dxgiSwapChainDesc1.Scaling = DXGI_SCALING.DXGI_SCALING_STRETCH; dxgiSwapChainDesc1.Stereo = 0; dxgiSwapChainDesc1.SwapEffect = DXGI_SWAP_EFFECT.DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; _ = dxgiFactory2.Get()->CreateSwapChainForHwnd( (IUnknown *)d3D12CommandQueue.Get(), hwnd, &dxgiSwapChainDesc1, null, null, dxgiSwapChain1); } // Create the command allocator to use fixed(ID3D12CommandAllocator **d3D12CommandAllocator = this.d3D12CommandAllocator) { this.d3D12Device.Get()->CreateCommandAllocator( D3D12_COMMAND_LIST_TYPE.D3D12_COMMAND_LIST_TYPE_DIRECT, FX.__uuidof <ID3D12CommandAllocator>(), (void **)d3D12CommandAllocator); } // Create the reusable command list to copy data to the back buffers fixed(ID3D12GraphicsCommandList **d3D12GraphicsCommandList = this.d3D12GraphicsCommandList) { this.d3D12Device.Get()->CreateCommandList( 0, D3D12_COMMAND_LIST_TYPE.D3D12_COMMAND_LIST_TYPE_DIRECT, d3D12CommandAllocator, null, FX.__uuidof <ID3D12GraphicsCommandList>(), (void **)d3D12GraphicsCommandList); } // Close the command list to prepare it for future use this.d3D12GraphicsCommandList.Get()->Close(); }
/// <inheritdoc/> public override unsafe void OnUpdate(TimeSpan time) { if (this.isResizePending) { ApplyResize(); this.isResizePending = false; } // Generate the new frame Gpu.Default.For(this.texture !.Width, this.texture.Height, this.shaderFactory(this.texture, time)); using ComPtr <ID3D12Resource> d3D12Resource = default; // Get the underlying ID3D12Resource pointer for the texture _ = InteropServices.TryGetID3D12Resource(this.texture, FX.__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++; } } }
/// <summary> /// Tries to check or create a default <see cref="ID3D12Device"/> object. /// </summary> /// <param name="d3D12Device">A pointer to the <see cref="ID3D12Device"/> object to create, or <see langword="null"/>.</param> /// <param name="dxgiAdapter">A pointer to the <see cref="IDXGIAdapter"/> object used to create <paramref name="d3D12Device"/>, or <see langword="null"/>.</param> /// <param name="dxgiDescription1">A pointer to the <see cref="DXGI_ADAPTER_DESC1"/> value for the device found.</param> /// <returns>Whether a default device was found with the requested feature level.</returns> private static unsafe bool TryGetDefaultDevice(ID3D12Device **d3D12Device, IDXGIAdapter **dxgiAdapter, DXGI_ADAPTER_DESC1 *dxgiDescription1) { using ComPtr <IDXGIFactory4> dxgiFactory4 = default; EnableDebugMode(); FX.CreateDXGIFactory2(IDXGIFactoryCreationFlags, FX.__uuidof <IDXGIFactory4>(), dxgiFactory4.GetVoidAddressOf()).Assert(); uint i = 0; while (true) { using ComPtr <IDXGIAdapter1> dxgiAdapter1 = default; HRESULT enumAdapters1Result = dxgiFactory4.Get()->EnumAdapters1(i++, dxgiAdapter1.GetAddressOf()); if (enumAdapters1Result == FX.DXGI_ERROR_NOT_FOUND) { return(false); } enumAdapters1Result.Assert(); dxgiAdapter1.Get()->GetDesc1(dxgiDescription1).Assert(); if (dxgiDescription1->VendorId == MicrosoftVendorId && dxgiDescription1->DeviceId == WarpDeviceId) { continue; } // Explicit paths for when a device is being retrieved or not, with special handling // for the additional check that is required for the SM6 level. This can't be checked // without creating a device first, so the path for when the target device pointer is // null is useful to do an initial filtering using D3D12CreateDevice to avoid creating // a device for adapters that would've failed at the FL11 check already. if (d3D12Device == null) { HRESULT createDeviceResult = FX.D3D12CreateDevice( dxgiAdapter1.AsIUnknown().Get(), D3D_FEATURE_LEVEL_11_0, FX.__uuidof <ID3D12Device>(), null); if (FX.SUCCEEDED(createDeviceResult)) { using ComPtr <ID3D12Device> d3D12DeviceCandidate = default; createDeviceResult = FX.D3D12CreateDevice( dxgiAdapter1.AsIUnknown().Get(), D3D_FEATURE_LEVEL_11_0, FX.__uuidof <ID3D12Device>(), d3D12DeviceCandidate.GetVoidAddressOf()); if (FX.SUCCEEDED(createDeviceResult) && d3D12DeviceCandidate.Get()->IsShaderModelSupported(D3D_SHADER_MODEL_6_0)) { return(true); } } } else { using ComPtr <ID3D12Device> d3D12DeviceCandidate = default; HRESULT createDeviceResult = FX.D3D12CreateDevice( dxgiAdapter1.AsIUnknown().Get(), D3D_FEATURE_LEVEL_11_0, FX.__uuidof <ID3D12Device>(), d3D12DeviceCandidate.GetVoidAddressOf()); if (FX.SUCCEEDED(createDeviceResult) && d3D12DeviceCandidate.Get()->IsShaderModelSupported(D3D_SHADER_MODEL_6_0)) { d3D12DeviceCandidate.CopyTo(d3D12Device); dxgiAdapter1.CopyTo(dxgiAdapter); return(true); } } } }
/// <inheritdoc/> public bool MoveNext() { if (!this.isInitialized) { this.isInitialized = true; fixed(IDXGIFactory4 **dxgiFactory4 = this.dxgiFactory4) { EnableDebugMode(); FX.CreateDXGIFactory2(IDXGIFactoryCreationFlags, FX.__uuidof <IDXGIFactory4>(), (void **)dxgiFactory4).Assert(); } } if (this.isCompleted) { return(false); } while (true) { using ComPtr <IDXGIAdapter1> dxgiAdapter1 = default; HRESULT enumAdapters1Result = this.dxgiFactory4.Get()->EnumAdapters1(this.index, dxgiAdapter1.GetAddressOf()); if (enumAdapters1Result == FX.DXGI_ERROR_NOT_FOUND) { this.dxgiFactory4.Get()->EnumWarpAdapter(FX.__uuidof <IDXGIAdapter1>(), dxgiAdapter1.GetVoidAddressOf()).Assert(); DXGI_ADAPTER_DESC1 dxgiDescription1; dxgiAdapter1.Get()->GetDesc1(&dxgiDescription1).Assert(); HRESULT createDeviceResult = FX.D3D12CreateDevice( dxgiAdapter1.AsIUnknown().Get(), D3D_FEATURE_LEVEL_11_0, FX.__uuidof <ID3D12Device>(), null); if (FX.SUCCEEDED(createDeviceResult) && this.predicate(new GraphicsDeviceInfo(&dxgiDescription1))) { using ComPtr <ID3D12Device> d3D12Device = default; FX.D3D12CreateDevice( dxgiAdapter1.AsIUnknown().Get(), D3D_FEATURE_LEVEL_11_0, FX.__uuidof <ID3D12Device>(), d3D12Device.GetVoidAddressOf()).Assert(); this.graphicsDevice = GetOrCreateDevice(d3D12Device.Get(), (IDXGIAdapter *)dxgiAdapter1.Get(), &dxgiDescription1); this.isCompleted = true; return(true); } return(false); } else { enumAdapters1Result.Assert(); this.index++; DXGI_ADAPTER_DESC1 dxgiDescription1; dxgiAdapter1.Get()->GetDesc1(&dxgiDescription1).Assert(); if (dxgiDescription1.VendorId == MicrosoftVendorId && dxgiDescription1.DeviceId == WarpDeviceId) { continue; } HRESULT createDeviceResult = FX.D3D12CreateDevice( dxgiAdapter1.AsIUnknown().Get(), D3D_FEATURE_LEVEL_11_0, FX.__uuidof <ID3D12Device>(), null); if (FX.SUCCEEDED(createDeviceResult) && this.predicate(new GraphicsDeviceInfo(&dxgiDescription1))) { using ComPtr <ID3D12Device> d3D12Device = default; FX.D3D12CreateDevice( dxgiAdapter1.AsIUnknown().Get(), D3D_FEATURE_LEVEL_11_0, FX.__uuidof <ID3D12Device>(), d3D12Device.GetVoidAddressOf()).Assert(); if (d3D12Device.Get()->IsShaderModelSupported(D3D_SHADER_MODEL_6_0)) { this.graphicsDevice = GetOrCreateDevice(d3D12Device.Get(), (IDXGIAdapter *)dxgiAdapter1.Get(), &dxgiDescription1); return(true); } } } } }