mirror of
https://github.com/par274/sharpemu.git
synced 2026-08-01 15:39:47 +08:00
[AGC/Vulkan] Extend PS5 runtime and rendering compatibility (#216)
* [Core] Add POSIX native execution and PS5 SELF support Extend the native backend, guest TLS, fixed-address memory, and loader paths needed by PS5 titles on Windows, Linux, and macOS. Keep workstation GC so high-core-count hosts do not reserve over fixed guest image bases. * [HLE] Expand PS5 service and media compatibility Add the kernel, threading, save-data, networking, audio, video-codec, font, dialog, and service exports required by newer PS5 software. Preserve every SysAbi NID currently registered by main while adding the compatibility surface used by ASTRO BOT. * [AGC/Vulkan] Extend Gen5 shader and presentation support Expand PM4 handling, Gen5 shader translation, MRT and packed export support, guest image tracking, depth initialization, texture aliasing, and Vulkan presentation. Add the performance overlay and address-filtered diagnostics used to validate ASTRO BOT with original shaders. * [Core] Align static TLS reservation across hosts * [Pad] Align primary user ID with UserService * [Gpu] Preserve runtime scalar buffers across renderer seam * [AGC] Restore omitted command helper exports * [Vulkan] Reuse primary views for promoted MRT targets * [Vulkan] Preserve scratch storage bindings in compute dispatches
This commit is contained in:
@@ -22,6 +22,8 @@ internal sealed record GuestDrawTexture(
|
||||
bool IsStorage,
|
||||
uint MipLevels = 1,
|
||||
uint MipLevel = 0,
|
||||
uint BaseMipLevel = 0,
|
||||
uint ResourceMipLevels = 1,
|
||||
uint Pitch = 0,
|
||||
uint TileMode = 0,
|
||||
uint DstSelect = 0xFAC,
|
||||
@@ -36,7 +38,11 @@ internal readonly record struct GuestSampler(
|
||||
|
||||
internal sealed record GuestMemoryBuffer(
|
||||
ulong BaseAddress,
|
||||
byte[] Data);
|
||||
byte[] Data,
|
||||
int Length,
|
||||
bool Pooled,
|
||||
bool Writable = false,
|
||||
bool WriteBackToGuest = true);
|
||||
|
||||
/// <summary>DataFormat/NumberFormat are raw guest vertex-attribute codes.</summary>
|
||||
internal sealed record GuestVertexBuffer(
|
||||
@@ -47,11 +53,15 @@ internal sealed record GuestVertexBuffer(
|
||||
ulong BaseAddress,
|
||||
uint Stride,
|
||||
uint OffsetBytes,
|
||||
byte[] Data);
|
||||
byte[] Data,
|
||||
int Length,
|
||||
bool Pooled);
|
||||
|
||||
internal sealed record GuestIndexBuffer(
|
||||
byte[] Data,
|
||||
bool Is32Bit);
|
||||
int Length,
|
||||
bool Is32Bit,
|
||||
bool Pooled);
|
||||
|
||||
internal readonly record struct GuestRect(
|
||||
int X,
|
||||
@@ -67,6 +77,25 @@ internal readonly record struct GuestViewport(
|
||||
float MinDepth,
|
||||
float MaxDepth);
|
||||
|
||||
internal readonly record struct GuestRasterState(
|
||||
bool CullFront,
|
||||
bool CullBack,
|
||||
bool FrontFaceClockwise,
|
||||
bool Wireframe)
|
||||
{
|
||||
public static GuestRasterState Default { get; } = new(false, false, false, false);
|
||||
}
|
||||
|
||||
// CompareOp uses the GCN DB_DEPTH_CONTROL ZFUNC encoding, which matches the
|
||||
// Vulkan CompareOp ordering (0=Never through 7=Always).
|
||||
internal readonly record struct GuestDepthState(
|
||||
bool TestEnable,
|
||||
bool WriteEnable,
|
||||
uint CompareOp)
|
||||
{
|
||||
public static GuestDepthState Default { get; } = new(false, false, 7);
|
||||
}
|
||||
|
||||
/// <summary>Factors/funcs are raw guest CB_BLEND*_CONTROL register bitfields; the
|
||||
/// defaults (1/0) are the guest ONE/ZERO codes.</summary>
|
||||
internal readonly record struct GuestBlendState(
|
||||
@@ -95,12 +124,16 @@ internal readonly record struct GuestBlendState(
|
||||
internal sealed record GuestRenderState(
|
||||
IReadOnlyList<GuestBlendState> Blends,
|
||||
GuestRect? Scissor,
|
||||
GuestViewport? Viewport)
|
||||
GuestViewport? Viewport,
|
||||
GuestRasterState Raster,
|
||||
GuestDepthState Depth)
|
||||
{
|
||||
public static GuestRenderState Default { get; } = new(
|
||||
[GuestBlendState.Default],
|
||||
Scissor: null,
|
||||
Viewport: null);
|
||||
Viewport: null,
|
||||
GuestRasterState.Default,
|
||||
GuestDepthState.Default);
|
||||
|
||||
public GuestBlendState Blend =>
|
||||
Blends.Count == 0 ? GuestBlendState.Default : Blends[0];
|
||||
@@ -114,3 +147,17 @@ internal sealed record GuestRenderTarget(
|
||||
uint Format,
|
||||
uint NumberType,
|
||||
uint MipLevels = 1);
|
||||
|
||||
/// <summary>Guest DB surface bound alongside a color render target.</summary>
|
||||
internal sealed record GuestDepthTarget(
|
||||
ulong ReadAddress,
|
||||
ulong WriteAddress,
|
||||
uint Width,
|
||||
uint Height,
|
||||
uint GuestFormat,
|
||||
uint SwizzleMode,
|
||||
float ClearDepth,
|
||||
bool ReadOnly)
|
||||
{
|
||||
public ulong Address => WriteAddress != 0 ? WriteAddress : ReadAddress;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,9 @@ internal interface IGuestGpuBackend
|
||||
int globalBufferBase = 0,
|
||||
int totalGlobalBufferCount = -1,
|
||||
int imageBindingBase = 0,
|
||||
int scalarRegisterBufferIndex = -1);
|
||||
int scalarRegisterBufferIndex = -1,
|
||||
int requiredVertexOutputCount = 0,
|
||||
ulong storageBufferOffsetAlignment = 1);
|
||||
|
||||
bool TryCompilePixelShader(
|
||||
Gen5ShaderState state,
|
||||
@@ -44,7 +46,10 @@ internal interface IGuestGpuBackend
|
||||
int globalBufferBase = 0,
|
||||
int totalGlobalBufferCount = -1,
|
||||
int imageBindingBase = 0,
|
||||
int scalarRegisterBufferIndex = -1);
|
||||
int scalarRegisterBufferIndex = -1,
|
||||
uint pixelInputEnable = 0,
|
||||
uint pixelInputAddress = 0,
|
||||
ulong storageBufferOffsetAlignment = 1);
|
||||
|
||||
bool TryCompileComputeShader(
|
||||
Gen5ShaderState state,
|
||||
@@ -53,7 +58,14 @@ internal interface IGuestGpuBackend
|
||||
uint localSizeY,
|
||||
uint localSizeZ,
|
||||
out IGuestCompiledShader? shader,
|
||||
out string error);
|
||||
out string error,
|
||||
int totalGlobalBufferCount = -1,
|
||||
int initialScalarBufferIndex = -1,
|
||||
uint waveLaneCount = 32,
|
||||
ulong storageBufferOffsetAlignment = 1);
|
||||
|
||||
/// <summary>Returns the backend's no-color-output fragment shader.</summary>
|
||||
IGuestCompiledShader GetDepthOnlyFragmentShader();
|
||||
|
||||
void HideSplashScreen();
|
||||
|
||||
@@ -78,6 +90,21 @@ internal interface IGuestGpuBackend
|
||||
IReadOnlyList<GuestVertexBuffer>? vertexBuffers = null,
|
||||
GuestRenderState? renderState = null);
|
||||
|
||||
void SubmitDepthOnlyTranslatedDraw(
|
||||
IGuestCompiledShader pixelShader,
|
||||
IReadOnlyList<GuestDrawTexture> textures,
|
||||
IReadOnlyList<GuestMemoryBuffer> globalMemoryBuffers,
|
||||
uint attributeCount,
|
||||
GuestDepthTarget depthTarget,
|
||||
IGuestCompiledShader? vertexShader = null,
|
||||
uint vertexCount = 3,
|
||||
uint instanceCount = 1,
|
||||
uint primitiveType = 4,
|
||||
GuestIndexBuffer? indexBuffer = null,
|
||||
IReadOnlyList<GuestVertexBuffer>? vertexBuffers = null,
|
||||
GuestRenderState? renderState = null,
|
||||
ulong shaderAddress = 0);
|
||||
|
||||
void SubmitOffscreenTranslatedDraw(
|
||||
IGuestCompiledShader pixelShader,
|
||||
IReadOnlyList<GuestDrawTexture> textures,
|
||||
@@ -90,7 +117,9 @@ internal interface IGuestGpuBackend
|
||||
uint primitiveType = 4,
|
||||
GuestIndexBuffer? indexBuffer = null,
|
||||
IReadOnlyList<GuestVertexBuffer>? vertexBuffers = null,
|
||||
GuestRenderState? renderState = null);
|
||||
GuestRenderState? renderState = null,
|
||||
GuestDepthTarget? depthTarget = null,
|
||||
ulong shaderAddress = 0);
|
||||
|
||||
void SubmitStorageTranslatedDraw(
|
||||
IGuestCompiledShader pixelShader,
|
||||
@@ -98,16 +127,28 @@ internal interface IGuestGpuBackend
|
||||
IReadOnlyList<GuestMemoryBuffer> globalMemoryBuffers,
|
||||
uint attributeCount,
|
||||
uint width,
|
||||
uint height);
|
||||
uint height,
|
||||
ulong shaderAddress = 0);
|
||||
|
||||
void SubmitComputeDispatch(
|
||||
long SubmitComputeDispatch(
|
||||
ulong shaderAddress,
|
||||
IGuestCompiledShader computeShader,
|
||||
IReadOnlyList<GuestDrawTexture> textures,
|
||||
IReadOnlyList<GuestMemoryBuffer> globalMemoryBuffers,
|
||||
uint groupCountX,
|
||||
uint groupCountY,
|
||||
uint groupCountZ);
|
||||
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);
|
||||
|
||||
bool TrySubmitGuestImage(
|
||||
ulong address,
|
||||
@@ -115,6 +156,14 @@ internal interface IGuestGpuBackend
|
||||
uint height,
|
||||
uint pitchInPixel);
|
||||
|
||||
bool TrySubmitOrderedGuestImageFlip(
|
||||
int videoOutHandle,
|
||||
int displayBufferIndex,
|
||||
ulong address,
|
||||
uint width,
|
||||
uint height,
|
||||
uint pitchInPixel);
|
||||
|
||||
/// <summary>Registers a display buffer with its guest texture format tag.</summary>
|
||||
void RegisterKnownDisplayBuffer(ulong address, uint guestFormat);
|
||||
|
||||
@@ -126,10 +175,12 @@ internal interface IGuestGpuBackend
|
||||
uint sourceWidth,
|
||||
uint sourceHeight,
|
||||
uint sourceFormat,
|
||||
uint sourceNumberType,
|
||||
ulong destinationAddress,
|
||||
uint destinationWidth,
|
||||
uint destinationHeight,
|
||||
uint destinationFormat);
|
||||
uint destinationFormat,
|
||||
uint destinationNumberType);
|
||||
|
||||
/// <summary>
|
||||
/// Whether the backend supports the guest render-target format, and how its pixel
|
||||
|
||||
@@ -15,6 +15,9 @@ namespace SharpEmu.Libs.Gpu.Vulkan;
|
||||
/// </summary>
|
||||
internal sealed class VulkanGuestGpuBackend : IGuestGpuBackend
|
||||
{
|
||||
private static readonly IGuestCompiledShader DepthOnlyFragmentShader =
|
||||
new VulkanCompiledGuestShader(SpirvFixedShaders.CreateDepthOnlyFragment());
|
||||
|
||||
public bool TryCompileVertexShader(
|
||||
Gen5ShaderState state,
|
||||
Gen5ShaderEvaluation evaluation,
|
||||
@@ -23,7 +26,9 @@ internal sealed class VulkanGuestGpuBackend : IGuestGpuBackend
|
||||
int globalBufferBase = 0,
|
||||
int totalGlobalBufferCount = -1,
|
||||
int imageBindingBase = 0,
|
||||
int scalarRegisterBufferIndex = -1)
|
||||
int scalarRegisterBufferIndex = -1,
|
||||
int requiredVertexOutputCount = 0,
|
||||
ulong storageBufferOffsetAlignment = 1)
|
||||
{
|
||||
shader = null;
|
||||
if (!Gen5SpirvTranslator.TryCompileVertexShader(
|
||||
@@ -34,7 +39,9 @@ internal sealed class VulkanGuestGpuBackend : IGuestGpuBackend
|
||||
globalBufferBase,
|
||||
totalGlobalBufferCount,
|
||||
imageBindingBase,
|
||||
scalarRegisterBufferIndex))
|
||||
scalarRegisterBufferIndex,
|
||||
requiredVertexOutputCount,
|
||||
storageBufferOffsetAlignment))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -52,7 +59,10 @@ internal sealed class VulkanGuestGpuBackend : IGuestGpuBackend
|
||||
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(
|
||||
@@ -64,7 +74,10 @@ internal sealed class VulkanGuestGpuBackend : IGuestGpuBackend
|
||||
globalBufferBase,
|
||||
totalGlobalBufferCount,
|
||||
imageBindingBase,
|
||||
scalarRegisterBufferIndex))
|
||||
scalarRegisterBufferIndex,
|
||||
pixelInputEnable,
|
||||
pixelInputAddress,
|
||||
storageBufferOffsetAlignment))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -80,7 +93,11 @@ internal sealed class VulkanGuestGpuBackend : IGuestGpuBackend
|
||||
uint localSizeY,
|
||||
uint localSizeZ,
|
||||
out IGuestCompiledShader? shader,
|
||||
out string error)
|
||||
out string error,
|
||||
int totalGlobalBufferCount = -1,
|
||||
int initialScalarBufferIndex = -1,
|
||||
uint waveLaneCount = 32,
|
||||
ulong storageBufferOffsetAlignment = 1)
|
||||
{
|
||||
shader = null;
|
||||
if (!Gen5SpirvTranslator.TryCompileComputeShader(
|
||||
@@ -90,7 +107,11 @@ internal sealed class VulkanGuestGpuBackend : IGuestGpuBackend
|
||||
localSizeY,
|
||||
localSizeZ,
|
||||
out var compiled,
|
||||
out error))
|
||||
out error,
|
||||
totalGlobalBufferCount,
|
||||
initialScalarBufferIndex,
|
||||
waveLaneCount,
|
||||
storageBufferOffsetAlignment))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -99,6 +120,9 @@ internal sealed class VulkanGuestGpuBackend : IGuestGpuBackend
|
||||
return true;
|
||||
}
|
||||
|
||||
public IGuestCompiledShader GetDepthOnlyFragmentShader() =>
|
||||
DepthOnlyFragmentShader;
|
||||
|
||||
public void EnsureStarted(uint width, uint height) =>
|
||||
VulkanVideoPresenter.EnsureStarted(width, height);
|
||||
|
||||
@@ -140,6 +164,35 @@ internal sealed class VulkanGuestGpuBackend : IGuestGpuBackend
|
||||
vertexBuffers,
|
||||
renderState);
|
||||
|
||||
public void SubmitDepthOnlyTranslatedDraw(
|
||||
IGuestCompiledShader pixelShader,
|
||||
IReadOnlyList<GuestDrawTexture> textures,
|
||||
IReadOnlyList<GuestMemoryBuffer> globalMemoryBuffers,
|
||||
uint attributeCount,
|
||||
GuestDepthTarget depthTarget,
|
||||
IGuestCompiledShader? vertexShader = null,
|
||||
uint vertexCount = 3,
|
||||
uint instanceCount = 1,
|
||||
uint primitiveType = 4,
|
||||
GuestIndexBuffer? indexBuffer = null,
|
||||
IReadOnlyList<GuestVertexBuffer>? vertexBuffers = null,
|
||||
GuestRenderState? renderState = null,
|
||||
ulong shaderAddress = 0) =>
|
||||
VulkanVideoPresenter.SubmitDepthOnlyTranslatedDraw(
|
||||
Spirv(pixelShader),
|
||||
textures,
|
||||
globalMemoryBuffers,
|
||||
attributeCount,
|
||||
depthTarget,
|
||||
vertexShader is null ? null : Spirv(vertexShader),
|
||||
vertexCount,
|
||||
instanceCount,
|
||||
primitiveType,
|
||||
indexBuffer,
|
||||
vertexBuffers,
|
||||
renderState,
|
||||
shaderAddress);
|
||||
|
||||
public void SubmitOffscreenTranslatedDraw(
|
||||
IGuestCompiledShader pixelShader,
|
||||
IReadOnlyList<GuestDrawTexture> textures,
|
||||
@@ -152,7 +205,9 @@ internal sealed class VulkanGuestGpuBackend : IGuestGpuBackend
|
||||
uint primitiveType = 4,
|
||||
GuestIndexBuffer? indexBuffer = null,
|
||||
IReadOnlyList<GuestVertexBuffer>? vertexBuffers = null,
|
||||
GuestRenderState? renderState = null) =>
|
||||
GuestRenderState? renderState = null,
|
||||
GuestDepthTarget? depthTarget = null,
|
||||
ulong shaderAddress = 0) =>
|
||||
VulkanVideoPresenter.SubmitOffscreenTranslatedDraw(
|
||||
Spirv(pixelShader),
|
||||
textures,
|
||||
@@ -165,7 +220,9 @@ internal sealed class VulkanGuestGpuBackend : IGuestGpuBackend
|
||||
primitiveType,
|
||||
indexBuffer,
|
||||
vertexBuffers,
|
||||
renderState);
|
||||
renderState,
|
||||
depthTarget,
|
||||
shaderAddress);
|
||||
|
||||
public void SubmitStorageTranslatedDraw(
|
||||
IGuestCompiledShader pixelShader,
|
||||
@@ -173,23 +230,36 @@ internal sealed class VulkanGuestGpuBackend : IGuestGpuBackend
|
||||
IReadOnlyList<GuestMemoryBuffer> globalMemoryBuffers,
|
||||
uint attributeCount,
|
||||
uint width,
|
||||
uint height) =>
|
||||
uint height,
|
||||
ulong shaderAddress = 0) =>
|
||||
VulkanVideoPresenter.SubmitStorageTranslatedDraw(
|
||||
Spirv(pixelShader),
|
||||
textures,
|
||||
globalMemoryBuffers,
|
||||
attributeCount,
|
||||
width,
|
||||
height);
|
||||
height,
|
||||
shaderAddress);
|
||||
|
||||
public void SubmitComputeDispatch(
|
||||
public long SubmitComputeDispatch(
|
||||
ulong shaderAddress,
|
||||
IGuestCompiledShader computeShader,
|
||||
IReadOnlyList<GuestDrawTexture> textures,
|
||||
IReadOnlyList<GuestMemoryBuffer> globalMemoryBuffers,
|
||||
uint groupCountX,
|
||||
uint groupCountY,
|
||||
uint groupCountZ) =>
|
||||
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) =>
|
||||
VulkanVideoPresenter.SubmitComputeDispatch(
|
||||
shaderAddress,
|
||||
Spirv(computeShader),
|
||||
@@ -197,7 +267,18 @@ internal sealed class VulkanGuestGpuBackend : IGuestGpuBackend
|
||||
globalMemoryBuffers,
|
||||
groupCountX,
|
||||
groupCountY,
|
||||
groupCountZ);
|
||||
groupCountZ,
|
||||
baseGroupX,
|
||||
baseGroupY,
|
||||
baseGroupZ,
|
||||
localSizeX,
|
||||
localSizeY,
|
||||
localSizeZ,
|
||||
isIndirect,
|
||||
writesGlobalMemory,
|
||||
threadCountX,
|
||||
threadCountY,
|
||||
threadCountZ);
|
||||
|
||||
public bool TrySubmitGuestImage(
|
||||
ulong address,
|
||||
@@ -206,6 +287,21 @@ internal sealed class VulkanGuestGpuBackend : IGuestGpuBackend
|
||||
uint pitchInPixel) =>
|
||||
VulkanVideoPresenter.TrySubmitGuestImage(address, width, height, pitchInPixel);
|
||||
|
||||
public bool TrySubmitOrderedGuestImageFlip(
|
||||
int videoOutHandle,
|
||||
int displayBufferIndex,
|
||||
ulong address,
|
||||
uint width,
|
||||
uint height,
|
||||
uint pitchInPixel) =>
|
||||
VulkanVideoPresenter.TrySubmitOrderedGuestImageFlip(
|
||||
videoOutHandle,
|
||||
displayBufferIndex,
|
||||
address,
|
||||
width,
|
||||
height,
|
||||
pitchInPixel);
|
||||
|
||||
public void RegisterKnownDisplayBuffer(ulong address, uint guestFormat) =>
|
||||
VulkanVideoPresenter.RegisterKnownDisplayBuffer(address, guestFormat);
|
||||
|
||||
@@ -217,19 +313,23 @@ internal sealed class VulkanGuestGpuBackend : IGuestGpuBackend
|
||||
uint sourceWidth,
|
||||
uint sourceHeight,
|
||||
uint sourceFormat,
|
||||
uint sourceNumberType,
|
||||
ulong destinationAddress,
|
||||
uint destinationWidth,
|
||||
uint destinationHeight,
|
||||
uint destinationFormat) =>
|
||||
uint destinationFormat,
|
||||
uint destinationNumberType) =>
|
||||
VulkanVideoPresenter.TrySubmitGuestImageBlit(
|
||||
sourceAddress,
|
||||
sourceWidth,
|
||||
sourceHeight,
|
||||
sourceFormat,
|
||||
sourceNumberType,
|
||||
destinationAddress,
|
||||
destinationWidth,
|
||||
destinationHeight,
|
||||
destinationFormat);
|
||||
destinationFormat,
|
||||
destinationNumberType);
|
||||
|
||||
public bool TryGetRenderTargetOutputKind(uint dataFormat, uint numberType, out Gen5PixelOutputKind outputKind)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user