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

@@ -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));
}
}