From 0bd63c5a74771100b508f208a95677fc9cd04d07 Mon Sep 17 00:00:00 2001 From: Spooks <62370103+Spooks4576@users.noreply.github.com> Date: Wed, 15 Jul 2026 18:34:06 -0600 Subject: [PATCH] Update native Vulkan backend interface --- .../NativeVulkanGuestGpuBackend.cs | 60 +++++++++++++++---- 1 file changed, 48 insertions(+), 12 deletions(-) diff --git a/src/SharpEmu.Libs/Gpu/NativeVulkan/NativeVulkanGuestGpuBackend.cs b/src/SharpEmu.Libs/Gpu/NativeVulkan/NativeVulkanGuestGpuBackend.cs index 7141e51f..17f5c2a0 100644 --- a/src/SharpEmu.Libs/Gpu/NativeVulkan/NativeVulkanGuestGpuBackend.cs +++ b/src/SharpEmu.Libs/Gpu/NativeVulkan/NativeVulkanGuestGpuBackend.cs @@ -12,6 +12,9 @@ namespace SharpEmu.Libs.Gpu.NativeVulkan; /// Native C++ Vulkan implementation of the guest-domain GPU seam. internal sealed unsafe class NativeVulkanGuestGpuBackend : IGuestGpuBackend { + private static readonly IGuestCompiledShader DepthOnlyFragmentShader = + new VulkanCompiledGuestShader(SpirvFixedShaders.CreateDepthOnlyFragment()); + private readonly object _startGate = new(); private readonly BlockingCollection> _commands = new(new ConcurrentQueue>(), 256); private readonly ManualResetEventSlim _ready = new(false); @@ -48,34 +51,43 @@ internal sealed unsafe class NativeVulkanGuestGpuBackend : IGuestGpuBackend public bool TryCompileVertexShader(Gen5ShaderState state, Gen5ShaderEvaluation evaluation, out IGuestCompiledShader? shader, out string error, int globalBufferBase = 0, - int totalGlobalBufferCount = -1, int imageBindingBase = 0, int scalarRegisterBufferIndex = -1) + int totalGlobalBufferCount = -1, int imageBindingBase = 0, int scalarRegisterBufferIndex = -1, + int requiredVertexOutputCount = 0, ulong storageBufferOffsetAlignment = 1) { shader = null; if (!Gen5SpirvTranslator.TryCompileVertexShader(state, evaluation, out var compiled, out error, - globalBufferBase, totalGlobalBufferCount, imageBindingBase, scalarRegisterBufferIndex)) return false; + globalBufferBase, totalGlobalBufferCount, imageBindingBase, scalarRegisterBufferIndex, + requiredVertexOutputCount, storageBufferOffsetAlignment)) return false; shader = new VulkanCompiledGuestShader(compiled.Spirv); return true; } public bool TryCompilePixelShader(Gen5ShaderState state, Gen5ShaderEvaluation evaluation, IReadOnlyList outputs, out IGuestCompiledShader? shader, out string error, int globalBufferBase = 0, int totalGlobalBufferCount = -1, int imageBindingBase = 0, - int scalarRegisterBufferIndex = -1) + int scalarRegisterBufferIndex = -1, uint pixelInputEnable = 0, uint pixelInputAddress = 0, + ulong storageBufferOffsetAlignment = 1) { shader = null; if (!Gen5SpirvTranslator.TryCompilePixelShader(state, evaluation, outputs, out var compiled, out error, - globalBufferBase, totalGlobalBufferCount, imageBindingBase, scalarRegisterBufferIndex)) return false; + globalBufferBase, totalGlobalBufferCount, imageBindingBase, scalarRegisterBufferIndex, + pixelInputEnable, pixelInputAddress, storageBufferOffsetAlignment)) return false; shader = new VulkanCompiledGuestShader(compiled.Spirv); return true; } public bool TryCompileComputeShader(Gen5ShaderState state, Gen5ShaderEvaluation evaluation, - uint localSizeX, uint localSizeY, uint localSizeZ, out IGuestCompiledShader? shader, out string error) + uint localSizeX, uint localSizeY, uint localSizeZ, out IGuestCompiledShader? shader, out string error, + int totalGlobalBufferCount = -1, int initialScalarBufferIndex = -1, uint waveLaneCount = 32, + ulong storageBufferOffsetAlignment = 1) { shader = null; if (!Gen5SpirvTranslator.TryCompileComputeShader(state, evaluation, localSizeX, localSizeY, localSizeZ, - out var compiled, out error)) return false; + out var compiled, out error, totalGlobalBufferCount, initialScalarBufferIndex, waveLaneCount, + storageBufferOffsetAlignment)) return false; shader = new VulkanCompiledGuestShader(compiled.Spirv); return true; } + public IGuestCompiledShader GetDepthOnlyFragmentShader() => DepthOnlyFragmentShader; + public void HideSplashScreen() { } public void Submit(byte[] bgraFrame, uint width, uint height) @@ -118,7 +130,7 @@ internal sealed unsafe class NativeVulkanGuestGpuBackend : IGuestGpuBackend uint attributeCount, IReadOnlyList targets, IGuestCompiledShader? vertexShader = null, uint vertexCount = 3, uint instanceCount = 1, uint primitiveType = 4, GuestIndexBuffer? indexBuffer = null, IReadOnlyList? vertexBuffers = null, - GuestRenderState? renderState = null) + GuestRenderState? renderState = null, GuestDepthTarget? depthTarget = null, ulong shaderAddress = 0) { if (targets.Count == 0) return; EnsureStarted(targets[0].Width, targets[0].Height); @@ -130,9 +142,25 @@ internal sealed unsafe class NativeVulkanGuestGpuBackend : IGuestGpuBackend primitiveType, indexBuffer, vertexCopy, renderState, targetCopy, true))); } + public void SubmitDepthOnlyTranslatedDraw(IGuestCompiledShader pixelShader, + IReadOnlyList textures, IReadOnlyList globalMemoryBuffers, + uint attributeCount, GuestDepthTarget depthTarget, IGuestCompiledShader? vertexShader = null, + uint vertexCount = 3, uint instanceCount = 1, uint primitiveType = 4, + GuestIndexBuffer? indexBuffer = null, IReadOnlyList? vertexBuffers = null, + GuestRenderState? renderState = null, ulong shaderAddress = 0) + { + EnsureStarted(depthTarget.Width, depthTarget.Height); + var ps = Spirv(pixelShader); var vs = vertexShader is null ? null : Spirv(vertexShader); + var textureCopy = textures.ToArray(); var memoryCopy = globalMemoryBuffers.ToArray(); + var vertexCopy = vertexBuffers?.ToArray(); + Enqueue(handle => Check(handle, NativeGpuPacket.SubmitDraw(handle, ps, textureCopy, memoryCopy, + depthTarget.Width, depthTarget.Height, attributeCount, vs, vertexCount, instanceCount, + primitiveType, indexBuffer, vertexCopy, renderState, null, false))); + } + public void SubmitStorageTranslatedDraw(IGuestCompiledShader pixelShader, IReadOnlyList textures, IReadOnlyList globalMemoryBuffers, - uint attributeCount, uint width, uint height) + uint attributeCount, uint width, uint height, ulong shaderAddress = 0) { EnsureStarted(width, height); var ps = Spirv(pixelShader); var textureCopy = textures.ToArray(); var memoryCopy = globalMemoryBuffers.ToArray(); @@ -141,14 +169,18 @@ internal sealed unsafe class NativeVulkanGuestGpuBackend : IGuestGpuBackend width, height, attributeCount, null, 3, 1, 4, null, null, null, targets, false))); } - public void SubmitComputeDispatch(ulong shaderAddress, IGuestCompiledShader computeShader, + public long SubmitComputeDispatch(ulong shaderAddress, IGuestCompiledShader computeShader, IReadOnlyList textures, IReadOnlyList globalMemoryBuffers, - uint groupCountX, uint groupCountY, uint groupCountZ) + uint groupCountX, uint groupCountY, uint groupCountZ, uint baseGroupX, uint baseGroupY, + uint baseGroupZ, uint localSizeX, uint localSizeY, uint localSizeZ, bool isIndirect, + bool writesGlobalMemory, uint threadCountX = uint.MaxValue, uint threadCountY = uint.MaxValue, + uint threadCountZ = uint.MaxValue) { EnsureStarted(1280, 720); var shader = Spirv(computeShader); var textureCopy = textures.ToArray(); var memoryCopy = globalMemoryBuffers.ToArray(); Enqueue(handle => Check(handle, NativeGpuPacket.SubmitCompute(handle, shaderAddress, shader, textureCopy, memoryCopy, groupCountX, groupCountY, groupCountZ))); + return 0; } public bool TrySubmitGuestImage(ulong address, uint width, uint height, uint pitchInPixel) @@ -158,6 +190,10 @@ internal sealed unsafe class NativeVulkanGuestGpuBackend : IGuestGpuBackend NativeGpuResult.Success; } + public bool TrySubmitOrderedGuestImageFlip(int videoOutHandle, int displayBufferIndex, ulong address, + uint width, uint height, uint pitchInPixel) => + TrySubmitGuestImage(address, width, height, pitchInPixel); + public void RegisterKnownDisplayBuffer(ulong address, uint guestFormat) { EnsureStarted(1280, 720); @@ -172,8 +208,8 @@ internal sealed unsafe class NativeVulkanGuestGpuBackend : IGuestGpuBackend } public bool TrySubmitGuestImageBlit(ulong sourceAddress, uint sourceWidth, uint sourceHeight, - uint sourceFormat, ulong destinationAddress, uint destinationWidth, uint destinationHeight, - uint destinationFormat) + uint sourceFormat, uint sourceNumberType, ulong destinationAddress, uint destinationWidth, + uint destinationHeight, uint destinationFormat, uint destinationNumberType) { EnsureStarted(destinationWidth, destinationHeight); return Invoke(handle => NativeVulkanApi.BlitGuestImage(handle, sourceAddress, sourceWidth, sourceHeight,