diff --git a/src/Direct3D12/07_DrawTexturedCube/07_DrawTexturedCube.csproj b/src/Direct3D12/07_DrawTexturedCube/07_DrawTexturedCube.csproj
index 93a04b2..730293d 100644
--- a/src/Direct3D12/07_DrawTexturedCube/07_DrawTexturedCube.csproj
+++ b/src/Direct3D12/07_DrawTexturedCube/07_DrawTexturedCube.csproj
@@ -7,6 +7,7 @@
+
diff --git a/src/Direct3D12/07_DrawTexturedCube/DrawTexturedCubeApp.cs b/src/Direct3D12/07_DrawTexturedCube/DrawTexturedCubeApp.cs
index 2f951ca..2d13897 100644
--- a/src/Direct3D12/07_DrawTexturedCube/DrawTexturedCubeApp.cs
+++ b/src/Direct3D12/07_DrawTexturedCube/DrawTexturedCubeApp.cs
@@ -4,6 +4,7 @@
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
+using System.Text;
using Vortice.Direct3D12;
using Vortice.Dxc;
using Vortice.DXGI;
@@ -79,7 +80,7 @@ protected override void Initialize()
// Create pipeline
ReadOnlyMemory vertexShaderByteCode = CompileBytecode(DxcShaderStage.Vertex, "TexturedCube.hlsl", "VSMain");
ReadOnlyMemory pixelShaderByteCode = CompileBytecode(DxcShaderStage.Pixel, "TexturedCube.hlsl", "PSMain");
-
+
GraphicsPipelineStateDescription psoDesc = new()
{
RootSignature = _rootSignature,
@@ -97,29 +98,41 @@ protected override void Initialize()
_pipelineState = Device.CreateGraphicsPipelineState(psoDesc);
}
- private void CreateTexture()
+ private void CreateTexture(bool fromFile = true)
{
- Span pixels = [
- 0xFFFFFFFF,
- 0x00000000,
- 0xFFFFFFFF,
- 0x00000000,
- 0x00000000,
- 0xFFFFFFFF,
- 0x00000000,
- 0xFFFFFFFF,
- 0xFFFFFFFF,
- 0x00000000,
- 0xFFFFFFFF,
- 0x00000000,
- 0x00000000,
- 0xFFFFFFFF,
- 0x00000000,
- 0xFFFFFFFF,
- ];
-
- _texture = D3D12ResourceUtils.CreateTexture2D(Device, UploadBatch, 4, 4,
- Format.R8G8B8A8_UNorm, pixels);
+ if (fromFile)
+ {
+ string assetsPath = Path.Combine(AppContext.BaseDirectory, "Textures");
+ string textureFile = Path.Combine(assetsPath, "10points.png");
+
+ Image image = Image.FromFile(textureFile)!;
+ _texture = D3D12ResourceUtils.CreateTexture2D(Device, UploadBatch,
+ image.Width, image.Height, image.Format, image.Data.Span,
+ generateMips: true);
+ }
+ else
+ {
+ Span pixels = [
+ 0xFFFFFFFF,
+ 0x00000000,
+ 0xFFFFFFFF,
+ 0x00000000,
+ 0x00000000,
+ 0xFFFFFFFF,
+ 0x00000000,
+ 0xFFFFFFFF,
+ 0xFFFFFFFF,
+ 0x00000000,
+ 0xFFFFFFFF,
+ 0x00000000,
+ 0x00000000,
+ 0xFFFFFFFF,
+ 0x00000000,
+ 0xFFFFFFFF,
+ ];
+
+ _texture = D3D12ResourceUtils.CreateTexture2D(Device, UploadBatch, 4, 4, Format.R8G8B8A8_UNorm, pixels);
+ }
}
protected override void OnDestroy()
diff --git a/src/Direct3D12/07_DrawTexturedCube/Shaders/TexturedCube.hlsl b/src/Direct3D12/07_DrawTexturedCube/Shaders/TexturedCube.hlsl
index 3d8a887..01ea208 100644
--- a/src/Direct3D12/07_DrawTexturedCube/Shaders/TexturedCube.hlsl
+++ b/src/Direct3D12/07_DrawTexturedCube/Shaders/TexturedCube.hlsl
@@ -24,7 +24,7 @@ PSInput VSMain(in VSInput input)
PSInput result;
result.Position = mul(worldViewProjection, float4(input.Position, 1.0f));
result.Normal = input.Normal;
- result.Texcoord = input.Texcoord * 5.0f;
+ result.Texcoord = input.Texcoord;
return result;
}
diff --git a/src/Direct3D12/07_DrawTexturedCube/Textures/10points.png b/src/Direct3D12/07_DrawTexturedCube/Textures/10points.png
new file mode 100644
index 0000000..a932146
Binary files /dev/null and b/src/Direct3D12/07_DrawTexturedCube/Textures/10points.png differ
diff --git a/src/Vortice.Framework/D3D12/D3D12ResourceUploadBatch.cs b/src/Vortice.Framework/D3D12/D3D12ResourceUploadBatch.cs
index ea467ff..98b8162 100644
--- a/src/Vortice.Framework/D3D12/D3D12ResourceUploadBatch.cs
+++ b/src/Vortice.Framework/D3D12/D3D12ResourceUploadBatch.cs
@@ -12,6 +12,8 @@
// Port of DirectXTK12 ResourceUploadBatch
using System.Diagnostics;
+using System.Numerics;
+using System.Runtime.InteropServices;
using CommunityToolkit.Diagnostics;
using Vortice.Direct3D12;
using Vortice.DXGI;
@@ -26,7 +28,8 @@ public sealed class D3D12ResourceUploadBatch
private bool _inBeginEndBlock;
private ID3D12CommandAllocator? _commandAllocator;
private ID3D12GraphicsCommandList? _commandList;
- private readonly List _trackedObjects = [];
+ private readonly List _trackedObjects = [];
+ private GenerateMipsResources? _genMipsResources;
public D3D12ResourceUploadBatch(ID3D12Device device)
{
@@ -77,7 +80,7 @@ public void End(ID3D12CommandQueue commandQueue)
commandQueue.Signal(fence, 1).CheckError();
fence.SetEventOnCompletion(1).CheckError();
- foreach (ID3D12Resource resource in _trackedObjects)
+ foreach (ID3D12DeviceChild resource in _trackedObjects)
{
resource.Dispose();
}
@@ -163,7 +166,291 @@ public unsafe void Upload(ID3D12Resource resource, int subresourceIndexStart,
// Resource must be in the PIXEL_SHADER_RESOURCE state
public void GenerateMips(ID3D12Resource resource)
{
- // TODO
+ if (!_inBeginEndBlock)
+ throw new InvalidOperationException("Can't call GenerateMips on a closed ResourceUploadBatch.");
+
+ if (_commandType == CommandListType.Copy)
+ {
+ throw new InvalidOperationException("GenerateMips cannot operate on a copy queue");
+ }
+
+ ResourceDescription desc = resource.Description;
+ if (desc.MipLevels == 1)
+ {
+ // Nothing to do
+ return;
+ }
+ if (desc.MipLevels == 0)
+ {
+ throw new InvalidOperationException("GenerateMips: texture has no mips");
+ }
+ if (desc.Dimension != ResourceDimension.Texture2D)
+ {
+ throw new InvalidOperationException("GenerateMips only supports Texture2D resources");
+ }
+
+ if (desc.DepthOrArraySize != 1)
+ {
+ throw new InvalidOperationException("GenerateMips only supports 2D textures of array size 1");
+ }
+
+ bool uavCompat = FormatIsUAVCompatible(Device, _options.TypedUAVLoadAdditionalFormats, desc.Format);
+
+ if (!uavCompat && !desc.Format.IsSRGB() && !desc.Format.IsBGR())
+ {
+ throw new InvalidOperationException("GenerateMips doesn't support this texture format on this device");
+ }
+
+ // Ensure that we have valid generate mips data
+ _genMipsResources ??= new GenerateMipsResources(Device);
+
+ // If the texture's format doesn't support UAVs we'll have to copy it to a texture that does first.
+ // This is true of BGRA or sRGB textures, for example.
+ if (uavCompat)
+ {
+ GenerateMips_UnorderedAccessPath(resource);
+ }
+ else if (!_options.TypedUAVLoadAdditionalFormats)
+ {
+ throw new InvalidOperationException("GenerateMips needs TypedUAVLoadAdditionalFormats device support for sRGB/BGR");
+ }
+ else if (desc.Format.IsBGR())
+ {
+ if (!_options.StandardSwizzle64KBSupported)
+ {
+ throw new InvalidOperationException("GenerateMips needs StandardSwizzle64KBSupported device support for BGR");
+ }
+
+ //GenerateMips_TexturePathBGR(resource);
+ }
+ else
+ {
+ GenerateMips_TexturePath(resource);
+ }
+ }
+
+ private unsafe void GenerateMips_UnorderedAccessPath(ID3D12Resource resource)
+ {
+ ResourceDescription desc = resource.Description;
+ Debug.Assert(!desc.Format.IsBGR() && !desc.Format.IsSRGB());
+ Debug.Assert(_commandList is not null);
+
+ //const CD3DX12_HEAP_PROPERTIES defaultHeapProperties(D3D12_HEAP_TYPE_DEFAULT);
+
+ Debug.Assert(_commandType != CommandListType.Copy);
+ ResourceStates originalState = (_commandType == CommandListType.Compute) ? ResourceStates.CopyDest : ResourceStates.PixelShaderResource;
+
+ // Create a staging resource if we have to
+ ID3D12Resource staging;
+ if ((desc.Flags & ResourceFlags.AllowUnorderedAccess) == 0)
+ {
+ ResourceDescription stagingDesc = desc;
+ stagingDesc.Flags |= ResourceFlags.AllowUnorderedAccess;
+ stagingDesc.Format = ConvertSRVtoResourceFormat(desc.Format);
+
+ staging = Device.CreateCommittedResource(
+ HeapType.Default,
+ HeapFlags.None,
+ stagingDesc,
+ ResourceStates.CopyDest
+ );
+
+ staging.Name = "GenerateMips Staging";
+
+ // Copy the top mip of resource to staging
+ Transition(resource, originalState, ResourceStates.CopySource);
+
+ TextureCopyLocation src = new(resource, 0);
+ TextureCopyLocation dst = new(staging, 0);
+ _commandList.CopyTextureRegion(dst, 0, 0, 0, src);
+
+ Transition(staging, ResourceStates.CopyDest, ResourceStates.NonPixelShaderResource);
+ }
+ else
+ {
+ // Resource is already a UAV so we can do this in-place
+ staging = resource;
+
+ Transition(staging, originalState, ResourceStates.NonPixelShaderResource);
+ }
+
+ // Create a descriptor heap that holds our resource descriptors
+ DescriptorHeapDescription descriptorHeapDesc = new(
+ DescriptorHeapType.ConstantBufferViewShaderResourceViewUnorderedAccessView,
+ desc.MipLevels,
+ DescriptorHeapFlags.ShaderVisible);
+ ID3D12DescriptorHeap descriptorHeap = Device.CreateDescriptorHeap(descriptorHeapDesc);
+ descriptorHeap.Name = "ResourceUploadBatch";
+ int descriptorSize = Device.GetDescriptorHandleIncrementSize(DescriptorHeapType.ConstantBufferViewShaderResourceViewUnorderedAccessView);
+
+ // Create the top-level SRV
+ CpuDescriptorHandle handleIt = descriptorHeap.GetCPUDescriptorHandleForHeapStart();
+ ShaderResourceViewDescription srvDesc = new()
+ {
+ Format = desc.Format,
+ ViewDimension = ShaderResourceViewDimension.Texture2D,
+ Shader4ComponentMapping = ShaderComponentMapping.Default
+ };
+ srvDesc.Texture2D.MostDetailedMip = 0;
+ srvDesc.Texture2D.MipLevels = desc.MipLevels;
+ Device.CreateShaderResourceView(staging, srvDesc, handleIt);
+
+ // Create the UAVs for the tail
+ for (int mip = 1; mip < desc.MipLevels; ++mip)
+ {
+ UnorderedAccessViewDescription uavDesc = new()
+ {
+ Format = desc.Format,
+ ViewDimension = UnorderedAccessViewDimension.Texture2D
+ };
+ uavDesc.Texture2D.MipSlice = mip;
+
+ handleIt.Offset(descriptorSize);
+ Device.CreateUnorderedAccessView(staging, null, uavDesc, handleIt);
+ }
+
+ // based on format, select srgb or not
+ ID3D12PipelineState pso = _genMipsResources!.GenerateMipsPSO;
+
+ // Set up state
+ _commandList.SetComputeRootSignature(_genMipsResources.RootSignature);
+ _commandList.SetPipelineState(pso);
+ _commandList.SetDescriptorHeaps(descriptorHeap);
+
+ GpuDescriptorHandle handle = descriptorHeap.GetGPUDescriptorHandleForHeapStart();
+
+ _commandList.SetComputeRootDescriptorTable((int)GenerateMipsResources.RootParameterIndex.SourceTexture, handle);
+
+ // Get the descriptor handle -- uavH will increment over each loop
+ GpuDescriptorHandle uavH = new(handle, descriptorSize); // offset by 1 descriptor
+
+ // Process each mip
+ int mipWidth = (int)desc.Width;
+ int mipHeight = desc.Height;
+ for (int mip = 1; mip < desc.MipLevels; ++mip)
+ {
+ mipWidth = Math.Max(1, mipWidth >> 1);
+ mipHeight = Math.Max(1, mipHeight >> 1);
+
+ // Transition the mip to a UAV
+ ResourceBarrier srv2uavDesc = ResourceBarrier.BarrierTransition(staging, ResourceStates.NonPixelShaderResource, ResourceStates.UnorderedAccess, mip);
+ _commandList.ResourceBarrier(srv2uavDesc);
+
+ // Bind the mip subresources
+ _commandList.SetComputeRootDescriptorTable((int)GenerateMipsResources.RootParameterIndex.TargetTexture, uavH);
+
+ // Set constants
+ GenerateMipsResources.ConstantData constants;
+ constants.SrcMipIndex = (uint)mip - 1;
+ constants.InvOutTexelSize = new(1 / (float)mipWidth, 1 / (float)mipHeight);
+ _commandList.SetComputeRoot32BitConstants(
+ (int)GenerateMipsResources.RootParameterIndex.Constants,
+ GenerateMipsResources.Num32BitConstants,
+ &constants,
+ 0);
+
+ // Process this mip
+ _commandList.Dispatch(
+ (mipWidth + GenerateMipsResources.ThreadGroupSize - 1) / GenerateMipsResources.ThreadGroupSize,
+ (mipHeight + GenerateMipsResources.ThreadGroupSize - 1) / GenerateMipsResources.ThreadGroupSize,
+ 1);
+
+ // Set up UAV barrier (used in loop)
+ ResourceBarrier barrierUAV = ResourceBarrier.BarrierUnorderedAccessView(staging);
+ _commandList.ResourceBarrier(barrierUAV);
+
+ // Transition the mip to an SRV
+ ResourceBarrier uav2srvDesc = ResourceBarrier.BarrierTransition(staging, ResourceStates.UnorderedAccess, ResourceStates.NonPixelShaderResource, mip);
+ _commandList.ResourceBarrier(uav2srvDesc);
+
+ // Offset the descriptor heap handles
+ uavH.Offset(descriptorSize);
+ }
+
+ // If the staging resource is NOT the same as the resource, we need to copy everything back
+ if (staging != resource)
+ {
+ // Transition the resources ready for copy
+ Span barriers = new ResourceBarrier[2];
+ barriers[0] = ResourceBarrier.BarrierTransition(staging, ResourceStates.NonPixelShaderResource, ResourceStates.CopySource);
+ barriers[1] = ResourceBarrier.BarrierTransition(resource, ResourceStates.CopySource, ResourceStates.CopyDest);
+ _commandList.ResourceBarrier(barriers);
+
+ // Copy the entire resource back
+ _commandList.CopyResource(resource, staging);
+
+ // Transition the target resource back to pixel shader resource
+ Transition(resource, ResourceStates.CopyDest, originalState);
+
+ _trackedObjects.Add(staging);
+ }
+ else
+ {
+ Transition(staging, ResourceStates.NonPixelShaderResource, originalState);
+ }
+
+ // Add our temporary objects to the deferred deletion queue
+ _trackedObjects.Add(_genMipsResources.RootSignature);
+ _trackedObjects.Add(pso);
+ if (staging != resource)
+ {
+ _trackedObjects.Add(staging);
+ }
+ _trackedObjects.Add(descriptorHeap);
+ }
+
+ private void GenerateMips_TexturePath(ID3D12Resource resource)
+ {
+ Debug.Assert(_commandList is not null);
+ Debug.Assert(_commandType != CommandListType.Copy);
+ ResourceDescription resourceDesc = resource.Description;
+ Debug.Assert(!resourceDesc.Format.IsBGR() || resourceDesc.Format.IsSRGB());
+
+ ResourceDescription copyDesc = resourceDesc;
+ copyDesc.Format = Format.R8G8B8A8_UNorm;
+ copyDesc.Flags |= ResourceFlags.AllowUnorderedAccess;
+
+ // Create a resource with the same description, but without SRGB, and with UAV flags
+ ID3D12Resource resourceCopy = Device.CreateCommittedResource(
+ HeapType.Default,
+ HeapFlags.None,
+ copyDesc,
+ ResourceStates.CopyDest
+ );
+
+ resourceCopy.Name = "GenerateMips Resource Copy";
+
+ ResourceStates originalState = _commandType == CommandListType.Compute
+ ? ResourceStates.CopyDest : ResourceStates.PixelShaderResource;
+
+ // Copy the top mip of resource data
+ Transition(resource, originalState, ResourceStates.CopySource);
+
+ TextureCopyLocation src = new(resource, 0);
+ TextureCopyLocation dst = new(resourceCopy, 0);
+ _commandList.CopyTextureRegion(dst, 0, 0, 0, src);
+
+ Transition(resourceCopy, ResourceStates.CopyDest, originalState);
+
+ // Generate the mips
+ GenerateMips_UnorderedAccessPath(resourceCopy);
+
+ // Direct copy back
+ Span barriers =
+ [
+ ResourceBarrier.BarrierTransition(resourceCopy, originalState, ResourceStates.CopySource),
+ ResourceBarrier.BarrierTransition(resource, ResourceStates.CopySource, ResourceStates.CopyDest)
+ ];
+ _commandList.ResourceBarrier(barriers);
+
+ // Copy the entire resource back
+ _commandList.CopyResource(resource, resourceCopy);
+
+ Transition(resource, ResourceStates.CopyDest, originalState);
+
+ // Track these object lifetimes on the GPU
+ _trackedObjects.Add(resourceCopy);
+ //_trackedObjects.Add(resource);
}
public bool IsSupportedForGenerateMips(Format format)
@@ -189,7 +476,7 @@ public bool IsSupportedForGenerateMips(Format format)
return false;
}
- static bool FormatIsUAVCompatible(ID3D12Device device, bool typedUAVLoadAdditionalFormats, Format format)
+ private static bool FormatIsUAVCompatible(ID3D12Device device, bool typedUAVLoadAdditionalFormats, Format format)
{
switch (format)
{
@@ -257,4 +544,150 @@ static bool FormatIsUAVCompatible(ID3D12Device device, bool typedUAVLoadAddition
return false;
}
}
+
+ private static Format ConvertSRVtoResourceFormat(Format format)
+ {
+ switch (format)
+ {
+ case Format.R32G32B32A32_Float:
+ case Format.R32G32B32A32_UInt:
+ case Format.R32G32B32A32_SInt:
+ return Format.R32G32B32A32_Typeless;
+
+ case Format.R16G16B16A16_Float:
+ case Format.R16G16B16A16_UNorm:
+ case Format.R16G16B16A16_UInt:
+ case Format.R16G16B16A16_SNorm:
+ case Format.R16G16B16A16_SInt:
+ return Format.R16G16B16A16_Typeless;
+
+ case Format.R32G32_Float:
+ case Format.R32G32_UInt:
+ case Format.R32G32_SInt:
+ return Format.R32G32_Typeless;
+
+ case Format.R10G10B10A2_UNorm:
+ case Format.R10G10B10A2_UInt:
+ return Format.R10G10B10A2_Typeless;
+
+ case Format.R8G8B8A8_UNorm:
+ case Format.R8G8B8A8_UInt:
+ case Format.R8G8B8A8_SNorm:
+ case Format.R8G8B8A8_SInt:
+ return Format.R8G8B8A8_Typeless;
+
+ case Format.R16G16_Float:
+ case Format.R16G16_UNorm:
+ case Format.R16G16_UInt:
+ case Format.R16G16_SNorm:
+ case Format.R16G16_SInt:
+ return Format.R16G16_Typeless;
+
+ case Format.R32_Float:
+ case Format.R32_UInt:
+ case Format.R32_SInt:
+ return Format.R32_Typeless;
+
+ case Format.R8G8_UNorm:
+ case Format.R8G8_UInt:
+ case Format.R8G8_SNorm:
+ case Format.R8G8_SInt:
+ return Format.R8G8_Typeless;
+
+ case Format.R16_Float:
+ case Format.R16_UNorm:
+ case Format.R16_UInt:
+ case Format.R16_SNorm:
+ case Format.R16_SInt:
+ return Format.R16_Typeless;
+
+ case Format.R8_UNorm:
+ case Format.R8_UInt:
+ case Format.R8_SNorm:
+ case Format.R8_SInt:
+ return Format.R8_Typeless;
+
+ default:
+ return format;
+ }
+ }
+
+ unsafe class GenerateMipsResources
+ {
+ private readonly ID3D12Device _device;
+ public readonly ID3D12RootSignature RootSignature;
+ public readonly ID3D12PipelineState GenerateMipsPSO;
+
+ public static readonly int Num32BitConstants = sizeof(ConstantData) / sizeof(uint);
+ public const int ThreadGroupSize = 8;
+
+ #region Bytecode
+ public static byte[] GenerateMipsBytecode => [
+ 68, 88, 66, 67, 145, 28, 144, 166, 89, 15, 96, 67, 230, 22, 237, 237, 0, 38, 12, 156, 1, 0, 0, 0, 56, 9, 0, 0, 7, 0, 0, 0, 60, 0, 0, 0, 76, 0, 0, 0, 92, 0, 0, 0, 108, 0, 0, 0, 36, 1, 0, 0, 232, 1, 0, 0, 4, 2, 0, 0, 83, 70, 73, 48, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73, 83, 71, 49, 8, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 79, 83, 71, 49, 8, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 80, 83, 86, 48, 176, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 4, 0, 0, 0, 24, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 109, 97, 105, 110, 0, 0, 0, 0, 0, 0, 0, 82, 84, 83, 48, 188, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 24, 0, 0, 0, 1, 0, 0, 0, 136, 0, 0, 0, 62, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 1, 0, 0, 0, 112, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 20, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 255, 255, 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 65, 83, 72, 20, 0, 0, 0, 0, 0, 0, 0, 186, 247, 129, 247, 85, 239, 239, 202, 76, 80, 78, 160, 156, 27, 111, 71, 68, 88, 73, 76, 44, 7, 0, 0, 100, 0, 5, 0, 203, 1, 0, 0, 68, 88, 73, 76, 4, 1, 0, 0, 16, 0, 0, 0, 20, 7, 0, 0, 66, 67, 192, 222, 33, 12, 0, 0, 194, 1, 0, 0, 11, 130, 32, 0, 2, 0, 0, 0, 19, 0, 0, 0, 7, 129, 35, 145, 65, 200, 4, 73, 6, 16, 50, 57, 146, 1, 132, 12, 37, 5, 8, 25, 30, 4, 139, 98, 128, 24, 69, 2, 66, 146, 11, 66, 196, 16, 50, 20, 56, 8, 24, 75, 10, 50, 98, 136, 72, 144, 20, 32, 67, 70, 136, 165, 0, 25, 50, 66, 228, 72, 14, 144, 17, 35, 196, 80, 65, 81, 129, 140, 225, 131, 229, 138, 4, 49, 70, 6, 81, 24, 0, 0, 8, 0, 0, 0, 27, 140, 224, 255, 255, 255, 255, 7, 64, 2, 168, 13, 132, 240, 255, 255, 255, 255, 3, 32, 109, 48, 134, 255, 255, 255, 255, 31, 0, 9, 168, 0, 73, 24, 0, 0, 3, 0, 0, 0, 19, 130, 96, 66, 32, 76, 8, 6, 0, 0, 0, 0, 137, 32, 0, 0, 101, 0, 0, 0, 50, 34, 136, 9, 32, 100, 133, 4, 19, 35, 164, 132, 4, 19, 35, 227, 132, 161, 144, 20, 18, 76, 140, 140, 11, 132, 196, 76, 16, 144, 193, 8, 64, 9, 0, 10, 230, 8, 192, 160, 12, 195, 48, 16, 49, 71, 128, 144, 113, 207, 112, 249, 19, 246, 16, 146, 31, 2, 205, 176, 16, 40, 56, 102, 0, 202, 2, 12, 200, 48, 12, 73, 146, 36, 6, 41, 55, 13, 151, 63, 97, 15, 33, 249, 43, 33, 173, 196, 228, 23, 183, 141, 138, 36, 73, 146, 161, 48, 204, 128, 32, 73, 146, 36, 195, 48, 36, 212, 28, 53, 92, 254, 132, 61, 132, 228, 115, 27, 85, 172, 196, 228, 35, 183, 141, 136, 97, 24, 134, 66, 60, 3, 50, 16, 116, 212, 112, 249, 19, 246, 16, 146, 207, 109, 84, 177, 18, 147, 95, 220, 54, 34, 146, 36, 73, 10, 33, 13, 200, 64, 211, 28, 65, 80, 12, 100, 48, 134, 161, 34, 107, 32, 96, 24, 129, 72, 102, 106, 131, 113, 96, 135, 112, 152, 135, 121, 112, 3, 90, 40, 7, 124, 160, 135, 122, 144, 135, 114, 144, 3, 82, 224, 3, 123, 40, 135, 113, 160, 135, 119, 144, 7, 62, 48, 7, 118, 120, 135, 112, 160, 7, 54, 0, 3, 58, 240, 3, 48, 240, 3, 61, 208, 131, 118, 72, 7, 120, 152, 135, 95, 160, 135, 124, 128, 135, 114, 64, 193, 48, 147, 24, 140, 3, 59, 132, 195, 60, 204, 131, 27, 208, 66, 57, 224, 3, 61, 212, 131, 60, 148, 131, 28, 144, 2, 31, 216, 67, 57, 140, 3, 61, 188, 131, 60, 240, 129, 57, 176, 195, 59, 132, 3, 61, 176, 1, 24, 208, 129, 31, 128, 129, 31, 32, 33, 211, 104, 155, 137, 12, 198, 129, 29, 194, 97, 30, 230, 193, 13, 100, 225, 22, 104, 161, 28, 240, 129, 30, 234, 65, 30, 202, 65, 14, 72, 129, 15, 236, 161, 28, 198, 129, 30, 222, 65, 30, 248, 192, 28, 216, 225, 29, 194, 129, 30, 216, 0, 12, 232, 192, 15, 192, 192, 15, 80, 144, 81, 55, 140, 32, 36, 199, 152, 200, 195, 57, 141, 52, 1, 205, 36, 33, 225, 27, 8, 188, 73, 154, 34, 74, 152, 124, 22, 96, 158, 133, 136, 216, 9, 152, 8, 20, 12, 36, 2, 19, 20, 114, 192, 135, 116, 96, 135, 54, 104, 135, 121, 104, 3, 114, 192, 135, 13, 175, 80, 14, 109, 208, 14, 122, 80, 14, 109, 0, 15, 122, 48, 7, 114, 160, 7, 115, 32, 7, 109, 144, 14, 113, 160, 7, 115, 32, 7, 109, 144, 14, 120, 160, 7, 115, 32, 7, 109, 144, 14, 113, 96, 7, 122, 48, 7, 114, 208, 6, 233, 48, 7, 114, 160, 7, 115, 32, 7, 109, 144, 14, 118, 64, 7, 122, 96, 7, 116, 208, 6, 230, 16, 7, 118, 160, 7, 115, 32, 7, 109, 96, 14, 115, 32, 7, 122, 48, 7, 114, 208, 6, 230, 96, 7, 116, 160, 7, 118, 64, 7, 109, 224, 14, 120, 160, 7, 113, 96, 7, 122, 48, 7, 114, 160, 7, 118, 64, 7, 67, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 60, 4, 16, 0, 1, 0, 0, 0, 0, 0, 0, 0, 12, 121, 20, 32, 0, 4, 0, 0, 0, 0, 0, 0, 0, 24, 242, 52, 64, 0, 12, 0, 0, 0, 0, 0, 0, 0, 48, 228, 129, 128, 0, 24, 0, 0, 0, 0, 0, 0, 0, 96, 200, 51, 1, 1, 48, 0, 0, 0, 0, 0, 0, 0, 192, 144, 199, 2, 2, 96, 0, 0, 0, 0, 0, 0, 0, 128, 44, 16, 12, 0, 0, 0, 50, 30, 152, 20, 25, 17, 76, 144, 140, 9, 38, 71, 198, 4, 67, 26, 74, 160, 16, 10, 162, 24, 70, 0, 138, 160, 36, 10, 131, 170, 17, 0, 226, 102, 0, 200, 155, 1, 160, 112, 6, 128, 198, 25, 0, 0, 0, 0, 121, 24, 0, 0, 68, 0, 0, 0, 26, 3, 76, 144, 70, 2, 19, 68, 143, 12, 111, 236, 237, 77, 12, 36, 198, 5, 199, 69, 134, 6, 166, 198, 37, 166, 6, 4, 197, 140, 236, 166, 172, 134, 70, 108, 140, 44, 101, 67, 16, 76, 16, 134, 99, 130, 48, 32, 27, 132, 129, 152, 32, 12, 201, 6, 97, 48, 40, 140, 205, 77, 16, 6, 101, 195, 128, 36, 196, 4, 97, 88, 38, 8, 28, 68, 96, 130, 48, 48, 19, 132, 161, 217, 32, 44, 207, 134, 100, 97, 154, 101, 25, 156, 5, 218, 16, 68, 19, 4, 47, 154, 32, 84, 207, 134, 101, 153, 154, 101, 25, 28, 138, 162, 160, 13, 65, 53, 65, 8, 3, 105, 130, 48, 56, 27, 144, 229, 106, 150, 101, 192, 128, 13, 65, 54, 65, 24, 131, 105, 3, 178, 108, 205, 178, 12, 11, 176, 33, 224, 54, 16, 146, 165, 117, 19, 4, 1, 32, 209, 22, 150, 230, 182, 97, 48, 140, 97, 131, 64, 132, 193, 134, 226, 3, 3, 192, 19, 131, 42, 108, 108, 118, 109, 46, 105, 100, 101, 110, 116, 83, 130, 160, 10, 25, 158, 139, 93, 153, 220, 92, 218, 155, 219, 148, 128, 104, 66, 134, 231, 98, 23, 198, 102, 87, 38, 55, 37, 48, 234, 144, 225, 185, 204, 161, 133, 145, 149, 201, 53, 189, 145, 149, 177, 77, 9, 146, 50, 100, 120, 46, 114, 101, 115, 111, 117, 114, 99, 101, 115, 83, 130, 174, 14, 25, 158, 75, 153, 27, 157, 92, 30, 212, 91, 154, 27, 221, 220, 148, 64, 12, 0, 121, 24, 0, 0, 76, 0, 0, 0, 51, 8, 128, 28, 196, 225, 28, 102, 20, 1, 61, 136, 67, 56, 132, 195, 140, 66, 128, 7, 121, 120, 7, 115, 152, 113, 12, 230, 0, 15, 237, 16, 14, 244, 128, 14, 51, 12, 66, 30, 194, 193, 29, 206, 161, 28, 102, 48, 5, 61, 136, 67, 56, 132, 131, 27, 204, 3, 61, 200, 67, 61, 140, 3, 61, 204, 120, 140, 116, 112, 7, 123, 8, 7, 121, 72, 135, 112, 112, 7, 122, 112, 3, 118, 120, 135, 112, 32, 135, 25, 204, 17, 14, 236, 144, 14, 225, 48, 15, 110, 48, 15, 227, 240, 14, 240, 80, 14, 51, 16, 196, 29, 222, 33, 28, 216, 33, 29, 194, 97, 30, 102, 48, 137, 59, 188, 131, 59, 208, 67, 57, 180, 3, 60, 188, 131, 60, 132, 3, 59, 204, 240, 20, 118, 96, 7, 123, 104, 7, 55, 104, 135, 114, 104, 7, 55, 128, 135, 112, 144, 135, 112, 96, 7, 118, 40, 7, 118, 248, 5, 118, 120, 135, 119, 128, 135, 95, 8, 135, 113, 24, 135, 114, 152, 135, 121, 152, 129, 44, 238, 240, 14, 238, 224, 14, 245, 192, 14, 236, 48, 3, 98, 200, 161, 28, 228, 161, 28, 204, 161, 28, 228, 161, 28, 220, 97, 28, 202, 33, 28, 196, 129, 29, 202, 97, 6, 214, 144, 67, 57, 200, 67, 57, 152, 67, 57, 200, 67, 57, 184, 195, 56, 148, 67, 56, 136, 3, 59, 148, 195, 47, 188, 131, 60, 252, 130, 59, 212, 3, 59, 176, 195, 12, 196, 33, 7, 124, 112, 3, 122, 40, 135, 118, 128, 135, 25, 209, 67, 14, 248, 224, 6, 228, 32, 14, 231, 224, 6, 246, 16, 14, 242, 192, 14, 225, 144, 15, 239, 80, 15, 244, 0, 0, 0, 113, 32, 0, 0, 30, 0, 0, 0, 86, 176, 13, 151, 239, 60, 190, 16, 80, 69, 65, 68, 165, 3, 12, 37, 97, 0, 2, 230, 23, 183, 109, 4, 219, 112, 249, 206, 227, 11, 1, 85, 20, 68, 84, 58, 192, 80, 18, 6, 32, 96, 62, 114, 219, 102, 32, 13, 151, 239, 60, 190, 16, 17, 192, 68, 132, 64, 51, 44, 132, 13, 84, 195, 229, 59, 143, 47, 1, 204, 179, 16, 37, 81, 17, 139, 95, 220, 182, 9, 88, 195, 229, 59, 143, 63, 17, 215, 68, 69, 4, 59, 57, 17, 225, 23, 183, 109, 1, 210, 112, 249, 206, 227, 79, 71, 68, 0, 131, 56, 248, 200, 109, 27, 0, 193, 0, 72, 3, 0, 97, 32, 0, 0, 56, 0, 0, 0, 19, 4, 65, 44, 16, 0, 0, 0, 9, 0, 0, 0, 52, 148, 92, 233, 6, 148, 221, 12, 64, 241, 149, 97, 0, 25, 37, 48, 2, 80, 6, 69, 80, 30, 148, 140, 17, 128, 32, 8, 194, 223, 12, 0, 0, 0, 0, 0, 35, 6, 9, 0, 130, 96, 96, 109, 205, 97, 89, 210, 136, 65, 2, 128, 32, 24, 88, 156, 115, 92, 215, 52, 98, 144, 0, 32, 8, 6, 86, 247, 28, 24, 70, 141, 24, 36, 0, 8, 130, 129, 229, 65, 71, 150, 85, 35, 6, 6, 0, 130, 96, 64, 144, 1, 164, 141, 24, 24, 0, 8, 130, 1, 81, 6, 209, 119, 66, 82, 39, 36, 101, 130, 2, 31, 19, 22, 248, 140, 24, 28, 0, 8, 130, 193, 100, 6, 213, 1, 6, 163, 9, 1, 48, 154, 32, 4, 38, 20, 242, 177, 66, 144, 207, 136, 193, 1, 128, 32, 24, 64, 108, 160, 49, 101, 48, 154, 16, 8, 23, 36, 53, 98, 240, 0, 32, 8, 6, 13, 28, 108, 17, 84, 16, 211, 132, 6, 104, 192, 5, 163, 9, 1, 48, 154, 32, 4, 163, 9, 131, 48, 154, 64, 12, 35, 6, 14, 0, 130, 96, 160, 216, 193, 119, 77, 82, 24, 16, 131, 16, 104, 8, 0, 0, 0, 0, 0, 0, 0
+ ];
+ #endregion
+
+ [StructLayout(LayoutKind.Sequential, Pack = 4)]
+ public struct ConstantData
+ {
+ public Vector2 InvOutTexelSize;
+ public uint SrcMipIndex;
+ private uint _pading;
+ };
+
+ public GenerateMipsResources(ID3D12Device device)
+ {
+ _device = device;
+
+ // CreateGenMipsRootSignature
+ RootSignatureFlags rootSignatureFlags = RootSignatureFlags.DenyVertexShaderRootAccess
+ | RootSignatureFlags.DenyHullShaderRootAccess
+ | RootSignatureFlags.DenyDomainShaderRootAccess
+ | RootSignatureFlags.DenyGeometryShaderRootAccess
+ | RootSignatureFlags.DenyPixelShaderRootAccess;
+
+ StaticSamplerDescription sampler = new(
+ Filter.MinMagLinearMipPoint,
+ TextureAddressMode.Clamp,
+ TextureAddressMode.Clamp,
+ TextureAddressMode.Clamp,
+ 0,
+ 16,
+ ComparisonFunction.LessEqual,
+ StaticBorderColor.OpaqueWhite, 0.0f, float.MaxValue,
+ 0, 0, ShaderVisibility.All);
+
+ DescriptorRange sourceDescriptorRange = new(DescriptorRangeType.ShaderResourceView, 1, 0);
+ DescriptorRange targetDescriptorRange = new(DescriptorRangeType.UnorderedAccessView, 1, 0);
+
+ RootParameter[] rootParameters = new RootParameter[(int)RootParameterIndex.Count];
+ rootParameters[(int)RootParameterIndex.Constants] = new RootParameter(new RootConstants(0, 0, Num32BitConstants), ShaderVisibility.All);
+ rootParameters[(int)RootParameterIndex.SourceTexture] = new RootParameter(new RootDescriptorTable(sourceDescriptorRange), ShaderVisibility.All);
+ rootParameters[(int)RootParameterIndex.TargetTexture] = new RootParameter(new RootDescriptorTable(targetDescriptorRange), ShaderVisibility.All);
+
+ RootSignature = device.CreateRootSignature(
+ new RootSignatureDescription(rootSignatureFlags, rootParameters,
+ [
+ sampler
+ ]), RootSignatureVersion.Version10
+ );
+
+
+ ComputePipelineStateDescription csoDesc = new()
+ {
+ RootSignature = RootSignature,
+ ComputeShader = GenerateMipsBytecode
+ };
+ GenerateMipsPSO = device.CreateComputePipelineState(csoDesc);
+ }
+
+ public enum RootParameterIndex
+ {
+ Constants,
+ SourceTexture,
+ TargetTexture,
+ Count
+ };
+ }
+
}
diff --git a/src/Vortice.Framework/D3D12/D3D12ResourceUtils.cs b/src/Vortice.Framework/D3D12/D3D12ResourceUtils.cs
index fd12156..e504b2f 100644
--- a/src/Vortice.Framework/D3D12/D3D12ResourceUtils.cs
+++ b/src/Vortice.Framework/D3D12/D3D12ResourceUtils.cs
@@ -156,7 +156,7 @@ public static ID3D12Resource CreateTexture2D(
D3D12ResourceUploadBatch resourceUpload,
int width, int height, Format format,
Span data,
- //bool generateMips = false,
+ bool generateMips = false,
ResourceStates afterState = ResourceStates.PixelShaderResource,
ResourceFlags flags = ResourceFlags.None)
where T : unmanaged
@@ -166,7 +166,6 @@ public static ID3D12Resource CreateTexture2D(
throw new InvalidOperationException($"ERROR: Resource dimensions too large for DirectX 12 (2D: size {width} by {height})");
}
- bool generateMips = false;
ushort mipLevels = 1;
if (generateMips)
{
diff --git a/src/Vortice.Framework/Vortice.Framework.csproj b/src/Vortice.Framework/Vortice.Framework.csproj
index 4b3f096..030b937 100644
--- a/src/Vortice.Framework/Vortice.Framework.csproj
+++ b/src/Vortice.Framework/Vortice.Framework.csproj
@@ -47,4 +47,8 @@
+
+
+
+