From 16eec3e0d635d32e56e9fabe54a7a77e1ce9614b Mon Sep 17 00:00:00 2001 From: Faber Sanchez Date: Fri, 5 Jul 2024 19:48:16 -0500 Subject: [PATCH] Add a renderer using very basic dx12 --- Src/Games/FPSTest.cs | 113 ++- Src/Games/Program.cs | 3 +- Src/Xultaik.Desktop/WindowSettings.cs | 4 +- Src/Xultaik.Graphics/Buffer.cs | 178 ++++ Src/Xultaik.Graphics/BufferDescription.cs | 32 + Src/Xultaik.Graphics/BufferFlags.cs | 42 + Src/Xultaik.Graphics/Class1.cs | 7 - Src/Xultaik.Graphics/CommandList.cs | 193 ++++ Src/Xultaik.Graphics/CommandListType.cs | 28 + Src/Xultaik.Graphics/CommandQueue.cs | 176 ++++ Src/Xultaik.Graphics/ConvertExtensions.cs | 595 ++++++++++++ Src/Xultaik.Graphics/CullMode.cs | 21 + Src/Xultaik.Graphics/DescriptorAllocator.cs | 62 ++ Src/Xultaik.Graphics/Fence.cs | 64 ++ Src/Xultaik.Graphics/FillMode.cs | 19 + Src/Xultaik.Graphics/GraphicsAdapter.cs | 64 ++ Src/Xultaik.Graphics/GraphicsDevice.cs | 262 ++++++ Src/Xultaik.Graphics/GraphicsResource.cs | 42 + Src/Xultaik.Graphics/HeapType.cs | 20 + Src/Xultaik.Graphics/Image/DDSLoader.cs | 883 ++++++++++++++++++ Src/Xultaik.Graphics/Image/WICLoader.cs | 216 +++++ Src/Xultaik.Graphics/IndexType.cs | 19 + Src/Xultaik.Graphics/Interop.cs | 165 ++++ Src/Xultaik.Graphics/PipelineState.cs | 156 ++++ .../PipelineStateDescription.cs | 20 + Src/Xultaik.Graphics/PixelFormat.cs | 254 +++++ Src/Xultaik.Graphics/PrimitiveType.cs | 100 ++ Src/Xultaik.Graphics/RenderDescriptor.cs | 26 + Src/Xultaik.Graphics/Settings.cs | 19 + Src/Xultaik.Graphics/ShaderByteCode.cs | 75 ++ Src/Xultaik.Graphics/ShaderModel.cs | 28 + Src/Xultaik.Graphics/ShaderStage.cs | 31 + Src/Xultaik.Graphics/SwapChain.cs | 148 +++ Src/Xultaik.Graphics/Texture.cs | 78 ++ Src/Xultaik.Graphics/TextureData.cs | 66 ++ Src/Xultaik.Graphics/Xultaik.Graphics.csproj | 12 + 36 files changed, 4199 insertions(+), 22 deletions(-) create mode 100644 Src/Xultaik.Graphics/Buffer.cs create mode 100644 Src/Xultaik.Graphics/BufferDescription.cs create mode 100644 Src/Xultaik.Graphics/BufferFlags.cs delete mode 100644 Src/Xultaik.Graphics/Class1.cs create mode 100644 Src/Xultaik.Graphics/CommandList.cs create mode 100644 Src/Xultaik.Graphics/CommandListType.cs create mode 100644 Src/Xultaik.Graphics/CommandQueue.cs create mode 100644 Src/Xultaik.Graphics/ConvertExtensions.cs create mode 100644 Src/Xultaik.Graphics/CullMode.cs create mode 100644 Src/Xultaik.Graphics/DescriptorAllocator.cs create mode 100644 Src/Xultaik.Graphics/Fence.cs create mode 100644 Src/Xultaik.Graphics/FillMode.cs create mode 100644 Src/Xultaik.Graphics/GraphicsAdapter.cs create mode 100644 Src/Xultaik.Graphics/GraphicsDevice.cs create mode 100644 Src/Xultaik.Graphics/GraphicsResource.cs create mode 100644 Src/Xultaik.Graphics/HeapType.cs create mode 100644 Src/Xultaik.Graphics/Image/DDSLoader.cs create mode 100644 Src/Xultaik.Graphics/Image/WICLoader.cs create mode 100644 Src/Xultaik.Graphics/IndexType.cs create mode 100644 Src/Xultaik.Graphics/Interop.cs create mode 100644 Src/Xultaik.Graphics/PipelineState.cs create mode 100644 Src/Xultaik.Graphics/PipelineStateDescription.cs create mode 100644 Src/Xultaik.Graphics/PixelFormat.cs create mode 100644 Src/Xultaik.Graphics/PrimitiveType.cs create mode 100644 Src/Xultaik.Graphics/RenderDescriptor.cs create mode 100644 Src/Xultaik.Graphics/Settings.cs create mode 100644 Src/Xultaik.Graphics/ShaderByteCode.cs create mode 100644 Src/Xultaik.Graphics/ShaderModel.cs create mode 100644 Src/Xultaik.Graphics/ShaderStage.cs create mode 100644 Src/Xultaik.Graphics/SwapChain.cs create mode 100644 Src/Xultaik.Graphics/Texture.cs create mode 100644 Src/Xultaik.Graphics/TextureData.cs diff --git a/Src/Games/FPSTest.cs b/Src/Games/FPSTest.cs index f238e2c..383c83d 100644 --- a/Src/Games/FPSTest.cs +++ b/Src/Games/FPSTest.cs @@ -5,26 +5,115 @@ using System.Text; using System.Threading.Tasks; using Xultaik.Desktop; +using Xultaik.Graphics; namespace Games { - public class FPSTest + public class FPSTest :IDisposable { + public Window Window { get; set; } + + public RenderDescriptor Parameters { get; set; } + + public GraphicsAdapter Adapter { get; set; } + + public GraphicsDevice Device { get; set; } + + public SwapChain SwapChain { get; set; } + + public CommandList CommandList { get; set; } + + + + + public FPSTest() { - Window window = new(new WindowSettings() + Window = new Window(WindowSettings.Default); + + + + Parameters = new RenderDescriptor() { - Border = WindowBorder.Hidden, - Position = Point.Empty, - Size = new Size(800, 600), - State = WindowState.Normal, - CursorMode = CursorMode.Normal, - Title = "Test", - UpdateFrequency = null, - Icon = WindowResourcePtr.LoadIcon("Content\\win.ico"), + BackBufferWidth = Window.ClientSize.Width, + BackBufferHeight = Window.ClientSize.Height, + DeviceHandle = Window.WindowHandler.Value, + Settings = new Settings() + { + Fullscreen = false, + VSync = false, + }, + }; + } + + public void Initialize() + { + + Adapter = new GraphicsAdapter(); + + Device = new GraphicsDevice(Adapter, Parameters); + + SwapChain = new SwapChain(Device); + + CommandList = new CommandList(Device); + } + + + public void Run() + { + Initialize(); + + BeginRun(); + + Window?.Show(); + + Tick(); + } + + public void Tick() + { + + Window.RenderLoop(() => + { + Update(); + Draw(); }); - window.Show(); - window.RenderLoop(() => { }); + } + + + + public void BeginRun() + { + foreach (var Description in Device.NativeAdapter.Description) + Console.WriteLine(Description); + + foreach (var VendorId in Device.NativeAdapter.VendorId) + Console.WriteLine(VendorId); + + } + + public void Update() + { + + } + + public void Draw() + { + CommandList.Reset(); + + CommandList.SetViewport(0, 0, 800, 600); + CommandList.SetScissor(0, 0, 800, 600); + CommandList.ClearTargetColor(SwapChain.BackBuffer, 0.0f, 0.2f, 0.4f, 1.0f); + + CommandList.ExecuteCommandList(); + + SwapChain.Present(); + + } + + public void Dispose() + { + //Device.Dispose(); } } } diff --git a/Src/Games/Program.cs b/Src/Games/Program.cs index 0aed26b..1ba1790 100644 --- a/Src/Games/Program.cs +++ b/Src/Games/Program.cs @@ -1,3 +1,4 @@ using Games; -new FPSTest(); \ No newline at end of file +using (var App = new FPSTest()) + App.Run(); \ No newline at end of file diff --git a/Src/Xultaik.Desktop/WindowSettings.cs b/Src/Xultaik.Desktop/WindowSettings.cs index dbb92e1..bbfabda 100644 --- a/Src/Xultaik.Desktop/WindowSettings.cs +++ b/Src/Xultaik.Desktop/WindowSettings.cs @@ -11,8 +11,8 @@ public struct WindowSettings { public static WindowSettings Default => new WindowSettings { - Title = "Default", - Size = new(600, 400), + Title = "Xultaik", + Size = new(800, 600), Position = new(0, 0), State = WindowState.Normal, Border = WindowBorder.Resizable, diff --git a/Src/Xultaik.Graphics/Buffer.cs b/Src/Xultaik.Graphics/Buffer.cs new file mode 100644 index 0000000..c9d0486 --- /dev/null +++ b/Src/Xultaik.Graphics/Buffer.cs @@ -0,0 +1,178 @@ +// Copyright (c) Faber Leonardo. All Rights Reserved. https://github.com/FaberSanZ +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + + + + +using System; +using System.Collections.Generic; +using System.Text; +using Vortice.Direct3D12; +using Vortice.DXGI; + +namespace Xultaik.Graphics +{ + public unsafe class Buffer : GraphicsResource + { + public BufferDescription Description { get; private set; } + + public int SizeInBytes => Description.SizeInBytes; + + //public BufferFlags Flags => BufferFlags. Description.Flags; + + public HeapType HeapType => Description.HeapType; + + public int StructureByteStride => Description.StructureByteStride; + + + internal ID3D12Resource NativeResource; + internal CpuDescriptorHandle? constantBufferView; + internal long GPUVirtualAddress; + + + + public Buffer(GraphicsDevice device, BufferDescription description) : base(device) + { + InitializeFrom(description); + } + + public void SetData(T[] data, int offsetInBytes = 0) where T : unmanaged + { + + if (HeapType == HeapType.Upload) + { + IntPtr mappedResource = IntPtr.Zero; + NativeResource.Map(0, null, mappedResource.ToPointer()); + + Interop.MemoryHelper.Write(mappedResource, data); + + NativeResource.Unmap(0); + } + else + { + + //IntPtr mappedResource = NativeResource.Map(0); + + //Interop.MemoryHelper.Write(mappedResource, data); + + //NativeResource.Unmap(0); + //mappedResource = IntPtr.Zero; + + + //CommandList CommandList = new CommandList(GraphicsDevice); + //CommandList.Reset(); + //var commandList = CommandList.nativeCommandList; + + ////commandList.Reset(); + //// Copy from upload heap to actual resource + //commandList.CopyBufferRegion(NativeResource, 0, uploadResource, uploadOffset, SizeInBytes); + + //// Switch resource to proper read state + //commandList.ResourceBarrierTransition(NativeResource, 0, ResourceStates.CopyDestination, NativeResourceState); + + //commandList.Close(); + + //GraphicsDevice.WaitCopyQueue(); + } + } + + + public void InitializeFrom(BufferDescription description) + { + Description = description; + + ResourceStates resourceStates = ResourceStates.Common; + + + + if (description.HeapType == HeapType.Upload) + resourceStates |= ResourceStates.GenericRead; + + + else if (description.HeapType == HeapType.Readback) + resourceStates |= ResourceStates.CopyDest; + + + if ((description.Flags & BufferFlags.ConstantBuffer) != 0) + constantBufferView = CreateConstantBufferView(); + + + + + + + ResourceDescription ResourceDesc = new ResourceDescription() + { + Width = (ulong)SizeInBytes, + Height = 1, + DepthOrArraySize = 1, + Dimension = ResourceDimension.Buffer, + Alignment = 65536, + Layout = TextureLayout.RowMajor, + Flags = ResourceFlags.None, + MipLevels = 1, + Format = Format.Unknown, + SampleDescription = new SampleDescription() + { + Count = 1, + Quality = 0 + } + }; + + + + + HeapProperties heapProp = new HeapProperties() + { + Type = (Vortice.Direct3D12.HeapType)description.HeapType, + CreationNodeMask = 1, + VisibleNodeMask = 1, + CPUPageProperty = CpuPageProperty.Unknown, + MemoryPoolPreference = MemoryPool.Unknown, + + }; + + NativeResource = GraphicsDevice.NativeDevice.CreateCommittedResource(heapProp, HeapFlags.None, ResourceDesc, resourceStates); + + + + + + + + GPUVirtualAddress = (long)NativeResource.GPUVirtualAddress; + + + //return InitializeFrom(resource, description); + } + + + internal Buffer InitializeFrom(ID3D12Resource resource, BufferDescription description, int firstElement = 0, int elementCount = 0) + { + + + return this; + } + + + internal CpuDescriptorHandle CreateConstantBufferView() + { + CpuDescriptorHandle cpuHandle = GraphicsDevice.ShaderResourceViewAllocator.Allocate(1); + + int constantBufferSize = (SizeInBytes + 255) & ~255; + + ConstantBufferViewDescription cbvDescription = new ConstantBufferViewDescription() + { + BufferLocation = NativeResource!.GPUVirtualAddress, + SizeInBytes = constantBufferSize + }; + + GraphicsDevice.NativeDevice.CreateConstantBufferView(cbvDescription, cpuHandle); + + return cpuHandle; + } + + } + + +} diff --git a/Src/Xultaik.Graphics/BufferDescription.cs b/Src/Xultaik.Graphics/BufferDescription.cs new file mode 100644 index 0000000..b137f63 --- /dev/null +++ b/Src/Xultaik.Graphics/BufferDescription.cs @@ -0,0 +1,32 @@ +// Copyright (c) Faber Leonardo. All Rights Reserved. https://github.com/FaberSanZ +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xultaik.Graphics +{ + public struct BufferDescription + { + public int SizeInBytes; + + public int StructureByteStride; + + public HeapType HeapType; + + public BufferFlags Flags; + + + + public BufferDescription(int sizeInBytes, BufferFlags bufferFlags, HeapType heapType, int structureByteStride = 0) + { + SizeInBytes = sizeInBytes; + Flags = bufferFlags; + HeapType = heapType; + StructureByteStride = structureByteStride; + } + + } +} diff --git a/Src/Xultaik.Graphics/BufferFlags.cs b/Src/Xultaik.Graphics/BufferFlags.cs new file mode 100644 index 0000000..61162dc --- /dev/null +++ b/Src/Xultaik.Graphics/BufferFlags.cs @@ -0,0 +1,42 @@ +// Copyright (c) Faber Leonardo. All Rights Reserved. https://github.com/FaberSanZ +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + + + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xultaik.Graphics +{ + [Flags] + public enum BufferFlags + { + None = 0, + + ConstantBuffer = 1, + + IndexBuffer = 2, + + VertexBuffer = 4, + + RenderTarget = 8, + + ShaderResource = 16, + + UnorderedAccess = 32, + + StructuredBuffer = 64, + + StructuredAppendBuffer = UnorderedAccess | StructuredBuffer | 128, + + StructuredCounterBuffer = UnorderedAccess | StructuredBuffer | 256, + + RawBuffer = 512, + + ArgumentBuffer = 1024, + + StreamOutput = 2048, + + } +} \ No newline at end of file diff --git a/Src/Xultaik.Graphics/Class1.cs b/Src/Xultaik.Graphics/Class1.cs deleted file mode 100644 index f92053b..0000000 --- a/Src/Xultaik.Graphics/Class1.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Xultaik.Graphics -{ - public class Class1 - { - - } -} diff --git a/Src/Xultaik.Graphics/CommandList.cs b/Src/Xultaik.Graphics/CommandList.cs new file mode 100644 index 0000000..0fcb0a5 --- /dev/null +++ b/Src/Xultaik.Graphics/CommandList.cs @@ -0,0 +1,193 @@ +// Copyright (c) Faber Leonardo. All Rights Reserved. https://github.com/FaberSanZ +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + + + +using System; +using System.Collections.Generic; +using System.Text; +using Vortice.Direct3D12; +using Vortice.Direct3D; +using static Vortice.Direct3D12.D3D12; +using static Vortice.DXGI.DXGI; + +namespace Xultaik.Graphics +{ + public unsafe class CommandList : GraphicsResource + { + internal ID3D12GraphicsCommandList nativeCommandList; + internal ID3D12PipelineState pipelineState; + internal ID3D12CommandAllocator commandAllocator; + internal Fence fence; + internal long fenceValue; + + + public CommandList(GraphicsDevice device) : base(device) + { + Initialize(); + } + + + + private void Initialize() + { + commandAllocator = GraphicsDevice.NativeDevice.CreateCommandAllocator( Vortice.Direct3D12.CommandListType.Direct); + + fenceValue = 0; + fence = new Fence(GraphicsDevice, fenceValue); + + nativeCommandList = GraphicsDevice.NativeDevice.CreateCommandList(0,Vortice.Direct3D12.CommandListType.Direct, commandAllocator, null); + // We close it as it starts in open state + nativeCommandList.Close(); + + } + + + + public void SetPipelineState(PipelineState pipelineState) + { + + nativeCommandList.SetPipelineState(pipelineState.oldPipelineState); + + nativeCommandList.SetGraphicsRootSignature(pipelineState.RootSignature); + + } + + + + public void Reset() + { + commandAllocator.Reset(); + nativeCommandList.Reset(commandAllocator, null); + } + + + public void SetViewport(int x, int y, int w, int h) + { + var viewport = new Vortice.Mathematics.Viewport + { + //Width = w, + //Height = h, + //X = x, + //Y = y, + //MaxDepth = 1.0f, + //MinDepth = 0.0f + }; + nativeCommandList.RSSetViewport(viewport); + } + + + public void SetScissor(int x, int y, int w, int h) + { + + + + nativeCommandList.RSSetScissorRect(x,y); + } + + + + + + public void SetRenderTargets(Texture depthStencilBuffer, Texture[] renderTargets) + { + CpuDescriptorHandle[] cpuDescriptorHandles = new CpuDescriptorHandle[renderTargets.Length]; + + for (int i = 0; i < cpuDescriptorHandles.Length; i++) + cpuDescriptorHandles[i] = renderTargets[i].NativeRenderTargetView; + + + nativeCommandList.OMSetRenderTargets(cpuDescriptorHandles, depthStencilBuffer?.NativeDepthStencilView); + } + + + public void ClearTargetColor(Texture texture, float r, float g, float b, float a) + { + ResourceTransition(texture, ResourceStates.RenderTarget, ResourceStates.Present); + + nativeCommandList.ClearRenderTargetView(texture.NativeRenderTargetView, new Vortice.Mathematics.Color4(r, g, b, a)); + nativeCommandList.OMSetRenderTargets(texture.NativeRenderTargetView); + + } + + + + public void ClearDepth(Texture texture, float depth) + { + ResourceTransition(texture, ResourceStates.DepthRead, ResourceStates.Present); + nativeCommandList.ClearDepthStencilView(texture.NativeDepthStencilView, ClearFlags.Depth, depth, 0); + } + + + + + + public void ResourceTransition(Texture resource, ResourceStates before, ResourceStates after) + { + //ResourceBarrier barrier = new ResourceBarrier(new ResourceTransitionBarrier(resource, (ResourceStates)before, (ResourceStates)after)); + var barriers = stackalloc ResourceBarrier[1]; + barriers[0] = new ResourceBarrier(new ResourceTransitionBarrier(resource.Resource, (ResourceStates)before, (ResourceStates)after)); + + nativeCommandList.ResourceBarrier(*barriers); + + + //NativeCommandList.ResourceBarrierTransition(resource.Resource, (ResourceStates)before, (ResourceStates)after); + } + + + + public void SetTopology(PrimitiveType primitiveType) => nativeCommandList.IASetPrimitiveTopology(ConvertExtensions.ToPrimitiveType(primitiveType)); + + + public void SetVertexBuffer(Buffer buffer) + { + + VertexBufferView vertexBufferView = new VertexBufferView() + { + BufferLocation = (ulong)buffer.GPUVirtualAddress, + SizeInBytes = buffer.SizeInBytes, + StrideInBytes = buffer.StructureByteStride + }; + nativeCommandList.IASetVertexBuffers(0,vertexBufferView); + } + + + public void SetIndexBuffer(Buffer buffer, IndexType type) + { + IndexBufferView indexBufferView = new IndexBufferView() + { + BufferLocation = (ulong)buffer.GPUVirtualAddress, + SizeInBytes = buffer.SizeInBytes, + Format = ConvertExtensions.ToIndexType(type), + }; + + nativeCommandList.IASetIndexBuffer(indexBufferView); + } + + + + public void DrawInstanced(int count) => nativeCommandList.DrawInstanced(count, 1, 0, 0); + + + public void DrawIndexedInstanced(int indexCountPerInstance, int instanceCount, int startIndexLocation, int baseVertexLocation, int startInstanceLocation) => + nativeCommandList.DrawIndexedInstanced(indexCountPerInstance, instanceCount, startIndexLocation, baseVertexLocation, startInstanceLocation); + + + + public void ExecuteCommandList() + { + nativeCommandList.Close(); + GraphicsDevice.NativeDirectCommandQueue.ExecuteCommandList(this); + + fenceValue++; + fence.Signal(GraphicsDevice.NativeDirectCommandQueue, fenceValue); + + fence.Wait(fenceValue); + + //commandAllocator.Reset(); + //nativeCommandList.Reset(commandAllocator, null); + } + + + } +} diff --git a/Src/Xultaik.Graphics/CommandListType.cs b/Src/Xultaik.Graphics/CommandListType.cs new file mode 100644 index 0000000..9a868d8 --- /dev/null +++ b/Src/Xultaik.Graphics/CommandListType.cs @@ -0,0 +1,28 @@ +// Copyright (c) Faber Leonardo. All Rights Reserved. https://github.com/FaberSanZ +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + + + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xultaik.Graphics +{ + public enum CommandListType + { + Direct = 0, + + Bundle = 1, + + Compute = 2, + + Copy = 3, + + VideoDecode = 4, + + VideoProcess = 5, + + VideoEncode = 6 + } +} diff --git a/Src/Xultaik.Graphics/CommandQueue.cs b/Src/Xultaik.Graphics/CommandQueue.cs new file mode 100644 index 0000000..3918625 --- /dev/null +++ b/Src/Xultaik.Graphics/CommandQueue.cs @@ -0,0 +1,176 @@ +// Copyright (c) Faber Leonardo. All Rights Reserved. https://github.com/FaberSanZ +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + + +using System; +using System.Collections.Generic; +using System.Text; +using Vortice.Direct3D12; + +namespace Xultaik.Graphics +{ + public class CommandQueue : GraphicsResource + { + internal ID3D12CommandQueue Queue { get; private set; } + + public CommandListType Type { get; set; } + + public CommandQueue(GraphicsDevice device, CommandListType type) : base(device) + { + Type = type; + + Recreate(); + + Queue = CreateCommandQueueDirect(); + + } + + + + public CommandQueue(GraphicsDevice device) : base(device) + { + Recreate(); + } + + + public void Recreate() + { + switch (Type) + { + case CommandListType.Direct: + Queue = CreateCommandQueueDirect(); + break; + + case CommandListType.Bundle: + Queue = CreateCommandQueueBundle(); + break; + + case CommandListType.Compute: + Queue = CreateCommandQueueCompute(); + break; + + case CommandListType.Copy: + Queue = CreateCommandQueueCopy(); + break; + + case CommandListType.VideoDecode: + Queue = CreateCommandQueueVideoDecode(); + break; + + case CommandListType.VideoProcess: + Queue = CreateCommandQueueVideoProcess(); + break; + + case CommandListType.VideoEncode: + Queue = CreateCommandQueueVideoEncode(); + break; + + default: + throw new ArgumentOutOfRangeException(nameof(Type)); + + } + } + + public void ExecuteCommandList(CommandList commandList) + { + Queue.ExecuteCommandList(commandList.nativeCommandList); + } + + public void Wait(/*Fence fence*/) + { + Queue.Wait(new ID3D12Fence(IntPtr.Zero), 20); + } + + + + internal ID3D12CommandQueue CreateCommandQueueDirect() + { + // Describe and create the command queue. + CommandQueueDescription QueueDesc = new CommandQueueDescription() + { + Type = Vortice.Direct3D12.CommandListType.Direct, + Flags = CommandQueueFlags.None, + }; + + return GraphicsDevice.NativeDevice.CreateCommandQueue(QueueDesc); + } + + + internal ID3D12CommandQueue CreateCommandQueueCopy() + { + // Describe and create the command queue. + CommandQueueDescription QueueDesc = new CommandQueueDescription() + { + Type = Vortice.Direct3D12.CommandListType.Copy, + Flags = CommandQueueFlags.None, + }; + + return GraphicsDevice.NativeDevice.CreateCommandQueue(QueueDesc); + } + + + internal ID3D12CommandQueue CreateCommandQueueBundle() + { + // Describe and create the command queue. + CommandQueueDescription QueueDesc = new CommandQueueDescription() + { + Type = Vortice.Direct3D12.CommandListType.Bundle, + Flags = CommandQueueFlags.None, + }; + + return GraphicsDevice.NativeDevice.CreateCommandQueue(QueueDesc); + } + + + internal ID3D12CommandQueue CreateCommandQueueCompute() + { + // Describe and create the command queue. + CommandQueueDescription QueueDesc = new CommandQueueDescription() + { + Type = Vortice.Direct3D12.CommandListType.Compute, + Flags = CommandQueueFlags.None, + }; + + return GraphicsDevice.NativeDevice.CreateCommandQueue(QueueDesc); + } + + + internal ID3D12CommandQueue CreateCommandQueueVideoDecode() + { + // Describe and create the command queue. + CommandQueueDescription QueueDesc = new CommandQueueDescription() + { + Type = Vortice.Direct3D12.CommandListType.VideoDecode, + Flags = CommandQueueFlags.None, + }; + + return GraphicsDevice.NativeDevice.CreateCommandQueue(QueueDesc); + } + + internal ID3D12CommandQueue CreateCommandQueueVideoEncode() + { + // Describe and create the command queue. + CommandQueueDescription QueueDesc = new CommandQueueDescription() + { + Type = Vortice.Direct3D12.CommandListType.VideoEncode, + Flags = CommandQueueFlags.None, + }; + + return GraphicsDevice.NativeDevice.CreateCommandQueue(QueueDesc); + } + + + internal ID3D12CommandQueue CreateCommandQueueVideoProcess() + { + // Describe and create the command queue. + CommandQueueDescription QueueDesc = new CommandQueueDescription() + { + Type = Vortice.Direct3D12.CommandListType.VideoProcess, + Flags = CommandQueueFlags.None, + }; + + return GraphicsDevice.NativeDevice.CreateCommandQueue(QueueDesc); + } + } + +} diff --git a/Src/Xultaik.Graphics/ConvertExtensions.cs b/Src/Xultaik.Graphics/ConvertExtensions.cs new file mode 100644 index 0000000..3be176e --- /dev/null +++ b/Src/Xultaik.Graphics/ConvertExtensions.cs @@ -0,0 +1,595 @@ +// Copyright (c) Faber Leonardo. All Rights Reserved. https://github.com/FaberSanZ +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + + + +using System; +using System.Collections.Generic; +using System.Text; +using Vortice.DXGI; +using Vortice.Direct3D; +using Vortice.Direct3D12; +using Vortice.Dxc; + +namespace Xultaik.Graphics +{ + public static class ConvertExtensions + { + public static string GetDefaultEntryPoint(ShaderStage stage) + { + switch (stage) + { + case ShaderStage.VertexShader: + return "VS"; + + case ShaderStage.PixelShader: + return "PS"; + + case ShaderStage.GeometryShader: + return "GS"; + + case ShaderStage.HullShader: + return "HS"; + + case ShaderStage.DomainShader: + return "DS"; + + case ShaderStage.ComputeShader: + return "CS"; + + default: + return string.Empty; + } + } + + + internal static DxcShaderModel ToDxcShaderModel(ShaderModel shaderStage) + { + switch (shaderStage) + { + case ShaderModel.Model6_0: + return new DxcShaderModel(6, 0); + + case ShaderModel.Model6_1: + return new DxcShaderModel(6, 1); + + case ShaderModel.Model6_2: + return new DxcShaderModel(6, 2); + + case ShaderModel.Model6_3: + return new DxcShaderModel(6, 3); + + case ShaderModel.Model6_4: + return new DxcShaderModel(6, 4); + + case ShaderModel.Model6_5: + return new DxcShaderModel(6, 5); + + default: + throw new ArgumentOutOfRangeException(nameof(shaderStage)); + } + } + + internal static DxcShaderStage ToDxcShaderStage(ShaderStage shaderStage) + { + switch (shaderStage) + { + case ShaderStage.VertexShader: + return DxcShaderStage.Vertex; + + case ShaderStage.PixelShader: + return DxcShaderStage.Pixel; + + case ShaderStage.GeometryShader: + return DxcShaderStage.Geometry; + + case ShaderStage.HullShader: + return DxcShaderStage.Hull; + + case ShaderStage.DomainShader: + return DxcShaderStage.Domain; + + case ShaderStage.ComputeShader: + return DxcShaderStage.Compute; + + //case ShaderStage.Library: + // return DxcShaderStage.Library; + + //case ShaderStage.Count: + // return DxcShaderStage.Count; + + default: + throw new ArgumentOutOfRangeException(nameof(shaderStage)); + } + } + + + internal static Format ToIndexType(IndexType primitiveType) + { + switch (primitiveType) + { + case IndexType.UInt32: + return Format.R32_UInt; + + case IndexType.UInt16: + return Format.R16_UInt; + + default: + throw new ArgumentOutOfRangeException(nameof(primitiveType)); + } + } + + + internal static PrimitiveTopology ToPrimitiveType(PrimitiveType primitiveType) + { + switch (primitiveType) + { + case PrimitiveType.PointList: + return PrimitiveTopology.PointList; + + case PrimitiveType.LineList: + return PrimitiveTopology.LineList; + + case PrimitiveType.LineStrip: + return PrimitiveTopology.LineStrip; + + case PrimitiveType.TriangleList: + return PrimitiveTopology.TriangleList; + + case PrimitiveType.TriangleStrip: + return PrimitiveTopology.TriangleStrip; + + case PrimitiveType.LineListAdjacency: + return PrimitiveTopology.LineListAdjacency; + + case PrimitiveType.LineStripAdjacency: + return PrimitiveTopology.LineStripAdjacency; + + case PrimitiveType.TriangleListAdjacency: + return PrimitiveTopology.TriangleListAdjacency; + + case PrimitiveType.TriangleStripAdjacency: + return PrimitiveTopology.TriangleStripAdjacency; + + default: + throw new ArgumentOutOfRangeException(nameof(primitiveType)); + } + } + + + internal static Vortice.Direct3D12.FillMode ToFillMode(FillMode fillMode) + { + switch (fillMode) + { + case FillMode.Solid: + return Vortice.Direct3D12.FillMode.Solid; + + case FillMode.Wireframe: + return Vortice.Direct3D12.FillMode.Wireframe; + + default: + throw new ArgumentOutOfRangeException(nameof(fillMode)); + } + } + + + internal static Vortice.Direct3D12.CullMode ToCullMode(CullMode cullMode) + { + switch (cullMode) + { + case CullMode.Back: + return Vortice.Direct3D12.CullMode.Back; + + case CullMode.Front: + return Vortice.Direct3D12.CullMode.Front; + + case CullMode.None: + return Vortice.Direct3D12.CullMode.None; + + default: + throw new ArgumentOutOfRangeException(nameof(cullMode)); + } + } + + + public static bool IsUAVCompatibleFormat(PixelFormat format) + { + switch (format) + { + case PixelFormat.R32G32B32A32_Float: + case PixelFormat.R32G32B32A32_UInt: + case PixelFormat.R32G32B32A32_SInt: + case PixelFormat.R16G16B16A16_Float: + case PixelFormat.R16G16B16A16_UInt: + case PixelFormat.R16G16B16A16_SInt: + case PixelFormat.R8G8B8A8_UNorm: + case PixelFormat.R8G8B8A8_UInt: + case PixelFormat.R8G8B8A8_SInt: + case PixelFormat.R32_Float: + case PixelFormat.R32_UInt: + case PixelFormat.R32_SInt: + case PixelFormat.R16_Float: + case PixelFormat.R16_UInt: + case PixelFormat.R16_SInt: + case PixelFormat.R8_UNorm: + case PixelFormat.R8_UInt: + case PixelFormat.R8_SInt: + return true; + + default: + return false; + } + } + + + internal static Format ToPixelFormat(PixelFormat format) + { + + switch (format) + { + case PixelFormat.Unknown: + return Format.Unknown; + + case PixelFormat.R32G32B32A32_Typeless: + return Format.R32G32B32A32_Typeless; + + case PixelFormat.R32G32B32A32_Float: + return Format.R32G32B32A32_Float; + + case PixelFormat.R32G32B32A32_UInt: + return Format.R32G32B32A32_UInt; + + case PixelFormat.R32G32B32A32_SInt: + return Format.R32G32B32A32_SInt; + + case PixelFormat.R32G32B32_Typeless: + return Format.R32G32B32_Typeless; + + case PixelFormat.R32G32B32_Float: + return Format.R32G32B32_Float; + + case PixelFormat.R32G32B32_UInt: + return Format.R32G32B32_UInt; + + case PixelFormat.R32G32B32_SInt: + return Format.R32G32B32_SInt; + + case PixelFormat.R16G16B16A16_Typeless: + return Format.R16G16B16A16_Typeless; + + case PixelFormat.R16G16B16A16_Float: + return Format.R16G16B16A16_Float; + + case PixelFormat.R16G16B16A16_UNorm: + return Format.R16G16B16A16_UNorm; + + case PixelFormat.R16G16B16A16_UInt: + return Format.R16G16B16A16_UInt; + + case PixelFormat.R16G16B16A16_SNorm: + return Format.R16G16B16A16_SNorm; + + case PixelFormat.R16G16B16A16_SInt: + return Format.R16G16B16A16_SInt; + + case PixelFormat.R32G32_Typeless: + return Format.R32G32_Typeless; + + case PixelFormat.R32G32_Float: + return Format.R32G32_Float; + + case PixelFormat.R32G32_UInt: + return Format.R32G32_UInt; + + case PixelFormat.R32G32_SInt: + return Format.R32G32_SInt; + + case PixelFormat.R32G8X24_Typeless: + return Format.R32G8X24_Typeless; + + case PixelFormat.D32_Float_S8X24_UInt: + return Format.D32_Float_S8X24_UInt; + + case PixelFormat.R32_Float_X8X24_Typeless: + return Format.R32_Float_X8X24_Typeless; + + case PixelFormat.X32_Typeless_G8X24_UInt: + return Format.X32_Typeless_G8X24_UInt; + + case PixelFormat.R10G10B10A2_Typeless: + return Format.R10G10B10A2_Typeless; + + case PixelFormat.R10G10B10A2_UNorm: + return Format.R10G10B10A2_UNorm; + + case PixelFormat.R10G10B10A2_UInt: + return Format.R10G10B10A2_UInt; + + case PixelFormat.R11G11B10_Float: + return Format.R11G11B10_Float; + + case PixelFormat.R8G8B8A8_Typeless: + return Format.R8G8B8A8_Typeless; + + case PixelFormat.R8G8B8A8_UNorm: + return Format.R8G8B8A8_UNorm; + + case PixelFormat.R8G8B8A8_UNorm_SRgb: + return Format.R8G8B8A8_UNorm_SRgb; + + case PixelFormat.R8G8B8A8_UInt: + return Format.R8G8B8A8_UInt; + + case PixelFormat.R8G8B8A8_SNorm: + return Format.R8G8B8A8_SNorm; + + case PixelFormat.R8G8B8A8_SInt: + return Format.R8G8B8A8_SInt; + + case PixelFormat.R16G16_Typeless: + return Format.R16G16_Typeless; + + case PixelFormat.R16G16_Float: + return Format.R16G16_Float; + + case PixelFormat.R16G16_UNorm: + return Format.R16G16_UNorm; + + case PixelFormat.R16G16_UInt: + return Format.R16G16_UInt; + + case PixelFormat.R16G16_SNorm: + return Format.R16G16_SNorm; + + case PixelFormat.R16G16_SInt: + return Format.R16G16_SInt; + + case PixelFormat.R32_Typeless: + return Format.R32_Typeless; + + case PixelFormat.D32_Float: + return Format.D32_Float; + + case PixelFormat.R32_Float: + return Format.R32_Float; + + case PixelFormat.R32_UInt: + return Format.R32_UInt; + + case PixelFormat.R32_SInt: + return Format.R32_SInt; + + case PixelFormat.R24G8_Typeless: + return Format.R24G8_Typeless; + + case PixelFormat.D24_UNorm_S8_UInt: + return Format.D24_UNorm_S8_UInt; + + case PixelFormat.R24_UNorm_X8_Typeless: + return Format.R24_UNorm_X8_Typeless; + + case PixelFormat.X24_Typeless_G8_UInt: + return Format.X24_Typeless_G8_UInt; + + case PixelFormat.R8G8_Typeless: + return Format.R8G8_Typeless; + + case PixelFormat.R8G8_UNorm: + return Format.R8G8_UNorm; + + case PixelFormat.R8G8_UInt: + return Format.R8G8_UInt; + + case PixelFormat.R8G8_SNorm: + return Format.R8G8_SNorm; + + case PixelFormat.R8G8_SInt: + return Format.R8G8_SInt; + + case PixelFormat.R16_Typeless: + return Format.R16_Typeless; + + case PixelFormat.R16_Float: + return Format.R16_Float; + + case PixelFormat.D16_UNorm: + return Format.D16_UNorm; + + case PixelFormat.R16_UNorm: + return Format.R16_UNorm; + + case PixelFormat.R16_UInt: + return Format.R16_UInt; + + case PixelFormat.R16_SNorm: + return Format.R16_SNorm; + + case PixelFormat.R16_SInt: + return Format.R16_SInt; + + case PixelFormat.R8_Typeless: + return Format.R8_Typeless; + + case PixelFormat.R8_UNorm: + return Format.R8_UNorm; + + case PixelFormat.R8_UInt: + return Format.R8_UInt; + + case PixelFormat.R8_SNorm: + return Format.R8_SNorm; + + case PixelFormat.R8_SInt: + return Format.R8_SInt; + + case PixelFormat.A8_UNorm: + return Format.A8_UNorm; + + case PixelFormat.R1_UNorm: + return Format.R1_UNorm; + + //case PixelFormat.R9G9B9E5_Sharedexp: + // return Format.R9G9B9E5_Sharedexp; + + case PixelFormat.R8G8_B8G8_UNorm: + return Format.R8G8_B8G8_UNorm; + + case PixelFormat.G8R8_G8B8_UNorm: + return Format.G8R8_G8B8_UNorm; + + case PixelFormat.BC1_Typeless: + return Format.BC1_Typeless; + + case PixelFormat.BC1_UNorm: + return Format.BC1_UNorm; + + case PixelFormat.BC1_UNorm_SRgb: + return Format.BC1_UNorm_SRgb; + + case PixelFormat.BC2_Typeless: + return Format.BC2_Typeless; + + case PixelFormat.BC2_UNorm: + return Format.BC2_UNorm; + + case PixelFormat.BC2_UNorm_SRgb: + return Format.BC2_UNorm_SRgb; + + case PixelFormat.BC3_Typeless: + return Format.BC3_Typeless; + + case PixelFormat.BC3_UNorm: + return Format.BC3_UNorm; + + case PixelFormat.BC3_UNorm_SRgb: + return Format.BC3_UNorm_SRgb; + + case PixelFormat.BC4_Typeless: + return Format.BC4_Typeless; + + case PixelFormat.BC4_UNorm: + return Format.BC4_UNorm; + + case PixelFormat.BC4_SNorm: + return Format.BC4_SNorm; + + case PixelFormat.BC5_Typeless: + return Format.BC5_Typeless; + + case PixelFormat.BC5_UNorm: + return Format.BC5_UNorm; + + case PixelFormat.BC5_SNorm: + return Format.BC5_SNorm; + + case PixelFormat.B5G6R5_UNorm: + return Format.B5G6R5_UNorm; + + case PixelFormat.B5G5R5A1_UNorm: + return Format.B5G5R5A1_UNorm; + + case PixelFormat.B8G8R8A8_UNorm: + return Format.B8G8R8A8_UNorm; + + case PixelFormat.B8G8R8X8_UNorm: + return Format.B8G8R8X8_UNorm; + + case PixelFormat.R10G10B10_Xr_Bias_A2_UNorm: + return Format.R10G10B10_Xr_Bias_A2_UNorm; + + case PixelFormat.B8G8R8A8_Typeless: + return Format.B8G8R8A8_Typeless; + + case PixelFormat.B8G8R8A8_UNorm_SRgb: + return Format.B8G8R8A8_UNorm_SRgb; + + case PixelFormat.B8G8R8X8_Typeless: + return Format.B8G8R8X8_Typeless; + + case PixelFormat.B8G8R8X8_UNorm_SRgb: + return Format.B8G8R8X8_UNorm_SRgb; + + case PixelFormat.BC6H_Typeless: + return Format.BC6H_Typeless; + + case PixelFormat.BC6H_Uf16: + return Format.BC6H_Uf16; + + case PixelFormat.BC6H_Sf16: + return Format.BC6H_Sf16; + + case PixelFormat.BC7_Typeless: + return Format.BC7_Typeless; + + case PixelFormat.BC7_UNorm: + return Format.BC7_UNorm; + + case PixelFormat.BC7_UNorm_SRgb: + return Format.BC7_UNorm_SRgb; + + case PixelFormat.AYUV: + return Format.AYUV; + + case PixelFormat.Y410: + return Format.Y410; + + case PixelFormat.Y416: + return Format.Y416; + + case PixelFormat.NV12: + return Format.NV12; + + case PixelFormat.P010: + return Format.P010; + + case PixelFormat.P016: + return Format.P016; + + case PixelFormat.Opaque420: + return Format.Opaque420; + + case PixelFormat.YUY2: + return Format.YUY2; + + case PixelFormat.Y210: + return Format.Y210; + + case PixelFormat.Y216: + return Format.Y216; + + case PixelFormat.NV11: + return Format.NV11; + + case PixelFormat.AI44: + return Format.AI44; + + case PixelFormat.IA44: + return Format.IA44; + + case PixelFormat.P8: + return Format.P8; + + case PixelFormat.A8P8: + return Format.A8P8; + + case PixelFormat.B4G4R4A4_UNorm: + return Format.B4G4R4A4_UNorm; + + case PixelFormat.P208: + return Format.P208; + + case PixelFormat.V208: + return Format.V208; + + case PixelFormat.V408: + return Format.V408; + + default: + throw new ArgumentOutOfRangeException(nameof(format)); + } + + + + } + } +} diff --git a/Src/Xultaik.Graphics/CullMode.cs b/Src/Xultaik.Graphics/CullMode.cs new file mode 100644 index 0000000..1aa220c --- /dev/null +++ b/Src/Xultaik.Graphics/CullMode.cs @@ -0,0 +1,21 @@ +// Copyright (c) Faber Leonardo. All Rights Reserved. https://github.com/FaberSanZ +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + + + + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xultaik.Graphics +{ + public enum CullMode : int + { + None = unchecked(0), + + Front = unchecked(1), + + Back = unchecked(2), + } +} diff --git a/Src/Xultaik.Graphics/DescriptorAllocator.cs b/Src/Xultaik.Graphics/DescriptorAllocator.cs new file mode 100644 index 0000000..a450be2 --- /dev/null +++ b/Src/Xultaik.Graphics/DescriptorAllocator.cs @@ -0,0 +1,62 @@ +// Copyright (c) Faber Leonardo. All Rights Reserved. https://github.com/FaberSanZ +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + + + + +using System; +using System.Collections.Generic; +using System.Text; +using Vortice.Direct3D12; + +namespace Xultaik.Graphics +{ + public class DescriptorAllocator : GraphicsResource + { + private const int DescriptorPerHeap = 256; + private DescriptorHeapType DescriptorHeapType; + private ID3D12DescriptorHeap currentHeap; + private CpuDescriptorHandle currentHandle; + private int remainingHandles; + private readonly int DescriptorSize; + + public DescriptorAllocator(GraphicsDevice device, DescriptorHeapType descriptorHeapType) : base(device) + { + DescriptorHeapType = descriptorHeapType; + DescriptorSize = device.NativeDevice.GetDescriptorHandleIncrementSize(descriptorHeapType); + } + + public void Dispose() + { + currentHeap?.Dispose(); + currentHeap = null; + } + + internal CpuDescriptorHandle Allocate(int count) + { + if (currentHeap == null || remainingHandles < count) + { + + DescriptorHeapDescription descriptorHeapDescription = new DescriptorHeapDescription() + { + Flags = DescriptorHeapFlags.None, + Type = DescriptorHeapType, + DescriptorCount = DescriptorPerHeap, + NodeMask = 1, + }; + + currentHeap = GraphicsDevice.NativeDevice.CreateDescriptorHeap(descriptorHeapDescription); + remainingHandles = DescriptorPerHeap; + currentHandle = currentHeap.GetCPUDescriptorHandleForHeapStart(); + } + + CpuDescriptorHandle result = currentHandle; + + currentHandle.Ptr += (uint)DescriptorSize; + remainingHandles -= count; + + return result; + } + + } +} diff --git a/Src/Xultaik.Graphics/Fence.cs b/Src/Xultaik.Graphics/Fence.cs new file mode 100644 index 0000000..83a13e6 --- /dev/null +++ b/Src/Xultaik.Graphics/Fence.cs @@ -0,0 +1,64 @@ +// Copyright (c) Faber Leonardo. All Rights Reserved. https://github.com/FaberSanZ +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + + + +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using Vortice.Direct3D12; + +namespace Xultaik.Graphics +{ + public class Fence : GraphicsResource + { + + internal ID3D12Fence fence; + internal AutoResetEvent fenceEvent; + + public Fence(GraphicsDevice device, long initialValue) : base(device) + { + Recreate(initialValue); + } + + public void Recreate(long initialValue) + { + fence = GraphicsDevice.NativeDevice.CreateFence((ulong)initialValue, FenceFlags.None); + fenceEvent = new AutoResetEvent(false); + } + + public void Signal(CommandQueue queue, long fenceValue) + { + queue.Queue.Signal(fence, (ulong)fenceValue); + } + + public void Wait(long fenceValue) + { + if (fence.CompletedValue < (ulong)fenceValue) + { + fence.SetEventOnCompletion((ulong)fenceValue, fenceEvent); + fenceEvent.WaitOne(); + } + } + + public bool IsSignaled(long fenceValue) + { + return fence.CompletedValue >= (ulong)fenceValue; + } + + public void Clear(long fenceValue) + { + fence.Signal((ulong)fenceValue); + } + + + + + //public void Dispose() + //{ + // //device.NativeDevice.DeferredRelease(ref fence); + // //fenceEvent.Dispose(); + //} + } +} diff --git a/Src/Xultaik.Graphics/FillMode.cs b/Src/Xultaik.Graphics/FillMode.cs new file mode 100644 index 0000000..416aadf --- /dev/null +++ b/Src/Xultaik.Graphics/FillMode.cs @@ -0,0 +1,19 @@ +// Copyright (c) Faber Leonardo. All Rights Reserved. https://github.com/FaberSanZ +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + + + + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xultaik.Graphics +{ + public enum FillMode : int + { + Wireframe = unchecked(0), + + Solid = unchecked(1), + } +} diff --git a/Src/Xultaik.Graphics/GraphicsAdapter.cs b/Src/Xultaik.Graphics/GraphicsAdapter.cs new file mode 100644 index 0000000..6b4b474 --- /dev/null +++ b/Src/Xultaik.Graphics/GraphicsAdapter.cs @@ -0,0 +1,64 @@ +// Copyright (c) Faber Leonardo. All Rights Reserved. https://github.com/FaberSanZ +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + + +using System; +using System.Collections.Generic; +using System.Text; +using Vortice; +using Vortice.DXGI; +using static Vortice.DXGI.DXGI; + +namespace Xultaik.Graphics +{ + public class GraphicsAdapter + { + public List Description { get; private set; } = new List(); + + public List VendorId { get; private set; } = new List(); + + + + internal IDXGIAdapter Adapter; + internal List Adapters = new List(); + internal IDXGIFactory4 NativeFactory; + + public GraphicsAdapter() + { + InitializeFromImpl(); + } + + + + + public void Recreate() + { + InitializeFromImpl(); + } + + internal void InitializeFromImpl() + { + + if (CreateDXGIFactory2(true, out IDXGIFactory4 tempDXGIFactory4).Failure) + throw new InvalidOperationException("Cannot create IDXGIFactory4"); + + + NativeFactory = tempDXGIFactory4; + + + NativeFactory.EnumAdapters1(0, out var adapter); + + AdapterDescription1 desc = adapter.Description1; + + + + Adapters.Add(adapter); + Description.Add(adapter.Description.Description); + VendorId.Add(adapter.Description.DeviceId); + + + Adapter = Adapters[0]; // TODO: + + } + } +} diff --git a/Src/Xultaik.Graphics/GraphicsDevice.cs b/Src/Xultaik.Graphics/GraphicsDevice.cs new file mode 100644 index 0000000..2f4bd1d --- /dev/null +++ b/Src/Xultaik.Graphics/GraphicsDevice.cs @@ -0,0 +1,262 @@ +// Copyright (c) Faber Leonardo. All Rights Reserved. https://github.com/FaberSanZ +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + + + + + +using System; +using System.Collections.Generic; +using System.Text; +using Vortice.Direct3D12; +using Vortice.Direct3D12.Debug; +using Vortice.Direct3D; +using Vortice.DXGI; +using static Vortice.Direct3D12.D3D12; +using static Vortice.DXGI.DXGI; + +namespace Xultaik.Graphics +{ + public sealed unsafe class GraphicsDevice : IDisposable + { + public CommandQueue NativeDirectCommandQueue { get; private set; } + + public GraphicsAdapter NativeAdapter { get; } + + public RenderDescriptor NativeParameters { get; internal set; } + + //public SwapChain NativeSwapChain { get; } + + public DescriptorAllocator DepthStencilViewAllocator { get; private set; } + + public DescriptorAllocator RenderTargetViewAllocator { get; private set; } + public DescriptorAllocator ShaderResourceViewAllocator { get; internal set; } + + internal ID3D12Device5 NativeDevice; + + public GraphicsDevice() + { + NativeAdapter = new GraphicsAdapter(); + InitializeFromImpl(); + } + + public GraphicsDevice(GraphicsAdapter graphicsAdapter, RenderDescriptor presentation) + { + NativeAdapter = graphicsAdapter; + NativeParameters = presentation; + InitializeFromImpl(); + } + + + public void InitializeFromImpl() + { + InitializePlatformDevice(); + } + + + + + private void InitializePlatformDevice() + { + + NativeDevice = CreateDevice(NativeAdapter); + + + SupportedFeature(); + + + + + + // Create the NativeCommandQueue + NativeDirectCommandQueue = CreateCommandQueueDirect(); + + CreateDescriptorAllocators(); + + } + + public bool SupportedFeature() + { + FeatureDataD3D12Options1 Options1 = NativeDevice.CheckFeatureSupport(Vortice.Direct3D12.Feature.Options1); + FeatureDataD3D12Options2 Options2 = NativeDevice.CheckFeatureSupport(Vortice.Direct3D12.Feature.Options2); + FeatureDataD3D12Options3 Options3 = NativeDevice.CheckFeatureSupport(Vortice.Direct3D12.Feature.Options3); + FeatureDataD3D12Options4 Options4 = NativeDevice.CheckFeatureSupport(Vortice.Direct3D12.Feature.Options4); + FeatureDataD3D12Options5 Options5 = NativeDevice.CheckFeatureSupport(Vortice.Direct3D12.Feature.Options5); + FeatureDataD3D12Options6 Options6 = NativeDevice.CheckFeatureSupport(Vortice.Direct3D12.Feature.Options6); + FeatureDataD3D12Options7 Options7 = NativeDevice.CheckFeatureSupport(Vortice.Direct3D12.Feature.Options7); + FeatureDataD3D12Options8 Options8 = NativeDevice.CheckFeatureSupport(Vortice.Direct3D12.Feature.Options8); + FeatureDataD3D12Options9 Options9 = NativeDevice.CheckFeatureSupport(Vortice.Direct3D12.Feature.Options9); + FeatureDataD3D12Options10 Options10 = NativeDevice.CheckFeatureSupport(Vortice.Direct3D12.Feature.Options10); + FeatureDataD3D12Options11 Options11 = NativeDevice.CheckFeatureSupport(Vortice.Direct3D12.Feature.Options11); + FeatureDataD3D12Options12 Options12 = NativeDevice.CheckFeatureSupport(Vortice.Direct3D12.Feature.Options12); + FeatureDataD3D12Options13 Options13 = NativeDevice.CheckFeatureSupport(Vortice.Direct3D12.Feature.Options13); + FeatureDataD3D12Options14 Options14 = NativeDevice.CheckFeatureSupport(Vortice.Direct3D12.Feature.Options14); + FeatureDataD3D12Options15 Options15 = NativeDevice.CheckFeatureSupport(Vortice.Direct3D12.Feature.Options15); + FeatureDataD3D12Options16 Options16 = NativeDevice.CheckFeatureSupport(Vortice.Direct3D12.Feature.Options16); + FeatureDataD3D12Options17 Options17 = NativeDevice.CheckFeatureSupport(Vortice.Direct3D12.Feature.Options17); + FeatureDataD3D12Options18 Options18 = NativeDevice.CheckFeatureSupport(Vortice.Direct3D12.Feature.Options18); + FeatureDataD3D12Options19 Options19 = NativeDevice.CheckFeatureSupport(Vortice.Direct3D12.Feature.Options19); + FeatureDataD3D12Options20 Options20 = NativeDevice.CheckFeatureSupport(Vortice.Direct3D12.Feature.Options20); + FeatureDataD3D12Options21 Options21 = NativeDevice.CheckFeatureSupport(Vortice.Direct3D12.Feature.Options21); + + + Console.WriteLine($"Int64ShaderOps {Options1.Int64ShaderOps}"); + Console.WriteLine($"ProgrammableSamplePositionsTier {Options2.ProgrammableSamplePositionsTier}"); + Console.WriteLine($"DepthBoundsTestSupported {Options2.DepthBoundsTestSupported}"); + Console.WriteLine($"SamplerFeedbackTier {Options7.SamplerFeedbackTier}"); + Console.WriteLine($"MeshShaderTier {Options7.MeshShaderTier}"); + Console.WriteLine($"UnalignedBlockTexturesSupported {Options8.UnalignedBlockTexturesSupported}"); + Console.WriteLine($"MeshShaderPipelineStatsSupported {Options9.MeshShaderPipelineStatsSupported}"); + Console.WriteLine($"ViewInstancingTier {Options3.ViewInstancingTier}"); + Console.WriteLine($"VariableShadingRateTier {Options6.VariableShadingRateTier}"); + Console.WriteLine($"MSAA64KBAlignedTextureSupported {Options4.MSAA64KBAlignedTextureSupported}"); + Console.WriteLine($"Native16BitShaderOpsSupported {Options4.Native16BitShaderOpsSupported}"); + Console.WriteLine($"Ray RaytracingTier {Options5.RaytracingTier}"); + Console.WriteLine($"SRVOnlyTiledResourceTier3 {Options5.SRVOnlyTiledResourceTier3}"); + Console.WriteLine($"VariableRateShadingSumCombinerSupported {Options10.VariableRateShadingSumCombinerSupported}"); + Console.WriteLine($"MeshShaderPerPrimitiveShadingRateSupported {Options10.MeshShaderPerPrimitiveShadingRateSupported}"); + Console.WriteLine($"AtomicInt64OnDescriptorHeapResourceSupported {Options11.AtomicInt64OnDescriptorHeapResourceSupported}"); + Console.WriteLine($"MSPrimitivesPipelineStatisticIncludesCulledPrimitives {Options12.MSPrimitivesPipelineStatisticIncludesCulledPrimitives}"); + Console.WriteLine($"EnhancedBarriersSupported {Options12.EnhancedBarriersSupported}"); + Console.WriteLine($"UnrestrictedBufferTextureCopyPitchSupported {Options13.UnrestrictedBufferTextureCopyPitchSupported}"); + Console.WriteLine($"InvertedViewportDepthFlipsZSupported {Options13.InvertedViewportDepthFlipsZSupported}"); + Console.WriteLine($"AlphaBlendFactorSupported {Options13.AlphaBlendFactorSupported}"); + Console.WriteLine($"WriteableMSAATexturesSupported {Options14.WriteableMSAATexturesSupported}"); + Console.WriteLine($"AdvancedTextureOpsSupported {Options14.AdvancedTextureOpsSupported}"); + Console.WriteLine($"IndependentFrontAndBackStencilRefMaskSupported {Options14.IndependentFrontAndBackStencilRefMaskSupported}"); + Console.WriteLine($"TriangleFanSupported {Options15.TriangleFanSupported}"); + Console.WriteLine($"GPUUploadHeapSupported {Options16.GPUUploadHeapSupported}"); + Console.WriteLine($"DynamicDepthBiasSupported {Options16.DynamicDepthBiasSupported}"); + Console.WriteLine($"ManualWriteTrackingResourceSupported {Options17.ManualWriteTrackingResourceSupported}"); + Console.WriteLine($"RenderPassesValid {Options18.RenderPassesValid}"); + Console.WriteLine($"ComputeOnlyCustomHeapSupported {Options19.ComputeOnlyCustomHeapSupported}"); + Console.WriteLine($"NarrowQuadrilateralLinesSupported {Options19.NarrowQuadrilateralLinesSupported}"); + Console.WriteLine($"RasterizerDesc2Supported {Options19.RasterizerDesc2Supported}"); + Console.WriteLine($"SupportedSampleCountsWithNoOutputs {Options19.SupportedSampleCountsWithNoOutputs}"); + Console.WriteLine($"ComputeOnlyWriteWatchSupported {Options20.ComputeOnlyWriteWatchSupported}"); + Console.WriteLine($"RecreateAtTier {Options20.RecreateAtTier}"); + Console.WriteLine($"ExecuteIndirectTier {Options21.ExecuteIndirectTier}"); + Console.WriteLine($"ExtendedCommandInfoSupported {Options21.ExtendedCommandInfoSupported}"); + Console.WriteLine($"SampleCmpGradientAndBiasSupported {Options21.SampleCmpGradientAndBiasSupported}"); + Console.WriteLine($"WorkGraphsTier {Options21.WorkGraphsTier}"); + + + + + Console.WriteLine(); + Console.WriteLine(); + return true; + + + } + + internal ID3D12Device5 CreateDevice(GraphicsAdapter factory4) + { + + + foreach (var Adapters in factory4.Adapters) + if (D3D12CreateDevice(Adapters, FeatureLevel.Level_12_2, out var device).Success) + return device.QueryInterface(); + + + return null; + } + + public void CreateDescriptorAllocators() + { + RenderTargetViewAllocator = new DescriptorAllocator(this, DescriptorHeapType.RenderTargetView); + + DepthStencilViewAllocator = new DescriptorAllocator(this, DescriptorHeapType.DepthStencilView); + + ShaderResourceViewAllocator = new DescriptorAllocator(this, DescriptorHeapType.ConstantBufferViewShaderResourceViewUnorderedAccessView); + } + + public CommandQueue CreateCommandQueueDirect() + { + // Describe and create the command queue. + CommandQueue Queue = new CommandQueue(this) + { + Type = CommandListType.Direct + }; + + return Queue; + } + + + public CommandQueue CreateCommandQueueCopy() + { + // Describe and create the command queue. + CommandQueue Queue = new CommandQueue(this) + { + Type = CommandListType.Copy + }; + + return Queue; + } + + + public CommandQueue CreateCommandQueueBundle() + { + // Describe and create the command queue. + CommandQueue Queue = new CommandQueue(this) + { + Type = CommandListType.Bundle + }; + + return Queue; + } + + + public CommandQueue CreateCommandQueueCompute() + { + // Describe and create the command queue. + CommandQueue Queue = new CommandQueue(this) + { + Type = CommandListType.Compute + }; + + return Queue; + } + + + public CommandQueue CreateCommandQueueVideoDecode() + { + // Describe and create the command queue. + CommandQueue Queue = new CommandQueue(this) + { + Type = CommandListType.VideoDecode + }; + + return Queue; + } + + public CommandQueue CreateCommandQueueVideoEncode() + { + // Describe and create the command queue. + CommandQueue Queue = new CommandQueue(this) + { + Type = CommandListType.VideoEncode + }; + + return Queue; + } + + + public CommandQueue CreateCommandQueueVideoProcess() + { + // Describe and create the command queue. + CommandQueue Queue = new CommandQueue(this) + { + Type = CommandListType.VideoProcess + }; + + return Queue; + } + + + public void Dispose() + { + + } + } +} diff --git a/Src/Xultaik.Graphics/GraphicsResource.cs b/Src/Xultaik.Graphics/GraphicsResource.cs new file mode 100644 index 0000000..aaaadbd --- /dev/null +++ b/Src/Xultaik.Graphics/GraphicsResource.cs @@ -0,0 +1,42 @@ +// Copyright (c) Faber Leonardo. All Rights Reserved. https://github.com/FaberSanZ +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + + + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xultaik.Graphics +{ + public class GraphicsResource + { + public GraphicsDevice GraphicsDevice { get; private set; } + + // ShaderResource + public const int ComponentMappingMask = 0x7; + public const int ComponentMappingShift = 3; + public const int ComponentMappingAlwaysSetBitAvoidingZeromemMistakes = (1 << (ComponentMappingShift * 4)); + + protected GraphicsResource(GraphicsDevice device) + { + GraphicsDevice = device; + } + + + + + + + protected static int ComponentMapping(int src0, int src1, int src2, int src3) => ((src0) & ComponentMappingMask) | + (((src1) & ComponentMappingMask) << ComponentMappingShift) | + (((src2) & ComponentMappingMask) << (ComponentMappingShift * 2)) | + (((src3) & ComponentMappingMask) << (ComponentMappingShift * 3)) | + ComponentMappingAlwaysSetBitAvoidingZeromemMistakes; + + protected static int DefaultComponentMapping() => ComponentMapping(0, 1, 2, 3); + + protected static int ComponentMapping(int ComponentToExtract, int Mapping) => Mapping >> (ComponentMappingShift * ComponentToExtract) & ComponentMappingMask; + + } +} diff --git a/Src/Xultaik.Graphics/HeapType.cs b/Src/Xultaik.Graphics/HeapType.cs new file mode 100644 index 0000000..5af85f9 --- /dev/null +++ b/Src/Xultaik.Graphics/HeapType.cs @@ -0,0 +1,20 @@ +// Copyright (c) Faber Leonardo. All Rights Reserved. https://github.com/FaberSanZ +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + + + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xultaik.Graphics +{ + public enum HeapType + { + Default = 1, + + Upload = 2, + + Readback = 3 + } +} diff --git a/Src/Xultaik.Graphics/Image/DDSLoader.cs b/Src/Xultaik.Graphics/Image/DDSLoader.cs new file mode 100644 index 0000000..e1a9f21 --- /dev/null +++ b/Src/Xultaik.Graphics/Image/DDSLoader.cs @@ -0,0 +1,883 @@ +// Copyright (c) Faber Leonardo. All Rights Reserved. https://github.com/FaberSanZ +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + + + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using Vortice.Direct3D12; + + +namespace Xultaik.Graphics +{ + + public class DDSLoader + { + + internal enum HeaderFlags + { + Caps = 0x1, + + Height = 0x2, + + Width = 0x4, + + Pitch = 0x8, + + PixelFormat = 0x1000, + + MipmapCount = 0x20000, + + LinearSize = 0x80000, + + Depth = 0x800000, + } + + + internal enum FlagsDX10 + { + AlphaModeUnknown = 0x0, + + AlphaModeStraight = 0x1, + + AlphaModePremultiplied = 0x2, + + AlphaModeOpaque = 0x3, + + AlphaModeCustom = 0x4, + } + + + internal enum DDSPixelFormats + { + AlphaPixels = 0x1, + + Alpha = 0x2, + + Fourcc = 0x4, + + RGB = 0x40, + + YUV = 0x200, + + Luminance = 0x20000, + } + + + [Flags] + public enum SurfaceFlags + { + Texture = 0x00001000, + + Mipmap = 0x00400008, + + Cubemap = 0x00000008, + } + + + + [Flags] + public enum CubemapFlags + { + CubeMap = 0x00000200, + + Volume = 0x00200000, + + PositiveX = 0x00000600, + + NegativeX = 0x00000a00, + + PositiveY = 0x00001200, + + NegativeY = 0x00002200, + + PositiveZ = 0x00004200, + + NegativeZ = 0x00008200, + + AllFaces = PositiveX | NegativeX | PositiveY | NegativeY | PositiveZ | NegativeZ, + } + + + public enum ResourceDimension : int + { + Unknown = unchecked(0), + + Buffer = unchecked(1), + + Texture1D = unchecked(2), + + Texture2D = unchecked(3), + + Texture3D = unchecked(4), + } + + + [Flags] + public enum ResourceOptionFlags : int + { + None = unchecked(0), + + GenerateMipMaps = unchecked(1), + + Shared = unchecked(2), + + TextureCube = unchecked(4), + + DrawindirectArgs = unchecked(16), + + BufferAllowRawViews = unchecked(32), + + BufferStructured = unchecked(64), + + ResourceClamp = unchecked(128), + + SharedKeyedmutex = unchecked(256), + + GdiCompatible = unchecked(512), + } + + + + [StructLayout(LayoutKind.Sequential)] + internal struct DdsHeader + { + const int DDSMagic = 0x20534444; + + public readonly static int StructSize = Interop.SizeOf(); + + public int Size; + + public HeaderFlags Flags; + + public int Height; + + public int Width; + + public int PitchOrLinearSize; + + public int Depth; + + public int MipMapCount; + + private readonly uint unused1; + private readonly uint unused2; + private readonly uint unused3; + private readonly uint unused4; + private readonly uint unused5; + private readonly uint unused6; + private readonly uint unused7; + private readonly uint unused8; + private readonly uint unused9; + private readonly uint unused10; + private readonly uint unused11; + + public DDSPixelFormat PixelFormat; + + public SurfaceFlags SurfaceFlags; + + public CubemapFlags CubemapFlags; + + private readonly uint unused12; + private readonly uint unused13; + private readonly uint unused14; + + + public static bool GetInfo(byte[] data, out DdsHeader header, out HeaderDXT10? header10, out int offset) + { + // Validate DDS file in memory + header = new DdsHeader(); + header10 = null; + offset = 0; + + if (data.Length < (sizeof(uint) + DdsHeader.StructSize)) + return false; + + + // First is magic number + int dwMagicNumber = BitConverter.ToInt32(data, 0x0); + if (dwMagicNumber != DdsHeader.DDSMagic) + return false; + + + header = Interop.ToStructure(data, 4, DdsHeader.StructSize); + + // Verify header to validate DDS file + if (header.Size != DdsHeader.StructSize || header.PixelFormat.Size != DDSPixelFormat.StructSize) + return false; + + + // Check for DX10 extension + if (header.PixelFormat.IsDX10()) + { + int h10Offset = 4 + DdsHeader.StructSize + HeaderDXT10.StructSize; + + // Must be long enough for both headers and magic value + if (data.Length < h10Offset) + return false; + + + header10 = Interop.ToStructure(data, 4, HeaderDXT10.StructSize); + + offset = h10Offset; + } + else + offset = 0x4 + DdsHeader.StructSize; + + + return true; + } + + public static bool GetInfo(string filename, out DdsHeader header, out HeaderDXT10? header10, out int offset, out byte[] buffer) + { + buffer = File.ReadAllBytes(filename); + return GetInfo(buffer, out header, out header10, out offset); + } + + + public static bool ValidateTexture(DdsHeader header, HeaderDXT10? header10, out int depth, out PixelFormat format, out ResourceDimension resDim, out int arraySize, out bool isCubeMap) + { + if (header10.HasValue) + return ValidateTexture(header10.Value, header.Flags, out depth, out format, out resDim, out arraySize, out isCubeMap); + + else + return ValidateTexture(header, out depth, out format, out resDim, out arraySize, out isCubeMap); + + } + + private static bool ValidateTexture(DdsHeader header, out int depth, out PixelFormat format, out ResourceDimension resDim, out int arraySize, out bool isCubeMap) + { + depth = 0x0; + format = Xultaik.Graphics.PixelFormat.Unknown; + resDim = ResourceDimension.Unknown; + arraySize = 1; + isCubeMap = false; + + format = header.PixelFormat.GetDXGIFormat(); + if (format == Xultaik.Graphics.PixelFormat.Unknown) + return false; + + + if (header.Flags.HasFlag(HeaderFlags.Depth)) + resDim = ResourceDimension.Texture3D; + + else + { + if (header.SurfaceFlags.HasFlag(SurfaceFlags.Cubemap)) + { + // We require all six faces to be defined + if ((header.CubemapFlags & CubemapFlags.AllFaces) != CubemapFlags.AllFaces) + return false; + + + arraySize = 6; + isCubeMap = true; + } + + depth = 1; + resDim = ResourceDimension.Texture2D; + } + + return true; + } + + private static bool ValidateTexture(HeaderDXT10 header, HeaderFlags flags, out int depth, out PixelFormat format, out ResourceDimension resDim, out int arraySize, out bool isCubeMap) + { + depth = 0; + format = Xultaik.Graphics.PixelFormat.Unknown; + resDim = ResourceDimension.Unknown; + arraySize = 0x1; + isCubeMap = false; + + arraySize = header.ArraySize; + if (arraySize == 0) + return false; + + + if (header.MiscFlag2 != FlagsDX10.AlphaModeUnknown) + return false; + + + if (DDSPixelFormat.BitsPerPixel(header.DXGIFormat) == 0) + return false; + + + format = header.DXGIFormat; + + switch (header.Dimension) + { + case ResourceDimension.Texture1D: + depth = 1; + break; + + case ResourceDimension.Texture2D: + if (header.MiscFlag.HasFlag(ResourceOptionFlags.TextureCube)) + { + arraySize *= 6; + isCubeMap = true; + } + depth = 1; + break; + + case ResourceDimension.Texture3D: + if (!flags.HasFlag(HeaderFlags.Depth)) + return false; + + + if (arraySize > 1) + return false; + + break; + + default: + return false; + } + + resDim = header.Dimension; + + return true; + } + + } + + + + + + + internal struct DDSPixelFormat + { + + public readonly static int StructSize = Interop.SizeOf(); + + public int Size; + + public DDSPixelFormats Flags; + + public int FourCC; + + public int RGBBitCount; + + public uint RBitMask; + + public uint GBitMask; + + public uint BBitMask; + + public uint ABitMask; + + public static int MakeFourCC(string text) + { + byte ch0 = (byte)text[0]; + byte ch1 = (byte)text[1]; + byte ch2 = (byte)text[2]; + byte ch3 = (byte)text[3]; + + return (ch0 | (ch1 << 8) | (ch2 << 16) | (ch3 << 24)); + } + + public static void GetSurfaceInfo(int width, int height, PixelFormat fmt, out int outNumBytes, out int outRowBytes, out int outNumRows) + { + int numBytes = 0; + int rowBytes = 0; + int numRows = 0; + + bool bc = false; + bool packed = false; + int bcnumBytesPerBlock = 0; + switch (fmt) + { + case PixelFormat.BC1_Typeless: + case PixelFormat.BC1_UNorm: + case PixelFormat.BC1_UNorm_SRgb: + case PixelFormat.BC4_Typeless: + case PixelFormat.BC4_UNorm: + case PixelFormat.BC4_SNorm: + bc = true; + bcnumBytesPerBlock = 8; + break; + + case PixelFormat.BC2_Typeless: + case PixelFormat.BC2_UNorm: + case PixelFormat.BC2_UNorm_SRgb: + case PixelFormat.BC3_Typeless: + case PixelFormat.BC3_UNorm: + case PixelFormat.BC3_UNorm_SRgb: + case PixelFormat.BC5_Typeless: + case PixelFormat.BC5_UNorm: + case PixelFormat.BC5_SNorm: + case PixelFormat.BC6H_Typeless: + case PixelFormat.BC6H_Uf16: + case PixelFormat.BC6H_Sf16: + case PixelFormat.BC7_Typeless: + case PixelFormat.BC7_UNorm: + case PixelFormat.BC7_UNorm_SRgb: + bc = true; + bcnumBytesPerBlock = 16; + break; + + case PixelFormat.R8G8_B8G8_UNorm: + case PixelFormat.G8R8_G8B8_UNorm: + packed = true; + break; + } + + if (bc) + { + int numBlocksWide = 0; + if (width > 0) + numBlocksWide = Math.Max(1, (width + 3) / 4); + + int numBlocksHigh = 0; + if (height > 0) + numBlocksHigh = Math.Max(1, (height + 3) / 4); + + rowBytes = numBlocksWide * bcnumBytesPerBlock; + numRows = numBlocksHigh; + } + else if (packed) + { + rowBytes = ((width + 1) >> 1) * 4; + numRows = height; + } + else + { + int bpp = BitsPerPixel(fmt); + rowBytes = (width * bpp + 7) / 8; // round up to nearest byte + numRows = height; + } + + numBytes = rowBytes * numRows; + + outNumBytes = numBytes; + outRowBytes = rowBytes; + outNumRows = numRows; + } + + public static int BitsPerPixel(PixelFormat fmt) + { + switch (fmt) + { + case PixelFormat.R32G32B32A32_Typeless: + case PixelFormat.R32G32B32A32_Float: + case PixelFormat.R32G32B32A32_UInt: + case PixelFormat.R32G32B32A32_SInt: + return 128; + + case PixelFormat.R32G32B32_Typeless: + case PixelFormat.R32G32B32_Float: + case PixelFormat.R32G32B32_UInt: + case PixelFormat.R32G32B32_SInt: + return 96; + + case PixelFormat.R16G16B16A16_Typeless: + case PixelFormat.R16G16B16A16_Float: + case PixelFormat.R16G16B16A16_UNorm: + case PixelFormat.R16G16B16A16_UInt: + case PixelFormat.R16G16B16A16_SNorm: + case PixelFormat.R16G16B16A16_SInt: + case PixelFormat.R32G32_Typeless: + case PixelFormat.R32G32_Float: + case PixelFormat.R32G32_UInt: + case PixelFormat.R32G32_SInt: + case PixelFormat.R32G8X24_Typeless: + case PixelFormat.D32_Float_S8X24_UInt: + case PixelFormat.R32_Float_X8X24_Typeless: + case PixelFormat.X32_Typeless_G8X24_UInt: + return 64; + + case PixelFormat.R10G10B10A2_Typeless: + case PixelFormat.R10G10B10A2_UNorm: + case PixelFormat.R10G10B10A2_UInt: + case PixelFormat.R11G11B10_Float: + case PixelFormat.R8G8B8A8_Typeless: + case PixelFormat.R8G8B8A8_UNorm: + case PixelFormat.R8G8B8A8_UNorm_SRgb: + case PixelFormat.R8G8B8A8_UInt: + case PixelFormat.R8G8B8A8_SNorm: + case PixelFormat.R8G8B8A8_SInt: + case PixelFormat.R16G16_Typeless: + case PixelFormat.R16G16_Float: + case PixelFormat.R16G16_UNorm: + case PixelFormat.R16G16_UInt: + case PixelFormat.R16G16_SNorm: + case PixelFormat.R16G16_SInt: + case PixelFormat.R32_Typeless: + case PixelFormat.D32_Float: + case PixelFormat.R32_Float: + case PixelFormat.R32_UInt: + case PixelFormat.R32_SInt: + case PixelFormat.R24G8_Typeless: + case PixelFormat.D24_UNorm_S8_UInt: + case PixelFormat.R24_UNorm_X8_Typeless: + case PixelFormat.X24_Typeless_G8_UInt: + case PixelFormat.R9G9B9E5_Sharedexp: + case PixelFormat.R8G8_B8G8_UNorm: + case PixelFormat.G8R8_G8B8_UNorm: + case PixelFormat.B8G8R8A8_UNorm: + case PixelFormat.B8G8R8X8_UNorm: + case PixelFormat.R10G10B10_Xr_Bias_A2_UNorm: + case PixelFormat.B8G8R8A8_Typeless: + case PixelFormat.B8G8R8A8_UNorm_SRgb: + case PixelFormat.B8G8R8X8_Typeless: + case PixelFormat.B8G8R8X8_UNorm_SRgb: + return 32; + + case PixelFormat.R8G8_Typeless: + case PixelFormat.R8G8_UNorm: + case PixelFormat.R8G8_UInt: + case PixelFormat.R8G8_SNorm: + case PixelFormat.R8G8_SInt: + case PixelFormat.R16_Typeless: + case PixelFormat.R16_Float: + case PixelFormat.D16_UNorm: + case PixelFormat.R16_UNorm: + case PixelFormat.R16_UInt: + case PixelFormat.R16_SNorm: + case PixelFormat.R16_SInt: + case PixelFormat.B5G6R5_UNorm: + case PixelFormat.B5G5R5A1_UNorm: + case PixelFormat.B4G4R4A4_UNorm: + return 16; + + case PixelFormat.R8_Typeless: + case PixelFormat.R8_UNorm: + case PixelFormat.R8_UInt: + case PixelFormat.R8_SNorm: + case PixelFormat.R8_SInt: + case PixelFormat.A8_UNorm: + return 8; + + case PixelFormat.R1_UNorm: + return 1; + + case PixelFormat.BC1_Typeless: + case PixelFormat.BC1_UNorm: + case PixelFormat.BC1_UNorm_SRgb: + case PixelFormat.BC4_Typeless: + case PixelFormat.BC4_UNorm: + case PixelFormat.BC4_SNorm: + return 4; + + case PixelFormat.BC2_Typeless: + case PixelFormat.BC2_UNorm: + case PixelFormat.BC2_UNorm_SRgb: + case PixelFormat.BC3_Typeless: + case PixelFormat.BC3_UNorm: + case PixelFormat.BC3_UNorm_SRgb: + case PixelFormat.BC5_Typeless: + case PixelFormat.BC5_UNorm: + case PixelFormat.BC5_SNorm: + case PixelFormat.BC6H_Typeless: + case PixelFormat.BC6H_Uf16: + case PixelFormat.BC6H_Sf16: + case PixelFormat.BC7_Typeless: + case PixelFormat.BC7_UNorm: + case PixelFormat.BC7_UNorm_SRgb: + return 8; + + default: + return 0; + } + } + + + + + public bool IsDX10() => this.Flags.HasFlag(DDSPixelFormats.Fourcc) && (MakeFourCC("DX10") == this.FourCC); + + + public PixelFormat GetDXGIFormat() + { + + switch (this.Flags) + { + case DDSPixelFormats.Alpha: + return GetFormatDDPFAlpha(); + + case DDSPixelFormats.Fourcc: + return GetFormatDDPFFOURCC(); + + case DDSPixelFormats.RGB: + return GetFormatDDPFRGB(); + + //case DDSPixelFormats.YUV: + // break; + + case DDSPixelFormats.Luminance: + return GetFormatDDPFLuminance(); + + default: + return PixelFormat.Unknown; + } + + + } + + private PixelFormat GetFormatDDPFRGB() + { + // Note that sRGB formats are written using the "DX10" extended header + switch (this.RGBBitCount) + { + case 32: + return GetFormatDDPFRGB32(); + + case 24: + return GetFormatDDPFRGB24(); + + case 16: + return GetFormatDDPFRGB16(); + } + + return PixelFormat.Unknown; + } + + private PixelFormat GetFormatDDPFRGB32() + { + if (this.IsBitMask(0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000)) + return PixelFormat.R8G8B8A8_UNorm; + + + if (this.IsBitMask(0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000)) + return PixelFormat.B8G8R8A8_UNorm; + + + if (this.IsBitMask(0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000)) + return PixelFormat.B8G8R8X8_UNorm; + + + // No DXGI format maps to ISBITMASK(0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000) aka D3DFMT_X8B8G8R8 + + // Note that many common DDS reader/writers (including D3DX) swap the + // the RED/BLUE masks for 10:10:10:2 formats. We assumme + // below that the 'backwards' header mask is being used since it is most + // likely written by D3DX. The more robust solution is to use the 'DX10' + // header extension and specify the DXGI_FORMAT_R10G10B10A2_UNORM format directly + + // For 'correct' writers, this should be 0x000003ff, 0x000ffc00, 0x3ff00000 for RGB data + if (this.IsBitMask(0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000)) + return PixelFormat.R10G10B10A2_UNorm; + + + // No DXGI format maps to ISBITMASK(0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000) aka D3DFMT_A2R10G10B10 + + if (this.IsBitMask(0x0000ffff, 0xffff0000, 0x00000000, 0x00000000)) + return PixelFormat.R16G16_UNorm; + + + if (this.IsBitMask(0xffffffff, 0x00000000, 0x00000000, 0x00000000)) + // Only 32-bit color channel format in D3D9 was R32F + return PixelFormat.R32_Float; // D3DX writes this out as a FourCC of 114 + + + return PixelFormat.Unknown; + } + + private PixelFormat GetFormatDDPFRGB24() => PixelFormat.Unknown; // No 24bpp DXGI formats aka D3DFMT_R8G8B8 + + + private PixelFormat GetFormatDDPFRGB16() + { + if (this.IsBitMask(0x7c00, 0x03e0, 0x001f, 0x8000)) + return PixelFormat.B5G5R5A1_UNorm; + + if (this.IsBitMask(0xf800, 0x07e0, 0x001f, 0x0000)) + return PixelFormat.B5G6R5_UNorm; + + + // No DXGI format maps to ISBITMASK(0x7c00, 0x03e0, 0x001f, 0x0000) aka D3DFMT_X1R5G5B5 + if (this.IsBitMask(0x0f00, 0x00f0, 0x000f, 0xf000)) + return PixelFormat.B4G4R4A4_UNorm; + + + // No DXGI format maps to ISBITMASK(0x0f00, 0x00f0, 0x000f, 0x0000) aka D3DFMT_X4R4G4B4 + + // No 3:3:2, 3:3:2:8, or paletted DXGI formats aka D3DFMT_A8R3G3B2, D3DFMT_R3G3B2, D3DFMT_P8, D3DFMT_A8P8, etc. + return PixelFormat.Unknown; + } + + private PixelFormat GetFormatDDPFLuminance() + { + if (8 == this.RGBBitCount && this.IsBitMask(0x000000ff, 0x00000000, 0x00000000, 0x00000000)) + return PixelFormat.R8_UNorm; // D3DX10/11 writes this out as DX10 extension + + // No DXGI format maps to ISBITMASK(0x0f, 0x00, 0x00, 0xf0) aka D3DFMT_A4L4 + + if (16 == this.RGBBitCount) + { + if (this.IsBitMask(0x0000ffff, 0x00000000, 0x00000000, 0x00000000)) + return PixelFormat.R16_UNorm; // D3DX10/11 writes this out as DX10 extension + + if (this.IsBitMask(0x000000ff, 0x00000000, 0x00000000, 0x0000ff00)) + return PixelFormat.R8G8_UNorm; // D3DX10/11 writes this out as DX10 extension + + } + + return PixelFormat.Unknown; + } + + private PixelFormat GetFormatDDPFAlpha() => 8 == this.RGBBitCount ? PixelFormat.A8_UNorm : PixelFormat.Unknown; + + + private PixelFormat GetFormatDDPFFOURCC() + { + if (MakeFourCC("DXT1") == this.FourCC) + return PixelFormat.BC1_UNorm; + + if (MakeFourCC("DXT3") == this.FourCC) + return PixelFormat.BC2_UNorm; + + if (MakeFourCC("DXT5") == this.FourCC) + return PixelFormat.BC3_UNorm; + + + // While pre-mulitplied alpha isn't directly supported by the DXGI formats, + // they are basically the same as these BC formats so they can be mapped + if (MakeFourCC("DXT2") == this.FourCC) + return PixelFormat.BC2_UNorm; + + if (MakeFourCC("DXT4") == this.FourCC) + return PixelFormat.BC3_UNorm; + + + if (MakeFourCC("ATI1") == this.FourCC) + return PixelFormat.BC4_UNorm; + + if (MakeFourCC("BC4U") == this.FourCC) + return PixelFormat.BC4_UNorm; + + if (MakeFourCC("BC4S") == this.FourCC) + return PixelFormat.BC4_SNorm; + + + if (MakeFourCC("ATI2") == this.FourCC) + return PixelFormat.BC5_UNorm; + + if (MakeFourCC("BC5U") == this.FourCC) + return PixelFormat.BC5_UNorm; + + if (MakeFourCC("BC5S") == this.FourCC) + return PixelFormat.BC5_SNorm; + + + // BC6H and BC7 are written using the "DX10" extended header + if (MakeFourCC("RGBG") == this.FourCC) + return PixelFormat.R8G8_B8G8_UNorm; + + if (MakeFourCC("GRGB") == this.FourCC) + return PixelFormat.G8R8_G8B8_UNorm; + + + // Check for D3DFORMAT enums being set here + switch (this.FourCC) + { + case 36: // D3DFMT_A16B16G16R16 + return PixelFormat.R16G16B16A16_UNorm; + + case 110: // D3DFMT_Q16W16V16U16 + return PixelFormat.R16G16B16A16_SNorm; + + case 111: // D3DFMT_R16F + return PixelFormat.R16_Float; + + case 112: // D3DFMT_G16R16F + return PixelFormat.R16G16_Float; + + case 113: // D3DFMT_A16B16G16R16F + return PixelFormat.R16G16B16A16_Float; + + case 114: // D3DFMT_R32F + return PixelFormat.R32_Float; + + case 115: // D3DFMT_G32R32F + return PixelFormat.R32G32_Float; + + case 116: // D3DFMT_A32B32G32R32F + return PixelFormat.R32G32B32A32_Float; + } + + return PixelFormat.Unknown; + } + + private bool IsBitMask(uint r, uint g, uint b, uint a) => RBitMask == r && GBitMask == g && BBitMask == b && ABitMask == a; + + } + + + + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct HeaderDXT10 + { + public readonly static int StructSize = Interop.SizeOf(); + + public PixelFormat DXGIFormat; + + public ResourceDimension Dimension; + + public ResourceOptionFlags MiscFlag; + + public int ArraySize; + + public FlagsDX10 MiscFlag2; + } + + + public TextureData TextureData { get; private set; } + + + + public DDSLoader(string filename) + { + + if (DdsHeader.GetInfo(filename, out DdsHeader header, out HeaderDXT10? header10, out int offset, out byte[] buffer)) + TextureData = LoadTexture(header, header10, buffer, offset, 0); + + else + TextureData = LoadTexture(header, header10, buffer, offset, 0); + + } + + + + + public static TextureData LoadFromFile(string filename) => new DDSLoader(filename).TextureData; + + + + + internal TextureData LoadTexture(DdsHeader header, HeaderDXT10? header10, byte[] bitData, int offset, int maxsize) + { + bool validFile = DdsHeader.ValidateTexture( + header, header10, + out int depth, out PixelFormat format, out ResourceDimension resDim, out int arraySize, out bool isCubeMap); + + TextureData textureData = new TextureData() + { + Width = header.Width, + Height = header.Height, + Depth = depth, + Format = format, + Size = arraySize, + IsCubeMap = isCubeMap, + MipMaps = header.MipMapCount is 0 ? 1 : header.MipMapCount, + }; + + + + byte[] bytes = new byte[bitData.Length - offset]; + + Array.Copy(bitData, offset, bytes, 0, bytes.Length); + + textureData.Data = bytes; + + return textureData; + } + + } +} diff --git a/Src/Xultaik.Graphics/Image/WICLoader.cs b/Src/Xultaik.Graphics/Image/WICLoader.cs new file mode 100644 index 0000000..c039e3a --- /dev/null +++ b/Src/Xultaik.Graphics/Image/WICLoader.cs @@ -0,0 +1,216 @@ +// Copyright (c) Faber Leonardo. All Rights Reserved. https://github.com/FaberSanZ +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + + + + + +using System; +using System.Collections.Generic; +using System.Text; +using System.Diagnostics; +using System.IO; +using Vortice.WIC; + +namespace Xultaik.Graphics +{ + + public unsafe class WICLoader + { + internal class WICConvert + { + private Dictionary Convert = new Dictionary(); + + public WICConvert() + { + Convert.Add(Vortice.WIC.PixelFormat.FormatBlackWhite, Vortice.WIC.PixelFormat.Format8bppGray); + Convert.Add(Vortice.WIC.PixelFormat.Format1bppIndexed, Vortice.WIC.PixelFormat.Format32bppRGBA); + Convert.Add(Vortice.WIC.PixelFormat.Format2bppIndexed, Vortice.WIC.PixelFormat.Format32bppRGBA); + Convert.Add(Vortice.WIC.PixelFormat.Format4bppIndexed, Vortice.WIC.PixelFormat.Format32bppRGBA); + Convert.Add(Vortice.WIC.PixelFormat.Format8bppIndexed, Vortice.WIC.PixelFormat.Format32bppRGBA); + Convert.Add(Vortice.WIC.PixelFormat.Format2bppGray, Vortice.WIC.PixelFormat.Format8bppGray); + Convert.Add(Vortice.WIC.PixelFormat.Format4bppGray, Vortice.WIC.PixelFormat.Format8bppGray); + Convert.Add(Vortice.WIC.PixelFormat.Format16bppGrayFixedPoint, Vortice.WIC.PixelFormat.Format16bppGrayHalf); + Convert.Add(Vortice.WIC.PixelFormat.Format32bppGrayFixedPoint, Vortice.WIC.PixelFormat.Format32bppGrayFloat); + Convert.Add(Vortice.WIC.PixelFormat.Format16bppBGR555, Vortice.WIC.PixelFormat.Format16bppBGRA5551); + Convert.Add(Vortice.WIC.PixelFormat.Format32bppBGR101010, Vortice.WIC.PixelFormat.Format32bppRGBA1010102); + Convert.Add(Vortice.WIC.PixelFormat.Format24bppBGR, Vortice.WIC.PixelFormat.Format32bppRGBA); + Convert.Add(Vortice.WIC.PixelFormat.Format24bppRGB, Vortice.WIC.PixelFormat.Format32bppRGBA); + Convert.Add(Vortice.WIC.PixelFormat.Format32bppPBGRA, Vortice.WIC.PixelFormat.Format32bppRGBA); + Convert.Add(Vortice.WIC.PixelFormat.Format32bppPRGBA, Vortice.WIC.PixelFormat.Format32bppRGBA); + Convert.Add(Vortice.WIC.PixelFormat.Format48bppRGB, Vortice.WIC.PixelFormat.Format48bppRGB); + Convert.Add(Vortice.WIC.PixelFormat.Format48bppBGR, Vortice.WIC.PixelFormat.Format64bppRGBA); + Convert.Add(Vortice.WIC.PixelFormat.Format64bppRGBAFixedPoint, Vortice.WIC.PixelFormat.Format64bppRGBAHalf); + Convert.Add(Vortice.WIC.PixelFormat.Format64bppBGRAFixedPoint, Vortice.WIC.PixelFormat.Format64bppRGBAHalf); + Convert.Add(Vortice.WIC.PixelFormat.Format64bppRGBFixedPoint, Vortice.WIC.PixelFormat.Format64bppRGBAHalf); + Convert.Add(Vortice.WIC.PixelFormat.Format64bppRGBHalf, Vortice.WIC.PixelFormat.Format64bppRGBAHalf); + Convert.Add(Vortice.WIC.PixelFormat.Format48bppRGBHalf, Vortice.WIC.PixelFormat.Format64bppRGBAHalf); + Convert.Add(Vortice.WIC.PixelFormat.Format128bppPRGBAFloat, Vortice.WIC.PixelFormat.Format128bppRGBAFloat); + Convert.Add(Vortice.WIC.PixelFormat.Format128bppRGBFloat, Vortice.WIC.PixelFormat.Format128bppRGBAFloat); + Convert.Add(Vortice.WIC.PixelFormat.Format128bppRGBAFixedPoint, Vortice.WIC.PixelFormat.Format128bppRGBAFloat); + Convert.Add(Vortice.WIC.PixelFormat.Format128bppRGBFixedPoint, Vortice.WIC.PixelFormat.Format128bppRGBAFloat); + Convert.Add(Vortice.WIC.PixelFormat.Format32bppRGBE, Vortice.WIC.PixelFormat.Format128bppRGBAFloat); + Convert.Add(Vortice.WIC.PixelFormat.Format32bppCMYK, Vortice.WIC.PixelFormat.Format32bppRGBA); + Convert.Add(Vortice.WIC.PixelFormat.Format64bppCMYK, Vortice.WIC.PixelFormat.Format64bppRGBA); + Convert.Add(Vortice.WIC.PixelFormat.Format40bppCMYKAlpha, Vortice.WIC.PixelFormat.Format32bppRGBA); + Convert.Add(Vortice.WIC.PixelFormat.Format80bppCMYKAlpha, Vortice.WIC.PixelFormat.Format64bppRGBA); + } + + + public Guid this[Guid index] + { + get + { + if (Convert.ContainsKey(index) is false) + throw new ArgumentException("Index Vailed"); + + return Convert[index]; + } + } + } + + internal class WICTranslate + { + internal Dictionary Translate = new Dictionary(); + + public WICTranslate() + { + Translate.Add(Vortice.WIC.PixelFormat.Format128bppRGBAFloat, PixelFormat.R32G32B32A32_Float); + Translate.Add(Vortice.WIC.PixelFormat.Format64bppRGBAHalf, PixelFormat.R16G16B16A16_Float); + Translate.Add(Vortice.WIC.PixelFormat.Format64bppRGBA, PixelFormat.R16G16B16A16_UNorm); + Translate.Add(Vortice.WIC.PixelFormat.Format32bppRGBA, PixelFormat.R8G8B8A8_UNorm); + Translate.Add(Vortice.WIC.PixelFormat.Format32bppBGRA, PixelFormat.B8G8R8A8_UNorm); + Translate.Add(Vortice.WIC.PixelFormat.Format32bppBGR, PixelFormat.B8G8R8X8_UNorm); + Translate.Add(Vortice.WIC.PixelFormat.Format32bppRGBA1010102XR, PixelFormat.R10G10B10_Xr_Bias_A2_UNorm); + Translate.Add(Vortice.WIC.PixelFormat.Format32bppRGBA1010102, PixelFormat.R10G10B10A2_UNorm); + Translate.Add(Vortice.WIC.PixelFormat.Format16bppBGRA5551, PixelFormat.B5G5R5A1_UNorm); + Translate.Add(Vortice.WIC.PixelFormat.Format16bppBGR565, PixelFormat.B5G6R5_UNorm); + Translate.Add(Vortice.WIC.PixelFormat.Format32bppGrayFloat, PixelFormat.R32_Float); + Translate.Add(Vortice.WIC.PixelFormat.Format16bppGrayHalf, PixelFormat.R16_Float); + Translate.Add(Vortice.WIC.PixelFormat.Format16bppGray, PixelFormat.R16_UNorm); + Translate.Add(Vortice.WIC.PixelFormat.Format8bppGray, PixelFormat.R8_UNorm); + Translate.Add(Vortice.WIC.PixelFormat.Format8bppAlpha, PixelFormat.A8_UNorm); + } + + public PixelFormat this[Guid index] + { + get + { + if (Translate.ContainsKey(index) is false) + return PixelFormat.Unknown; + + return Translate[index]; + } + } + } + + + + public TextureData TextureData { get; private set; } + + + public WICLoader(string filename) + { + var bitmap = ReadBitmap(filename); + + WICTranslate Translate = new WICTranslate(); + + int mipLevelCount = (int)Math.Floor(Math.Log(Math.Max(bitmap.Size.Width, bitmap.Size.Height), 2)) + 1; + + TextureData = new TextureData() + { + Height = bitmap.Size.Height, + Width = bitmap.Size.Width, + Depth = 1, + Format = Translate[bitmap.PixelFormat], + MipMaps = mipLevelCount, + }; + + + int bpp = GetBitsPerPixel(TextureData.Format); + + int rowPitch = (TextureData.Width * bpp + 7) / 8; + int slicePitch = rowPitch * TextureData.Height; + + byte[] data = new byte[slicePitch]; + + bitmap.CopyPixels(rowPitch, data); + + + + // TODO: Size ------- + TextureData.Size = TextureData.Width * 4; //(slicePitch / rowPitch) * 4; + //------------------- + + TextureData.Data = data; + } + + + + + + public static TextureData LoadFromFile(string filename) => new WICLoader(filename).TextureData; + + internal IWICBitmapSource ReadBitmap(string filename) + { + using var factory = new IWICImagingFactory2(); + + IWICBitmapDecoder bitmapDecoder = factory.CreateDecoderFromFileName(filename, FileAccess.Read, DecodeOptions.CacheOnLoad); + + IWICFormatConverter formatConverter = factory.CreateFormatConverter(); + + IWICBitmapFrameDecode frame = bitmapDecoder.GetFrame(0); + + formatConverter.Initialize(frame, Vortice.WIC.PixelFormat.Format32bppRGBA, BitmapDitherType.None, null, 0.0, BitmapPaletteType.Custom); + + + return formatConverter; + } + + + internal int GetBitsPerPixel(PixelFormat dxgiFormat) + { + + + switch (dxgiFormat) + { + case PixelFormat.R32G32B32A32_Float: + return 128; + + case PixelFormat.R16G16B16A16_Float: + case PixelFormat.R16G16B16A16_UNorm: + return 64; + + case PixelFormat.R8G8B8A8_UNorm: + case PixelFormat.B8G8R8X8_UNorm: + case PixelFormat.B8G8R8A8_UNorm: + case PixelFormat.R32_Float: + case PixelFormat.R10G10B10_Xr_Bias_A2_UNorm: + return 32; + + + + case PixelFormat.B5G5R5A1_UNorm: + case PixelFormat.B5G6R5_UNorm: + case PixelFormat.R16_Float: + case PixelFormat.R16_UNorm: + return 16; + + + case PixelFormat.R8_UNorm: + case PixelFormat.A8_UNorm: + return 8; + + + + default: + return 8; + + + } + + } + + + } +} diff --git a/Src/Xultaik.Graphics/IndexType.cs b/Src/Xultaik.Graphics/IndexType.cs new file mode 100644 index 0000000..ed89d4e --- /dev/null +++ b/Src/Xultaik.Graphics/IndexType.cs @@ -0,0 +1,19 @@ +// Copyright (c) Faber Leonardo. All Rights Reserved. https://github.com/FaberSanZ +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + + + + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xultaik.Graphics +{ + public enum IndexType + { + UInt32, + + UInt16 + } +} diff --git a/Src/Xultaik.Graphics/Interop.cs b/Src/Xultaik.Graphics/Interop.cs new file mode 100644 index 0000000..3a29249 --- /dev/null +++ b/Src/Xultaik.Graphics/Interop.cs @@ -0,0 +1,165 @@ +// Copyright (c) Faber Leonardo. All Rights Reserved. https://github.com/FaberSanZ +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + + + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; + +namespace Xultaik.Graphics +{ + public static unsafe class Interop + { + + public static int SizeOf() => Unsafe.SizeOf(); + + + public static int SizeOf(T[] values) => Unsafe.SizeOf() * values.Length; + + public static IntPtr Alloc(int count = 1) => Alloc(Unsafe.SizeOf() * count); + + + public static IntPtr Alloc(int byteCount) + { + if (byteCount == 0) + return IntPtr.Zero; + + return Marshal.AllocHGlobal(byteCount); + } + + public static T ToStructure(byte[] bytes, int start, int count) where T : struct + { + byte[] temp = bytes.Skip(start).Take(count).ToArray(); + GCHandle handle = GCHandle.Alloc(temp, GCHandleType.Pinned); + T stuff = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T)); + handle.Free(); + return stuff; + } + + public static T AllocToPointer(T[] values) where T : unmanaged + { + //if (values == null || values.Length == 0) + // return (; + + + int structSize = SizeOf(); + int totalSize = values.Length * structSize; + IntPtr ptr = Marshal.AllocHGlobal(totalSize); + + byte* walk = (byte*)ptr; + for (int i = 0; i < values.Length; i++) + { + Unsafe.Copy(walk, ref values[i]); + walk += structSize; + } + + return (T)Marshal.PtrToStructure(ptr, typeof(T)); ; + } + + + + public static class MemoryHelper + { + public static void Read(IntPtr srcPointer, ref T value) => Unsafe.Copy(ref value, srcPointer.ToPointer()); + + + public static void Write(IntPtr dstPointer, ref T value) => Unsafe.Copy(dstPointer.ToPointer(), ref value); + + + public static void Write(IntPtr dstPointer, T[] values) + { + if (values == null || values.Length == 0) + return; + + int stride = SizeOf(); + uint size = (uint)(stride * values.Length); + void* srcPtr = Unsafe.AsPointer(ref values[0]); + Unsafe.CopyBlock(dstPointer.ToPointer(), srcPtr, size); + } + + + public static void Read(IntPtr srcPointer, Span values) + { + int stride = SizeOf(); + long size = stride * values.Length; + void* dstPtr = Unsafe.AsPointer(ref values[0]); + System.Buffer.MemoryCopy(srcPointer.ToPointer(), dstPtr, size, size); + } + + public static void CopyMemory(object uploadMemory, IntPtr dataPointer, object sizeInBytes) + { + throw new NotImplementedException(); + } + } + + public static class String + { + + public static byte* ToPointer(string value) => (byte*)(void*)AllocToPointer(value); + + + public static string FromPointer(IntPtr pointer) => FromPointer((byte*)(void*)pointer); + + + public static string FromPointer(byte* pointer) + { + if (pointer == null) + return string.Empty; + + // Read until null-terminator. + byte* walkPtr = pointer; + while (*walkPtr != 0) + walkPtr++; + + // Decode UTF-8 bytes to string. + return Encoding.UTF8.GetString(pointer, (int)(walkPtr - pointer)); + } + + + public static IntPtr AllocToPointer(string value) + { + if (value == null) + return IntPtr.Zero; + + // Get max number of bytes the string may need. + int maxSize = GetMaxByteCount(value); + + // Allocate unmanaged memory. + IntPtr managedPtr = Alloc(maxSize); + byte* ptr = (byte*)managedPtr; + + // Encode to utf-8, null-terminate and write to unmanaged memory. + int actualNumberOfBytesWritten; + fixed (char* ch = value) + actualNumberOfBytesWritten = Encoding.UTF8.GetBytes(ch, value.Length, ptr, maxSize); + ptr[actualNumberOfBytesWritten] = 0; + + // Return pointer to the beginning of unmanaged memory. + return managedPtr; + } + + public static byte** AllocToPointers(string[] values) + { + if (values == null || values.Length == 0) + return null; + + // Allocate unmanaged memory for string pointers. + IntPtr* stringHandlesPtr = (IntPtr*)Alloc(values.Length); + + for (var i = 0; i < values.Length; i++) + // Store the pointer to the string. + stringHandlesPtr[i] = AllocToPointer(values[i]); + + return (byte**)stringHandlesPtr; + } + + public static int GetMaxByteCount(string value) => value == null ? 0 : Encoding.UTF8.GetMaxByteCount(value.Length + 1); + } + } + + +} diff --git a/Src/Xultaik.Graphics/PipelineState.cs b/Src/Xultaik.Graphics/PipelineState.cs new file mode 100644 index 0000000..b351835 --- /dev/null +++ b/Src/Xultaik.Graphics/PipelineState.cs @@ -0,0 +1,156 @@ +// Copyright (c) Faber Leonardo. All Rights Reserved. https://github.com/FaberSanZ +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + + + + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Vortice.Direct3D12; +using Vortice.Dxc; +using Vortice.DXGI; + +namespace Xultaik.Graphics +{ + + public class PipelineState : GraphicsResource + { + PipelineStateDescription PipelineStateDescription { get; set; } + + + + //Internal + internal ID3D12RootSignature RootSignature; + internal ID3D12PipelineState oldPipelineState; + + + public PipelineState(GraphicsDevice device, PipelineStateDescription description) : base(device) + { + PipelineStateDescription = description; + Recreate(); + } + + public void Recreate() + { + CreateRootSignature(); + CreatePipeline(); + } + + + public void CreatePipeline() + { + InputElementDescription[] inputElementDescs = new InputElementDescription[] + { + new InputElementDescription("POSITION", 0, Format.R32G32B32_Float, 0, 0), + new InputElementDescription("COLOR", 0, Format.R32G32B32A32_Float, 12, 0), + + }; + + var psoDesc = new GraphicsPipelineStateDescription() + { + RootSignature = RootSignature, + + InputLayout = new InputLayoutDescription(inputElementDescs), + SampleMask = uint.MaxValue, + PrimitiveTopologyType = PrimitiveTopologyType.Triangle, + RasterizerState = RasterizerDescription.CullCounterClockwise, + BlendState = BlendDescription.Opaque, + DepthStencilState = DepthStencilDescription.None, + RenderTargetFormats = new[] { Format.R8G8B8A8_UNorm }, + DepthStencilFormat = Format.Unknown, + SampleDescription = new SampleDescription(1, 0), + //IndexBufferStripCutValue = IndexBufferStripCutValue.Value0xFFFF + StreamOutput = new StreamOutputDescription() + { + //RasterizedStream = + }, + + + HullShader = PipelineStateDescription.HullShader == null ? null : PipelineStateDescription.HullShader.Data, + + GeometryShader = PipelineStateDescription.GeometryShader == null ? null : PipelineStateDescription.GeometryShader.Data, + + DomainShader = PipelineStateDescription.DomainShader == null ? null : PipelineStateDescription.DomainShader.Data, + + VertexShader = PipelineStateDescription.VertexShader == null ? null : PipelineStateDescription.VertexShader.Data, + + PixelShader = PipelineStateDescription.PixelShader == null ? null : PipelineStateDescription.PixelShader.Data, + }; + + oldPipelineState = GraphicsDevice.NativeDevice.CreateGraphicsPipelineState(psoDesc); + } + + + private void CreateRootSignature() + { + + //RootDescriptorTable table = new RootDescriptorTable() + //{ + //Ranges = new DescriptorRange() + // { + + // } + //} + + //RootParameter rootParameter = new RootParameter(RootDescriptorTable) + //{ + // DescriptorTable = new RootDescriptorTable + //} + + + DescriptorRange Ranges = new DescriptorRange() + { + BaseShaderRegister = 0, + NumDescriptors = 1, + OffsetInDescriptorsFromTableStart = 0, + RangeType = DescriptorRangeType.ShaderResourceView, + RegisterSpace = 0, + }; + + RootParameter[] slotRootParameters = new RootParameter[] + { + //new RootParameter(new roo + //new RootParameter(RootParameterType.ConstantBufferView, new RootDescriptor(0, 0), ShaderVisibility.All), + //new RootParameter(RootParameterType.ConstantBufferView, new RootDescriptor(1, 0), ShaderVisibility.All), + //new RootParameter(RootParameterType.ShaderResourceView, new RootDescriptor(1, 0), ShaderVisibility.All), + //new RootParameter(new RootDescriptorTable(new DescriptorRange[]{ Ranges }), ShaderVisibility.All) + }; + + + + + RootSignatureDescription SignatureDesc = new RootSignatureDescription() + { + Flags = RootSignatureFlags.AllowInputAssemblerInputLayout, + //Parameters = slotRootParameters, + //StaticSamplers = new StaticSamplerDescription[] + //{ + // new StaticSamplerDescription() + // { + + // ShaderRegister = 0, + // RegisterSpace = 0, + // ShaderVisibility = ShaderVisibility.Pixel, + + // Filter = Filter.MinMagMipPoint, + // AddressU = TextureAddressMode.Border, + // AddressV = TextureAddressMode.Border, + // AddressW = TextureAddressMode.Border, + // MipLODBias = 0, + // MaxAnisotropy = 0, + // ComparisonFunction = ComparisonFunction.Never, + // BorderColor = StaticBorderColor.TransparentBlack, + // MinLOD = 0.0f, + // MaxLOD = int.MaxValue, + // } + //}, + }; + + + RootSignature = GraphicsDevice.NativeDevice.CreateRootSignature(0, SignatureDesc, RootSignatureVersion.Version10); + //RootSignature. + } + } +} diff --git a/Src/Xultaik.Graphics/PipelineStateDescription.cs b/Src/Xultaik.Graphics/PipelineStateDescription.cs new file mode 100644 index 0000000..ab23e13 --- /dev/null +++ b/Src/Xultaik.Graphics/PipelineStateDescription.cs @@ -0,0 +1,20 @@ +// Copyright (c) Faber Leonardo. All Rights Reserved. https://github.com/FaberSanZ +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + + + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xultaik.Graphics +{ + public class PipelineStateDescription + { + public ShaderByteCode VertexShader { get; set; } + public ShaderByteCode PixelShader { get; set; } + public ShaderByteCode HullShader { get; set; } + public ShaderByteCode GeometryShader { get; set; } + public ShaderByteCode DomainShader { get; set; } + } +} diff --git a/Src/Xultaik.Graphics/PixelFormat.cs b/Src/Xultaik.Graphics/PixelFormat.cs new file mode 100644 index 0000000..28791eb --- /dev/null +++ b/Src/Xultaik.Graphics/PixelFormat.cs @@ -0,0 +1,254 @@ +// Copyright (c) Faber Leonardo. All Rights Reserved. https://github.com/FaberSanZ +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + + + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xultaik.Graphics +{ + public enum PixelFormat : int + { + + Unknown = 0, + + R32G32B32A32_Typeless = 1, + + R32G32B32A32_Float = 2, + + R32G32B32A32_UInt = 3, + + R32G32B32A32_SInt = 4, + + R32G32B32_Typeless = 5, + + R32G32B32_Float = 6, + + R32G32B32_UInt = 7, + + R32G32B32_SInt = 8, + + R16G16B16A16_Typeless = 9, + + R16G16B16A16_Float = 10, + + R16G16B16A16_UNorm = 11, + + R16G16B16A16_UInt = 12, + + R16G16B16A16_SNorm = 13, + + R16G16B16A16_SInt = 14, + + R32G32_Typeless = 15, + + R32G32_Float = 16, + + R32G32_UInt = 17, + + R32G32_SInt = 18, + + R32G8X24_Typeless = 19, + + D32_Float_S8X24_UInt = 20, + + R32_Float_X8X24_Typeless = 21, + + X32_Typeless_G8X24_UInt = 22, + + R10G10B10A2_Typeless = 23, + + R10G10B10A2_UNorm = 24, + + R10G10B10A2_UInt = 25, + + R11G11B10_Float = 26, + + R8G8B8A8_Typeless = 27, + + R8G8B8A8_UNorm = 28, + + R8G8B8A8_UNorm_SRgb = 29, + + R8G8B8A8_UInt = 30, + + R8G8B8A8_SNorm = 31, + + R8G8B8A8_SInt = 32, + + R16G16_Typeless = 33, + + R16G16_Float = 34, + + R16G16_UNorm = 35, + + R16G16_UInt = 36, + + R16G16_SNorm = 37, + + R16G16_SInt = 38, + + R32_Typeless = 39, + + D32_Float = 40, + + R32_Float = 41, + + R32_UInt = 42, + + R32_SInt = 43, + + R24G8_Typeless = 44, + + D24_UNorm_S8_UInt = 45, + + R24_UNorm_X8_Typeless = 46, + + X24_Typeless_G8_UInt = 47, + + R8G8_Typeless = 48, + + R8G8_UNorm = 49, + + R8G8_UInt = 50, + + R8G8_SNorm = 51, + + R8G8_SInt = 52, + + R16_Typeless = 53, + + R16_Float = 54, + + D16_UNorm = 55, + + R16_UNorm = 56, + + R16_UInt = 57, + + R16_SNorm = 58, + + R16_SInt = 59, + + R8_Typeless = 60, + + R8_UNorm = 61, + + R8_UInt = 62, + + R8_SNorm = 63, + + R8_SInt = 64, + + A8_UNorm = 65, + + R1_UNorm = 66, + + R9G9B9E5_Sharedexp = 67, + + R8G8_B8G8_UNorm = 68, + + G8R8_G8B8_UNorm = 69, + + BC1_Typeless = 70, + + BC1_UNorm = 71, + + BC1_UNorm_SRgb = 72, + + BC2_Typeless = 73, + + BC2_UNorm = 74, + + BC2_UNorm_SRgb = 75, + + BC3_Typeless = 76, + + BC3_UNorm = 77, + + BC3_UNorm_SRgb = 78, + + BC4_Typeless = 79, + + BC4_UNorm = 80, + + BC4_SNorm = 81, + + BC5_Typeless = 82, + + BC5_UNorm = 83, + + BC5_SNorm = 84, + + B5G6R5_UNorm = 85, + + B5G5R5A1_UNorm = 86, + + B8G8R8A8_UNorm = 87, + + B8G8R8X8_UNorm = 88, + + R10G10B10_Xr_Bias_A2_UNorm = 89, + + B8G8R8A8_Typeless = 90, + + B8G8R8A8_UNorm_SRgb = 91, + + B8G8R8X8_Typeless = 92, + + B8G8R8X8_UNorm_SRgb = 93, + + BC6H_Typeless = 94, + + BC6H_Uf16 = 95, + + BC6H_Sf16 = 96, + + BC7_Typeless = 97, + + BC7_UNorm = 98, + + BC7_UNorm_SRgb = 99, + + AYUV = 100, + + Y410 = 101, + + Y416 = 102, + + NV12 = 103, + + P010 = 104, + + P016 = 105, + + Opaque420 = 106, + + YUY2 = 107, + + Y210 = 108, + + Y216 = 109, + + NV11 = 110, + + AI44 = 111, + + IA44 = 112, + + P8 = 113, + + A8P8 = 114, + + B4G4R4A4_UNorm = 115, + + P208 = 130, + + V208 = 131, + + V408 = 132 + } + +} \ No newline at end of file diff --git a/Src/Xultaik.Graphics/PrimitiveType.cs b/Src/Xultaik.Graphics/PrimitiveType.cs new file mode 100644 index 0000000..74ccbb9 --- /dev/null +++ b/Src/Xultaik.Graphics/PrimitiveType.cs @@ -0,0 +1,100 @@ +// Co// Copyright (c) Faber Leonardo. All Rights Reserved. https://github.com/FaberSanZ +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + + + + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xultaik.Graphics +{ + public enum PrimitiveType : int + { + + Undefined = unchecked(0), + + PointList = unchecked(1), + + LineList = unchecked(2), + + LineStrip = unchecked(3), + + TriangleList = unchecked(4), + + TriangleStrip = unchecked(5), + + LineListAdjacency = unchecked(10), + + LineStripAdjacency = unchecked(11), + + TriangleListAdjacency = unchecked(12), + + TriangleStripAdjacency = unchecked(13), + + PatchListWith1ControlPoints = unchecked(33), + + PatchListWith2ControlPoints = unchecked(34), + + PatchListWith3ControlPoints = unchecked(35), + + PatchListWith4ControlPoints = unchecked(36), + + PatchListWith5ControlPoints = unchecked(37), + + PatchListWith6ControlPoints = unchecked(38), + + PatchListWith7ControlPoints = unchecked(39), + + PatchListWith8ControlPoints = unchecked(40), + + PatchListWith9ControlPoints = unchecked(41), + + PatchListWith10ControlPoints = unchecked(42), + + PatchListWith11ControlPoints = unchecked(43), + + PatchListWith12ControlPoints = unchecked(44), + + PatchListWith13ControlPoints = unchecked(45), + + PatchListWith14ControlPoints = unchecked(46), + + PatchListWith15ControlPoints = unchecked(47), + + PatchListWith16ControlPoints = unchecked(48), + + PatchListWith17ControlPoints = unchecked(49), + + PatchListWith18ControlPoints = unchecked(50), + + PatchListWith19ControlPoints = unchecked(51), + + PatchListWith20ControlPoints = unchecked(52), + + PatchListWith21ControlPoints = unchecked(53), + + PatchListWith22ControlPoints = unchecked(54), + + PatchListWith23ControlPoints = unchecked(55), + + PatchListWith24ControlPoints = unchecked(56), + + PatchListWith25ControlPoints = unchecked(57), + + PatchListWith26ControlPoints = unchecked(58), + + PatchListWith27ControlPoints = unchecked(59), + + PatchListWith28ControlPoints = unchecked(60), + + PatchListWith29ControlPoints = unchecked(61), + + PatchListWith30ControlPoints = unchecked(62), + + PatchListWith31ControlPoints = unchecked(63), + + PatchListWith32ControlPoints = unchecked(64) + } +} diff --git a/Src/Xultaik.Graphics/RenderDescriptor.cs b/Src/Xultaik.Graphics/RenderDescriptor.cs new file mode 100644 index 0000000..54d77fc --- /dev/null +++ b/Src/Xultaik.Graphics/RenderDescriptor.cs @@ -0,0 +1,26 @@ +// Copyright (c) Faber Leonardo. All Rights Reserved. https://github.com/FaberSanZ +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + + + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xultaik.Graphics +{ + public struct RenderDescriptor + { + + public PixelFormat BackBufferFormat { get; set; } + + public int BackBufferWidth { get; set; } + + public int BackBufferHeight { get; set; } + + public IntPtr DeviceHandle { get; set; } + + public Settings Settings { get; set; } + + } +} \ No newline at end of file diff --git a/Src/Xultaik.Graphics/Settings.cs b/Src/Xultaik.Graphics/Settings.cs new file mode 100644 index 0000000..c55588d --- /dev/null +++ b/Src/Xultaik.Graphics/Settings.cs @@ -0,0 +1,19 @@ +// Copyright (c) Faber Leonardo. All Rights Reserved. https://github.com/FaberSanZ +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + + + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xultaik.Graphics +{ + public class Settings + { + public bool Fullscreen { get; set; } + + public bool VSync { get; set; } + + } +} \ No newline at end of file diff --git a/Src/Xultaik.Graphics/ShaderByteCode.cs b/Src/Xultaik.Graphics/ShaderByteCode.cs new file mode 100644 index 0000000..c9ece22 --- /dev/null +++ b/Src/Xultaik.Graphics/ShaderByteCode.cs @@ -0,0 +1,75 @@ +// Copyright (c) Faber Leonardo. All Rights Reserved. https://github.com/FaberSanZ +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + + + + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Vortice.Dxc; + +namespace Xultaik.Graphics +{ + public class ShaderByteCode + { + + public byte[] Data = Array.Empty(); + + + public ShaderStage ShaderStage { get; set; } + + public ShaderModel ShaderModel { get; set; } + + public string Source { get; set; } + + public string EntryPoint { get; set; } + + public ShaderByteCode() + { + + } + + + public ShaderByteCode(string source, ShaderStage stage, string entrypoint, ShaderModel shaderModel) + { + Source = source; + ShaderStage = stage; + EntryPoint = entrypoint; + ShaderModel = shaderModel; + + Recreate(); + } + + + internal void Recreate() + { + DxcCompilerOptions options = new DxcCompilerOptions() + { + ShaderModel = ConvertExtensions.ToDxcShaderModel(ShaderModel), + + }; + + + //IDxcOperationResult result = DxcCompiler.Compile(ConvertExtensions.ToDxcShaderStage(ShaderStage), Source, EntryPoint, "", options); + + //Data = Dxc.GetBytesFromBlob(result.GetResult()); + } + + + public static ShaderByteCode CompileFromFile(string fileName, ShaderStage stage, string entrypoint = "", ShaderModel shaderModel = ShaderModel.Model6_0) + { + if (string.IsNullOrEmpty(entrypoint)) + entrypoint = ConvertExtensions.GetDefaultEntryPoint(stage); + + + return new ShaderByteCode(File.ReadAllText(fileName), stage, entrypoint, shaderModel); + } + + + + public static implicit operator byte[](ShaderByteCode value) => value.Data; + + } +} diff --git a/Src/Xultaik.Graphics/ShaderModel.cs b/Src/Xultaik.Graphics/ShaderModel.cs new file mode 100644 index 0000000..b3838ee --- /dev/null +++ b/Src/Xultaik.Graphics/ShaderModel.cs @@ -0,0 +1,28 @@ +// Copyright (c) Faber Leonardo. All Rights Reserved. https://github.com/FaberSanZ +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + + + + + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xultaik.Graphics +{ + public enum ShaderModel + { + Model6_0, + + Model6_1, + + Model6_2, + + Model6_3, + + Model6_4, + + Model6_5, + } +} diff --git a/Src/Xultaik.Graphics/ShaderStage.cs b/Src/Xultaik.Graphics/ShaderStage.cs new file mode 100644 index 0000000..6944f50 --- /dev/null +++ b/Src/Xultaik.Graphics/ShaderStage.cs @@ -0,0 +1,31 @@ +// Copyright (c) Faber Leonardo. All Rights Reserved. https://github.com/FaberSanZ +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + + + + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xultaik.Graphics +{ + public enum ShaderStage + { + VertexShader = 0, + + PixelShader = 1, + + GeometryShader = 2, + + HullShader = 3, + + DomainShader = 4, + + ComputeShader = 5, + + //Library = 6, + + //Count = 7 + } +} diff --git a/Src/Xultaik.Graphics/SwapChain.cs b/Src/Xultaik.Graphics/SwapChain.cs new file mode 100644 index 0000000..1bc089b --- /dev/null +++ b/Src/Xultaik.Graphics/SwapChain.cs @@ -0,0 +1,148 @@ +// Copyright (c) Faber Leonardo. All Rights Reserved. https://github.com/FaberSanZ +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + + + +using System; +using System.Collections.Generic; +using System.Text; +using Vortice.Direct3D; +using Vortice.DXGI; +using static Vortice.DXGI.DXGI; + +using static Vortice.Direct3D12.D3D12; +using System.Runtime.InteropServices; +using Vortice.Direct3D12; + +namespace Xultaik.Graphics +{ + public class SwapChain + { + public RenderDescriptor Description { get; private set; } + + public Texture BackBuffer { get; set; } + + public int BackBufferIndex { get; private set; } = 0; + + + + + internal IDXGISwapChain3 NativeSwapChain; + internal GraphicsDevice GraphicsDevice; + private int bufferCount = 3; + + public SwapChain(GraphicsDevice graphicsDevice) + { + GraphicsDevice = graphicsDevice; + Description = graphicsDevice.NativeParameters; + + CreateSwapChain(); + + BackBufferIndex = NativeSwapChain.CurrentBackBufferIndex; + + + BackBuffer = new Texture(GraphicsDevice); + BackBuffer.InitializeFromImpl(NativeSwapChain.GetBuffer(BackBufferIndex)); + } + + + + private void CreateSwapChain() + { + + //switch (Description.Settings.Platform) + //{ + // case Platform.Win32: + // CreateSwapChainForDesktop(); + + // case Platform.UWP: + // default: + // throw new ArgumentException(); + + //} + + + CreateSwapChainForDesktop(); + + } + + public void Present() + { + NativeSwapChain.Present(1, PresentFlags.None); + BackBufferIndex = NativeSwapChain.CurrentBackBufferIndex; + + BackBuffer.Resource.Dispose(); + BackBuffer.InitializeFromImpl(NativeSwapChain.GetBuffer(BackBufferIndex)); + + } + + + + private void CreateSwapChainForDesktop() + { + + ModeDescription BackBufferDesc = new ModeDescription() + { + Width = Description.BackBufferWidth, + Height = Description.BackBufferHeight, + Format = Format.R8G8B8A8_UNorm, + RefreshRate = new Rational() + { + Numerator = 60, + Denominator = 1 + }, + ScanlineOrdering = ModeScanlineOrder.Unspecified, + Scaling = ModeScaling.Unspecified, + }; + + SampleDescription sampleDescription = new SampleDescription() + { + Count = 1, + Quality = 0 + }; + + SwapChainFlags Flags = Description.Settings.Fullscreen ? SwapChainFlags.None : SwapChainFlags.AllowModeSwitch; + + + + SwapChainDescription swapChainDesc = new SwapChainDescription() // Initialize the swap chain description. + { + BufferCount = bufferCount, // Set to a single back buffer. + BufferDescription = BackBufferDesc, // Set the width and height of the back buffer. + BufferUsage = Usage.Backbuffer | Usage.RenderTargetOutput, // Set the usage of the back buffer. + OutputWindow = Description.DeviceHandle, // Set the handle for the window to render to. + SampleDescription = sampleDescription, // Turn multisampling off. + Windowed = true, // Set to full screen or windowed mode. + Flags = Flags, // Don't set the advanced flags. + SwapEffect = SwapEffect.FlipDiscard, // Discard the back buffer content after presenting. + + + }; + + + + + + + IDXGIFactory4 Factory = GraphicsDevice.NativeAdapter.NativeFactory; + + IDXGISwapChain swapChain = Factory.CreateSwapChain(GraphicsDevice.NativeDirectCommandQueue.Queue, swapChainDesc); + + if (Description.Settings.Fullscreen) + { + // Before fullscreen switch + swapChain.ResizeTarget(BackBufferDesc); + + // Switch to full screen + swapChain.SetFullscreenState(true, default); + + // This is really important to call ResizeBuffers AFTER switching to IsFullScreen + swapChain.ResizeBuffers(3, Description.BackBufferWidth, Description.BackBufferHeight, Format.R8G8B8A8_UNorm, SwapChainFlags.AllowModeSwitch); + } + + + + NativeSwapChain = swapChain.QueryInterface(); + } + } +} diff --git a/Src/Xultaik.Graphics/Texture.cs b/Src/Xultaik.Graphics/Texture.cs new file mode 100644 index 0000000..25f6379 --- /dev/null +++ b/Src/Xultaik.Graphics/Texture.cs @@ -0,0 +1,78 @@ +// Copyright (c) Faber Leonardo. All Rights Reserved. https://github.com/FaberSanZ +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + + +using System; +using System.Collections.Generic; +using System.Text; +using Vortice.Direct3D12; +using Vortice.Direct3D; +using static Vortice.Direct3D12.D3D12; +using static Vortice.DXGI.DXGI; + +namespace Xultaik.Graphics +{ + public class Texture : GraphicsResource + { + public int Width { get; private set; } + + public int Height { get; private set; } + + + + internal CpuDescriptorHandle NativeRenderTargetView; + internal CpuDescriptorHandle NativeDepthStencilView; + internal ID3D12Resource Resource; + internal ID3D12Resource UploadResource; + + public Texture(GraphicsDevice device) : base(device) + { + + } + + + + internal void InitializeFromImpl(ID3D12Resource resource) + { + Resource = resource; + + NativeRenderTargetView = GetRenderTargetView(); + } + + private CpuDescriptorHandle GetRenderTargetView() + { + RenderTargetViewDescription RTVDescription = new RenderTargetViewDescription() + { + Buffer = new BufferRenderTargetView() + { + FirstElement = 0, + NumElements = 0 + }, + //Texture1D, + Format = Vortice.DXGI.Format.R8G8B8A8_UNorm, + //Texture1DArray + Texture2D = new Texture2DRenderTargetView() + { + MipSlice = 1, + PlaneSlice = 0 + }, + //Texture2DArray + Texture2DMS = new Texture2DMultisampledRenderTargetView() + { + // UnusedFieldNothingToDefine = 0x001, + }, + //Texture2DMSArray + //Texture3D + ViewDimension = RenderTargetViewDimension.Texture2D + + }; + + CpuDescriptorHandle descriptorHandle = GraphicsDevice.RenderTargetViewAllocator.Allocate(1); + + GraphicsDevice.NativeDevice.CreateRenderTargetView(Resource,/*null*/ RTVDescription, descriptorHandle); + + return descriptorHandle; + } + + } +} diff --git a/Src/Xultaik.Graphics/TextureData.cs b/Src/Xultaik.Graphics/TextureData.cs new file mode 100644 index 0000000..fffca4a --- /dev/null +++ b/Src/Xultaik.Graphics/TextureData.cs @@ -0,0 +1,66 @@ +// Copyright (c) Faber Leonardo. All Rights Reserved. https://github.com/FaberSanZ +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + + + + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xultaik.Graphics +{ + public class TextureData + { + public byte[] Data { get; internal set; } = Array.Empty(); + + public int Width { get; set; } + + public int Height { get; set; } + + public int Depth { get; set; } + + public int MipMaps { get; set; } + + public int Size { get; set; } + + public bool IsCubeMap { get; set; } + + public PixelFormat Format { get; set; } + + + + public TextureData(byte[] data, int width, int height, int depth, int mipMaps, int size, bool isCubeMap, PixelFormat format) + { + Data = data; + Width = width; + Height = height; + Depth = depth; + MipMaps = mipMaps; + Size = size; + IsCubeMap = isCubeMap; + Format = format; + } + + + public TextureData() + { + Data = Array.Empty(); + Width = 0; + Height = 0; + Depth = 0; + MipMaps = 0; + Size = 0; + IsCubeMap = false; + Format = PixelFormat.Unknown; + } + + + + + + //public override string ToString() => string.Format("Data:{0} Width:{1} Depth:{0} Width:{1} Data:{0} Width:{1}", Data.Length, Width, Height, Depth, MipMaps, Size, IsCubeMap, Format); + + + } +} diff --git a/Src/Xultaik.Graphics/Xultaik.Graphics.csproj b/Src/Xultaik.Graphics/Xultaik.Graphics.csproj index fa71b7a..8fce5b7 100644 --- a/Src/Xultaik.Graphics/Xultaik.Graphics.csproj +++ b/Src/Xultaik.Graphics/Xultaik.Graphics.csproj @@ -4,6 +4,18 @@ net8.0 enable enable + true + + + + + + + + + + +