Compare commits

...

13 Commits

Author SHA1 Message Date
ParantezTech 05e971ce85 [Gpu] Update Vk compute tests for synchronization2 2026-09-22 15:59:06 +03:00
ParantezTech 5bda682821 [Gpu] Update Vk image tests for synchronization2 2026-09-22 15:59:06 +03:00
ParantezTech 43a599b4f7 [Gpu] Migrate Vk rendering barriers to synchronization2 2026-09-22 15:59:00 +03:00
ParantezTech c2d20af21c [Gpu] Migrate Vk present barriers to synchronization2 2026-09-22 15:59:00 +03:00
ParantezTech a57a448291 [Gpu] Migrate Vk command stream barriers to synchronization2 2026-09-22 15:59:00 +03:00
ParantezTech ae04202815 [Gpu] Migrate Vk cached image barriers to synchronization2 2026-09-22 15:59:00 +03:00
ParantezTech 945717b320 [Gpu] Migrate Vk GDS barrier to synchronization2 2026-09-22 15:58:49 +03:00
ParantezTech ad849891b4 [Gpu] Migrate Vk image barriers to synchronization2 2026-09-22 15:58:49 +03:00
ParantezTech e7c9dca969 [Gpu] Migrate Vk buffer barriers to synchronization2 2026-09-22 15:58:49 +03:00
ParantezTech 43315e9b7a [Gpu] Migrate Vk timestamps to synchronization2 2026-09-22 15:58:36 +03:00
ParantezTech ed2d6f0f52 [Gpu] Migrate Vk queue submission to synchronization2 2026-09-22 15:58:36 +03:00
ParantezTech f06d2aa1b1 [Gpu] Add Vk synchronization2 helper 2026-09-22 15:58:36 +03:00
ParantezTech 92704490a7 [Gpu] Vk version update 2026-09-22 15:58:26 +03:00
24 changed files with 402 additions and 364 deletions

View File

@ -5,6 +5,7 @@ using System.Runtime.InteropServices;
using SharpEmu.HLE.GpuMemory;
using SharpEmu.Libs.Gpu.Scheduling;
using SharpEmu.ShaderCompiler.Vulkan;
using SharpEmu.Libs.Gpu.Vulkan;
using Silk.NET.Vulkan;
namespace SharpEmu.Libs.Gpu.Buffers;
@ -191,11 +192,11 @@ public sealed unsafe class BdaFaultProcessor : IDisposable
_downloadBuffer.Mapped.Slice((int)offset, (int)PageFaultAreaSize).Clear();
_downloadBuffer.Flush(offset, PageFaultAreaSize);
var preBarrier = new BufferMemoryBarrier
var preBarrier = new BufferMemoryBarrier2
{
SType = StructureType.BufferMemoryBarrier,
SrcAccessMask = AccessFlags.ShaderWriteBit,
DstAccessMask = AccessFlags.ShaderReadBit,
SType = StructureType.BufferMemoryBarrier2,
SrcAccessMask = AccessFlags2.ShaderWriteBit,
DstAccessMask = AccessFlags2.ShaderReadBit,
SrcQueueFamilyIndex = Vk.QueueFamilyIgnored,
DstQueueFamilyIndex = Vk.QueueFamilyIgnored,
Buffer = _faultBuffer.Handle,
@ -203,12 +204,12 @@ public sealed unsafe class BdaFaultProcessor : IDisposable
Size = _faultBufferSize,
};
var postBarrier = preBarrier;
postBarrier.DstAccessMask = AccessFlags.ShaderWriteBit;
postBarrier.DstAccessMask = AccessFlags2.ShaderWriteBit;
_scheduler.EndRendering();
var vk = _device.Vk;
var command = new CommandBuffer(_scheduler.Current.Handle);
vk.CmdPipelineBarrier(
VulkanSynchronization.PipelineBarrier(vk,
command, PipelineStageFlags.AllCommandsBit, PipelineStageFlags.ComputeShaderBit, DependencyFlags.ByRegionBit,
0, null, 1, &preBarrier, 0, null);
vk.CmdBindPipeline(command, PipelineBindPoint.Compute, _pipeline);
@ -216,7 +217,7 @@ public sealed unsafe class BdaFaultProcessor : IDisposable
vk.CmdBindDescriptorSets(command, PipelineBindPoint.Compute, _pipelineLayout, 0, 1, &set, 0, null);
var threads = _pageCount / 32;
vk.CmdDispatch(command, (uint)((threads + 63) / 64), 1, 1);
vk.CmdPipelineBarrier(
VulkanSynchronization.PipelineBarrier(vk,
command, PipelineStageFlags.ComputeShaderBit, PipelineStageFlags.AllCommandsBit, DependencyFlags.ByRegionBit,
0, null, 1, &postBarrier, 0, null);

View File

@ -3,6 +3,7 @@
using System.Numerics;
using SharpEmu.Libs.Gpu.Scheduling;
using SharpEmu.Libs.Gpu.Vulkan;
using Silk.NET.Vulkan;
using VkBuffer = Silk.NET.Vulkan.Buffer;
@ -190,18 +191,18 @@ public unsafe class GpuBuffer : IDisposable
command.EndRendering();
var vk = _device.Vk;
var native = new CommandBuffer(command.Handle);
var before = stackalloc BufferMemoryBarrier[2];
var before = stackalloc BufferMemoryBarrier2[2];
before[0] = source.CreateBarrier(sourceOffset, size, sourceBefore, AccessFlags.TransferReadBit);
before[1] = CreateBarrier(destinationOffset, size, destinationBefore, AccessFlags.TransferWriteBit);
vk.CmdPipelineBarrier(
VulkanSynchronization.PipelineBarrier(vk,
native, GetAccessStage(sourceBefore | destinationBefore), PipelineStageFlags.TransferBit, DependencyFlags.ByRegionBit,
0, null, 2, before, 0, null);
var copy = new BufferCopy(sourceOffset, destinationOffset, size);
vk.CmdCopyBuffer(native, source.Handle, Handle, 1, &copy);
var after = stackalloc BufferMemoryBarrier[2];
var after = stackalloc BufferMemoryBarrier2[2];
after[0] = source.CreateBarrier(sourceOffset, size, AccessFlags.TransferReadBit, sourceAfter);
after[1] = CreateBarrier(destinationOffset, size, AccessFlags.TransferWriteBit, destinationAfter);
vk.CmdPipelineBarrier(
VulkanSynchronization.PipelineBarrier(vk,
native, PipelineStageFlags.TransferBit, GetAccessStage(sourceAfter | destinationAfter), DependencyFlags.ByRegionBit,
0, null, 2, after, 0, null);
}
@ -218,12 +219,12 @@ public unsafe class GpuBuffer : IDisposable
var vk = _device.Vk;
var native = new CommandBuffer(command.Handle);
var before = CreateBarrier(offset, size, MemoryAccess, AccessFlags.TransferWriteBit);
vk.CmdPipelineBarrier(
VulkanSynchronization.PipelineBarrier(vk,
native, PipelineStageFlags.AllCommandsBit, PipelineStageFlags.TransferBit, DependencyFlags.ByRegionBit,
0, null, 1, &before, 0, null);
vk.CmdFillBuffer(native, Handle, offset, size, value);
var after = CreateBarrier(offset, size, AccessFlags.TransferWriteBit, MemoryAccess);
vk.CmdPipelineBarrier(
VulkanSynchronization.PipelineBarrier(vk,
native, PipelineStageFlags.TransferBit, PipelineStageFlags.AllCommandsBit, DependencyFlags.ByRegionBit,
0, null, 1, &after, 0, null);
}
@ -284,7 +285,7 @@ public unsafe class GpuBuffer : IDisposable
};
}
private BufferMemoryBarrier CreateBarrier(ulong offset, ulong size, AccessFlags source, AccessFlags destination)
private BufferMemoryBarrier2 CreateBarrier(ulong offset, ulong size, AccessFlags source, AccessFlags destination)
{
if (Handle.Handle == 0 || size == 0 || offset > Size || size > Size - offset)
{
@ -292,11 +293,11 @@ public unsafe class GpuBuffer : IDisposable
$"The DMA barrier range is invalid: handle=0x{Handle.Handle:X} offset=0x{offset:X16} size=0x{size:X16} capacity=0x{Size:X16}");
}
return new BufferMemoryBarrier
return new BufferMemoryBarrier2
{
SType = StructureType.BufferMemoryBarrier,
SrcAccessMask = source,
DstAccessMask = destination,
SType = StructureType.BufferMemoryBarrier2,
SrcAccessMask = VulkanSynchronization.Access(source),
DstAccessMask = VulkanSynchronization.Access(destination),
SrcQueueFamilyIndex = Vk.QueueFamilyIgnored,
DstQueueFamilyIndex = Vk.QueueFamilyIgnored,
Buffer = Handle,

View File

@ -8,6 +8,7 @@ using SharpEmu.HLE.GuestMemory;
using SharpEmu.Libs.Gpu.Scheduling;
using SharpEmu.Libs.Kernel;
using SharpEmu.Libs.VideoOut;
using SharpEmu.Libs.Gpu.Vulkan;
using Silk.NET.Vulkan;
namespace SharpEmu.Libs.Gpu.Buffers;
@ -1014,18 +1015,18 @@ public sealed unsafe class GuestBufferCache : IGuestBufferStore, IDisposable
command.EndRendering();
var native = new CommandBuffer(command.Handle);
var vk = _device.Vk;
var before = new BufferMemoryBarrier
var before = new BufferMemoryBarrier2
{
SType = StructureType.BufferMemoryBarrier,
SrcAccessMask = AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit | AccessFlags.TransferReadBit | AccessFlags.TransferWriteBit,
DstAccessMask = AccessFlags.TransferWriteBit,
SType = StructureType.BufferMemoryBarrier2,
SrcAccessMask = AccessFlags2.MemoryReadBit | AccessFlags2.MemoryWriteBit | AccessFlags2.TransferReadBit | AccessFlags2.TransferWriteBit,
DstAccessMask = AccessFlags2.TransferWriteBit,
SrcQueueFamilyIndex = Vk.QueueFamilyIgnored,
DstQueueFamilyIndex = Vk.QueueFamilyIgnored,
Buffer = buffer.Handle,
Offset = 0,
Size = buffer.Size,
};
vk.CmdPipelineBarrier(
VulkanSynchronization.PipelineBarrier(vk,
native, PipelineStageFlags.AllCommandsBit, PipelineStageFlags.TransferBit, DependencyFlags.ByRegionBit,
0, null, 1, &before, 0, null);
var regions = CollectionsMarshal.AsSpan(copies);
@ -1035,9 +1036,9 @@ public sealed unsafe class GuestBufferCache : IGuestBufferStore, IDisposable
}
var after = before;
after.SrcAccessMask = AccessFlags.TransferWriteBit;
after.DstAccessMask = AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit;
vk.CmdPipelineBarrier(
after.SrcAccessMask = AccessFlags2.TransferWriteBit;
after.DstAccessMask = AccessFlags2.MemoryReadBit | AccessFlags2.MemoryWriteBit;
VulkanSynchronization.PipelineBarrier(vk,
native, PipelineStageFlags.TransferBit, PipelineStageFlags.AllCommandsBit, DependencyFlags.ByRegionBit,
0, null, 1, &after, 0, null);
}

View File

@ -3,6 +3,7 @@
using SharpEmu.Libs.Gpu.Buffers;
using SharpEmu.Libs.Gpu.Scheduling;
using SharpEmu.Libs.Gpu.Vulkan;
using Silk.NET.Vulkan;
using VkBuffer = Silk.NET.Vulkan.Buffer;
@ -17,11 +18,11 @@ public sealed unsafe partial class CachedImage
private const ImageLayout ReadyLayout = ImageLayout.General;
private const AccessFlags ReadyAccess = AccessFlags.ShaderReadBit | AccessFlags.TransferReadBit;
private ImageMemoryBarrier MakeBarrier(in ImageAccessState from, ImageLayout layout, AccessFlags access, uint baseLevel, uint levelCount, uint baseLayer, uint layerCount) => new()
private ImageMemoryBarrier2 MakeBarrier(in ImageAccessState from, ImageLayout layout, AccessFlags access, uint baseLevel, uint levelCount, uint baseLayer, uint layerCount) => new()
{
SType = StructureType.ImageMemoryBarrier,
SrcAccessMask = from.Access,
DstAccessMask = access,
SType = StructureType.ImageMemoryBarrier2,
SrcAccessMask = VulkanSynchronization.Access(from.Access),
DstAccessMask = VulkanSynchronization.Access(access),
OldLayout = from.Layout,
NewLayout = layout,
SrcQueueFamilyIndex = Vk.QueueFamilyIgnored,
@ -31,9 +32,9 @@ public sealed unsafe partial class CachedImage
};
// Barriers for the requested state; a repeated write always gets a barrier.
public (List<ImageMemoryBarrier> Barriers, PipelineStageFlags SourceStages) GetBarriers(ImageLayout layout, AccessFlags access, PipelineStageFlags stage, SubresourceRange? range)
public (List<ImageMemoryBarrier2> Barriers, PipelineStageFlags SourceStages) GetBarriers(ImageLayout layout, AccessFlags access, PipelineStageFlags stage, SubresourceRange? range)
{
var barriers = new List<ImageMemoryBarrier>();
var barriers = new List<ImageMemoryBarrier2>();
PipelineStageFlags sourceStages = 0;
if (range is { } && Description.IsVolume)
{
@ -128,22 +129,22 @@ public sealed unsafe partial class CachedImage
RecordBarriers(command, sourceStages, stage, null, barriers);
}
private void RecordBarriers(CommandBuffer command, PipelineStageFlags sourceStages, PipelineStageFlags destinationStages, BufferMemoryBarrier* bufferBarrier, List<ImageMemoryBarrier> imageBarriers)
private void RecordBarriers(CommandBuffer command, PipelineStageFlags sourceStages, PipelineStageFlags destinationStages, BufferMemoryBarrier2* bufferBarrier, List<ImageMemoryBarrier2> imageBarriers)
{
var images = imageBarriers.ToArray();
fixed (ImageMemoryBarrier* imagePointer = images)
fixed (ImageMemoryBarrier2* imagePointer = images)
{
_device.Vk.CmdPipelineBarrier(
VulkanSynchronization.PipelineBarrier(_device.Vk,
command, sourceStages == 0 ? PipelineStageFlags.TopOfPipeBit : sourceStages, destinationStages, DependencyFlags.ByRegionBit,
0, null, bufferBarrier == null ? 0u : 1u, bufferBarrier, (uint)images.Length, imagePointer);
}
}
private static BufferMemoryBarrier BufferBarrier(VkBuffer buffer, ulong offset, ulong size, AccessFlags source, AccessFlags destination) => new()
private static BufferMemoryBarrier2 BufferBarrier(VkBuffer buffer, ulong offset, ulong size, AccessFlags source, AccessFlags destination) => new()
{
SType = StructureType.BufferMemoryBarrier,
SrcAccessMask = source,
DstAccessMask = destination,
SType = StructureType.BufferMemoryBarrier2,
SrcAccessMask = VulkanSynchronization.Access(source),
DstAccessMask = VulkanSynchronization.Access(destination),
SrcQueueFamilyIndex = Vk.QueueFamilyIgnored,
DstQueueFamilyIndex = Vk.QueueFamilyIgnored,
Buffer = buffer,
@ -218,7 +219,7 @@ public sealed unsafe partial class CachedImage
}
bufferBarrier = BufferBarrier(buffer, offset, size, AccessFlags.TransferReadBit, MemoryAccess);
_device.Vk.CmdPipelineBarrier(command, PipelineStageFlags.TransferBit, PipelineStageFlags.AllCommandsBit, DependencyFlags.ByRegionBit, 0, null, 1, &bufferBarrier, 0, null);
VulkanSynchronization.PipelineBarrier(_device.Vk,command, PipelineStageFlags.TransferBit, PipelineStageFlags.AllCommandsBit, DependencyFlags.ByRegionBit, 0, null, 1, &bufferBarrier, 0, null);
Transition(ReadyLayout, ReadyAccess, null, command);
}
@ -234,7 +235,7 @@ public sealed unsafe partial class CachedImage
}
bufferBarrier = BufferBarrier(buffer, offset, size, AccessFlags.TransferWriteBit, MemoryAccess);
_device.Vk.CmdPipelineBarrier(command, PipelineStageFlags.TransferBit, PipelineStageFlags.AllCommandsBit, DependencyFlags.ByRegionBit, 0, null, 1, &bufferBarrier, 0, null);
VulkanSynchronization.PipelineBarrier(_device.Vk,command, PipelineStageFlags.TransferBit, PipelineStageFlags.AllCommandsBit, DependencyFlags.ByRegionBit, 0, null, 1, &bufferBarrier, 0, null);
}
private static (uint SourceLayers, uint DestinationLayers) SanitizeCopyLayers(CachedImage source, CachedImage destination, uint depth)
@ -528,10 +529,10 @@ public sealed unsafe partial class CachedImage
destinationCopy.ImageSubresource = new ImageSubresourceLayers(destinationAspect, level, Backing.ImageType == ImageType.Type3D ? 0 : slice, 1);
destinationCopy.ImageOffset.Z = Backing.ImageType == ImageType.Type3D ? (int)slice : 0;
var barrier = BufferBarrier(buffer.Handle, 0, copySize, AccessFlags.TransferReadBit, AccessFlags.TransferWriteBit);
_device.Vk.CmdPipelineBarrier(command, PipelineStageFlags.TransferBit, PipelineStageFlags.TransferBit, DependencyFlags.ByRegionBit, 0, null, 1, &barrier, 0, null);
VulkanSynchronization.PipelineBarrier(_device.Vk,command, PipelineStageFlags.TransferBit, PipelineStageFlags.TransferBit, DependencyFlags.ByRegionBit, 0, null, 1, &barrier, 0, null);
_device.Vk.CmdCopyImageToBuffer(command, source.Backing.Handle, ImageLayout.TransferSrcOptimal, buffer.Handle, 1, &sourceCopy);
barrier = BufferBarrier(buffer.Handle, 0, copySize, AccessFlags.TransferWriteBit, AccessFlags.TransferReadBit);
_device.Vk.CmdPipelineBarrier(command, PipelineStageFlags.TransferBit, PipelineStageFlags.TransferBit, DependencyFlags.ByRegionBit, 0, null, 1, &barrier, 0, null);
VulkanSynchronization.PipelineBarrier(_device.Vk,command, PipelineStageFlags.TransferBit, PipelineStageFlags.TransferBit, DependencyFlags.ByRegionBit, 0, null, 1, &barrier, 0, null);
_device.Vk.CmdCopyBufferToImage(command, buffer.Handle, Backing.Handle, ImageLayout.TransferDstOptimal, 1, &destinationCopy);
}
}

View File

@ -5,6 +5,7 @@ using System.Runtime.InteropServices;
using SharpEmu.Libs.Gpu.Buffers;
using SharpEmu.Libs.Gpu.Scheduling;
using SharpEmu.ShaderCompiler.Vulkan;
using SharpEmu.Libs.Gpu.Vulkan;
using Silk.NET.Vulkan;
using VkBuffer = Silk.NET.Vulkan.Buffer;
@ -437,11 +438,11 @@ public sealed unsafe class GpuTiler : IDisposable
}
}
private static BufferMemoryBarrier Barrier(VkBuffer buffer, ulong offset, ulong size, AccessFlags source, AccessFlags destination) => new()
private static BufferMemoryBarrier2 Barrier(VkBuffer buffer, ulong offset, ulong size, AccessFlags source, AccessFlags destination) => new()
{
SType = StructureType.BufferMemoryBarrier,
SrcAccessMask = source,
DstAccessMask = destination,
SType = StructureType.BufferMemoryBarrier2,
SrcAccessMask = VulkanSynchronization.Access(source),
DstAccessMask = VulkanSynchronization.Access(destination),
SrcQueueFamilyIndex = Vk.QueueFamilyIgnored,
DstQueueFamilyIndex = Vk.QueueFamilyIgnored,
Buffer = buffer,
@ -496,21 +497,21 @@ public sealed unsafe class GpuTiler : IDisposable
_scheduler.EndRendering();
var command = new CommandBuffer(_scheduler.Current.Handle);
var barriers = stackalloc BufferMemoryBarrier[3];
var barriers = stackalloc BufferMemoryBarrier2[3];
barriers[0] = Barrier(source, sourceOffset, sourceCapacity, AccessFlags.MemoryWriteBit | AccessFlags.HostWriteBit, AccessFlags.ShaderReadBit);
barriers[1] = Barrier(target, targetOffset, targetCapacity, AccessFlags.MemoryWriteBit | AccessFlags.HostWriteBit,
clearTarget ? AccessFlags.TransferWriteBit : AccessFlags.ShaderReadBit | AccessFlags.ShaderWriteBit);
var first = dispatches[0].ArgumentsOffset;
var last = dispatches[^1].ArgumentsOffset;
barriers[2] = Barrier(dispatches[0].ArgumentsBuffer, first, last - first + TileTransferArguments.Size, AccessFlags.HostWriteBit, AccessFlags.UniformReadBit);
vk.CmdPipelineBarrier(command, PipelineStageFlags.AllCommandsBit | PipelineStageFlags.HostBit,
VulkanSynchronization.PipelineBarrier(vk,command, PipelineStageFlags.AllCommandsBit | PipelineStageFlags.HostBit,
PipelineStageFlags.ComputeShaderBit | PipelineStageFlags.TransferBit, 0, 0, null, 3, barriers, 0, null);
if (clearTarget)
{
vk.CmdFillBuffer(command, target, targetOffset, targetCapacity, 0);
barriers[1].SrcAccessMask = AccessFlags.TransferWriteBit;
barriers[1].DstAccessMask = AccessFlags.ShaderReadBit | AccessFlags.ShaderWriteBit;
vk.CmdPipelineBarrier(command, PipelineStageFlags.TransferBit, PipelineStageFlags.ComputeShaderBit, 0, 0, null, 1, barriers + 1, 0, null);
barriers[1].SrcAccessMask = AccessFlags2.TransferWriteBit;
barriers[1].DstAccessMask = AccessFlags2.ShaderReadBit | AccessFlags2.ShaderWriteBit;
VulkanSynchronization.PipelineBarrier(vk,command, PipelineStageFlags.TransferBit, PipelineStageFlags.ComputeShaderBit, 0, 0, null, 1, barriers + 1, 0, null);
}
Span<DescriptorBufferInfo> infos = stackalloc DescriptorBufferInfo[3];
@ -524,9 +525,9 @@ public sealed unsafe class GpuTiler : IDisposable
vk.CmdDispatch(command, (dispatch.Arguments.Width + 7) / 8, (dispatch.Arguments.Height + 7) / 8, dispatch.Arguments.Depth);
}
barriers[1].SrcAccessMask = AccessFlags.ShaderWriteBit;
barriers[1].DstAccessMask = AccessFlags.TransferReadBit | AccessFlags.MemoryReadBit;
vk.CmdPipelineBarrier(command, PipelineStageFlags.ComputeShaderBit, PipelineStageFlags.AllCommandsBit, 0, 0, null, 1, barriers + 1, 0, null);
barriers[1].SrcAccessMask = AccessFlags2.ShaderWriteBit;
barriers[1].DstAccessMask = AccessFlags2.TransferReadBit | AccessFlags2.MemoryReadBit;
VulkanSynchronization.PipelineBarrier(vk,command, PipelineStageFlags.ComputeShaderBit, PipelineStageFlags.AllCommandsBit, 0, 0, null, 1, barriers + 1, 0, null);
}
// Detiles into a scratch buffer that lives through the current tick.
@ -673,13 +674,13 @@ public sealed unsafe class GpuTiler : IDisposable
var vk = _device.Vk;
_scheduler.EndRendering();
var command = new CommandBuffer(_scheduler.Current.Handle);
var barriers = stackalloc BufferMemoryBarrier[2];
var barriers = stackalloc BufferMemoryBarrier2[2];
barriers[0] = Barrier(source.Buffer, source.Offset, sourceBarrierSize,
AccessFlags.MemoryWriteBit | AccessFlags.HostWriteBit | AccessFlags.TransferWriteBit | AccessFlags.ShaderWriteBit, AccessFlags.ShaderReadBit);
barriers[1] = Barrier(target.Buffer, target.Offset, targetBarrierSize,
AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit | AccessFlags.HostWriteBit | AccessFlags.TransferWriteBit | AccessFlags.ShaderWriteBit,
AccessFlags.ShaderReadBit | AccessFlags.ShaderWriteBit);
vk.CmdPipelineBarrier(command, PipelineStageFlags.AllCommandsBit | PipelineStageFlags.HostBit, PipelineStageFlags.ComputeShaderBit, 0, 0, null, 2, barriers, 0, null);
VulkanSynchronization.PipelineBarrier(vk,command, PipelineStageFlags.AllCommandsBit | PipelineStageFlags.HostBit, PipelineStageFlags.ComputeShaderBit, 0, 0, null, 2, barriers, 0, null);
vk.CmdBindPipeline(command, PipelineBindPoint.Compute, pipeline);
var descriptorAlignment = StorageAlignment;
@ -737,9 +738,9 @@ public sealed unsafe class GpuTiler : IDisposable
}
}
barriers[1].SrcAccessMask = AccessFlags.ShaderWriteBit;
barriers[1].DstAccessMask = AccessFlags.TransferReadBit | AccessFlags.MemoryReadBit;
vk.CmdPipelineBarrier(command, PipelineStageFlags.ComputeShaderBit, PipelineStageFlags.AllCommandsBit, 0, 0, null, 1, barriers + 1, 0, null);
barriers[1].SrcAccessMask = AccessFlags2.ShaderWriteBit;
barriers[1].DstAccessMask = AccessFlags2.TransferReadBit | AccessFlags2.MemoryReadBit;
VulkanSynchronization.PipelineBarrier(vk,command, PipelineStageFlags.ComputeShaderBit, PipelineStageFlags.AllCommandsBit, 0, 0, null, 1, barriers + 1, 0, null);
}
private void SwapBgra16(TilerBufferSpan input, TilerBufferSpan output, uint pixels)
@ -760,20 +761,20 @@ public sealed unsafe class GpuTiler : IDisposable
Span<DescriptorBufferInfo> infos = stackalloc DescriptorBufferInfo[2];
infos[0] = inputBinding.Info;
infos[1] = outputBinding.Info;
var barriers = stackalloc BufferMemoryBarrier[2];
var barriers = stackalloc BufferMemoryBarrier2[2];
barriers[0] = Barrier(infos[0].Buffer, infos[0].Offset, infos[0].Range, AccessFlags.MemoryWriteBit | AccessFlags.HostWriteBit | AccessFlags.ShaderWriteBit, AccessFlags.ShaderReadBit);
barriers[1] = Barrier(infos[1].Buffer, infos[1].Offset, infos[1].Range, AccessFlags.MemoryReadBit, AccessFlags.ShaderWriteBit);
var vk = _device.Vk;
_scheduler.EndRendering();
var command = new CommandBuffer(_scheduler.Current.Handle);
vk.CmdPipelineBarrier(command, PipelineStageFlags.AllCommandsBit | PipelineStageFlags.HostBit, PipelineStageFlags.ComputeShaderBit, 0, 0, null, 2, barriers, 0, null);
VulkanSynchronization.PipelineBarrier(vk,command, PipelineStageFlags.AllCommandsBit | PipelineStageFlags.HostBit, PipelineStageFlags.ComputeShaderBit, 0, 0, null, 2, barriers, 0, null);
vk.CmdBindPipeline(command, PipelineBindPoint.Compute, _swapBgra16);
BindDescriptorSet(command, WriteDescriptorSet(infos, -1));
PushArguments(command, new TileTransferArguments { SourceBase = inputBinding.Base, DestinationBase = outputBinding.Base, Width = pixels });
vk.CmdDispatch(command, (pixels + 63) / 64, 1, 1);
barriers[1].SrcAccessMask = AccessFlags.ShaderWriteBit;
barriers[1].DstAccessMask = AccessFlags.TransferReadBit;
vk.CmdPipelineBarrier(command, PipelineStageFlags.ComputeShaderBit, PipelineStageFlags.TransferBit, 0, 0, null, 1, barriers + 1, 0, null);
barriers[1].SrcAccessMask = AccessFlags2.ShaderWriteBit;
barriers[1].DstAccessMask = AccessFlags2.TransferReadBit;
VulkanSynchronization.PipelineBarrier(vk,command, PipelineStageFlags.ComputeShaderBit, PipelineStageFlags.TransferBit, 0, 0, null, 1, barriers + 1, 0, null);
}
public TilerBufferSpan SwapBgra16(TilerBufferSpan input)

View File

@ -3,6 +3,7 @@
using SharpEmu.Libs.Gpu.Buffers;
using SharpEmu.Libs.Gpu.Scheduling;
using SharpEmu.Libs.Gpu.Vulkan;
using Silk.NET.Vulkan;
using SharpEmu.Libs.VideoOut;
@ -686,11 +687,11 @@ public sealed unsafe partial class GuestImageCache
download.Flush(offset, range.Size);
DownloadToBuffer(image, download, offset, range.Size, plan);
var barrier = new BufferMemoryBarrier
var barrier = new BufferMemoryBarrier2
{
SType = StructureType.BufferMemoryBarrier,
SrcAccessMask = AccessFlags.MemoryWriteBit | AccessFlags.TransferWriteBit | AccessFlags.ShaderWriteBit,
DstAccessMask = AccessFlags.HostReadBit,
SType = StructureType.BufferMemoryBarrier2,
SrcAccessMask = AccessFlags2.MemoryWriteBit | AccessFlags2.TransferWriteBit | AccessFlags2.ShaderWriteBit,
DstAccessMask = AccessFlags2.HostReadBit,
SrcQueueFamilyIndex = Vk.QueueFamilyIgnored,
DstQueueFamilyIndex = Vk.QueueFamilyIgnored,
Buffer = download.Handle,
@ -698,7 +699,7 @@ public sealed unsafe partial class GuestImageCache
Size = range.Size,
};
_scheduler.EndRendering();
_device.Vk.CmdPipelineBarrier(new CommandBuffer(_scheduler.Current.Handle), PipelineStageFlags.AllCommandsBit, PipelineStageFlags.HostBit, 0, 0, null, 1, &barrier, 0, null);
VulkanSynchronization.PipelineBarrier(_device.Vk,new CommandBuffer(_scheduler.Current.Handle), PipelineStageFlags.AllCommandsBit, PipelineStageFlags.HostBit, 0, 0, null, 1, &barrier, 0, null);
var backing = _backing;
_scheduler.QueuePriorityCompletionAction(() =>
{

View File

@ -13,18 +13,18 @@ public static class GlobalDataShareBarrier
public const PipelineStageFlags SourceStages =
PipelineStageFlags.HostBit | PipelineStageFlags.TransferBit | PipelineStageFlags.AllGraphicsBit | PipelineStageFlags.ComputeShaderBit;
public static BufferMemoryBarrier Make(VkBuffer buffer)
public static BufferMemoryBarrier2 Make(VkBuffer buffer)
{
if (buffer.Handle == 0)
{
throw SubmissionScheduler.Fatal("The global data share buffer is missing.");
}
return new BufferMemoryBarrier
return new BufferMemoryBarrier2
{
SType = StructureType.BufferMemoryBarrier,
SrcAccessMask = AccessFlags.HostWriteBit | AccessFlags.TransferWriteBit | AccessFlags.ShaderWriteBit,
DstAccessMask = AccessFlags.ShaderReadBit | AccessFlags.ShaderWriteBit,
SType = StructureType.BufferMemoryBarrier2,
SrcAccessMask = AccessFlags2.HostWriteBit | AccessFlags2.TransferWriteBit | AccessFlags2.ShaderWriteBit,
DstAccessMask = AccessFlags2.ShaderReadBit | AccessFlags2.ShaderWriteBit,
SrcQueueFamilyIndex = Vk.QueueFamilyIgnored,
DstQueueFamilyIndex = Vk.QueueFamilyIgnored,
Buffer = buffer,

View File

@ -89,7 +89,7 @@ internal sealed unsafe class VulkanCommandProfile : IDisposable
queries.Count = 1;
queries.Submitted = false;
_vulkan.CmdResetQueryPool(command, queries.Pool, 0, QueryCapacity);
_vulkan.CmdWriteTimestamp(command, PipelineStageFlags.TopOfPipeBit, queries.Pool, 0);
_vulkan.CmdWriteTimestamp2(command, PipelineStageFlags2.TopOfPipeBit, queries.Pool, 0);
}
public void WriteMarker(CommandBuffer command, IntervalKind kind, ulong pipeline = 0, uint first = 0, uint second = 0, uint third = 0)
@ -108,7 +108,7 @@ internal sealed unsafe class VulkanCommandProfile : IDisposable
var index = queries.Count++;
queries.Markers[index] = new Marker(new IntervalKey(kind, pipeline), first, second, third);
// Completion intervals do not isolate shader stages or eliminate overlap with later work.
_vulkan.CmdWriteTimestamp(command, PipelineStageFlags.BottomOfPipeBit, queries.Pool, (uint)index);
_vulkan.CmdWriteTimestamp2(command, PipelineStageFlags2.BottomOfPipeBit, queries.Pool, (uint)index);
}
public void MarkSubmitted(nint command)

View File

@ -0,0 +1,56 @@
// Copyright (C) 2026 SharpEmu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
using Silk.NET.Vulkan;
namespace SharpEmu.Libs.Gpu.Vulkan;
internal static unsafe class VulkanSynchronization
{
public static AccessFlags2 Access(AccessFlags access) => (AccessFlags2)(ulong)access;
public static void PipelineBarrier(
Vk vk,
CommandBuffer command,
PipelineStageFlags sourceStages,
PipelineStageFlags destinationStages,
DependencyFlags dependencyFlags,
uint memoryBarrierCount,
MemoryBarrier2* memoryBarriers,
uint bufferMemoryBarrierCount,
BufferMemoryBarrier2* bufferMemoryBarriers,
uint imageMemoryBarrierCount,
ImageMemoryBarrier2* imageMemoryBarriers)
{
var sourceStages2 = (PipelineStageFlags2)(ulong)sourceStages;
var destinationStages2 = (PipelineStageFlags2)(ulong)destinationStages;
for (var index = 0u; index < memoryBarrierCount; index++)
{
memoryBarriers[index].SrcStageMask = sourceStages2;
memoryBarriers[index].DstStageMask = destinationStages2;
}
for (var index = 0u; index < bufferMemoryBarrierCount; index++)
{
bufferMemoryBarriers[index].SrcStageMask = sourceStages2;
bufferMemoryBarriers[index].DstStageMask = destinationStages2;
}
for (var index = 0u; index < imageMemoryBarrierCount; index++)
{
imageMemoryBarriers[index].SrcStageMask = sourceStages2;
imageMemoryBarriers[index].DstStageMask = destinationStages2;
}
var dependencyInfo = new DependencyInfo
{
SType = StructureType.DependencyInfo,
DependencyFlags = dependencyFlags,
MemoryBarrierCount = memoryBarrierCount,
PMemoryBarriers = memoryBarriers,
BufferMemoryBarrierCount = bufferMemoryBarrierCount,
PBufferMemoryBarriers = bufferMemoryBarriers,
ImageMemoryBarrierCount = imageMemoryBarrierCount,
PImageMemoryBarriers = imageMemoryBarriers,
};
vk.CmdPipelineBarrier2(command, &dependencyInfo);
}
}

View File

@ -128,27 +128,47 @@ internal sealed unsafe class VulkanTickDevice : IGpuTickDevice
fixed (ulong* signalSemaphores = bundle.SignalSemaphores)
fixed (ulong* signalTicks = bundle.SignalTicks)
{
var timelineInfo = new TimelineSemaphoreSubmitInfo
var waitInfos = stackalloc SemaphoreSubmitInfo[bundle.WaitCount];
for (var index = 0; index < bundle.WaitCount; index++)
{
SType = StructureType.TimelineSemaphoreSubmitInfo,
WaitSemaphoreValueCount = (uint)bundle.WaitCount,
PWaitSemaphoreValues = waitTicks,
SignalSemaphoreValueCount = (uint)bundle.SignalCount,
PSignalSemaphoreValues = signalTicks,
};
var submitInfo = new SubmitInfo
waitInfos[index] = new SemaphoreSubmitInfo
{
SType = StructureType.SemaphoreSubmitInfo,
Semaphore = new VkSemaphore(waitSemaphores[index]),
Value = waitTicks[index],
StageMask = (PipelineStageFlags2)waitStages[index],
};
}
var signalInfos = stackalloc SemaphoreSubmitInfo[bundle.SignalCount];
for (var index = 0; index < bundle.SignalCount; index++)
{
SType = StructureType.SubmitInfo,
PNext = &timelineInfo,
WaitSemaphoreCount = (uint)bundle.WaitCount,
PWaitSemaphores = (VkSemaphore*)waitSemaphores,
PWaitDstStageMask = (PipelineStageFlags*)waitStages,
CommandBufferCount = 1,
PCommandBuffers = &commandBuffer,
SignalSemaphoreCount = (uint)bundle.SignalCount,
PSignalSemaphores = (VkSemaphore*)signalSemaphores,
signalInfos[index] = new SemaphoreSubmitInfo
{
SType = StructureType.SemaphoreSubmitInfo,
Semaphore = new VkSemaphore(signalSemaphores[index]),
Value = signalTicks[index],
StageMask = PipelineStageFlags2.AllCommandsBit,
};
}
var commandInfo = new CommandBufferSubmitInfo
{
SType = StructureType.CommandBufferSubmitInfo,
CommandBuffer = commandBuffer,
DeviceMask = 1,
};
var result = _vk.QueueSubmit(_queue, 1, &submitInfo, default);
var submitInfo = new SubmitInfo2
{
SType = StructureType.SubmitInfo2,
WaitSemaphoreInfoCount = (uint)bundle.WaitCount,
PWaitSemaphoreInfos = waitInfos,
CommandBufferInfoCount = 1,
PCommandBufferInfos = &commandInfo,
SignalSemaphoreInfoCount = (uint)bundle.SignalCount,
PSignalSemaphoreInfos = signalInfos,
};
var result = _vk.QueueSubmit2(_queue, 1, &submitInfo, default);
if (result == Result.Success)
CommandProfile?.MarkSubmitted(buffer);
failure = result.ToString();

View File

@ -8,6 +8,7 @@ using SharpEmu.Libs.Gpu;
using SharpEmu.Libs.Gpu.Buffers;
using SharpEmu.Libs.Gpu.Images;
using SharpEmu.Libs.Gpu.Scheduling;
using SharpEmu.Libs.Gpu.Vulkan;
using Silk.NET.Vulkan;
using VkBuffer = Silk.NET.Vulkan.Buffer;
@ -751,11 +752,11 @@ internal static unsafe partial class VulkanVideoPresenter
}
var initialized = texture.HostMoviePlane == 0 ? _hostMovieImageInitialized : _hostMovieChromaImageInitialized;
var toTransfer = new ImageMemoryBarrier
var toTransfer = new ImageMemoryBarrier2
{
SType = StructureType.ImageMemoryBarrier,
SrcAccessMask = initialized ? AccessFlags.ShaderReadBit : 0,
DstAccessMask = AccessFlags.TransferWriteBit,
SType = StructureType.ImageMemoryBarrier2,
SrcAccessMask = initialized ? AccessFlags2.ShaderReadBit : 0,
DstAccessMask = AccessFlags2.TransferWriteBit,
OldLayout = initialized ? ImageLayout.ShaderReadOnlyOptimal : ImageLayout.Undefined,
NewLayout = ImageLayout.TransferDstOptimal,
SrcQueueFamilyIndex = Vk.QueueFamilyIgnored,
@ -763,7 +764,7 @@ internal static unsafe partial class VulkanVideoPresenter
Image = texture.Image,
SubresourceRange = ColorSubresourceRange(),
};
_vk.CmdPipelineBarrier(
VulkanSynchronization.PipelineBarrier(_vk,
_commandBuffer, initialized ? PipelineStageFlags.AllCommandsBit : PipelineStageFlags.TopOfPipeBit, PipelineStageFlags.TransferBit,
0, 0, null, 0, null, 1, &toTransfer);
var copyRegion = new BufferImageCopy
@ -773,11 +774,11 @@ internal static unsafe partial class VulkanVideoPresenter
ImageExtent = new Extent3D(texture.Width, texture.Height, 1),
};
_vk.CmdCopyBufferToImage(_commandBuffer, texture.StagingBuffer, texture.Image, ImageLayout.TransferDstOptimal, 1, &copyRegion);
var toShaderRead = new ImageMemoryBarrier
var toShaderRead = new ImageMemoryBarrier2
{
SType = StructureType.ImageMemoryBarrier,
SrcAccessMask = AccessFlags.TransferWriteBit,
DstAccessMask = AccessFlags.ShaderReadBit,
SType = StructureType.ImageMemoryBarrier2,
SrcAccessMask = AccessFlags2.TransferWriteBit,
DstAccessMask = AccessFlags2.ShaderReadBit,
OldLayout = ImageLayout.TransferDstOptimal,
NewLayout = ImageLayout.ShaderReadOnlyOptimal,
SrcQueueFamilyIndex = Vk.QueueFamilyIgnored,
@ -785,7 +786,7 @@ internal static unsafe partial class VulkanVideoPresenter
Image = texture.Image,
SubresourceRange = ColorSubresourceRange(),
};
_vk.CmdPipelineBarrier(_commandBuffer, PipelineStageFlags.TransferBit, shaderStage, 0, 0, null, 0, null, 1, &toShaderRead);
VulkanSynchronization.PipelineBarrier(_vk,_commandBuffer, PipelineStageFlags.TransferBit, shaderStage, 0, 0, null, 0, null, 1, &toShaderRead);
if (texture.HostMoviePlane == 0)
{
_hostMovieImageInitialized = true;

View File

@ -10,6 +10,7 @@ using SharpEmu.Libs.Gpu.GpuCommands;
using SharpEmu.Libs.Gpu.Images;
using SharpEmu.Libs.Gpu.Scheduling;
using SharpEmu.ShaderCompiler;
using SharpEmu.Libs.Gpu.Vulkan;
using Silk.NET.Vulkan;
internal static unsafe partial class VulkanVideoPresenter
@ -311,13 +312,13 @@ internal static unsafe partial class VulkanVideoPresenter
EndRendering();
EndRendering();
var commandBuffer = BeginBatchedGuestCommands();
var barrier = new MemoryBarrier
var barrier = new MemoryBarrier2
{
SType = StructureType.MemoryBarrier,
SrcAccessMask = AccessFlags.MemoryWriteBit,
DstAccessMask = AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit,
SType = StructureType.MemoryBarrier2,
SrcAccessMask = AccessFlags2.MemoryWriteBit,
DstAccessMask = AccessFlags2.MemoryReadBit | AccessFlags2.MemoryWriteBit,
};
_vk.CmdPipelineBarrier(
VulkanSynchronization.PipelineBarrier(_vk,
commandBuffer,
PipelineStageFlags.AllCommandsBit,
PipelineStageFlags.AllCommandsBit,
@ -547,11 +548,11 @@ internal static unsafe partial class VulkanVideoPresenter
snapshot = CreateGuestFlipSnapshot(GetPresentationSnapshotFormat(source.Backing.Format),
extent.Width, extent.Height, displayBuffer.Address, version);
source.Transition(ImageLayout.TransferSrcOptimal, AccessFlags.TransferReadBit, null, commandBuffer);
var toTransferDst = new ImageMemoryBarrier
var toTransferDst = new ImageMemoryBarrier2
{
SType = StructureType.ImageMemoryBarrier,
SType = StructureType.ImageMemoryBarrier2,
SrcAccessMask = 0,
DstAccessMask = AccessFlags.TransferWriteBit,
DstAccessMask = AccessFlags2.TransferWriteBit,
OldLayout = ImageLayout.Undefined,
NewLayout = ImageLayout.TransferDstOptimal,
SrcQueueFamilyIndex = Vk.QueueFamilyIgnored,
@ -559,7 +560,7 @@ internal static unsafe partial class VulkanVideoPresenter
Image = snapshot.Image,
SubresourceRange = ColorSubresourceRange(),
};
_vk.CmdPipelineBarrier(
VulkanSynchronization.PipelineBarrier(_vk,
commandBuffer, PipelineStageFlags.TopOfPipeBit, PipelineStageFlags.TransferBit, 0, 0, null, 0, null, 1, &toTransferDst);
var copy = new ImageCopy
{
@ -569,11 +570,11 @@ internal static unsafe partial class VulkanVideoPresenter
};
_vk.CmdCopyImage(
commandBuffer, source.Backing.Handle, ImageLayout.TransferSrcOptimal, snapshot.Image, ImageLayout.TransferDstOptimal, 1, &copy);
var toShaderRead = new ImageMemoryBarrier
var toShaderRead = new ImageMemoryBarrier2
{
SType = StructureType.ImageMemoryBarrier,
SrcAccessMask = AccessFlags.TransferWriteBit,
DstAccessMask = AccessFlags.ShaderReadBit | AccessFlags.TransferReadBit,
SType = StructureType.ImageMemoryBarrier2,
SrcAccessMask = AccessFlags2.TransferWriteBit,
DstAccessMask = AccessFlags2.ShaderReadBit | AccessFlags2.TransferReadBit,
OldLayout = ImageLayout.TransferDstOptimal,
NewLayout = ImageLayout.ShaderReadOnlyOptimal,
SrcQueueFamilyIndex = Vk.QueueFamilyIgnored,
@ -581,7 +582,7 @@ internal static unsafe partial class VulkanVideoPresenter
Image = snapshot.Image,
SubresourceRange = ColorSubresourceRange(),
};
_vk.CmdPipelineBarrier(
VulkanSynchronization.PipelineBarrier(_vk,
commandBuffer, PipelineStageFlags.TransferBit, PipelineStageFlags.AllCommandsBit, 0, 0, null, 0, null, 1, &toShaderRead);
FlushBatchedGuestCommands();

View File

@ -13,6 +13,7 @@ using SharpEmu.Libs.Gpu.Rendering;
using SharpEmu.Libs.Gpu.Scheduling;
using SharpEmu.ShaderCompiler;
using SharpEmu.ShaderCompiler.Resources;
using SharpEmu.Libs.Gpu.Vulkan;
using Silk.NET.Vulkan;
using VkBuffer = Silk.NET.Vulkan.Buffer;
@ -678,7 +679,7 @@ internal static unsafe partial class VulkanVideoPresenter
EndRendering();
command = BeginBatchedGuestCommands();
var barrier = GlobalDataShareBarrier.Make(descriptors.GlobalDataShare.Buffer);
_vk.CmdPipelineBarrier(command, GlobalDataShareBarrier.SourceStages, DescriptorWriter.PipelineStageFlag(stageFlag), 0, 0, null, 1, &barrier, 0, null);
VulkanSynchronization.PipelineBarrier(_vk,command, GlobalDataShareBarrier.SourceStages, DescriptorWriter.PipelineStageFlag(stageFlag), 0, 0, null, 1, &barrier, 0, null);
}
RecordStageTextureTransitions(stage.Textures);

View File

@ -63,6 +63,14 @@ internal static unsafe partial class VulkanVideoPresenter
_relay.BindCurrentThread();
WaitForRenderDocAttachIfRequested();
_vk = Vk.GetApi();
uint loaderVersion = Vk.Version10;
Check(_vk.EnumerateInstanceVersion(ref loaderVersion), "vkEnumerateInstanceVersion");
if (loaderVersion < Vk.Version13)
{
throw new InvalidOperationException(
$"SharpEmu requires Vulkan 1.3; loader exposes {loaderVersion >> 22}.{(loaderVersion >> 12) & 0x3ff}.");
}
CreateInstance();
CreateSurface();
SelectPhysicalDevice();
@ -253,7 +261,7 @@ internal static unsafe partial class VulkanVideoPresenter
ApplicationVersion = Vk.MakeVersion(0, 0, 1),
PEngineName = applicationName,
EngineVersion = Vk.MakeVersion(0, 0, 1),
ApiVersion = Vk.Version12,
ApiVersion = Vk.Version13,
};
var extensions = _window.GetRequiredVulkanInstanceExtensions(out var extensionCount);
@ -515,6 +523,14 @@ internal static unsafe partial class VulkanVideoPresenter
}
_vk.GetPhysicalDeviceProperties(device, out var properties);
if (properties.ApiVersion < Vk.Version13)
{
var unsupportedName = SilkMarshal.PtrToString((nint)properties.DeviceName) ?? string.Empty;
Console.Error.WriteLine(
$"[LOADER][INFO] Vulkan candidate skipped: {unsupportedName} api={properties.ApiVersion >> 22}.{(properties.ApiVersion >> 12) & 0x3ff} requires=1.3");
break;
}
var name = SilkMarshal.PtrToString((nint)properties.DeviceName) ?? string.Empty;
var score = ScorePhysicalDevice(properties, name, deviceOverride);
Console.Error.WriteLine(
@ -740,25 +756,15 @@ internal static unsafe partial class VulkanVideoPresenter
SType = StructureType.PhysicalDeviceColorWriteEnableFeaturesExt,
PNext = &depthClipControlFeatures,
};
var extendedDynamicState2Features = new PhysicalDeviceExtendedDynamicState2FeaturesEXT
var vulkan13Features = new PhysicalDeviceVulkan13Features
{
SType = StructureType.PhysicalDeviceExtendedDynamicState2FeaturesExt,
SType = StructureType.PhysicalDeviceVulkan13Features,
PNext = &colorWriteEnableFeatures,
};
var extendedDynamicStateFeatures = new PhysicalDeviceExtendedDynamicStateFeaturesEXT
{
SType = StructureType.PhysicalDeviceExtendedDynamicStateFeaturesExt,
PNext = &extendedDynamicState2Features,
};
var dynamicRenderingFeatures = new PhysicalDeviceDynamicRenderingFeaturesKHR
{
SType = StructureType.PhysicalDeviceDynamicRenderingFeaturesKhr,
PNext = &extendedDynamicStateFeatures,
};
var maintenance8Features = new PhysicalDeviceMaintenance8FeaturesKHR
{
SType = StructureType.PhysicalDeviceMaintenance8FeaturesKhr,
PNext = &dynamicRenderingFeatures,
PNext = &vulkan13Features,
};
var robustness2Features = new PhysicalDeviceRobustness2FeaturesEXT
{
@ -790,10 +796,8 @@ internal static unsafe partial class VulkanVideoPresenter
var supportsRobustness2 = supportsRobustImageAccess2 || supportsNullDescriptor;
_vk.GetPhysicalDeviceProperties(_physicalDevice, out var deviceProperties);
var deviceName = SilkMarshal.PtrToString((nint)deviceProperties.DeviceName) ?? "unknown";
RequireRenderingFeature(dynamicRenderingFeatures.DynamicRendering, DynamicRenderingExtensionName, deviceName);
RequireRenderingFeature(extendedDynamicStateFeatures.ExtendedDynamicState, ExtendedDynamicStateExtensionName, deviceName);
RequireRenderingFeature(
extendedDynamicState2Features.ExtendedDynamicState2, ExtendedDynamicState2ExtensionName, deviceName);
RequireRenderingFeature(vulkan13Features.DynamicRendering, "Vulkan 1.3 dynamicRendering", deviceName);
RequireRenderingFeature(vulkan13Features.Synchronization2, "Vulkan 1.3 synchronization2", deviceName);
var supportsColorWriteEnable = colorWriteEnableFeatures.ColorWriteEnable;
_supportsDepthClipControl = depthClipControlFeatures.DepthClipControl;
_supportsDepthClipEnable = depthClipEnableFeatures.DepthClipEnable;
@ -821,9 +825,6 @@ internal static unsafe partial class VulkanVideoPresenter
var maintenance8Extension = (byte*)SilkMarshal.StringToPtr("VK_KHR_maintenance8");
var robustness2Extension = (byte*)SilkMarshal.StringToPtr("VK_EXT_robustness2");
var portabilitySubsetExtension = (byte*)SilkMarshal.StringToPtr(PortabilitySubsetExtensionName);
var dynamicRenderingExtension = (byte*)SilkMarshal.StringToPtr(DynamicRenderingExtensionName);
var extendedDynamicStateExtension = (byte*)SilkMarshal.StringToPtr(ExtendedDynamicStateExtensionName);
var extendedDynamicState2Extension = (byte*)SilkMarshal.StringToPtr(ExtendedDynamicState2ExtensionName);
var colorWriteEnableExtension = (byte*)SilkMarshal.StringToPtr(ColorWriteEnableExtensionName);
var depthClipControlExtension = (byte*)SilkMarshal.StringToPtr(DepthClipControlExtensionName);
var depthClipEnableExtension = (byte*)SilkMarshal.StringToPtr(DepthClipEnableExtensionName);
@ -834,9 +835,6 @@ internal static unsafe partial class VulkanVideoPresenter
var extensionCount = 0u;
extensions[extensionCount++] = swapchainExtension;
extensions[extensionCount++] = pushDescriptorExtension;
extensions[extensionCount++] = dynamicRenderingExtension;
extensions[extensionCount++] = extendedDynamicStateExtension;
extensions[extensionCount++] = extendedDynamicState2Extension;
if (_supportsFragmentShaderBarycentric)
{
extensions[extensionCount++] = barycentricExtension;
@ -941,28 +939,17 @@ internal static unsafe partial class VulkanVideoPresenter
renderingChain = &colorWriteEnableFeatures;
}
extendedDynamicState2Features = new PhysicalDeviceExtendedDynamicState2FeaturesEXT
vulkan13Features = new PhysicalDeviceVulkan13Features
{
SType = StructureType.PhysicalDeviceExtendedDynamicState2FeaturesExt,
ExtendedDynamicState2 = true,
PNext = renderingChain,
};
extendedDynamicStateFeatures = new PhysicalDeviceExtendedDynamicStateFeaturesEXT
{
SType = StructureType.PhysicalDeviceExtendedDynamicStateFeaturesExt,
ExtendedDynamicState = true,
PNext = &extendedDynamicState2Features,
};
dynamicRenderingFeatures = new PhysicalDeviceDynamicRenderingFeaturesKHR
{
SType = StructureType.PhysicalDeviceDynamicRenderingFeaturesKhr,
SType = StructureType.PhysicalDeviceVulkan13Features,
DynamicRendering = true,
PNext = &extendedDynamicStateFeatures,
Synchronization2 = true,
PNext = renderingChain,
};
var features2 = new PhysicalDeviceFeatures2
{
SType = StructureType.PhysicalDeviceFeatures2,
PNext = &dynamicRenderingFeatures,
PNext = &vulkan13Features,
Features = enabledFeatures,
};
var createInfo = new DeviceCreateInfo
@ -983,9 +970,6 @@ internal static unsafe partial class VulkanVideoPresenter
SilkMarshal.Free((nint)maintenance8Extension);
SilkMarshal.Free((nint)robustness2Extension);
SilkMarshal.Free((nint)portabilitySubsetExtension);
SilkMarshal.Free((nint)dynamicRenderingExtension);
SilkMarshal.Free((nint)extendedDynamicStateExtension);
SilkMarshal.Free((nint)extendedDynamicState2Extension);
SilkMarshal.Free((nint)colorWriteEnableExtension);
SilkMarshal.Free((nint)depthClipControlExtension);
SilkMarshal.Free((nint)depthClipEnableExtension);

View File

@ -6,6 +6,7 @@ namespace SharpEmu.Libs.VideoOut;
using SharpEmu.Libs.Gpu;
using SharpEmu.ShaderCompiler;
using SharpEmu.Libs.Gpu.Images;
using SharpEmu.Libs.Gpu.Vulkan;
using Silk.NET.Vulkan;
using VkBuffer = Silk.NET.Vulkan.Buffer;
@ -66,12 +67,12 @@ internal static unsafe partial class VulkanVideoPresenter
var oldLayout = _imageInitialized[imageIndex]
? PresentationTargetFinalLayout
: ImageLayout.Undefined;
var toTransfer = new ImageMemoryBarrier
var toTransfer = new ImageMemoryBarrier2
{
SType = StructureType.ImageMemoryBarrier,
SType = StructureType.ImageMemoryBarrier2,
SrcAccessMask = _hdrOutputActive && _imageInitialized[imageIndex]
? AccessFlags.ShaderReadBit : 0,
DstAccessMask = AccessFlags.TransferWriteBit,
? AccessFlags2.ShaderReadBit : 0,
DstAccessMask = AccessFlags2.TransferWriteBit,
OldLayout = oldLayout,
NewLayout = ImageLayout.TransferDstOptimal,
SrcQueueFamilyIndex = Vk.QueueFamilyIgnored,
@ -79,7 +80,7 @@ internal static unsafe partial class VulkanVideoPresenter
Image = presentationTarget,
SubresourceRange = ColorSubresourceRange(),
};
_vk.CmdPipelineBarrier(
VulkanSynchronization.PipelineBarrier(_vk,
_commandBuffer,
GetPresentationUploadSourceStage(_hdrOutputActive, _imageInitialized[imageIndex]),
PipelineStageFlags.TransferBit,
@ -108,13 +109,13 @@ internal static unsafe partial class VulkanVideoPresenter
1,
&copyRegion);
var toFinalLayout = new ImageMemoryBarrier
var toFinalLayout = new ImageMemoryBarrier2
{
SType = StructureType.ImageMemoryBarrier,
SrcAccessMask = AccessFlags.TransferWriteBit,
SType = StructureType.ImageMemoryBarrier2,
SrcAccessMask = AccessFlags2.TransferWriteBit,
DstAccessMask = _hdrOutputActive
? AccessFlags.ShaderReadBit
: AccessFlags.MemoryReadBit,
? AccessFlags2.ShaderReadBit
: AccessFlags2.MemoryReadBit,
OldLayout = ImageLayout.TransferDstOptimal,
NewLayout = PresentationTargetFinalLayout,
SrcQueueFamilyIndex = Vk.QueueFamilyIgnored,
@ -122,7 +123,7 @@ internal static unsafe partial class VulkanVideoPresenter
Image = presentationTarget,
SubresourceRange = ColorSubresourceRange(),
};
_vk.CmdPipelineBarrier(
VulkanSynchronization.PipelineBarrier(_vk,
_commandBuffer,
PipelineStageFlags.TransferBit,
_hdrOutputActive
@ -246,9 +247,9 @@ internal static unsafe partial class VulkanVideoPresenter
_commandBuffer,
$"SharpEmu present image 0x{source.Address:X16}");
var sourceToTransfer = new ImageMemoryBarrier
var sourceToTransfer = new ImageMemoryBarrier2
{
SType = StructureType.ImageMemoryBarrier,
SType = StructureType.ImageMemoryBarrier2,
// An offscreen target is last written as a color attachment,
// then put in ShaderReadOnlyOptimal for later sampling. A
// layout-only handoff to ShaderRead does not make that write
@ -257,8 +258,8 @@ internal static unsafe partial class VulkanVideoPresenter
// (usually black) image while Windows drivers happened to
// tolerate it. Include all preceding writes before blitting
// the image into the swapchain.
SrcAccessMask = AccessFlags.MemoryWriteBit | AccessFlags.ShaderReadBit,
DstAccessMask = AccessFlags.TransferReadBit,
SrcAccessMask = AccessFlags2.MemoryWriteBit | AccessFlags2.ShaderReadBit,
DstAccessMask = AccessFlags2.TransferReadBit,
OldLayout = ImageLayout.ShaderReadOnlyOptimal,
NewLayout = ImageLayout.TransferSrcOptimal,
SrcQueueFamilyIndex = Vk.QueueFamilyIgnored,
@ -266,15 +267,15 @@ internal static unsafe partial class VulkanVideoPresenter
Image = source.Image,
SubresourceRange = ColorSubresourceRange(),
};
var destinationToTransfer = new ImageMemoryBarrier
var destinationToTransfer = new ImageMemoryBarrier2
{
SType = StructureType.ImageMemoryBarrier,
SType = StructureType.ImageMemoryBarrier2,
SrcAccessMask = _imageInitialized[imageIndex]
? _hdrOutputActive
? AccessFlags.ShaderReadBit
: AccessFlags.MemoryReadBit
? AccessFlags2.ShaderReadBit
: AccessFlags2.MemoryReadBit
: 0,
DstAccessMask = AccessFlags.TransferWriteBit,
DstAccessMask = AccessFlags2.TransferWriteBit,
OldLayout = _imageInitialized[imageIndex]
? PresentationTargetFinalLayout
: ImageLayout.Undefined,
@ -293,11 +294,11 @@ internal static unsafe partial class VulkanVideoPresenter
encodeForPresent = TryGetPresentEncodeImage(out encodeImage);
}
var encodeToTransferDst = new ImageMemoryBarrier
var encodeToTransferDst = new ImageMemoryBarrier2
{
SType = StructureType.ImageMemoryBarrier,
SrcAccessMask = AccessFlags.TransferReadBit,
DstAccessMask = AccessFlags.TransferWriteBit,
SType = StructureType.ImageMemoryBarrier2,
SrcAccessMask = AccessFlags2.TransferReadBit,
DstAccessMask = AccessFlags2.TransferWriteBit,
OldLayout = ImageLayout.Undefined,
NewLayout = ImageLayout.TransferDstOptimal,
SrcQueueFamilyIndex = Vk.QueueFamilyIgnored,
@ -305,11 +306,11 @@ internal static unsafe partial class VulkanVideoPresenter
Image = _presentEncodeImage,
SubresourceRange = ColorSubresourceRange(),
};
var barriers = stackalloc ImageMemoryBarrier[3];
var barriers = stackalloc ImageMemoryBarrier2[3];
barriers[0] = sourceToTransfer;
barriers[1] = destinationToTransfer;
barriers[2] = encodeToTransferDst;
_vk.CmdPipelineBarrier(
VulkanSynchronization.PipelineBarrier(_vk,
_commandBuffer,
PipelineStageFlags.AllCommandsBit,
PipelineStageFlags.TransferBit,
@ -382,13 +383,13 @@ internal static unsafe partial class VulkanVideoPresenter
&clearColor,
1,
&clearRange);
var clearComplete = new MemoryBarrier
var clearComplete = new MemoryBarrier2
{
SType = StructureType.MemoryBarrier,
SrcAccessMask = AccessFlags.TransferWriteBit,
DstAccessMask = AccessFlags.TransferWriteBit,
SType = StructureType.MemoryBarrier2,
SrcAccessMask = AccessFlags2.TransferWriteBit,
DstAccessMask = AccessFlags2.TransferWriteBit,
};
_vk.CmdPipelineBarrier(
VulkanSynchronization.PipelineBarrier(_vk,
_commandBuffer, PipelineStageFlags.TransferBit, PipelineStageFlags.TransferBit,
0, 1, &clearComplete, 0, null, 0, null);
}
@ -479,11 +480,11 @@ internal static unsafe partial class VulkanVideoPresenter
if (encodeForPresent)
{
var encodeToTransferSrc = new ImageMemoryBarrier
var encodeToTransferSrc = new ImageMemoryBarrier2
{
SType = StructureType.ImageMemoryBarrier,
SrcAccessMask = AccessFlags.TransferWriteBit,
DstAccessMask = AccessFlags.TransferReadBit,
SType = StructureType.ImageMemoryBarrier2,
SrcAccessMask = AccessFlags2.TransferWriteBit,
DstAccessMask = AccessFlags2.TransferReadBit,
OldLayout = ImageLayout.TransferDstOptimal,
NewLayout = ImageLayout.TransferSrcOptimal,
SrcQueueFamilyIndex = Vk.QueueFamilyIgnored,
@ -491,7 +492,7 @@ internal static unsafe partial class VulkanVideoPresenter
Image = encodeImage,
SubresourceRange = ColorSubresourceRange(),
};
_vk.CmdPipelineBarrier(
VulkanSynchronization.PipelineBarrier(_vk,
_commandBuffer,
PipelineStageFlags.TransferBit,
PipelineStageFlags.TransferBit,
@ -525,11 +526,11 @@ internal static unsafe partial class VulkanVideoPresenter
if (traceDestination)
{
var destinationToReadback = new ImageMemoryBarrier
var destinationToReadback = new ImageMemoryBarrier2
{
SType = StructureType.ImageMemoryBarrier,
SrcAccessMask = AccessFlags.TransferWriteBit,
DstAccessMask = AccessFlags.TransferReadBit,
SType = StructureType.ImageMemoryBarrier2,
SrcAccessMask = AccessFlags2.TransferWriteBit,
DstAccessMask = AccessFlags2.TransferReadBit,
OldLayout = ImageLayout.TransferDstOptimal,
NewLayout = ImageLayout.TransferSrcOptimal,
SrcQueueFamilyIndex = Vk.QueueFamilyIgnored,
@ -537,7 +538,7 @@ internal static unsafe partial class VulkanVideoPresenter
Image = presentationTarget,
SubresourceRange = ColorSubresourceRange(),
};
_vk.CmdPipelineBarrier(
VulkanSynchronization.PipelineBarrier(_vk,
_commandBuffer,
PipelineStageFlags.TransferBit,
PipelineStageFlags.TransferBit,
@ -568,11 +569,11 @@ internal static unsafe partial class VulkanVideoPresenter
_swapchainReadbackPending = true;
}
var sourceToShaderRead = new ImageMemoryBarrier
var sourceToShaderRead = new ImageMemoryBarrier2
{
SType = StructureType.ImageMemoryBarrier,
SrcAccessMask = AccessFlags.TransferReadBit,
DstAccessMask = AccessFlags.ShaderReadBit,
SType = StructureType.ImageMemoryBarrier2,
SrcAccessMask = AccessFlags2.TransferReadBit,
DstAccessMask = AccessFlags2.ShaderReadBit,
OldLayout = ImageLayout.TransferSrcOptimal,
NewLayout = ImageLayout.ShaderReadOnlyOptimal,
SrcQueueFamilyIndex = Vk.QueueFamilyIgnored,
@ -580,15 +581,15 @@ internal static unsafe partial class VulkanVideoPresenter
Image = source.Image,
SubresourceRange = ColorSubresourceRange(),
};
var destinationToFinalLayout = new ImageMemoryBarrier
var destinationToFinalLayout = new ImageMemoryBarrier2
{
SType = StructureType.ImageMemoryBarrier,
SType = StructureType.ImageMemoryBarrier2,
SrcAccessMask = traceDestination
? AccessFlags.TransferReadBit
: AccessFlags.TransferWriteBit,
? AccessFlags2.TransferReadBit
: AccessFlags2.TransferWriteBit,
DstAccessMask = _hdrOutputActive
? AccessFlags.ShaderReadBit
: AccessFlags.MemoryReadBit,
? AccessFlags2.ShaderReadBit
: AccessFlags2.MemoryReadBit,
OldLayout = traceDestination
? ImageLayout.TransferSrcOptimal
: ImageLayout.TransferDstOptimal,
@ -600,7 +601,7 @@ internal static unsafe partial class VulkanVideoPresenter
};
barriers[0] = sourceToShaderRead;
barriers[1] = destinationToFinalLayout;
_vk.CmdPipelineBarrier(
VulkanSynchronization.PipelineBarrier(_vk,
_commandBuffer,
PipelineStageFlags.TransferBit,
_hdrOutputActive

View File

@ -5,6 +5,7 @@ namespace SharpEmu.Libs.VideoOut;
using SharpEmu.ShaderCompiler.Vulkan;
using Silk.NET.Core.Native;
using SharpEmu.Libs.Gpu.Vulkan;
using Silk.NET.Vulkan;
internal static unsafe partial class VulkanVideoPresenter
@ -309,13 +310,13 @@ internal static unsafe partial class VulkanVideoPresenter
private void RecordHdrPresentation(uint imageIndex, bool isHdr)
{
var sourceBarrier = new ImageMemoryBarrier
var sourceBarrier = new ImageMemoryBarrier2
{
SType = StructureType.ImageMemoryBarrier,
SrcAccessMask = AccessFlags.MemoryWriteBit |
AccessFlags.TransferWriteBit |
AccessFlags.ColorAttachmentWriteBit,
DstAccessMask = AccessFlags.ShaderReadBit,
SType = StructureType.ImageMemoryBarrier2,
SrcAccessMask = AccessFlags2.MemoryWriteBit |
AccessFlags2.TransferWriteBit |
AccessFlags2.ColorAttachmentWriteBit,
DstAccessMask = AccessFlags2.ShaderReadBit,
OldLayout = ImageLayout.ShaderReadOnlyOptimal,
NewLayout = ImageLayout.ShaderReadOnlyOptimal,
SrcQueueFamilyIndex = Vk.QueueFamilyIgnored,
@ -323,7 +324,7 @@ internal static unsafe partial class VulkanVideoPresenter
Image = _presentationImages[imageIndex],
SubresourceRange = ColorSubresourceRange(),
};
_vk.CmdPipelineBarrier(
VulkanSynchronization.PipelineBarrier(_vk,
_commandBuffer,
PipelineStageFlags.AllCommandsBit,
PipelineStageFlags.FragmentShaderBit,

View File

@ -3,6 +3,7 @@
namespace SharpEmu.Libs.VideoOut;
using SharpEmu.Libs.Gpu.Vulkan;
using Silk.NET.Vulkan;
using VkBuffer = Silk.NET.Vulkan.Buffer;
@ -91,11 +92,11 @@ internal static unsafe partial class VulkanVideoPresenter
PerfOverlay.Fill(pixels, pendingWork, _pendingGuestSubmissions.Count);
var presentationTarget = PresentationTargetImage(imageIndex);
var toTransferDst = new ImageMemoryBarrier
var toTransferDst = new ImageMemoryBarrier2
{
SType = StructureType.ImageMemoryBarrier,
SrcAccessMask = _overlayImageInitialized ? AccessFlags.TransferReadBit : 0,
DstAccessMask = AccessFlags.TransferWriteBit,
SType = StructureType.ImageMemoryBarrier2,
SrcAccessMask = _overlayImageInitialized ? AccessFlags2.TransferReadBit : 0,
DstAccessMask = AccessFlags2.TransferWriteBit,
OldLayout = _overlayImageInitialized
? ImageLayout.TransferSrcOptimal
: ImageLayout.Undefined,
@ -105,7 +106,7 @@ internal static unsafe partial class VulkanVideoPresenter
Image = _overlayImage,
SubresourceRange = ColorSubresourceRange(),
};
_vk.CmdPipelineBarrier(
VulkanSynchronization.PipelineBarrier(_vk,
_commandBuffer,
PipelineStageFlags.TransferBit,
PipelineStageFlags.TransferBit,
@ -124,11 +125,11 @@ internal static unsafe partial class VulkanVideoPresenter
1,
&copyRegion);
var toTransferSrc = new ImageMemoryBarrier
var toTransferSrc = new ImageMemoryBarrier2
{
SType = StructureType.ImageMemoryBarrier,
SrcAccessMask = AccessFlags.TransferWriteBit,
DstAccessMask = AccessFlags.TransferReadBit,
SType = StructureType.ImageMemoryBarrier2,
SrcAccessMask = AccessFlags2.TransferWriteBit,
DstAccessMask = AccessFlags2.TransferReadBit,
OldLayout = ImageLayout.TransferDstOptimal,
NewLayout = ImageLayout.TransferSrcOptimal,
SrcQueueFamilyIndex = Vk.QueueFamilyIgnored,
@ -136,11 +137,11 @@ internal static unsafe partial class VulkanVideoPresenter
Image = _overlayImage,
SubresourceRange = ColorSubresourceRange(),
};
var swapchainToDst = new ImageMemoryBarrier
var swapchainToDst = new ImageMemoryBarrier2
{
SType = StructureType.ImageMemoryBarrier,
SType = StructureType.ImageMemoryBarrier2,
SrcAccessMask = 0,
DstAccessMask = AccessFlags.TransferWriteBit,
DstAccessMask = AccessFlags2.TransferWriteBit,
OldLayout = PresentationTargetFinalLayout,
NewLayout = ImageLayout.TransferDstOptimal,
SrcQueueFamilyIndex = Vk.QueueFamilyIgnored,
@ -148,8 +149,8 @@ internal static unsafe partial class VulkanVideoPresenter
Image = presentationTarget,
SubresourceRange = ColorSubresourceRange(),
};
var preBlitBarriers = stackalloc ImageMemoryBarrier[2] { toTransferSrc, swapchainToDst };
_vk.CmdPipelineBarrier(
var preBlitBarriers = stackalloc ImageMemoryBarrier2[2] { toTransferSrc, swapchainToDst };
VulkanSynchronization.PipelineBarrier(_vk,
_commandBuffer,
PipelineStageFlags.TransferBit | PipelineStageFlags.ColorAttachmentOutputBit,
PipelineStageFlags.TransferBit,
@ -180,11 +181,11 @@ internal static unsafe partial class VulkanVideoPresenter
1,
&copy);
var presentationTargetToFinal = new ImageMemoryBarrier
var presentationTargetToFinal = new ImageMemoryBarrier2
{
SType = StructureType.ImageMemoryBarrier,
SrcAccessMask = AccessFlags.TransferWriteBit,
DstAccessMask = _hdrOutputActive ? AccessFlags.ShaderReadBit : 0,
SType = StructureType.ImageMemoryBarrier2,
SrcAccessMask = AccessFlags2.TransferWriteBit,
DstAccessMask = _hdrOutputActive ? AccessFlags2.ShaderReadBit : 0,
OldLayout = ImageLayout.TransferDstOptimal,
NewLayout = PresentationTargetFinalLayout,
SrcQueueFamilyIndex = Vk.QueueFamilyIgnored,
@ -192,7 +193,7 @@ internal static unsafe partial class VulkanVideoPresenter
Image = presentationTarget,
SubresourceRange = ColorSubresourceRange(),
};
_vk.CmdPipelineBarrier(
VulkanSynchronization.PipelineBarrier(_vk,
_commandBuffer,
PipelineStageFlags.TransferBit,
_hdrOutputActive

View File

@ -24,20 +24,17 @@ using VkBuffer = Silk.NET.Vulkan.Buffer;
// This partial is the render host: it records what the executor resolved with dynamic rendering.
internal static unsafe partial class VulkanVideoPresenter
{
private const string DynamicRenderingExtensionName = "VK_KHR_dynamic_rendering";
private const string ExtendedDynamicStateExtensionName = "VK_EXT_extended_dynamic_state";
private const string ExtendedDynamicState2ExtensionName = "VK_EXT_extended_dynamic_state2";
private const string ColorWriteEnableExtensionName = "VK_EXT_color_write_enable";
private const string DepthClipControlExtensionName = "VK_EXT_depth_clip_control";
private const string DepthClipEnableExtensionName = "VK_EXT_depth_clip_enable";
private const int DrawsPerBatch = 64;
private const uint SingleRectangleVertexCount = 4;
private static void RequireRenderingFeature(bool supported, string extension, string deviceName)
private static void RequireRenderingFeature(bool supported, string feature, string deviceName)
{
if (!supported)
{
throw SubmissionScheduler.Fatal($"The device lacks a required rendering feature: device={deviceName} extension={extension}.");
throw SubmissionScheduler.Fatal($"The device lacks a required rendering feature: device={deviceName} feature={feature}.");
}
}
@ -99,9 +96,6 @@ internal static unsafe partial class VulkanVideoPresenter
}
}
private KhrDynamicRendering _dynamicRenderingApi = null!;
private ExtExtendedDynamicState _extendedDynamicStateApi = null!;
private ExtExtendedDynamicState2 _extendedDynamicState2Api = null!;
private ExtColorWriteEnable? _colorWriteEnableApi;
private bool _supportsDepthClipControl;
private bool _supportsDepthClipEnable;
@ -127,21 +121,6 @@ internal static unsafe partial class VulkanVideoPresenter
private void LoadRenderingCommands(bool supportsColorWriteEnable, string deviceName)
{
if (!_vk.TryGetDeviceExtension(_instance, _device, out _dynamicRenderingApi))
{
throw SubmissionScheduler.Fatal($"The device extension commands are unavailable: device={deviceName} extension={DynamicRenderingExtensionName}.");
}
if (!_vk.TryGetDeviceExtension(_instance, _device, out _extendedDynamicStateApi))
{
throw SubmissionScheduler.Fatal($"The device extension commands are unavailable: device={deviceName} extension={ExtendedDynamicStateExtensionName}.");
}
if (!_vk.TryGetDeviceExtension(_instance, _device, out _extendedDynamicState2Api))
{
throw SubmissionScheduler.Fatal($"The device extension commands are unavailable: device={deviceName} extension={ExtendedDynamicState2ExtensionName}.");
}
if (!_vk.TryGetDeviceExtension(_instance, _device, out _pushDescriptorApi))
{
throw SubmissionScheduler.Fatal($"The device extension commands are unavailable: device={deviceName} extension={PushDescriptorExtensionName}.");
@ -525,10 +504,10 @@ internal static unsafe partial class VulkanVideoPresenter
_vk.CmdSetLineWidth(command, state.LineWidth);
var blendConstants = stackalloc float[4] { state.BlendRed, state.BlendGreen, state.BlendBlue, state.BlendAlpha };
_vk.CmdSetBlendConstants(command, blendConstants);
_extendedDynamicStateApi.CmdSetDepthTestEnable(command, state.DepthTestEnabled);
_extendedDynamicStateApi.CmdSetDepthWriteEnable(command, state.DepthWriteEnabled);
_extendedDynamicStateApi.CmdSetDepthCompareOp(command, state.DepthCompare);
_extendedDynamicState2Api.CmdSetDepthBiasEnable(command, state.DepthBiasEnabled);
_vk.CmdSetDepthTestEnable(command, state.DepthTestEnabled);
_vk.CmdSetDepthWriteEnable(command, state.DepthWriteEnabled);
_vk.CmdSetDepthCompareOp(command, state.DepthCompare);
_vk.CmdSetDepthBiasEnable(command, state.DepthBiasEnabled);
if (state.DepthBiasEnabled)
{
_vk.CmdSetDepthBias(command, state.DepthBiasConstantFactor, _supportsDepthBiasClamp ? state.DepthBiasClamp : 0f, state.DepthBiasSlopeFactor);
@ -718,7 +697,7 @@ internal static unsafe partial class VulkanVideoPresenter
PDepthAttachment = depthStencil.HasDepth ? &depth : null,
PStencilAttachment = depthStencil.HasStencil ? &stencil : null,
};
_dynamicRenderingApi.CmdBeginRendering(command, &rendering);
_vk.CmdBeginRendering(command, &rendering);
_renderingScopesBegun++;
_renderingActive = true;
_renderingState = state;
@ -733,7 +712,7 @@ internal static unsafe partial class VulkanVideoPresenter
_renderingActive = false;
_renderingState = default;
_dynamicRenderingApi.CmdEndRendering(new CommandBuffer(_scheduler.Current.Handle));
_vk.CmdEndRendering(new CommandBuffer(_scheduler.Current.Handle));
}
public void BindPipeline(PipelineBindPoint bindPoint, in PipelineHandle pipeline)
@ -832,18 +811,18 @@ internal static unsafe partial class VulkanVideoPresenter
using var profileScope = RenderPhaseProfile.MeasureDetail(RenderPhaseProfile.Phase.DrawRecording);
var (buffer, offset) = _bufferCache.ObtainBuffer(argumentsAddress, 3u * sizeof(uint), false);
var command = BeginBatchedGuestCommands();
var barrier = new BufferMemoryBarrier
var barrier = new BufferMemoryBarrier2
{
SType = StructureType.BufferMemoryBarrier,
SrcAccessMask = AccessFlags.ShaderWriteBit | AccessFlags.TransferWriteBit | AccessFlags.MemoryWriteBit,
DstAccessMask = AccessFlags.IndirectCommandReadBit,
SType = StructureType.BufferMemoryBarrier2,
SrcAccessMask = AccessFlags2.ShaderWriteBit | AccessFlags2.TransferWriteBit | AccessFlags2.MemoryWriteBit,
DstAccessMask = AccessFlags2.IndirectCommandReadBit,
SrcQueueFamilyIndex = Vk.QueueFamilyIgnored,
DstQueueFamilyIndex = Vk.QueueFamilyIgnored,
Buffer = buffer.Handle,
Offset = offset,
Size = 3u * sizeof(uint),
};
_vk.CmdPipelineBarrier(command, PipelineStageFlags.AllCommandsBit, PipelineStageFlags.DrawIndirectBit, 0, 0, null, 1, &barrier, 0, null);
VulkanSynchronization.PipelineBarrier(_vk,command, PipelineStageFlags.AllCommandsBit, PipelineStageFlags.DrawIndirectBit, 0, 0, null, 1, &barrier, 0, null);
_vk.CmdDispatchIndirect(command, buffer.Handle, offset);
CountDraw();
return true;
@ -853,13 +832,13 @@ internal static unsafe partial class VulkanVideoPresenter
{
EndRendering();
var command = BeginBatchedGuestCommands();
var barrier = new MemoryBarrier
var barrier = new MemoryBarrier2
{
SType = StructureType.MemoryBarrier,
SrcAccessMask = sourceAccess,
DstAccessMask = destinationAccess,
SType = StructureType.MemoryBarrier2,
SrcAccessMask = VulkanSynchronization.Access(sourceAccess),
DstAccessMask = VulkanSynchronization.Access(destinationAccess),
};
_vk.CmdPipelineBarrier(command, sourceStages, destinationStages, 0, 1, &barrier, 0, null, 0, null);
VulkanSynchronization.PipelineBarrier(_vk,command, sourceStages, destinationStages, 0, 1, &barrier, 0, null, 0, null);
}
public void ShaderWriteBarrier(PipelineStageFlags sourceStages) =>

View File

@ -5,6 +5,7 @@ using System.Runtime.InteropServices;
using SharpEmu.Libs.Gpu.Buffers;
using SharpEmu.Libs.Gpu.Images;
using SharpEmu.Libs.Gpu.Scheduling;
using SharpEmu.Libs.Gpu.Vulkan;
using SharpEmu.Libs.Tests.Gpu.Scheduling;
using SharpEmu.Libs.Tests.Gpu.Vulkan;
using SharpEmu.ShaderCompiler.Vulkan;
@ -122,18 +123,18 @@ internal sealed unsafe class MultisampleDepthSampleReader : IDisposable
var count = samples;
vk.CmdPushConstants(command, _pipelineLayout, ShaderStageFlags.ComputeBit, 0, 4, &count);
vk.CmdDispatch(command, 1, 1, 1);
var barrier = new BufferMemoryBarrier
var barrier = new BufferMemoryBarrier2
{
SType = StructureType.BufferMemoryBarrier,
SrcAccessMask = AccessFlags.ShaderWriteBit,
DstAccessMask = AccessFlags.HostReadBit,
SType = StructureType.BufferMemoryBarrier2,
SrcAccessMask = AccessFlags2.ShaderWriteBit,
DstAccessMask = AccessFlags2.HostReadBit,
SrcQueueFamilyIndex = Vk.QueueFamilyIgnored,
DstQueueFamilyIndex = Vk.QueueFamilyIgnored,
Buffer = output.Handle,
Offset = 0,
Size = output.Size,
};
vk.CmdPipelineBarrier(command, PipelineStageFlags.ComputeShaderBit, PipelineStageFlags.HostBit, 0, 0, null, 1, &barrier, 0, null);
VulkanSynchronization.PipelineBarrier(vk, command, PipelineStageFlags.ComputeShaderBit, PipelineStageFlags.HostBit, 0, 0, null, 1, &barrier, 0, null);
_scheduler.Finish();
output.Invalidate(0, output.Size);
bytes = output.Mapped[..(int)(samples * 4)].ToArray();

View File

@ -6,6 +6,7 @@ using SharpEmu.HLE.GpuMemory;
using SharpEmu.HLE.Host;
using SharpEmu.Libs.Gpu.Buffers;
using SharpEmu.Libs.Gpu.Images;
using SharpEmu.Libs.Gpu.Vulkan;
using SharpEmu.Libs.Tests.Gpu.Buffers;
using Silk.NET.Vulkan;
using Xunit;
@ -176,22 +177,22 @@ internal static class ImageCacheTestSupport
var aligned = (size + 3) & ~3UL;
using var download = new GpuBuffer(harness.Vulkan.DeviceInfo, harness.Scheduler, GpuBufferUsage.Download, 0, GpuBuffer.AllFlags, aligned);
var command = new CommandBuffer(harness.Scheduler.Current.Handle);
var before = new BufferMemoryBarrier
var before = new BufferMemoryBarrier2
{
SType = StructureType.BufferMemoryBarrier,
SrcAccessMask = AccessFlags.MemoryWriteBit | AccessFlags.ShaderWriteBit | AccessFlags.TransferWriteBit | AccessFlags.HostWriteBit,
DstAccessMask = AccessFlags.TransferReadBit,
SType = StructureType.BufferMemoryBarrier2,
SrcAccessMask = AccessFlags2.MemoryWriteBit | AccessFlags2.ShaderWriteBit | AccessFlags2.TransferWriteBit | AccessFlags2.HostWriteBit,
DstAccessMask = AccessFlags2.TransferReadBit,
SrcQueueFamilyIndex = Vk.QueueFamilyIgnored,
DstQueueFamilyIndex = Vk.QueueFamilyIgnored,
Buffer = source,
Offset = offset,
Size = aligned,
};
vk.CmdPipelineBarrier(command, PipelineStageFlags.AllCommandsBit | PipelineStageFlags.HostBit, PipelineStageFlags.TransferBit, 0, 0, null, 1, &before, 0, null);
VulkanSynchronization.PipelineBarrier(vk, command, PipelineStageFlags.AllCommandsBit | PipelineStageFlags.HostBit, PipelineStageFlags.TransferBit, 0, 0, null, 1, &before, 0, null);
var region = new BufferCopy(offset, 0, aligned);
vk.CmdCopyBuffer(command, source, download.Handle, 1, &region);
var after = before with { Buffer = download.Handle, Offset = 0, SrcAccessMask = AccessFlags.TransferWriteBit, DstAccessMask = AccessFlags.HostReadBit };
vk.CmdPipelineBarrier(command, PipelineStageFlags.TransferBit, PipelineStageFlags.HostBit, 0, 0, null, 1, &after, 0, null);
var after = before with { Buffer = download.Handle, Offset = 0, SrcAccessMask = AccessFlags2.TransferWriteBit, DstAccessMask = AccessFlags2.HostReadBit };
VulkanSynchronization.PipelineBarrier(vk, command, PipelineStageFlags.TransferBit, PipelineStageFlags.HostBit, 0, 0, null, 1, &after, 0, null);
harness.Scheduler.Finish();
download.Invalidate(0, aligned);
return download.Mapped[..(int)size].ToArray();

View File

@ -9,6 +9,7 @@ using SharpEmu.HLE.Host;
using SharpEmu.Libs.Gpu.Buffers;
using SharpEmu.Libs.Gpu.Images;
using SharpEmu.Libs.Gpu.Scheduling;
using SharpEmu.Libs.Gpu.Vulkan;
using SharpEmu.Libs.Tests.Gpu.Buffers;
using SharpEmu.Libs.Tests.Gpu.Vulkan;
using Silk.NET.Vulkan;
@ -231,22 +232,22 @@ internal sealed unsafe class ImageTestHarness : IDisposable
var aligned = (size + 3) & ~3UL;
using var download = new GpuBuffer(Device, Scheduler, GpuBufferUsage.Download, 0, GpuBuffer.AllFlags, aligned);
var command = new CommandBuffer(Scheduler.Current.Handle);
var before = new BufferMemoryBarrier
var before = new BufferMemoryBarrier2
{
SType = StructureType.BufferMemoryBarrier,
SrcAccessMask = AccessFlags.MemoryWriteBit | AccessFlags.ShaderWriteBit | AccessFlags.TransferWriteBit | AccessFlags.HostWriteBit,
DstAccessMask = AccessFlags.TransferReadBit,
SType = StructureType.BufferMemoryBarrier2,
SrcAccessMask = AccessFlags2.MemoryWriteBit | AccessFlags2.ShaderWriteBit | AccessFlags2.TransferWriteBit | AccessFlags2.HostWriteBit,
DstAccessMask = AccessFlags2.TransferReadBit,
SrcQueueFamilyIndex = Vk.QueueFamilyIgnored,
DstQueueFamilyIndex = Vk.QueueFamilyIgnored,
Buffer = source,
Offset = offset,
Size = aligned,
};
Vk.CmdPipelineBarrier(command, PipelineStageFlags.AllCommandsBit | PipelineStageFlags.HostBit, PipelineStageFlags.TransferBit, 0, 0, null, 1, &before, 0, null);
VulkanSynchronization.PipelineBarrier(Vk, command, PipelineStageFlags.AllCommandsBit | PipelineStageFlags.HostBit, PipelineStageFlags.TransferBit, 0, 0, null, 1, &before, 0, null);
var region = new BufferCopy(offset, 0, aligned);
Vk.CmdCopyBuffer(command, source, download.Handle, 1, &region);
var after = before with { Buffer = download.Handle, Offset = 0, SrcAccessMask = AccessFlags.TransferWriteBit, DstAccessMask = AccessFlags.HostReadBit };
Vk.CmdPipelineBarrier(command, PipelineStageFlags.TransferBit, PipelineStageFlags.HostBit, 0, 0, null, 1, &after, 0, null);
var after = before with { Buffer = download.Handle, Offset = 0, SrcAccessMask = AccessFlags2.TransferWriteBit, DstAccessMask = AccessFlags2.HostReadBit };
VulkanSynchronization.PipelineBarrier(Vk, command, PipelineStageFlags.TransferBit, PipelineStageFlags.HostBit, 0, 0, null, 1, &after, 0, null);
Scheduler.Finish();
download.Invalidate(0, aligned);
return download.Mapped[..(int)size].ToArray();
@ -499,14 +500,14 @@ internal sealed unsafe class TilerComputeRunner : IDisposable
vk.UpdateDescriptorSets(device, 3, writes, 0, null);
var command = new CommandBuffer(_harness.Scheduler.Current.Handle);
var barriers = stackalloc BufferMemoryBarrier[3];
var barriers = stackalloc BufferMemoryBarrier2[3];
for (var index = 0; index < 3; index++)
{
barriers[index] = new BufferMemoryBarrier
barriers[index] = new BufferMemoryBarrier2
{
SType = StructureType.BufferMemoryBarrier,
SrcAccessMask = AccessFlags.HostWriteBit | AccessFlags.MemoryWriteBit,
DstAccessMask = index == 1 ? AccessFlags.ShaderReadBit | AccessFlags.ShaderWriteBit : index == 2 ? AccessFlags.UniformReadBit : AccessFlags.ShaderReadBit,
SType = StructureType.BufferMemoryBarrier2,
SrcAccessMask = AccessFlags2.HostWriteBit | AccessFlags2.MemoryWriteBit,
DstAccessMask = index == 1 ? AccessFlags2.ShaderReadBit | AccessFlags2.ShaderWriteBit : index == 2 ? AccessFlags2.UniformReadBit : AccessFlags2.ShaderReadBit,
SrcQueueFamilyIndex = Vk.QueueFamilyIgnored,
DstQueueFamilyIndex = Vk.QueueFamilyIgnored,
Buffer = infos[index].Buffer,
@ -515,7 +516,7 @@ internal sealed unsafe class TilerComputeRunner : IDisposable
};
}
vk.CmdPipelineBarrier(command, PipelineStageFlags.AllCommandsBit | PipelineStageFlags.HostBit, PipelineStageFlags.ComputeShaderBit, 0, 0, null, 3, barriers, 0, null);
VulkanSynchronization.PipelineBarrier(vk, command, PipelineStageFlags.AllCommandsBit | PipelineStageFlags.HostBit, PipelineStageFlags.ComputeShaderBit, 0, 0, null, 3, barriers, 0, null);
vk.CmdBindPipeline(command, PipelineBindPoint.Compute, pipeline);
vk.CmdBindDescriptorSets(command, PipelineBindPoint.Compute, _pipelineLayout, 0, 1, &set, 0, null);
fixed (TileTransferArguments* pointer = &push)
@ -524,8 +525,8 @@ internal sealed unsafe class TilerComputeRunner : IDisposable
}
vk.CmdDispatch(command, groupsX, groupsY, groupsZ);
var after = barriers[1] with { SrcAccessMask = AccessFlags.ShaderWriteBit, DstAccessMask = AccessFlags.TransferReadBit | AccessFlags.MemoryReadBit };
vk.CmdPipelineBarrier(command, PipelineStageFlags.ComputeShaderBit, PipelineStageFlags.AllCommandsBit, 0, 0, null, 1, &after, 0, null);
var after = barriers[1] with { SrcAccessMask = AccessFlags2.ShaderWriteBit, DstAccessMask = AccessFlags2.TransferReadBit | AccessFlags2.MemoryReadBit };
VulkanSynchronization.PipelineBarrier(vk, command, PipelineStageFlags.ComputeShaderBit, PipelineStageFlags.AllCommandsBit, 0, 0, null, 1, &after, 0, null);
}
public void Dispose()

View File

@ -3,6 +3,7 @@
using SharpEmu.Libs.Tests.Gpu.Scheduling;
using SharpEmu.Libs.Tests.Gpu.Vulkan;
using SharpEmu.Libs.Gpu.Vulkan;
using SharpEmu.Libs.VideoOut;
using Silk.NET.Vulkan;
using Xunit;
@ -64,13 +65,13 @@ public sealed unsafe class PresentationColorTests : IClassFixture<HeadlessVulkan
var range = new ImageSubresourceRange(ImageAspectFlags.ColorBit, 0, 1, 0, 1);
harness.Vk.CmdClearColorImage(command, target.Backing.Handle,
ImageLayout.TransferDstOptimal, &black, 1, &range);
var clearComplete = new MemoryBarrier
var clearComplete = new MemoryBarrier2
{
SType = StructureType.MemoryBarrier,
SrcAccessMask = AccessFlags.TransferWriteBit,
DstAccessMask = AccessFlags.TransferWriteBit,
SType = StructureType.MemoryBarrier2,
SrcAccessMask = AccessFlags2.TransferWriteBit,
DstAccessMask = AccessFlags2.TransferWriteBit,
};
harness.Vk.CmdPipelineBarrier(command, PipelineStageFlags.TransferBit, PipelineStageFlags.TransferBit,
VulkanSynchronization.PipelineBarrier(harness.Vk, command, PipelineStageFlags.TransferBit, PipelineStageFlags.TransferBit,
0, 1, &clearComplete, 0, null, 0, null);
var blit = new ImageBlit
{

View File

@ -40,15 +40,12 @@ internal sealed unsafe class HeadlessVulkan : IDisposable
SupportsDynamicRendering = dynamicRendering;
}
// Dynamic rendering with the two extended dynamic state extensions, as the presenter's render host needs.
// Dynamic rendering support required by the presenter's render host.
public bool SupportsDynamicRendering { get; }
public bool SupportsFragmentShaderBarycentric { get; private init; }
private static readonly string[] RenderingExtensionNames =
[
"VK_KHR_dynamic_rendering",
"VK_EXT_extended_dynamic_state",
"VK_EXT_extended_dynamic_state2",
"VK_KHR_push_descriptor",
];
@ -78,7 +75,7 @@ internal sealed unsafe class HeadlessVulkan : IDisposable
public object QueueGate { get; } = new();
// The device API version: 1.3 when the loader and the device support it, else 1.2.
// The device API version. The production renderer requires Vulkan 1.3.
public uint ApiVersion { get; }
// SPIR-V 1.6 modules (the compiled reference blobs) need a Vulkan 1.3 device.
@ -209,7 +206,11 @@ internal sealed unsafe class HeadlessVulkan : IDisposable
var vk = Vk.GetApi();
uint instanceVersion = Vk.Version10;
vk.EnumerateInstanceVersion(ref instanceVersion);
var apiVersion = instanceVersion >= Vk.Version13 ? Vk.Version13 : Vk.Version12;
if (instanceVersion < Vk.Version13)
{
return null;
}
var apiVersion = Vk.Version13;
var appInfo = new ApplicationInfo { SType = StructureType.ApplicationInfo, ApiVersion = apiVersion };
var validation = Environment.GetEnvironmentVariable(ValidationVariable) == "1";
var layers = validation ? SilkMarshal.StringArrayToPtr(new[] { "VK_LAYER_KHRONOS_validation" }) : 0;
@ -261,9 +262,10 @@ internal sealed unsafe class HeadlessVulkan : IDisposable
}
vk.GetPhysicalDeviceProperties(physical, out var physicalProperties);
if (physicalProperties.ApiVersion < apiVersion)
if (physicalProperties.ApiVersion < Vk.Version13)
{
apiVersion = Vk.Version12;
vk.DestroyInstance(instance, null);
return null;
}
uint familyCount = 0;
@ -301,24 +303,14 @@ internal sealed unsafe class HeadlessVulkan : IDisposable
}
var barycentric = (bool)barycentricFeatures.FragmentShaderBarycentric;
var extendedDynamicState2Features = new PhysicalDeviceExtendedDynamicState2FeaturesEXT
var vulkan13Features = new PhysicalDeviceVulkan13Features
{
SType = StructureType.PhysicalDeviceExtendedDynamicState2FeaturesExt,
};
var extendedDynamicStateFeatures = new PhysicalDeviceExtendedDynamicStateFeaturesEXT
{
SType = StructureType.PhysicalDeviceExtendedDynamicStateFeaturesExt,
PNext = &extendedDynamicState2Features,
};
var dynamicRenderingFeatures = new PhysicalDeviceDynamicRenderingFeaturesKHR
{
SType = StructureType.PhysicalDeviceDynamicRenderingFeaturesKhr,
PNext = &extendedDynamicStateFeatures,
SType = StructureType.PhysicalDeviceVulkan13Features,
};
var addressFeatures = new PhysicalDeviceBufferDeviceAddressFeatures
{
SType = StructureType.PhysicalDeviceBufferDeviceAddressFeatures,
PNext = &dynamicRenderingFeatures,
PNext = &vulkan13Features,
};
var timelineFeatures = new PhysicalDeviceTimelineSemaphoreFeatures
{
@ -327,9 +319,10 @@ internal sealed unsafe class HeadlessVulkan : IDisposable
};
var features = new PhysicalDeviceFeatures2 { SType = StructureType.PhysicalDeviceFeatures2, PNext = &timelineFeatures };
vk.GetPhysicalDeviceFeatures2(physical, &features);
var dynamicRendering = dynamicRenderingFeatures.DynamicRendering && extendedDynamicStateFeatures.ExtendedDynamicState &&
extendedDynamicState2Features.ExtendedDynamicState2 && HasDeviceExtensions(vk, physical, RenderingExtensionNames);
if (family == uint.MaxValue || !timelineFeatures.TimelineSemaphore || !addressFeatures.BufferDeviceAddress)
var dynamicRendering = vulkan13Features.DynamicRendering && vulkan13Features.Synchronization2 &&
HasDeviceExtensions(vk, physical, RenderingExtensionNames);
if (family == uint.MaxValue || !timelineFeatures.TimelineSemaphore || !addressFeatures.BufferDeviceAddress ||
!vulkan13Features.Synchronization2)
{
vk.DestroyInstance(instance, null);
return null;
@ -352,34 +345,23 @@ internal sealed unsafe class HeadlessVulkan : IDisposable
PQueuePriorities = &priority,
};
timelineFeatures.TimelineSemaphore = true;
extendedDynamicState2Features = new PhysicalDeviceExtendedDynamicState2FeaturesEXT
vulkan13Features = new PhysicalDeviceVulkan13Features
{
SType = StructureType.PhysicalDeviceExtendedDynamicState2FeaturesExt,
ExtendedDynamicState2 = true,
};
extendedDynamicStateFeatures = new PhysicalDeviceExtendedDynamicStateFeaturesEXT
{
SType = StructureType.PhysicalDeviceExtendedDynamicStateFeaturesExt,
ExtendedDynamicState = true,
PNext = &extendedDynamicState2Features,
};
dynamicRenderingFeatures = new PhysicalDeviceDynamicRenderingFeaturesKHR
{
SType = StructureType.PhysicalDeviceDynamicRenderingFeaturesKhr,
DynamicRendering = true,
PNext = &extendedDynamicStateFeatures,
SType = StructureType.PhysicalDeviceVulkan13Features,
DynamicRendering = dynamicRendering,
Synchronization2 = true,
};
addressFeatures = new PhysicalDeviceBufferDeviceAddressFeatures
{
SType = StructureType.PhysicalDeviceBufferDeviceAddressFeatures,
BufferDeviceAddress = true,
PNext = dynamicRendering ? &dynamicRenderingFeatures : null,
PNext = &vulkan13Features,
};
timelineFeatures.PNext = &addressFeatures;
if (barycentric)
{
barycentricFeatures.PNext = addressFeatures.PNext;
addressFeatures.PNext = &barycentricFeatures;
barycentricFeatures.PNext = vulkan13Features.PNext;
vulkan13Features.PNext = &barycentricFeatures;
}
var extensionNames = new List<string>();
if (dynamicRendering) extensionNames.AddRange(RenderingExtensionNames);

View File

@ -3,6 +3,7 @@
using System.Runtime.InteropServices;
using SharpEmu.Libs.Gpu.Buffers;
using SharpEmu.Libs.Gpu.Vulkan;
using SharpEmu.Libs.Tests.Gpu.Images;
using SharpEmu.ShaderCompiler;
using SharpEmu.ShaderCompiler.Resources;
@ -288,13 +289,13 @@ internal sealed unsafe class LayoutComputeRunner : IDisposable
}
var command = new CommandBuffer(_harness.Scheduler.Current.Handle);
var barrier = new MemoryBarrier
var barrier = new MemoryBarrier2
{
SType = StructureType.MemoryBarrier,
SrcAccessMask = AccessFlags.HostWriteBit | AccessFlags.MemoryWriteBit,
DstAccessMask = AccessFlags.ShaderReadBit | AccessFlags.ShaderWriteBit,
SType = StructureType.MemoryBarrier2,
SrcAccessMask = AccessFlags2.HostWriteBit | AccessFlags2.MemoryWriteBit,
DstAccessMask = AccessFlags2.ShaderReadBit | AccessFlags2.ShaderWriteBit,
};
vk.CmdPipelineBarrier(command, PipelineStageFlags.AllCommandsBit | PipelineStageFlags.HostBit, PipelineStageFlags.ComputeShaderBit, 0, 1, &barrier, 0, null, 0, null);
VulkanSynchronization.PipelineBarrier(vk, command, PipelineStageFlags.AllCommandsBit | PipelineStageFlags.HostBit, PipelineStageFlags.ComputeShaderBit, 0, 1, &barrier, 0, null, 0, null);
vk.CmdBindPipeline(command, PipelineBindPoint.Compute, _pipeline);
vk.CmdBindDescriptorSets(command, PipelineBindPoint.Compute, _pipelineLayout, 0, 1, &set, 0, null);
if (layout.UsesPushData)
@ -306,13 +307,13 @@ internal sealed unsafe class LayoutComputeRunner : IDisposable
}
vk.CmdDispatch(command, groupsX, groupsY, groupsZ);
var after = new MemoryBarrier
var after = new MemoryBarrier2
{
SType = StructureType.MemoryBarrier,
SrcAccessMask = AccessFlags.ShaderWriteBit,
DstAccessMask = AccessFlags.TransferReadBit | AccessFlags.MemoryReadBit | AccessFlags.HostReadBit,
SType = StructureType.MemoryBarrier2,
SrcAccessMask = AccessFlags2.ShaderWriteBit,
DstAccessMask = AccessFlags2.TransferReadBit | AccessFlags2.MemoryReadBit | AccessFlags2.HostReadBit,
};
vk.CmdPipelineBarrier(command, PipelineStageFlags.ComputeShaderBit, PipelineStageFlags.AllCommandsBit | PipelineStageFlags.HostBit, 0, 1, &after, 0, null, 0, null);
VulkanSynchronization.PipelineBarrier(vk, command, PipelineStageFlags.ComputeShaderBit, PipelineStageFlags.AllCommandsBit | PipelineStageFlags.HostBit, 0, 1, &after, 0, null, 0, null);
}
public byte[] ReadBack(GpuBuffer buffer, ulong offset, ulong size) => _harness.ReadBack(buffer.Handle, offset, size);