feat(rhi): refactor resource & barrier management for D3D12

Modernizes resource and barrier management for the D3D12 backend. Key changes:
- Simplifies BarrierDesc by removing nullable "before" states; now inferred from resource database.
- Adds IsAliasing flag to BarrierDesc for aliasing transitions.
- Replaces ResourceMemoryType with HeapType in BufferDesc and related APIs.
- Enhances ResourceViewGroup with usage inference methods.
- Adds D3D12 utility helpers for heap/flag conversions and resource description extraction.
- Optimizes command buffer barrier emission, skipping redundant barriers.
- Refactors Material and RenderContext to use new APIs and state tracking.
- Updates ResourceManager pooling to use HeapType and standard Queue.
- Simplifies RenderGraphExecutor barrier logic and aliasing handling.
- Improves RenderSystem frame synchronization and resource retirement.
- Cleans up obsolete code and improves debug output.

BREAKING CHANGE: Updates to resource and barrier APIs require changes to all code interfacing with resource creation, barriers, and memory types.
This commit is contained in:
2026-04-03 17:03:41 +09:00
parent 6321b36ef5
commit ba9e24c46c
20 changed files with 316 additions and 422 deletions

View File

@@ -200,13 +200,20 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
switch (desc.Type)
{
case BarrierType.Global:
if (desc.SyncAfter == _resourceDatabase.globalBarrier.sync && desc.AccessAfter == _resourceDatabase.globalBarrier.access)
{
continue;
}
pGlobalBarriers[globalIndex++] = new D3D12_GLOBAL_BARRIER
{
SyncBefore = (D3D12_BARRIER_SYNC)(desc.SyncBefore ?? 0),
SyncBefore = (D3D12_BARRIER_SYNC)_resourceDatabase.globalBarrier.sync,
SyncAfter = (D3D12_BARRIER_SYNC)desc.SyncAfter,
AccessBefore = (D3D12_BARRIER_ACCESS)(desc.AccessBefore ?? 0),
AccessBefore = (D3D12_BARRIER_ACCESS)_resourceDatabase.globalBarrier.access,
AccessAfter = (D3D12_BARRIER_ACCESS)desc.AccessAfter
};
_resourceDatabase.globalBarrier = new ResourceBarrierData(BarrierLayout.Undefined, desc.AccessAfter, desc.SyncAfter);
break;
case BarrierType.Buffer:
{
@@ -218,12 +225,19 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
}
ref var record = ref r.Value;
var accessBefore = desc.IsAliasing ? BarrierAccess.NoAccess : record.barrierData.access;
if (record.barrierData.sync == desc.SyncAfter && accessBefore == desc.AccessAfter)
{
continue;
}
var resource = record.ResourcePtr;
pBufferBarriers[bufferIndex++] = new D3D12_BUFFER_BARRIER
{
SyncBefore = (D3D12_BARRIER_SYNC)(desc.SyncBefore ?? record.barrierData.sync),
SyncBefore = (D3D12_BARRIER_SYNC)record.barrierData.sync,
SyncAfter = (D3D12_BARRIER_SYNC)desc.SyncAfter,
AccessBefore = (D3D12_BARRIER_ACCESS)(desc.AccessBefore ?? record.barrierData.access),
AccessBefore = (D3D12_BARRIER_ACCESS)accessBefore,
AccessAfter = (D3D12_BARRIER_ACCESS)desc.AccessAfter,
pResource = resource,
Offset = 0,
@@ -243,14 +257,22 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
}
ref var record = ref r.Value;
var accessBefore = desc.IsAliasing ? BarrierAccess.NoAccess : record.barrierData.access;
var layoutBefore = desc.IsAliasing ? BarrierLayout.Undefined : record.barrierData.layout;
if (record.barrierData.sync == desc.SyncAfter && accessBefore == desc.AccessAfter && layoutBefore == desc.LayoutAfter)
{
continue;
}
var resource = record.ResourcePtr;
pTextureBarriers[textureIndex++] = new D3D12_TEXTURE_BARRIER
{
SyncBefore = (D3D12_BARRIER_SYNC)(desc.SyncBefore ?? record.barrierData.sync),
SyncBefore = (D3D12_BARRIER_SYNC)record.barrierData.sync,
SyncAfter = (D3D12_BARRIER_SYNC)desc.SyncAfter,
AccessBefore = (D3D12_BARRIER_ACCESS)(desc.AccessBefore ?? record.barrierData.access),
AccessBefore = (D3D12_BARRIER_ACCESS)accessBefore,
AccessAfter = (D3D12_BARRIER_ACCESS)desc.AccessAfter,
LayoutBefore = (D3D12_BARRIER_LAYOUT)(desc.LayoutBefore ?? record.barrierData.layout),
LayoutBefore = (D3D12_BARRIER_LAYOUT)layoutBefore,
LayoutAfter = (D3D12_BARRIER_LAYOUT)desc.LayoutAfter,
pResource = resource,
Subresources = new D3D12_BARRIER_SUBRESOURCE_RANGE
@@ -272,39 +294,44 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
var groups = stackalloc D3D12_BARRIER_GROUP[3];
var groupCount = 0u;
if (globalCount > 0)
if (globalIndex > 0)
{
groups[groupCount] = new D3D12_BARRIER_GROUP
{
Type = D3D12_BARRIER_TYPE.D3D12_BARRIER_TYPE_GLOBAL,
NumBarriers = (uint)globalCount,
NumBarriers = (uint)globalIndex,
};
groups[groupCount].Anonymous.pGlobalBarriers = pGlobalBarriers;
groupCount++;
}
if (bufferCount > 0)
if (bufferIndex > 0)
{
groups[groupCount] = new D3D12_BARRIER_GROUP
{
Type = D3D12_BARRIER_TYPE.D3D12_BARRIER_TYPE_BUFFER,
NumBarriers = (uint)bufferCount,
NumBarriers = (uint)bufferIndex,
};
groups[groupCount].Anonymous.pBufferBarriers = pBufferBarriers;
groupCount++;
}
if (textureCount > 0)
if (textureIndex > 0)
{
groups[groupCount] = new D3D12_BARRIER_GROUP
{
Type = D3D12_BARRIER_TYPE.D3D12_BARRIER_TYPE_TEXTURE,
NumBarriers = (uint)textureCount,
NumBarriers = (uint)textureIndex,
};
groups[groupCount].Anonymous.pTextureBarriers = pTextureBarriers;
groupCount++;
}
if (groupCount == 0)
{
return;
}
pNativeObject->Barrier(groupCount, groups);
}

View File

@@ -140,7 +140,7 @@ internal unsafe class D3D12PipelineLibrary : D3D12Object<ID3D12PipelineLibrary1>
fs.Write(buffer.AsSpan());
}
private static Result<CBufferInfo> ValidateReflectionData(ShaderReflectionData reflectionData)
private static Result ValidateReflectionData(ShaderReflectionData reflectionData)
{
if (reflectionData.ResourcesBindings.Count > RootSignatureLayout.ROOT_PARAMETER_COUNT)
{
@@ -149,7 +149,7 @@ internal unsafe class D3D12PipelineLibrary : D3D12Object<ID3D12PipelineLibrary1>
if (reflectionData.ResourcesBindings.Count == 0)
{
return Result.Success(default(CBufferInfo));
return Result.Success();
}
var rootConstant = reflectionData.ResourcesBindings[0];
@@ -163,16 +163,7 @@ internal unsafe class D3D12PipelineLibrary : D3D12Object<ID3D12PipelineLibrary1>
return Result.Failure($"Root constant buffer size must be {sizeof(PushConstantsData)} bytes.");
}
var cbufferInfo = new CBufferInfo
{
Name = rootConstant.Name,
RegisterSlot = rootConstant.BindPoint,
RegisterSpace = rootConstant.Space,
SizeInBytes = rootConstant.Size,
Properties = rootConstant.Properties
};
return Result.Success(cbufferInfo);
return Result.Success();
}
private static D3D12_DEPTH_STENCIL_DESC BuildDepthStencil(ZTest ztest, ZWrite zwrite)
@@ -185,7 +176,7 @@ internal unsafe class D3D12PipelineLibrary : D3D12Object<ID3D12PipelineLibrary1>
public Result<Key128<GraphicsPipeline>> CompilePSO(ref readonly GraphicsPSODescriptor descriptor, ref readonly GraphicsCompiledResult compiled)
{
static Result<CBufferInfo> ValidatePassReflectionData(ref readonly GraphicsCompiledResult compiled)
static Result ValidatePassReflectionData(ref readonly GraphicsCompiledResult compiled)
{
var msr = ValidateReflectionData(compiled.msResult.reflectionData);
if (msr.IsFailure)
@@ -199,12 +190,6 @@ internal unsafe class D3D12PipelineLibrary : D3D12Object<ID3D12PipelineLibrary1>
return Result.Failure("Validation of pixel shader reflection data failed: " + psr.Message);
}
if (msr.Value.Properties != null
&& msr.Value.SizeInBytes != psr.Value.SizeInBytes)
{
return Result.Failure("Mesh shader and pixel shader constant buffer layouts do not match.");
}
if (compiled.tsResult.IsCreated)
{
var tsr = ValidateReflectionData(compiled.tsResult.reflectionData);
@@ -212,16 +197,9 @@ internal unsafe class D3D12PipelineLibrary : D3D12Object<ID3D12PipelineLibrary1>
{
return Result.Failure("Validation of task shader reflection data failed: " + tsr.Message);
}
if (tsr.Value.Properties != null
&& tsr.Value.SizeInBytes != psr.Value.SizeInBytes)
{
return Result.Failure("Task shader and pixel shader constant buffer layouts do not match.");
}
}
// ts and ms may not use per material cbuffer at all, so we return the psr value.
return psr.Value;
return Result.Success();
}
AssertNotDisposed();
@@ -236,11 +214,11 @@ internal unsafe class D3D12PipelineLibrary : D3D12Object<ID3D12PipelineLibrary1>
if (!_pipelineCache.ContainsKey(pipelineKey))
{
//var result = ValidatePassReflectionData(in compiled);
//if (result.IsFailure)
//{
// return Result.Failure(result.Message);
//}
var result = ValidatePassReflectionData(in compiled);
if (result.IsFailure)
{
return result;
}
var desc = new D3DX12_MESH_SHADER_PIPELINE_STATE_DESC
{

View File

@@ -437,17 +437,6 @@ internal sealed unsafe partial class D3D12ResourceAllocator
return uavDesc;
}
private static D3D12_HEAP_TYPE ConvertMemoryType(ResourceMemoryType memoryType)
{
return memoryType switch
{
ResourceMemoryType.Default => D3D12_HEAP_TYPE_DEFAULT,
ResourceMemoryType.Upload => D3D12_HEAP_TYPE_UPLOAD,
ResourceMemoryType.Readback => D3D12_HEAP_TYPE_READBACK,
_ => throw new ArgumentException($"Unsupported memory type: {memoryType}")
};
}
}
internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
@@ -658,7 +647,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
Handle<GPUResource> resource;
if (isSubAllocation)
{
resource = _resourceDatabase.ImportExternalResource(pResource, barrierData, resourceDescriptor, name);
resource = _resourceDatabase.ImportExternalResource(pResource, barrierData, resourceDescriptor, ResourceDesc.Texture(desc), name);
}
else
{
@@ -686,7 +675,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
var allocationDesc = new D3D12MA_ALLOCATION_DESC
{
HeapType = ConvertMemoryType(desc.MemoryType),
HeapType = desc.HeapType.ToD3D12HeapType(),
Flags = D3D12MA_ALLOCATION_FLAG_NONE,
};
@@ -695,11 +684,11 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
ID3D12Resource* pResource = default;
HRESULT hr;
var initialState = desc.MemoryType switch
var initialState = desc.HeapType switch
{
ResourceMemoryType.Default => D3D12_RESOURCE_STATE_COMMON,
ResourceMemoryType.Upload => D3D12_RESOURCE_STATE_GENERIC_READ,
ResourceMemoryType.Readback => D3D12_RESOURCE_STATE_COPY_DEST,
HeapType.Default => D3D12_RESOURCE_STATE_COMMON,
HeapType.Upload => D3D12_RESOURCE_STATE_GENERIC_READ,
HeapType.Readback => D3D12_RESOURCE_STATE_COPY_DEST,
_ => D3D12_RESOURCE_STATE_COMMON
};
@@ -770,7 +759,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
Handle<GPUResource> resource;
if (isSubAllocation)
{
resource = _resourceDatabase.ImportExternalResource(pResource, barrierData, resourceDescriptor, name);
resource = _resourceDatabase.ImportExternalResource(pResource, barrierData, resourceDescriptor, ResourceDesc.Buffer(desc), name);
}
else
{

View File

@@ -45,24 +45,24 @@ internal unsafe class D3D12ResourceDatabase : IResourceDatabase
public readonly bool Allocated => isExternal ? resource.resource.Get() != null : resource.allocation.Get() != null;
public readonly SharedPtr<ID3D12Resource> ResourcePtr => isExternal ? resource.resource.Get() : resource.allocation.Get()->GetResource();
public ResourceRecord(D3D12MA_Allocation* allocation, ResourceBarrierData barrierData, ResourceViewGroup resourceDescriptor, ResourceDesc desc)
public ResourceRecord(D3D12MA_Allocation* allocation, ResourceBarrierData barrierData, ResourceViewGroup viewGroup, ResourceDesc desc)
{
this.resource = new ResourceUnion(allocation);
this.isExternal = false;
this.viewGroup = resourceDescriptor;
this.viewGroup = viewGroup;
this.barrierData = barrierData;
this.desc = desc;
}
public ResourceRecord(ID3D12Resource* resource, ResourceBarrierData barrierData, ResourceViewGroup viewGroup)
public ResourceRecord(ID3D12Resource* resource, ResourceBarrierData barrierData, ResourceViewGroup viewGroup, ResourceDesc desc)
{
this.resource = new ResourceUnion(resource);
this.isExternal = true;
this.viewGroup = viewGroup;
this.barrierData = barrierData;
this.desc = resource->GetDesc().ToResourceDesc();
this.desc = desc;
}
public readonly uint Release(D3D12DescriptorAllocator descriptorAllocator)
@@ -112,6 +112,8 @@ internal unsafe class D3D12ResourceDatabase : IResourceDatabase
private ulong _cpuFrame;
private bool _disposed;
public ResourceBarrierData globalBarrier;
public D3D12ResourceDatabase(D3D12DescriptorAllocator descriptorAllocator)
{
_descriptorAllocator = descriptorAllocator;
@@ -130,7 +132,7 @@ internal unsafe class D3D12ResourceDatabase : IResourceDatabase
Dispose();
}
internal unsafe Handle<GPUResource> ImportExternalResource(ID3D12Resource* pResource, ResourceBarrierData initialBarrierData, ResourceViewGroup viewGroup, string? name = null)
internal Handle<GPUResource> ImportExternalResource(ID3D12Resource* pResource, ResourceBarrierData initialBarrierData, ResourceViewGroup viewGroup, ResourceDesc desc, string? name = null)
{
Debug.Assert(!_disposed);
@@ -150,7 +152,7 @@ internal unsafe class D3D12ResourceDatabase : IResourceDatabase
try
{
var id = _resources.Add(new ResourceRecord(pResource, initialBarrierData, viewGroup), out var generation);
var id = _resources.Add(new ResourceRecord(pResource, initialBarrierData, viewGroup, desc), out var generation);
var handle = new Handle<GPUResource>(id, generation);
#if DEBUG || GHOST_EDITOR
@@ -169,7 +171,7 @@ internal unsafe class D3D12ResourceDatabase : IResourceDatabase
}
}
internal unsafe Handle<GPUResource> AddAllocation(D3D12MA_Allocation* allocation, ResourceBarrierData initialBarrierData, ResourceViewGroup resourceDescriptor, ResourceDesc desc, string? name = null)
internal Handle<GPUResource> AddAllocation(D3D12MA_Allocation* allocation, ResourceBarrierData initialBarrierData, ResourceViewGroup resourceDescriptor, ResourceDesc desc, string? name = null)
{
Debug.Assert(!_disposed);
@@ -399,7 +401,7 @@ internal unsafe class D3D12ResourceDatabase : IResourceDatabase
return Error.None;
}
public Error Map(Handle<GPUResource> handle, uint subResource, ResourceRange? readRange, ResourceRange? writeRange, void* pData, nuint size)
public Error MapResource(Handle<GPUResource> handle, uint subResource, ResourceRange? readRange, ResourceRange? writeRange, void* pData, nuint size)
{
var r = GetResourceRecord(handle);
if (r.IsFailure)

View File

@@ -160,7 +160,7 @@ internal unsafe class DXGISwapChain : ISwapChain
sync = BarrierSync.None,
};
var handle = _resourceDatabase.ImportExternalResource(pBackBuffer, barrierData, view);
var handle = _resourceDatabase.ImportExternalResource(pBackBuffer, barrierData, view, D3D12Utility.GetResourceDesc(pBackBuffer, view));
_backBuffers[i] = handle.AsTexture();
}
}

View File

@@ -1,4 +1,5 @@
using Ghost.Core;
using Ghost.Graphics.RHI;
namespace Ghost.Graphics.D3D12;
@@ -25,4 +26,52 @@ internal struct ResourceViewGroup
uav = Identifier<CbvSrvUavDescriptor>.Invalid,
sampler = Identifier<SamplerDescriptor>.Invalid,
};
public readonly TextureUsage GetTextureUsage()
{
var usage = TextureUsage.None;
if (rtv.IsValid)
{
usage |= TextureUsage.RenderTarget;
}
if (dsv.IsValid)
{
usage |= TextureUsage.DepthStencil;
}
if (srv.IsValid)
{
usage |= TextureUsage.ShaderResource;
}
if (uav.IsValid)
{
usage |= TextureUsage.UnorderedAccess;
}
return usage;
}
public readonly BufferUsage GetBufferUsage()
{
var usage = BufferUsage.None;
if (cbv.IsValid)
{
usage |= BufferUsage.Constant;
}
if (srv.IsValid)
{
usage |= BufferUsage.ShaderResource;
}
if (uav.IsValid)
{
usage |= BufferUsage.UnorderedAccess;
}
return usage;
}
}

View File

@@ -397,6 +397,17 @@ internal static unsafe class D3D12Utility
};
}
public static HeapType ToHeapType(this D3D12_HEAP_TYPE heapType)
{
return heapType switch
{
D3D12_HEAP_TYPE_DEFAULT => HeapType.Default,
D3D12_HEAP_TYPE_UPLOAD => HeapType.Upload,
D3D12_HEAP_TYPE_READBACK => HeapType.Readback,
_ => throw new ArgumentException($"Unknown D3D12 heap type: {heapType}")
};
}
public static D3D12_HEAP_FLAGS ToD3D12HeapFlags(this HeapFlags flags)
{
return flags switch
@@ -411,6 +422,24 @@ internal static unsafe class D3D12Utility
};
}
public static HeapFlags ToHeapFlags(this D3D12_HEAP_FLAGS flags)
{
if (flags == D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES)
{
return HeapFlags.AllowAllBufferAndTexture;
}
return flags switch
{
D3D12_HEAP_FLAG_NONE => HeapFlags.None,
D3D12_HEAP_FLAG_SHARED => HeapFlags.Shared,
D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS => HeapFlags.AllowOnlyBuffers,
D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES => HeapFlags.AllowOnlyTextures,
D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES => HeapFlags.AllowOnlyRTAndDS,
_ => throw new ArgumentException($"Unknown D3D12 heap flags: {flags}")
};
}
public static D3D12_RESOURCE_DESC ToD3D12ResourceDesc(this in TextureDesc desc)
{
var dxgiFormat = desc.Format.ToDXGIFormat();
@@ -497,17 +526,22 @@ internal static unsafe class D3D12Utility
return D3D12_RESOURCE_DESC.Buffer(alignedSize, resourceFlags);
}
public static ResourceDesc ToResourceDesc(this D3D12_RESOURCE_DESC desc)
public static ResourceDesc GetResourceDesc(ID3D12Resource* pResource, ResourceViewGroup viewGroup)
{
D3D12_HEAP_PROPERTIES heapProperties;
D3D12_HEAP_FLAGS heapFlags;
ThrowIfFailed(pResource->GetHeapProperties(&heapProperties, &heapFlags));
var desc = pResource->GetDesc();
if (desc.Dimension == D3D12_RESOURCE_DIMENSION.D3D12_RESOURCE_DIMENSION_BUFFER)
{
return ResourceDesc.Buffer(new BufferDesc
{
Size = (uint)desc.Width,
Stride = 0,
Usage = BufferUsage.None,
MemoryType = ResourceMemoryType.Default
Usage = viewGroup.GetBufferUsage(),
HeapType = heapProperties.Type.ToHeapType()
});
}
else
@@ -520,7 +554,7 @@ internal static unsafe class D3D12Utility
Format = desc.Format.ToTextureFormat(),
Dimension = desc.Dimension.ToTextureDimension(),
MipLevels = desc.MipLevels,
Usage = TextureUsage.None,
Usage = viewGroup.GetTextureUsage(),
});
}
}

View File

@@ -556,31 +556,16 @@ public struct BarrierDesc
get; set;
}
public BarrierSync? SyncBefore
{
get; set;
}
public BarrierSync SyncAfter
{
get; set;
}
public BarrierAccess? AccessBefore
{
get; set;
}
public BarrierAccess AccessAfter
{
get; set;
}
public BarrierLayout? LayoutBefore
{
get; set;
}
public BarrierLayout LayoutAfter
{
get; set;
@@ -601,45 +586,45 @@ public struct BarrierDesc
get; set;
}
public static BarrierDesc Global(BarrierSync syncBefore, BarrierSync syncAfter, BarrierAccess accessBefore, BarrierAccess accessAfter)
public bool IsAliasing
{
get; set;
}
public static BarrierDesc Global(BarrierSync syncAfter, BarrierAccess accessAfter)
{
return new BarrierDesc
{
Type = BarrierType.Global,
SyncBefore = syncBefore,
SyncAfter = syncAfter,
AccessBefore = accessBefore,
AccessAfter = accessAfter
};
}
public static BarrierDesc Buffer(Handle<GPUResource> resource, BarrierSync? syncBefore, BarrierSync syncAfter, BarrierAccess? accessBefore, BarrierAccess accessAfter)
public static BarrierDesc Buffer(Handle<GPUResource> resource, BarrierSync syncAfter, BarrierAccess accessAfter, bool isAliasing = false)
{
return new BarrierDesc
{
Type = BarrierType.Buffer,
Resource = resource,
SyncBefore = syncBefore,
SyncAfter = syncAfter,
AccessBefore = accessBefore,
AccessAfter = accessAfter
AccessAfter = accessAfter,
IsAliasing = isAliasing
};
}
public static BarrierDesc Texture(Handle<GPUResource> resource, BarrierSync? syncBefore, BarrierSync syncAfter, BarrierAccess? accessBefore, BarrierAccess accessAfter, BarrierLayout? layoutBefore, BarrierLayout layoutAfter, BarrierSubresourceRange subresources = default, bool discard = false)
public static BarrierDesc Texture(Handle<GPUResource> resource, BarrierSync syncAfter, BarrierAccess accessAfter, BarrierLayout layoutAfter, BarrierSubresourceRange subresources = default, bool discard = false, bool isAliasing = false)
{
return new BarrierDesc
{
Type = BarrierType.Texture,
Resource = resource,
SyncBefore = syncBefore,
SyncAfter = syncAfter,
AccessBefore = accessBefore,
AccessAfter = accessAfter,
LayoutBefore = layoutBefore,
LayoutAfter = layoutAfter,
Subresources = subresources,
Discard = discard
Discard = discard,
IsAliasing = isAliasing
};
}
}
@@ -724,6 +709,16 @@ public record struct ResourceDesc
_ => throw new InvalidOperationException($"Unknown resource type: {Type}")
};
}
public override string ToString()
{
return Type switch
{
ResourceType.Texture => $"Texture: {TextureDescription}",
ResourceType.Buffer => $"Buffer: {BufferDescription}",
_ => $"Unknown resource type: {Type}"
};
}
}
/// <summary>
@@ -998,7 +993,7 @@ public record struct BufferDesc
get; set;
}
public ResourceMemoryType MemoryType
public HeapType HeapType
{
get; set;
}
@@ -1255,13 +1250,6 @@ public enum RenderTargetCreationFlags
GenerateMips = 1 << 3
}
public enum ResourceMemoryType
{
Default, // GPU memory
Upload, // CPU-to-GPU memory
Readback // GPU-to-CPU memory
}
public enum ResourceType
{
Texture,

View File

@@ -126,7 +126,7 @@ public unsafe interface IResourceDatabase : IDisposable
/// <returns>An Error indicating the success or failure of the swap operation.</returns>
Error Swap(Handle<GPUResource> handleA, Handle<GPUResource> handleB);
Error Map(Handle<GPUResource> handle, uint subResource, ResourceRange? readRange, ResourceRange? writeRange, void* pData, nuint size);
Error MapResource(Handle<GPUResource> handle, uint subResource, ResourceRange? readRange, ResourceRange? writeRange, void* pData, nuint size);
ulong GetIntermediateResourceSize(Handle<GPUResource> resource, uint firstSubResource, uint numSubResources);
}

View File

@@ -117,7 +117,7 @@ public struct Material : IResourceReleasable
{
Size = shader.CBufferSize,
Usage = BufferUsage.Raw | BufferUsage.ShaderResource,
MemoryType = ResourceMemoryType.Default,
HeapType = HeapType.Default,
};
var buffer = resourceAllocator.CreateBuffer(ref desc, "MaterialCBuffer");
@@ -243,7 +243,7 @@ public struct Material : IResourceReleasable
return _keywordMask.IsKeywordEnabled(localIndex);
}
public readonly void UploadData(ICommandBuffer cmd, IResourceDatabase resourceDatabase)
public readonly void UploadData(RenderContext ctx)
{
if (!_isDirty)
{
@@ -251,31 +251,20 @@ public struct Material : IResourceReleasable
}
var cbufferResource = _cBufferCache.GpuResource.AsResource();
var r = resourceDatabase.GetResourceBarrierData(cbufferResource);
if (r.IsFailure)
{
return;
}
var barrierData = r.Value;
var desc = BarrierDesc.Buffer(
cbufferResource,
barrierData.sync,
BarrierSync.Copy,
barrierData.access,
BarrierAccess.CopyDest);
cmd.Barrier(desc);
cmd.UploadBuffer(_cBufferCache.GpuResource, _cBufferCache.CpuData.AsSpan());
ctx.CommandBuffer.Barrier(desc);
ctx.UploadBuffer(_cBufferCache.GpuResource, _cBufferCache.CpuData.AsSpan());
desc = BarrierDesc.Buffer(
cbufferResource,
BarrierSync.Copy,
BarrierSync.AllShading,
BarrierAccess.CopyDest,
BarrierAccess.ShaderResource);
cmd.Barrier(desc);
ctx.CommandBuffer.Barrier(desc);
}
public void ReleaseResource(IResourceDatabase database)

View File

@@ -7,13 +7,13 @@ using System.Diagnostics;
namespace Ghost.Graphics.Core;
// TODO: Temporary rendering context for heap creation and data upload. We will refactor it later when we have a better understanding of the engine architecture.
public readonly unsafe ref struct RenderingContext
public readonly unsafe ref struct RenderContext
{
private readonly IGraphicsEngine _engine;
private readonly ResourceManager _resourceManager;
private readonly ICommandBuffer _directCmd;
private readonly ICommandBuffer _cmd;
public ICommandBuffer DirectCommandBuffer => _directCmd;
public ICommandBuffer CommandBuffer => _cmd;
public IShaderCompiler ShaderCompiler => _engine.ShaderCompiler;
public ResourceManager ResourceManager => _resourceManager;
@@ -21,69 +21,29 @@ public readonly unsafe ref struct RenderingContext
public IResourceDatabase ResourceDatabase => _engine.ResourceDatabase;
public IPipelineLibrary PipelineLibrary => _engine.PipelineLibrary;
internal RenderingContext(IGraphicsEngine engine, ResourceManager resourceManager, ICommandBuffer directCmd)
internal RenderContext(IGraphicsEngine engine, ResourceManager resourceManager, ICommandBuffer cmd)
{
_engine = engine;
_resourceManager = resourceManager;
_directCmd = directCmd;
}
public ICommandBuffer CrearteCommandBuffer(CommandBufferType type)
{
return _engine.CreateCommandBuffer(type);
}
// TODO: ExecuteCommandBufferAsync with fencene.Device.GraphicsQueue.Submit(commandBuffer);
public void ExecuteCommandBuffer(ICommandBuffer commandBuffer)
{
var queue = commandBuffer.Type switch
{
CommandBufferType.Graphics => _engine.Device.GraphicsQueue,
CommandBufferType.Compute => _engine.Device.ComputeQueue,
CommandBufferType.Copy => _engine.Device.CopyQueue,
_ => throw new InvalidOperationException("Unknown command buffer type."),
};
queue.Submit(commandBuffer);
queue.WaitIdle();
_cmd = cmd;
}
private void TransitionBarrier(Handle<GPUResource> resource, bool isTexture, BarrierLayout newLayout, BarrierAccess newAccess, BarrierSync newSync)
{
var r = ResourceDatabase.GetResourceBarrierData(resource);
if (r.IsFailure)
{
return;
}
var data = r.Value;
if (data.layout == newLayout && data.access == newAccess && data.sync == newSync)
{
return;
}
BarrierDesc desc;
if (isTexture)
{
desc = BarrierDesc.Texture(
resource,
data.sync, newSync,
data.access, newAccess,
data.layout, newLayout);
desc = BarrierDesc.Texture(resource, newSync, newAccess, newLayout);
}
else
{
desc = BarrierDesc.Buffer(
resource,
data.sync, newSync,
data.access, newAccess);
desc = BarrierDesc.Buffer(resource, newSync, newAccess);
}
_directCmd.Barrier(new ReadOnlySpan<BarrierDesc>(in desc));
ResourceDatabase.SetResourceBarrierData(resource, new ResourceBarrierData(newLayout, newAccess, newSync));
_cmd.Barrier(desc);
}
private void UploadBuffer<T>(Handle<GPUBuffer> buffer, params ReadOnlySpan<T> data)
public void UploadBuffer<T>(Handle<GPUBuffer> buffer, params ReadOnlySpan<T> data)
where T : unmanaged
{
var r = _engine.ResourceDatabase.GetResourceDescription(buffer.AsResource());
@@ -95,34 +55,43 @@ public readonly unsafe ref struct RenderingContext
Debug.Assert(r.Value.Type == ResourceType.Buffer);
var sizeInBytes = (nuint)(data.Length * sizeof(T));
var memoryType = r.Value.BufferDescription.MemoryType;
var memoryType = r.Value.BufferDescription.HeapType;
if (memoryType == ResourceMemoryType.Upload)
if (memoryType == HeapType.Upload)
{
fixed (T* pData = data)
{
ResourceDatabase.Map(buffer.AsResource(), 0, null, null, pData, sizeInBytes);
ResourceDatabase.MapResource(buffer.AsResource(), 0, null, null, pData, sizeInBytes);
}
}
else
{
//var uploadHandle = _resourceAllocator.CreateTempUploadBuffer(sizeInBytes, out var offset);
//var uploadResource = _resourceDatabase.GetResource(uploadHandle.AsResource());
var uploadDesc = new BufferDesc
{
Size = sizeInBytes,
Usage = BufferUsage.Upload,
MemoryType = ResourceMemoryType.Upload,
HeapType = HeapType.Upload,
};
var uploadHandle = _resourceManager.CreateTransientBuffer(in uploadDesc);
fixed (T* pData = data)
if (uploadHandle.IsInvalid)
{
ResourceDatabase.Map(uploadHandle.AsResource(), 0, null, null, pData, sizeInBytes);
throw new OutOfMemoryException("Failed to create upload buffer for buffer data.");
}
_directCmd.CopyBuffer(buffer, uploadHandle, 0, 0, sizeInBytes);
try
{
fixed (T* pData = data)
{
ResourceDatabase.MapResource(uploadHandle.AsResource(), 0, null, null, pData, sizeInBytes);
}
_cmd.CopyBuffer(buffer, uploadHandle, 0, 0, sizeInBytes);
}
finally
{
ResourceDatabase.ReleaseResource(uploadHandle.AsResource());
}
}
}
@@ -169,8 +138,6 @@ public readonly unsafe ref struct RenderingContext
return CreateMesh(vertexList, indexList, staticMesh);
}
// TODO: Make one memory pool for upload.
/// <summary>
/// Uploads the mesh data to the GPU.
/// </summary>
@@ -221,14 +188,14 @@ public readonly unsafe ref struct RenderingContext
Size = (uint)(meshletData.meshlets.Count * sizeof(Meshlet)),
Stride = (uint)sizeof(Meshlet),
Usage = BufferUsage.Raw | BufferUsage.ShaderResource,
MemoryType = ResourceMemoryType.Default,
HeapType = HeapType.Default,
};
var verticesDesc = new BufferDesc
{
Size = (uint)(meshletData.meshletVertices.Count * sizeof(uint)),
Stride = sizeof(uint),
Usage = BufferUsage.Raw | BufferUsage.ShaderResource,
MemoryType = ResourceMemoryType.Default,
HeapType = HeapType.Default,
};
// Ensure size is multiple of 4 for Raw buffer
var trianglesSize = (uint)meshletData.meshletTriangles.Count * sizeof(uint);
@@ -237,7 +204,7 @@ public readonly unsafe ref struct RenderingContext
Size = trianglesSize,
Stride = sizeof(uint),
Usage = BufferUsage.Raw | BufferUsage.ShaderResource,
MemoryType = ResourceMemoryType.Default,
HeapType = HeapType.Default,
};
meshRef.MeshLetBuffer = _engine.ResourceAllocator.CreateBuffer(in meshletDesc, "Meshlets");
@@ -296,12 +263,6 @@ public readonly unsafe ref struct RenderingContext
public void UploadTexture<T>(Handle<GPUTexture> texture, ReadOnlySpan<T> data)
where T : unmanaged
{
//var size = ResourceAllocator.GetSizeInfo(desc).Size;
//if ((ulong)(data.Length * sizeof(T)) != ResourceAllocator.GetSizeInfo(desc).Size)
//{
// throw new ArgumentException("Data size does not match texture size.");
//}
var desc = ResourceDatabase.GetResourceDescription(texture.AsResource()).GetValueOrThrow();
desc.TextureDescription.Format.GetSurfaceInfo(desc.TextureDescription.Width, desc.TextureDescription.Height, out var rowPitch, out var slicePitch, out _);
@@ -310,7 +271,7 @@ public readonly unsafe ref struct RenderingContext
{
Size = requiredSize,
Usage = BufferUsage.Upload,
MemoryType = ResourceMemoryType.Upload,
HeapType = HeapType.Upload,
};
var uploadHandle = _resourceManager.CreateTransientBuffer(in uploadDesc);
@@ -319,18 +280,25 @@ public readonly unsafe ref struct RenderingContext
throw new OutOfMemoryException("Failed to create upload buffer for texture data.");
}
TransitionBarrier(texture.AsResource(), true, BarrierLayout.CopyDest, BarrierAccess.CopyDest, BarrierSync.Copy);
fixed (T* pData = data)
try
{
var subresourceData = new SubResourceData
{
pData = pData,
rowPitch = rowPitch,
slicePitch = slicePitch
};
TransitionBarrier(texture.AsResource(), true, BarrierLayout.CopyDest, BarrierAccess.CopyDest, BarrierSync.Copy);
_directCmd.UpdateSubResources(texture.AsResource(), uploadHandle.AsResource(), subresourceData);
fixed (T* pData = data)
{
var subresourceData = new SubResourceData
{
pData = pData,
rowPitch = rowPitch,
slicePitch = slicePitch
};
_cmd.UpdateSubResources(texture.AsResource(), uploadHandle.AsResource(), subresourceData);
}
}
finally
{
ResourceDatabase.ReleaseResource(uploadHandle.AsResource());
}
}
}

View File

@@ -1,94 +0,0 @@
using Ghost.Core;
using Ghost.Graphics.RHI;
namespace Ghost.Graphics.Core;
internal class SwapChainRenderOutput : IRenderOutput
{
private readonly ISwapChain _swapChain;
public ViewportDesc Viewport
{
get; set;
}
public ScissorRectDesc Scissor
{
get; set;
}
public SwapChainRenderOutput(ISwapChain swapChain)
{
_swapChain = swapChain;
Viewport = new ViewportDesc { Width = swapChain.Width, Height = swapChain.Height, MinDepth = 0, MaxDepth = 1 };
Scissor = new ScissorRectDesc { Right = swapChain.Width, Bottom = swapChain.Height };
}
public Handle<GPUTexture> GetRenderTarget()
{
return _swapChain.GetCurrentBackBuffer();
}
public void BeginRender(ICommandBuffer cmd)
{
var barrierDesc = BarrierDesc.Texture(_swapChain.GetCurrentBackBuffer().AsResource(),
BarrierSync.None, BarrierSync.RenderTarget,
BarrierAccess.NoAccess, BarrierAccess.RenderTarget,
BarrierLayout.Present, BarrierLayout.RenderTarget);
cmd.Barrier(barrierDesc);
}
public void EndRender(ICommandBuffer cmd)
{
var barrierDesc = BarrierDesc.Texture(_swapChain.GetCurrentBackBuffer().AsResource(),
BarrierSync.RenderTarget, BarrierSync.None,
BarrierAccess.RenderTarget, BarrierAccess.NoAccess,
BarrierLayout.RenderTarget, BarrierLayout.Present);
cmd.Barrier(barrierDesc);
}
public void Present()
{
_swapChain.Present();
}
}
internal class TextureRenderOutput : IRenderOutput
{
private readonly Handle<GPUTexture> _texture;
public ViewportDesc Viewport
{
get; set;
}
public ScissorRectDesc Scissor
{
get; set;
}
public TextureRenderOutput(Handle<GPUTexture> texture)
{
_texture = texture;
}
public Handle<GPUTexture> GetRenderTarget()
{
return _texture;
}
public void BeginRender(ICommandBuffer cmd)
{
}
public void EndRender(ICommandBuffer cmd)
{
}
public void Present()
{
}
}

View File

@@ -217,6 +217,7 @@ internal sealed class RenderGraphExecutor
}
// Process all pre-compiled barriers for this pass
// TODO: We can insert BarrierAccess.NoAccess to the resource that aliased with others after their last usage to reduce cache burden.
while (barrierIndex < compiledBarriers.Count && compiledBarriers[barrierIndex].PassIndex == passIndex)
{
var compiledBarrier = compiledBarriers[barrierIndex++];
@@ -231,60 +232,23 @@ internal sealed class RenderGraphExecutor
}
var currentState = currentStateResult.Value;
BarrierLayout layoutBefore;
BarrierAccess accessBefore;
BarrierSync syncBefore;
// Handle aliasing barriers specially
if (compiledBarrier.AliasingPredecessor.IsValid)
{
var predHandle = _resources.GetResource(compiledBarrier.AliasingPredecessor).backingResource;
var predStateResult = _resourceDatabase.GetResourceBarrierData(predHandle);
if (predStateResult.IsFailure)
{
return predStateResult.Error;
}
var predState = predStateResult.Value;
layoutBefore = BarrierLayout.Undefined;
accessBefore = BarrierAccess.NoAccess;
syncBefore = predState.sync;
}
else
{
layoutBefore = currentState.layout;
accessBefore = currentState.access;
syncBefore = currentState.sync;
}
var target = compiledBarrier.TargetState;
// Skip if already in target state (optimization)
if (!compiledBarrier.AliasingPredecessor.IsValid &&
layoutBefore == target.layout &&
accessBefore == target.access &&
syncBefore == target.sync)
{
continue;
}
// Create barrier descriptor
BarrierDesc desc;
if (compiledBarrier.ResourceType == RenderGraphResourceType.Texture)
{
desc = BarrierDesc.Texture(resourceHandle,
syncBefore, target.sync,
accessBefore, target.access,
layoutBefore, target.layout,
desc = BarrierDesc.Texture(resourceHandle, target.sync, target.access, target.layout,
discard: compiledBarrier.Flags.HasFlag(BarrierFlags.Discard));
}
else
{
desc = BarrierDesc.Buffer(resourceHandle,
syncBefore, target.sync,
accessBefore, target.access);
desc = BarrierDesc.Buffer(resourceHandle, target.sync, target.access);
}
if (compiledBarrier.AliasingPredecessor.IsValid)
{
desc.IsAliasing = true;
}
if (barrierCount >= MaxBatch)

View File

@@ -1,16 +1,10 @@
using Ghost.Core;
using Ghost.Graphics.Core;
using Ghost.Graphics.RHI;
using System.Diagnostics;
namespace Ghost.Graphics.RenderPipeline;
public readonly struct RenderContext
{
public ICommandBuffer CommandBuffer { get; init; }
public ICommandQueue GraphicsQueue { get; init; }
public ICommandQueue ComputeQueue { get; init; }
public ICommandQueue CopyQueue { get; init; }
}
public interface IRenderPipelineSettings
{
IRenderPipeline CreatePipeline(RenderSystem renderSystem);

View File

@@ -100,7 +100,8 @@ public class RenderSystem : IDisposable
private uint _frameIndex;
private ulong _cpuFenceValue;
private ulong _gpuFenceValue;
private ulong _submittedFenceValue;
private ulong _completedFenceValue;
private bool _isRunning;
private bool _disposed;
@@ -112,7 +113,8 @@ public class RenderSystem : IDisposable
public bool IsRunning => _isRunning;
public ulong CPUFenceValue => _cpuFenceValue;
public ulong GPUFenceValue => _gpuFenceValue;
public ulong SubmittedFenceValue => _submittedFenceValue;
public ulong CompletedFenceValue => _completedFenceValue;
public uint FrameIndex => _frameIndex;
public uint MaxFrameLatency => _config.FrameBufferCount;
@@ -219,7 +221,7 @@ public class RenderSystem : IDisposable
while (_isRunning)
{
_frameIndex = (uint)(_gpuFenceValue % _config.FrameBufferCount);
_frameIndex = (uint)(_submittedFenceValue % _config.FrameBufferCount);
ref var frameResource = ref _frameResources[_frameIndex];
// Wait for either CPU ready signal or shutdown signal
@@ -242,17 +244,7 @@ public class RenderSystem : IDisposable
if (!_resizeRequest.IsEmpty)
{
_gpuFenceValue++;
var flushFence = _graphicsEngine.Device.GraphicsQueue.Signal(_gpuFenceValue);
_graphicsEngine.Device.GraphicsQueue.WaitForValue(flushFence);
// Sync the current frame heap to this new fence to keep state consistent
frameResource.FenceValue = flushFence;
foreach (var resource in _frameResources)
{
resource.CommandAllocator.Reset();
}
WaitIdle();
var keys = _resizeRequest.Keys.ToArray();
foreach (var swapChain in keys)
@@ -262,17 +254,19 @@ public class RenderSystem : IDisposable
swapChain.Resize(newSize.x, newSize.y);
}
}
frameResource.GpuReadyEvent.Set();
continue; // Skip rendering this frame since we just resized and may have invalid render targets
}
_completedFenceValue = _graphicsEngine.Device.GraphicsQueue.GetCompletedValue();
if (_submittedFenceValue < _completedFenceValue)
{
_submittedFenceValue = _completedFenceValue;
}
// Begin rendering for this frame
frameResource.CommandAllocator.Reset();
_resourceManager.BeginFrame(_cpuFenceValue);
var r = _graphicsEngine.BeginFrame(_cpuFenceValue);
_resourceManager.BeginFrame(_submittedFenceValue + 1);
var r = _graphicsEngine.BeginFrame(_submittedFenceValue + 1);
if (r.IsFailure)
{
@@ -290,11 +284,9 @@ public class RenderSystem : IDisposable
{
cmd.Begin(frameResource.CommandAllocator);
var renderCtx = new RenderContext
{
CommandBuffer = cmd
};
var renderCtx = new RenderContext(_graphicsEngine, _resourceManager, cmd);
//Debug.WriteLine($"GPU: Frame started.");
_renderPipeline.Render(renderCtx, renderRequests.AsSpan());
_swapChainManager.TransitionToPresent(cmd);
@@ -321,9 +313,9 @@ public class RenderSystem : IDisposable
renderRequests.Clear();
}
// End the frame and present
_resourceManager.EndFrame(_gpuFenceValue);
r = _graphicsEngine.EndFrame(_gpuFenceValue);
// End the frame and retire resources based on actual GPU progress.
_resourceManager.EndFrame(_completedFenceValue);
r = _graphicsEngine.EndFrame(_completedFenceValue);
if (r.IsFailure)
{
@@ -331,11 +323,9 @@ public class RenderSystem : IDisposable
break;
}
// Prepare for the next frame.
_gpuFenceValue++;
_submittedFenceValue++;
frameResource.GpuReadyEvent.Set();
frameResource.FenceValue = _graphicsEngine.Device.GraphicsQueue.Signal(_gpuFenceValue);
frameResource.FenceValue = _graphicsEngine.Device.GraphicsQueue.Signal(_submittedFenceValue);
}
}
@@ -381,6 +371,21 @@ public class RenderSystem : IDisposable
_resizeRequest.AddOrUpdate(swapChain, newSize, (_, _) => newSize);
}
internal bool TryAcquireCPUFrame()
{
ulong requiredGpuFence = _cpuFenceValue < _config.FrameBufferCount ? 0 : _cpuFenceValue - _config.FrameBufferCount + 1;
if (requiredGpuFence > 0 && _graphicsEngine.Device.GraphicsQueue.GetCompletedValue() < requiredGpuFence)
{
return false;
}
var eventIndex = (int)(_cpuFenceValue % _config.FrameBufferCount);
_frameResources[eventIndex].RenderRequests.Clear();
return true;
}
public void AddRenderRequest(in RenderRequest request)
{
Debug.Assert(!_disposed, "Cannot add render request to a disposed RenderSystem.");

View File

@@ -10,6 +10,7 @@ public partial class ResourceManager
{
private const ulong _DEFAULT_TRANSIENT_PAGE_SIZE = 16 * 1024 * 1024; // 16MB
[DebuggerDisplay("Heap: {heap}, Offset: {offset}, HeapType: {heapType}, HeapFlags: {heapFlags}")]
private struct Page
{
public Handle<GPUResource> heap;
@@ -19,6 +20,7 @@ public partial class ResourceManager
public HeapType heapType;
}
[DebuggerDisplay("Page Heap: {page.heap}, RetireFrame: {retireFrame}")]
private struct RetiringPage
{
public Page page;
@@ -26,14 +28,14 @@ public partial class ResourceManager
}
private UnsafeList<Page> _activePages;
private UnsafeQueue<RetiringPage> _retiringPages;
private Queue<RetiringPage> _retiringPages;
private UnsafeList<Handle<GPUResource>> _oversizedTransientResources;
private void InitializePool()
{
_activePages = new UnsafeList<Page>(4, Allocator.Persistent);
_retiringPages = new UnsafeQueue<RetiringPage>(4, Allocator.Persistent);
_retiringPages = new Queue<RetiringPage>(4);
_oversizedTransientResources = new UnsafeList<Handle<GPUResource>>(4, Allocator.Persistent);
}
@@ -152,10 +154,10 @@ public partial class ResourceManager
return bufHandle;
}
var requiredHeapType = desc.MemoryType switch
var requiredHeapType = desc.HeapType switch
{
ResourceMemoryType.Upload => HeapType.Upload,
ResourceMemoryType.Readback => HeapType.Readback,
HeapType.Upload => HeapType.Upload,
HeapType.Readback => HeapType.Readback,
_ => HeapType.Default
};
@@ -265,7 +267,7 @@ public partial class ResourceManager
}
_activePages.Dispose();
_retiringPages.Dispose();
//_retiringPages.Dispose();
_oversizedTransientResources.Dispose();
}
}

View File

@@ -83,7 +83,7 @@ public sealed partial class ResourceManager : IDisposable
Size = (uint)(vertices.Count * sizeof(Vertex)),
Stride = (uint)sizeof(Vertex),
Usage = BufferUsage.Vertex | BufferUsage.ShaderResource | BufferUsage.Raw,
MemoryType = ResourceMemoryType.Default,
HeapType = HeapType.Default,
};
var indexBufferDesc = new BufferDesc
@@ -91,7 +91,7 @@ public sealed partial class ResourceManager : IDisposable
Size = (uint)(indices.Count * sizeof(uint)),
Stride = sizeof(uint),
Usage = BufferUsage.Index | BufferUsage.ShaderResource | BufferUsage.Raw,
MemoryType = ResourceMemoryType.Default,
HeapType = HeapType.Default,
};
var objectBufferDesc = new BufferDesc
@@ -99,7 +99,7 @@ public sealed partial class ResourceManager : IDisposable
Size = (uint)sizeof(MeshData),
Stride = (uint)sizeof(MeshData),
Usage = BufferUsage.Raw | BufferUsage.ShaderResource,
MemoryType = ResourceMemoryType.Default,
HeapType = HeapType.Default,
};
var vertexBuffer = _resourceAllocator.CreateBuffer(in vertexBufferDesc, "VertexBuffer");

View File

@@ -127,9 +127,9 @@ internal class SwapChainManager : IDisposable
}
commandBuffer.Barrier(BarrierDesc.Texture(record.SwapChain.GetCurrentBackBuffer().AsResource(),
null, BarrierSync.None,
null, BarrierAccess.NoAccess,
null, BarrierLayout.Present));
BarrierSync.None,
BarrierAccess.NoAccess,
BarrierLayout.Present));
}
}