diff --git a/src/grabs.Graphics.D3D11/D3D11Device.cs b/src/grabs.Graphics.D3D11/D3D11Device.cs index f3f2a3d..99001a5 100644 --- a/src/grabs.Graphics.D3D11/D3D11Device.cs +++ b/src/grabs.Graphics.D3D11/D3D11Device.cs @@ -97,6 +97,11 @@ public override DescriptorSet CreateDescriptorSet(DescriptorLayout layout, in Re return new D3D11DescriptorSet(descriptions.ToArray()); } + public override Sampler CreateSampler(in SamplerDescription description) + { + return new D3D11Sampler(Device, description); + } + public override void UpdateBuffer(Buffer buffer, uint offsetInBytes, uint sizeInBytes, void* pData) { D3D11Buffer d3dBuffer = (D3D11Buffer) buffer; diff --git a/src/grabs.Graphics.D3D11/D3D11Sampler.cs b/src/grabs.Graphics.D3D11/D3D11Sampler.cs new file mode 100644 index 0000000..71bae0d --- /dev/null +++ b/src/grabs.Graphics.D3D11/D3D11Sampler.cs @@ -0,0 +1,62 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using TerraFX.Interop.DirectX; +using static TerraFX.Interop.DirectX.D3D11_FILTER; +using static grabs.Graphics.D3D11.D3DResult; + +namespace grabs.Graphics.D3D11; + +[SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")] +public sealed unsafe class D3D11Sampler : Sampler +{ + public ID3D11SamplerState* SamplerState; + + public D3D11Sampler(ID3D11Device* device, in SamplerDescription description) : base(description) + { + D3D11_FILTER filter; + if (description.EnableAnisotropy) + filter = D3D11_FILTER_ANISOTROPIC; + else + { + filter = (description.MinFilter, description.MagFilter, description.MipFilter) switch + { + (TextureFilter.Point, TextureFilter.Point, TextureFilter.Point) => D3D11_FILTER_MIN_MAG_MIP_POINT, + (TextureFilter.Point, TextureFilter.Point, TextureFilter.Linear) => D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR, + (TextureFilter.Point, TextureFilter.Linear, TextureFilter.Point) => D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT, + (TextureFilter.Point, TextureFilter.Linear, TextureFilter.Linear) => D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR, + (TextureFilter.Linear, TextureFilter.Point, TextureFilter.Point) => D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT, + (TextureFilter.Linear, TextureFilter.Point, TextureFilter.Linear) => D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR, + (TextureFilter.Linear, TextureFilter.Linear, TextureFilter.Point) => D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT, + (TextureFilter.Linear, TextureFilter.Linear, TextureFilter.Linear) => D3D11_FILTER_MIN_MAG_MIP_LINEAR, + _ => throw new ArgumentOutOfRangeException() + }; + } + + D3D11_SAMPLER_DESC desc = new() + { + Filter = filter, + AddressU = D3D11Utils.TextureAddressToD3D(description.AddressU), + AddressV = D3D11Utils.TextureAddressToD3D(description.AddressV), + AddressW = D3D11Utils.TextureAddressToD3D(description.AddressW), + MipLODBias = description.MipLodBias, + MaxAnisotropy = description.MaxAnisotropy, + ComparisonFunc = D3D11Utils.ComparisonFunctionToD3D(description.Comparison), + MinLOD = description.MinLod, + MaxLOD = description.MaxLod + }; + + // TODO: Is there a better way of doing this? + desc.BorderColor[0] = description.BorderColor.X; + desc.BorderColor[1] = description.BorderColor.Y; + desc.BorderColor[2] = description.BorderColor.Z; + desc.BorderColor[3] = description.BorderColor.W; + + fixed (ID3D11SamplerState** samplerState = &SamplerState) + CheckResult(device->CreateSamplerState(&desc, samplerState), "Create sampler state"); + } + + public override void Dispose() + { + SamplerState->Release(); + } +} \ No newline at end of file diff --git a/src/grabs.Graphics.D3D11/D3D11Utils.cs b/src/grabs.Graphics.D3D11/D3D11Utils.cs index 226cd1b..0a95b68 100644 --- a/src/grabs.Graphics.D3D11/D3D11Utils.cs +++ b/src/grabs.Graphics.D3D11/D3D11Utils.cs @@ -7,6 +7,7 @@ using static TerraFX.Interop.DirectX.D3D11_BLEND_OP; using static TerraFX.Interop.DirectX.D3D11_COMPARISON_FUNC; using static TerraFX.Interop.DirectX.D3D11_MAP; +using static TerraFX.Interop.DirectX.D3D11_TEXTURE_ADDRESS_MODE; using static TerraFX.Interop.DirectX.DXGI_FORMAT; namespace grabs.Graphics.D3D11; @@ -173,4 +174,16 @@ public static D3D11_MAP MapModeToD3D(MapMode mapMode) _ => throw new ArgumentOutOfRangeException(nameof(mapMode), mapMode, null) }; } + + public static D3D11_TEXTURE_ADDRESS_MODE TextureAddressToD3D(TextureAddress address) + { + return address switch + { + TextureAddress.RepeatWrap => D3D11_TEXTURE_ADDRESS_WRAP, + TextureAddress.RepeatWrapMirrored => D3D11_TEXTURE_ADDRESS_MIRROR, + TextureAddress.ClampToEdge => D3D11_TEXTURE_ADDRESS_CLAMP, + TextureAddress.ClampToBorder => D3D11_TEXTURE_ADDRESS_BORDER, + _ => throw new ArgumentOutOfRangeException(nameof(address), address, null) + }; + } } \ No newline at end of file diff --git a/src/grabs.Graphics.GL43/GL43Device.cs b/src/grabs.Graphics.GL43/GL43Device.cs index 44b7dae..5ee0205 100644 --- a/src/grabs.Graphics.GL43/GL43Device.cs +++ b/src/grabs.Graphics.GL43/GL43Device.cs @@ -77,6 +77,11 @@ public override DescriptorSet CreateDescriptorSet(DescriptorLayout layout, in Re return new GL43DescriptorSet(descriptions.ToArray()); } + public override Sampler CreateSampler(in SamplerDescription description) + { + throw new NotImplementedException(); + } + public override unsafe void UpdateBuffer(Buffer buffer, uint offsetInBytes, uint sizeInBytes, void* pData) { GL43Buffer glBuffer = (GL43Buffer) buffer; diff --git a/src/grabs.Graphics.Vulkan/VkDevice.cs b/src/grabs.Graphics.Vulkan/VkDevice.cs index db4bdc4..a4dbd4d 100644 --- a/src/grabs.Graphics.Vulkan/VkDevice.cs +++ b/src/grabs.Graphics.Vulkan/VkDevice.cs @@ -102,6 +102,11 @@ public override DescriptorSet CreateDescriptorSet(DescriptorLayout layout, in Re throw new NotImplementedException(); } + public override Sampler CreateSampler(in SamplerDescription description) + { + throw new NotImplementedException(); + } + public override unsafe void UpdateBuffer(Buffer buffer, uint offsetInBytes, uint sizeInBytes, void* pData) { throw new NotImplementedException(); diff --git a/src/grabs.Graphics/Device.cs b/src/grabs.Graphics/Device.cs index 2c7e3a3..8cf43d6 100644 --- a/src/grabs.Graphics/Device.cs +++ b/src/grabs.Graphics/Device.cs @@ -90,6 +90,8 @@ public DescriptorSet CreateDescriptorSet(DescriptorLayout layout, params Descrip public abstract DescriptorSet CreateDescriptorSet(DescriptorLayout layout, in ReadOnlySpan descriptions); + public abstract Sampler CreateSampler(in SamplerDescription description); + public unsafe void UpdateBuffer(Buffer buffer, uint offsetInBytes, T data) where T : unmanaged => UpdateBuffer(buffer, offsetInBytes, (uint) sizeof(T), data); diff --git a/src/grabs.Graphics/Sampler.cs b/src/grabs.Graphics/Sampler.cs index 7db5732..ff25510 100644 --- a/src/grabs.Graphics/Sampler.cs +++ b/src/grabs.Graphics/Sampler.cs @@ -4,5 +4,12 @@ namespace grabs.Graphics; public abstract class Sampler : IDisposable { + public readonly SamplerDescription Description; + + protected Sampler(in SamplerDescription description) + { + Description = description; + } + public abstract void Dispose(); } \ No newline at end of file diff --git a/tests/grabs.Tests/Tests/CubeTest.cs b/tests/grabs.Tests/Tests/CubeTest.cs index 48e8872..6ce82c8 100644 --- a/tests/grabs.Tests/Tests/CubeTest.cs +++ b/tests/grabs.Tests/Tests/CubeTest.cs @@ -20,12 +20,13 @@ public class CubeTest : TestBase private Buffer _cameraBuffer; private Buffer _transformBuffer; - + private Pipeline _pipeline; private Texture _texture1; private Texture _texture2; - + private Sampler _sampler; + private DescriptorSet _transformSet; private DescriptorSet _textureSet; @@ -77,6 +78,8 @@ protected override void Initialize() new InputLayoutDescription(Format.R32G32_Float, 12, 0, InputType.PerVertex) // TexCoord }, DepthStencilDescription.DepthLessEqual, RasterizerDescription.CullClockwise, BlendDescription.Disabled, [transformLayout, textureLayout])); + + _sampler = Device.CreateSampler(SamplerDescription.LinearWrap); ImageResult result1 = ImageResult.FromMemory(File.ReadAllBytes("Assets/awesomeface.png"), ColorComponents.RedGreenBlueAlpha); ImageResult result2 = ImageResult.FromMemory(File.ReadAllBytes("Assets/BAGELMIP.png"), ColorComponents.RedGreenBlueAlpha); @@ -160,6 +163,7 @@ public override void Dispose() _texture2.Dispose(); _texture1.Dispose(); + _sampler.Dispose(); _pipeline.Dispose();