mirror of
https://github.com/ryujinx-mirror/ryujinx.git
synced 2024-12-23 03:45:46 +00:00
Vulkan: Add workarounds for MoltenVK (#4202)
* Add MVK basics. * Use appropriate output attribute types * 4kb vertex alignment, bunch of fixes * Add reduced shader precision mode for mvk. * Disable ASTC on MVK for now * Only request robustnes2 when it is available. * It's just the one feature actually * Add triangle fan conversion * Allow NullDescriptor on MVK for some reason. * Force safe blit on MoltenVK * Use ASTC only when formats are all available. * Disable multilevel 3d texture views * Filter duplicate render targets (on backend) * Add Automatic MoltenVK Configuration * Do not create color attachment views with formats that are not RT compatible * Make sure that the host format matches the vertex shader input types for invalid/unknown guest formats * FIx rebase for Vertex Attrib State * Fix 4b alignment for vertex * Use asynchronous queue submits for MVK * Ensure color clear shader has correct output type * Update MoltenVK config * Always use MoltenVK workarounds on MacOS * Make MVK supersede all vendors * Fix rebase * Various fixes on rebase * Get portability flags from extension * Fix some minor rebasing issues * Style change * Use LibraryImport for MVKConfiguration * Rename MoltenVK vendor to Apple Intel and AMD GPUs on moltenvk report with the those vendors - only apple silicon reports with vendor 0x106B. * Fix features2 rebase conflict * Rename fragment output type * Add missing check for fragment output types Might have caused the crash in MK8 * Only do fragment output specialization on MoltenVK * Avoid copy when passing capabilities * Self feedback * Address feedback Co-authored-by: gdk <gab.dark.100@gmail.com> Co-authored-by: nastys <nastys@users.noreply.github.com>
This commit is contained in:
parent
30862b5ffd
commit
8fa248ceb4
36 changed files with 739 additions and 61 deletions
|
@ -9,6 +9,8 @@ namespace Ryujinx.Graphics.GAL
|
||||||
|
|
||||||
public readonly bool HasFrontFacingBug;
|
public readonly bool HasFrontFacingBug;
|
||||||
public readonly bool HasVectorIndexingBug;
|
public readonly bool HasVectorIndexingBug;
|
||||||
|
public readonly bool NeedsFragmentOutputSpecialization;
|
||||||
|
public readonly bool ReduceShaderPrecision;
|
||||||
|
|
||||||
public readonly bool SupportsAstcCompression;
|
public readonly bool SupportsAstcCompression;
|
||||||
public readonly bool SupportsBc123Compression;
|
public readonly bool SupportsBc123Compression;
|
||||||
|
@ -49,6 +51,8 @@ namespace Ryujinx.Graphics.GAL
|
||||||
string vendorName,
|
string vendorName,
|
||||||
bool hasFrontFacingBug,
|
bool hasFrontFacingBug,
|
||||||
bool hasVectorIndexingBug,
|
bool hasVectorIndexingBug,
|
||||||
|
bool needsFragmentOutputSpecialization,
|
||||||
|
bool reduceShaderPrecision,
|
||||||
bool supportsAstcCompression,
|
bool supportsAstcCompression,
|
||||||
bool supportsBc123Compression,
|
bool supportsBc123Compression,
|
||||||
bool supportsBc45Compression,
|
bool supportsBc45Compression,
|
||||||
|
@ -85,6 +89,8 @@ namespace Ryujinx.Graphics.GAL
|
||||||
VendorName = vendorName;
|
VendorName = vendorName;
|
||||||
HasFrontFacingBug = hasFrontFacingBug;
|
HasFrontFacingBug = hasFrontFacingBug;
|
||||||
HasVectorIndexingBug = hasVectorIndexingBug;
|
HasVectorIndexingBug = hasVectorIndexingBug;
|
||||||
|
NeedsFragmentOutputSpecialization = needsFragmentOutputSpecialization;
|
||||||
|
ReduceShaderPrecision = reduceShaderPrecision;
|
||||||
SupportsAstcCompression = supportsAstcCompression;
|
SupportsAstcCompression = supportsAstcCompression;
|
||||||
SupportsBc123Compression = supportsBc123Compression;
|
SupportsBc123Compression = supportsBc123Compression;
|
||||||
SupportsBc45Compression = supportsBc45Compression;
|
SupportsBc45Compression = supportsBc45Compression;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using Ryujinx.Common.Memory;
|
using Ryujinx.Common.Memory;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
|
using Ryujinx.Graphics.Gpu.Engine.Types;
|
||||||
using Ryujinx.Graphics.Gpu.Shader;
|
using Ryujinx.Graphics.Gpu.Shader;
|
||||||
using Ryujinx.Graphics.Shader;
|
using Ryujinx.Graphics.Shader;
|
||||||
|
|
||||||
|
@ -10,6 +11,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal class SpecializationStateUpdater
|
internal class SpecializationStateUpdater
|
||||||
{
|
{
|
||||||
|
private readonly GpuContext _context;
|
||||||
private GpuChannelGraphicsState _graphics;
|
private GpuChannelGraphicsState _graphics;
|
||||||
private GpuChannelPoolState _pool;
|
private GpuChannelPoolState _pool;
|
||||||
|
|
||||||
|
@ -18,6 +20,15 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
|
|
||||||
private bool _changed;
|
private bool _changed;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the specialization state updater class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">GPU context</param>
|
||||||
|
public SpecializationStateUpdater(GpuContext context)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Signal that the specialization state has changed.
|
/// Signal that the specialization state has changed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -232,6 +243,42 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the type of the outputs produced by the fragment shader based on the current render target state.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rtControl">The render target control register</param>
|
||||||
|
/// <param name="state">The color attachment state</param>
|
||||||
|
public void SetFragmentOutputTypes(RtControl rtControl, ref Array8<RtColorState> state)
|
||||||
|
{
|
||||||
|
bool changed = false;
|
||||||
|
int count = rtControl.UnpackCount();
|
||||||
|
|
||||||
|
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
||||||
|
{
|
||||||
|
int rtIndex = rtControl.UnpackPermutationIndex(index);
|
||||||
|
|
||||||
|
var colorState = state[rtIndex];
|
||||||
|
|
||||||
|
if (index < count && StateUpdater.IsRtEnabled(colorState))
|
||||||
|
{
|
||||||
|
Format format = colorState.Format.Convert().Format;
|
||||||
|
|
||||||
|
AttributeType type = format.IsInteger() ? (format.IsSint() ? AttributeType.Sint : AttributeType.Uint) : AttributeType.Float;
|
||||||
|
|
||||||
|
if (type != _graphics.FragmentOutputTypes[index])
|
||||||
|
{
|
||||||
|
_graphics.FragmentOutputTypes[index] = type;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changed && _context.Capabilities.NeedsFragmentOutputSpecialization)
|
||||||
|
{
|
||||||
|
Signal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates that the draw is writing the base vertex, base instance and draw index to Constant Buffer 0.
|
/// Indicates that the draw is writing the base vertex, base instance and draw index to Constant Buffer 0.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -138,6 +138,16 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
_dirtyMask = ulong.MaxValue >> ((sizeof(ulong) * 8) - _callbacks.Length);
|
_dirtyMask = ulong.MaxValue >> ((sizeof(ulong) * 8) - _callbacks.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if the given register group is dirty without clearing it.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="groupIndex">Index of the group to check</param>
|
||||||
|
/// <returns>True if dirty, false otherwise</returns>
|
||||||
|
public bool IsDirty(int groupIndex)
|
||||||
|
{
|
||||||
|
return (_dirtyMask & (1UL << groupIndex)) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Check all the groups specified by <paramref name="checkMask"/> for modification, and update if modified.
|
/// Check all the groups specified by <paramref name="checkMask"/> for modification, and update if modified.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -20,6 +20,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
public const int ScissorStateIndex = 16;
|
public const int ScissorStateIndex = 16;
|
||||||
public const int VertexBufferStateIndex = 0;
|
public const int VertexBufferStateIndex = 0;
|
||||||
public const int PrimitiveRestartStateIndex = 12;
|
public const int PrimitiveRestartStateIndex = 12;
|
||||||
|
public const int RenderTargetStateIndex = 27;
|
||||||
|
|
||||||
private readonly GpuContext _context;
|
private readonly GpuContext _context;
|
||||||
private readonly GpuChannel _channel;
|
private readonly GpuChannel _channel;
|
||||||
|
@ -264,6 +265,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
_prevTfEnable = false;
|
_prevTfEnable = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_updateTracker.IsDirty(RenderTargetStateIndex))
|
||||||
|
{
|
||||||
|
UpdateRenderTargetSpecialization();
|
||||||
|
}
|
||||||
|
|
||||||
_updateTracker.Update(ulong.MaxValue);
|
_updateTracker.Update(ulong.MaxValue);
|
||||||
|
|
||||||
// If any state that the shader depends on changed,
|
// If any state that the shader depends on changed,
|
||||||
|
@ -526,12 +532,20 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates specialization state based on render target state.
|
||||||
|
/// </summary>
|
||||||
|
public void UpdateRenderTargetSpecialization()
|
||||||
|
{
|
||||||
|
_currentSpecState.SetFragmentOutputTypes(_state.State.RtControl, ref _state.State.RtColorState);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if a render target color buffer is used.
|
/// Checks if a render target color buffer is used.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="colorState">Color buffer information</param>
|
/// <param name="colorState">Color buffer information</param>
|
||||||
/// <returns>True if the specified buffer is enabled/used, false otherwise</returns>
|
/// <returns>True if the specified buffer is enabled/used, false otherwise</returns>
|
||||||
private static bool IsRtEnabled(RtColorState colorState)
|
internal static bool IsRtEnabled(RtColorState colorState)
|
||||||
{
|
{
|
||||||
// Colors are disabled by writing 0 to the format.
|
// Colors are disabled by writing 0 to the format.
|
||||||
return colorState.Format != 0 && colorState.WidthOrStride != 0;
|
return colorState.Format != 0 && colorState.WidthOrStride != 0;
|
||||||
|
@ -893,7 +907,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
{
|
{
|
||||||
Logger.Debug?.Print(LogClass.Gpu, $"Invalid attribute format 0x{vertexAttrib.UnpackFormat():X}.");
|
Logger.Debug?.Print(LogClass.Gpu, $"Invalid attribute format 0x{vertexAttrib.UnpackFormat():X}.");
|
||||||
|
|
||||||
format = Format.R32G32B32A32Float;
|
format = vertexAttrib.UnpackType() switch
|
||||||
|
{
|
||||||
|
VertexAttribType.Sint => Format.R32G32B32A32Sint,
|
||||||
|
VertexAttribType.Uint => Format.R32G32B32A32Uint,
|
||||||
|
_ => Format.R32G32B32A32Float
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
vertexAttribs[index] = new VertexAttribDescriptor(
|
vertexAttribs[index] = new VertexAttribDescriptor(
|
||||||
|
|
|
@ -71,7 +71,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
|
|
||||||
_i2mClass = new InlineToMemoryClass(context, channel, initializeState: false);
|
_i2mClass = new InlineToMemoryClass(context, channel, initializeState: false);
|
||||||
|
|
||||||
var spec = new SpecializationStateUpdater();
|
var spec = new SpecializationStateUpdater(context);
|
||||||
var drawState = new DrawState();
|
var drawState = new DrawState();
|
||||||
|
|
||||||
_drawManager = new DrawManager(context, channel, _state, drawState, spec);
|
_drawManager = new DrawManager(context, channel, _state, drawState, spec);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Ryujinx.Graphics.Gpu.Engine.GPFifo;
|
using Ryujinx.Graphics.GAL;
|
||||||
|
using Ryujinx.Graphics.Gpu.Engine.GPFifo;
|
||||||
using Ryujinx.Graphics.Gpu.Image;
|
using Ryujinx.Graphics.Gpu.Image;
|
||||||
using Ryujinx.Graphics.Gpu.Memory;
|
using Ryujinx.Graphics.Gpu.Memory;
|
||||||
using System;
|
using System;
|
||||||
|
@ -31,6 +32,11 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal MemoryManager MemoryManager => _memoryManager;
|
internal MemoryManager MemoryManager => _memoryManager;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Host hardware capabilities from the GPU context.
|
||||||
|
/// </summary>
|
||||||
|
internal ref Capabilities Capabilities => ref _context.Capabilities;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of a GPU channel.
|
/// Creates a new instance of a GPU channel.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -107,6 +107,12 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||||
return _oldSpecState.GraphicsState.AttributeTypes[location];
|
return _oldSpecState.GraphicsState.AttributeTypes[location];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public AttributeType QueryFragmentOutputType(int location)
|
||||||
|
{
|
||||||
|
return _oldSpecState.GraphicsState.FragmentOutputTypes[location];
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public int QueryComputeLocalSizeX() => _oldSpecState.ComputeState.LocalSizeX;
|
public int QueryComputeLocalSizeX() => _oldSpecState.ComputeState.LocalSizeX;
|
||||||
|
|
||||||
|
|
|
@ -113,6 +113,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
return _state.GraphicsState.AttributeTypes[location];
|
return _state.GraphicsState.AttributeTypes[location];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public AttributeType QueryFragmentOutputType(int location)
|
||||||
|
{
|
||||||
|
return _state.GraphicsState.FragmentOutputTypes[location];
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public int QueryComputeLocalSizeX() => _state.ComputeState.LocalSizeX;
|
public int QueryComputeLocalSizeX() => _state.ComputeState.LocalSizeX;
|
||||||
|
|
||||||
|
|
|
@ -112,6 +112,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool QueryHostReducedPrecision() => _context.Capabilities.ReduceShaderPrecision;
|
||||||
|
|
||||||
public bool QueryHostHasFrontFacingBug() => _context.Capabilities.HasFrontFacingBug;
|
public bool QueryHostHasFrontFacingBug() => _context.Capabilities.HasFrontFacingBug;
|
||||||
|
|
||||||
public bool QueryHostHasVectorIndexingBug() => _context.Capabilities.HasVectorIndexingBug;
|
public bool QueryHostHasVectorIndexingBug() => _context.Capabilities.HasVectorIndexingBug;
|
||||||
|
|
|
@ -87,6 +87,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool HasUnalignedStorageBuffer;
|
public bool HasUnalignedStorageBuffer;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Type of the fragment shader outputs.
|
||||||
|
/// </summary>
|
||||||
|
public Array8<AttributeType> FragmentOutputTypes;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new GPU graphics state.
|
/// Creates a new GPU graphics state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -105,6 +110,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
/// <param name="attributeTypes">Type of the vertex attributes consumed by the shader</param>
|
/// <param name="attributeTypes">Type of the vertex attributes consumed by the shader</param>
|
||||||
/// <param name="hasConstantBufferDrawParameters">Indicates that the draw is writing the base vertex, base instance and draw index to Constant Buffer 0</param>
|
/// <param name="hasConstantBufferDrawParameters">Indicates that the draw is writing the base vertex, base instance and draw index to Constant Buffer 0</param>
|
||||||
/// <param name="hasUnalignedStorageBuffer">Indicates that any storage buffer use is unaligned</param>
|
/// <param name="hasUnalignedStorageBuffer">Indicates that any storage buffer use is unaligned</param>
|
||||||
|
/// <param name="fragmentOutputTypes">Type of the fragment shader outputs</param>
|
||||||
public GpuChannelGraphicsState(
|
public GpuChannelGraphicsState(
|
||||||
bool earlyZForce,
|
bool earlyZForce,
|
||||||
PrimitiveTopology topology,
|
PrimitiveTopology topology,
|
||||||
|
@ -120,7 +126,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
float alphaTestReference,
|
float alphaTestReference,
|
||||||
ref Array32<AttributeType> attributeTypes,
|
ref Array32<AttributeType> attributeTypes,
|
||||||
bool hasConstantBufferDrawParameters,
|
bool hasConstantBufferDrawParameters,
|
||||||
bool hasUnalignedStorageBuffer)
|
bool hasUnalignedStorageBuffer,
|
||||||
|
ref Array8<AttributeType> fragmentOutputTypes)
|
||||||
{
|
{
|
||||||
EarlyZForce = earlyZForce;
|
EarlyZForce = earlyZForce;
|
||||||
Topology = topology;
|
Topology = topology;
|
||||||
|
@ -137,6 +144,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
AttributeTypes = attributeTypes;
|
AttributeTypes = attributeTypes;
|
||||||
HasConstantBufferDrawParameters = hasConstantBufferDrawParameters;
|
HasConstantBufferDrawParameters = hasConstantBufferDrawParameters;
|
||||||
HasUnalignedStorageBuffer = hasUnalignedStorageBuffer;
|
HasUnalignedStorageBuffer = hasUnalignedStorageBuffer;
|
||||||
|
FragmentOutputTypes = fragmentOutputTypes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -530,6 +530,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (channel.Capabilities.NeedsFragmentOutputSpecialization && !graphicsState.FragmentOutputTypes.AsSpan().SequenceEqual(GraphicsState.FragmentOutputTypes.AsSpan()))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return Matches(channel, ref poolState, checkTextures, isCompute: false);
|
return Matches(channel, ref poolState, checkTextures, isCompute: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -106,6 +106,8 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
vendorName: GpuVendor,
|
vendorName: GpuVendor,
|
||||||
hasFrontFacingBug: HwCapabilities.Vendor == HwCapabilities.GpuVendor.IntelWindows,
|
hasFrontFacingBug: HwCapabilities.Vendor == HwCapabilities.GpuVendor.IntelWindows,
|
||||||
hasVectorIndexingBug: HwCapabilities.Vendor == HwCapabilities.GpuVendor.AmdWindows,
|
hasVectorIndexingBug: HwCapabilities.Vendor == HwCapabilities.GpuVendor.AmdWindows,
|
||||||
|
needsFragmentOutputSpecialization: false,
|
||||||
|
reduceShaderPrecision: false,
|
||||||
supportsAstcCompression: HwCapabilities.SupportsAstcCompression,
|
supportsAstcCompression: HwCapabilities.SupportsAstcCompression,
|
||||||
supportsBc123Compression: HwCapabilities.SupportsTextureCompressionS3tc,
|
supportsBc123Compression: HwCapabilities.SupportsTextureCompressionS3tc,
|
||||||
supportsBc45Compression: HwCapabilities.SupportsTextureCompressionRgtc,
|
supportsBc45Compression: HwCapabilities.SupportsTextureCompressionRgtc,
|
||||||
|
|
|
@ -346,12 +346,17 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
{
|
{
|
||||||
string name = context.OperandManager.DeclareLocal(decl);
|
string name = context.OperandManager.DeclareLocal(decl);
|
||||||
|
|
||||||
context.AppendLine(GetVarTypeName(decl.VarType) + " " + name + ";");
|
context.AppendLine(GetVarTypeName(context, decl.VarType) + " " + name + ";");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetVarTypeName(AggregateType type, bool precise = true)
|
public static string GetVarTypeName(CodeGenContext context, AggregateType type, bool precise = true)
|
||||||
{
|
{
|
||||||
|
if (context.Config.GpuAccessor.QueryHostReducedPrecision())
|
||||||
|
{
|
||||||
|
precise = false;
|
||||||
|
}
|
||||||
|
|
||||||
return type switch
|
return type switch
|
||||||
{
|
{
|
||||||
AggregateType.Void => "void",
|
AggregateType.Void => "void",
|
||||||
|
@ -666,7 +671,22 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
context.AppendLine($"layout (location = {attr}) out vec4 {name};");
|
string type = context.Config.Stage != ShaderStage.Fragment ? "vec4" :
|
||||||
|
context.Config.GpuAccessor.QueryFragmentOutputType(attr) switch
|
||||||
|
{
|
||||||
|
AttributeType.Sint => "ivec4",
|
||||||
|
AttributeType.Uint => "uvec4",
|
||||||
|
_ => "vec4"
|
||||||
|
};
|
||||||
|
|
||||||
|
if (context.Config.GpuAccessor.QueryHostReducedPrecision() && context.Config.Stage == ShaderStage.Vertex && attr == 0)
|
||||||
|
{
|
||||||
|
context.AppendLine($"layout (location = {attr}) invariant out {type} {name};");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.AppendLine($"layout (location = {attr}) out {type} {name};");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
{
|
{
|
||||||
for (int i = 1; i < info.Functions.Count; i++)
|
for (int i = 1; i < info.Functions.Count; i++)
|
||||||
{
|
{
|
||||||
context.AppendLine($"{GetFunctionSignature(info.Functions[i])};");
|
context.AppendLine($"{GetFunctionSignature(context, info.Functions[i])};");
|
||||||
}
|
}
|
||||||
|
|
||||||
context.AppendLine();
|
context.AppendLine();
|
||||||
|
@ -44,7 +44,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
{
|
{
|
||||||
context.CurrentFunction = function;
|
context.CurrentFunction = function;
|
||||||
|
|
||||||
context.AppendLine(GetFunctionSignature(function, funcName));
|
context.AppendLine(GetFunctionSignature(context, function, funcName));
|
||||||
context.EnterScope();
|
context.EnterScope();
|
||||||
|
|
||||||
Declarations.DeclareLocals(context, function);
|
Declarations.DeclareLocals(context, function);
|
||||||
|
@ -54,23 +54,23 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
context.LeaveScope();
|
context.LeaveScope();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetFunctionSignature(StructuredFunction function, string funcName = null)
|
private static string GetFunctionSignature(CodeGenContext context, StructuredFunction function, string funcName = null)
|
||||||
{
|
{
|
||||||
string[] args = new string[function.InArguments.Length + function.OutArguments.Length];
|
string[] args = new string[function.InArguments.Length + function.OutArguments.Length];
|
||||||
|
|
||||||
for (int i = 0; i < function.InArguments.Length; i++)
|
for (int i = 0; i < function.InArguments.Length; i++)
|
||||||
{
|
{
|
||||||
args[i] = $"{Declarations.GetVarTypeName(function.InArguments[i])} {OperandManager.GetArgumentName(i)}";
|
args[i] = $"{Declarations.GetVarTypeName(context, function.InArguments[i])} {OperandManager.GetArgumentName(i)}";
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < function.OutArguments.Length; i++)
|
for (int i = 0; i < function.OutArguments.Length; i++)
|
||||||
{
|
{
|
||||||
int j = i + function.InArguments.Length;
|
int j = i + function.InArguments.Length;
|
||||||
|
|
||||||
args[j] = $"out {Declarations.GetVarTypeName(function.OutArguments[i])} {OperandManager.GetArgumentName(j)}";
|
args[j] = $"out {Declarations.GetVarTypeName(context, function.OutArguments[i])} {OperandManager.GetArgumentName(j)}";
|
||||||
}
|
}
|
||||||
|
|
||||||
return $"{Declarations.GetVarTypeName(function.ReturnType)} {funcName ?? function.Name}({string.Join(", ", args)})";
|
return $"{Declarations.GetVarTypeName(context, function.ReturnType)} {funcName ?? function.Name}({string.Join(", ", args)})";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void PrintBlock(CodeGenContext context, AstBlock block)
|
private static void PrintBlock(CodeGenContext context, AstBlock block)
|
||||||
|
|
|
@ -32,7 +32,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||||
|
|
||||||
if ((outputType & AggregateType.ElementCountMask) != 0)
|
if ((outputType & AggregateType.ElementCountMask) != 0)
|
||||||
{
|
{
|
||||||
return $"{Declarations.GetVarTypeName(outputType, precise: false)}({imageConst})";
|
return $"{Declarations.GetVarTypeName(context, outputType, precise: false)}({imageConst})";
|
||||||
}
|
}
|
||||||
|
|
||||||
return imageConst;
|
return imageConst;
|
||||||
|
@ -513,7 +513,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||||
|
|
||||||
if ((outputType & AggregateType.ElementCountMask) != 0)
|
if ((outputType & AggregateType.ElementCountMask) != 0)
|
||||||
{
|
{
|
||||||
return $"{Declarations.GetVarTypeName(outputType, precise: false)}({scalarValue})";
|
return $"{Declarations.GetVarTypeName(context, outputType, precise: false)}({scalarValue})";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -577,6 +577,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
context.Decorate(spvVar, Decoration.Patch);
|
context.Decorate(spvVar, Decoration.Patch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (context.Config.GpuAccessor.QueryHostReducedPrecision() && attr == AttributeConsts.PositionX && context.Config.Stage != ShaderStage.Fragment)
|
||||||
|
{
|
||||||
|
context.Decorate(spvVar, Decoration.Invariant);
|
||||||
|
}
|
||||||
|
|
||||||
context.Decorate(spvVar, Decoration.BuiltIn, (LiteralInteger)GetBuiltIn(context, attrInfo.BaseValue));
|
context.Decorate(spvVar, Decoration.BuiltIn, (LiteralInteger)GetBuiltIn(context, attrInfo.BaseValue));
|
||||||
|
|
||||||
if (context.Config.TransformFeedbackEnabled && context.Config.LastInVertexPipeline && isOutAttr)
|
if (context.Config.TransformFeedbackEnabled && context.Config.LastInVertexPipeline && isOutAttr)
|
||||||
|
|
|
@ -2194,13 +2194,23 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
if (operation.Inst.HasFlag(Instruction.FP64))
|
if (operation.Inst.HasFlag(Instruction.FP64))
|
||||||
{
|
{
|
||||||
var result = emitF(context.TypeFP64(), context.GetFP64(src1), context.GetFP64(src2));
|
var result = emitF(context.TypeFP64(), context.GetFP64(src1), context.GetFP64(src2));
|
||||||
context.Decorate(result, Decoration.NoContraction);
|
|
||||||
|
if (!context.Config.GpuAccessor.QueryHostReducedPrecision())
|
||||||
|
{
|
||||||
|
context.Decorate(result, Decoration.NoContraction);
|
||||||
|
}
|
||||||
|
|
||||||
return new OperationResult(AggregateType.FP64, result);
|
return new OperationResult(AggregateType.FP64, result);
|
||||||
}
|
}
|
||||||
else if (operation.Inst.HasFlag(Instruction.FP32))
|
else if (operation.Inst.HasFlag(Instruction.FP32))
|
||||||
{
|
{
|
||||||
var result = emitF(context.TypeFP32(), context.GetFP32(src1), context.GetFP32(src2));
|
var result = emitF(context.TypeFP32(), context.GetFP32(src1), context.GetFP32(src2));
|
||||||
context.Decorate(result, Decoration.NoContraction);
|
|
||||||
|
if (!context.Config.GpuAccessor.QueryHostReducedPrecision())
|
||||||
|
{
|
||||||
|
context.Decorate(result, Decoration.NoContraction);
|
||||||
|
}
|
||||||
|
|
||||||
return new OperationResult(AggregateType.FP32, result);
|
return new OperationResult(AggregateType.FP32, result);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -2255,13 +2265,23 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
if (operation.Inst.HasFlag(Instruction.FP64))
|
if (operation.Inst.HasFlag(Instruction.FP64))
|
||||||
{
|
{
|
||||||
var result = emitF(context.TypeFP64(), context.GetFP64(src1), context.GetFP64(src2), context.GetFP64(src3));
|
var result = emitF(context.TypeFP64(), context.GetFP64(src1), context.GetFP64(src2), context.GetFP64(src3));
|
||||||
context.Decorate(result, Decoration.NoContraction);
|
|
||||||
|
if (!context.Config.GpuAccessor.QueryHostReducedPrecision())
|
||||||
|
{
|
||||||
|
context.Decorate(result, Decoration.NoContraction);
|
||||||
|
}
|
||||||
|
|
||||||
return new OperationResult(AggregateType.FP64, result);
|
return new OperationResult(AggregateType.FP64, result);
|
||||||
}
|
}
|
||||||
else if (operation.Inst.HasFlag(Instruction.FP32))
|
else if (operation.Inst.HasFlag(Instruction.FP32))
|
||||||
{
|
{
|
||||||
var result = emitF(context.TypeFP32(), context.GetFP32(src1), context.GetFP32(src2), context.GetFP32(src3));
|
var result = emitF(context.TypeFP32(), context.GetFP32(src1), context.GetFP32(src2), context.GetFP32(src3));
|
||||||
context.Decorate(result, Decoration.NoContraction);
|
|
||||||
|
if (!context.Config.GpuAccessor.QueryHostReducedPrecision())
|
||||||
|
{
|
||||||
|
context.Decorate(result, Decoration.NoContraction);
|
||||||
|
}
|
||||||
|
|
||||||
return new OperationResult(AggregateType.FP32, result);
|
return new OperationResult(AggregateType.FP32, result);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -114,6 +114,16 @@ namespace Ryujinx.Graphics.Shader
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queries output type for fragment shaders.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="location">Location of the framgent output</param>
|
||||||
|
/// <returns>Output location</returns>
|
||||||
|
AttributeType QueryFragmentOutputType(int location)
|
||||||
|
{
|
||||||
|
return AttributeType.Float;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Queries Local Size X for compute shaders.
|
/// Queries Local Size X for compute shaders.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -186,6 +196,15 @@ namespace Ryujinx.Graphics.Shader
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queries host about whether to reduce precision to improve performance.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if precision is limited to vertex position, false otherwise</returns>
|
||||||
|
bool QueryHostReducedPrecision()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Queries host about the presence of the FrontFacing built-in variable bug.
|
/// Queries host about the presence of the FrontFacing built-in variable bug.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -128,7 +128,15 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
}
|
}
|
||||||
else if (value >= AttributeConsts.FragmentOutputColorBase && value < AttributeConsts.FragmentOutputColorEnd)
|
else if (value >= AttributeConsts.FragmentOutputColorBase && value < AttributeConsts.FragmentOutputColorEnd)
|
||||||
{
|
{
|
||||||
return new AttributeInfo(value & ~0xf, (value >> 2) & 3, 4, AggregateType.Vector4 | AggregateType.FP32, false);
|
int location = (value - AttributeConsts.FragmentOutputColorBase) / 16;
|
||||||
|
var elemType = config.GpuAccessor.QueryFragmentOutputType(location) switch
|
||||||
|
{
|
||||||
|
AttributeType.Sint => AggregateType.S32,
|
||||||
|
AttributeType.Uint => AggregateType.U32,
|
||||||
|
_ => AggregateType.FP32
|
||||||
|
};
|
||||||
|
|
||||||
|
return new AttributeInfo(value & ~0xf, (value >> 2) & 3, 4, AggregateType.Vector4 | elemType, false);
|
||||||
}
|
}
|
||||||
else if (value == AttributeConsts.SupportBlockViewInverseX || value == AttributeConsts.SupportBlockViewInverseY)
|
else if (value == AttributeConsts.SupportBlockViewInverseX || value == AttributeConsts.SupportBlockViewInverseY)
|
||||||
{
|
{
|
||||||
|
|
|
@ -140,6 +140,25 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
return _attachments[index];
|
return _attachments[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ComponentType GetAttachmentComponentType(int index)
|
||||||
|
{
|
||||||
|
if (_colors != null && (uint)index < _colors.Length)
|
||||||
|
{
|
||||||
|
var format = _colors[index].Info.Format;
|
||||||
|
|
||||||
|
if (format.IsSint())
|
||||||
|
{
|
||||||
|
return ComponentType.SignedInteger;
|
||||||
|
}
|
||||||
|
else if (format.IsUint())
|
||||||
|
{
|
||||||
|
return ComponentType.UnsignedInteger;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ComponentType.Float;
|
||||||
|
}
|
||||||
|
|
||||||
public bool IsValidColorAttachment(int bindIndex)
|
public bool IsValidColorAttachment(int bindIndex)
|
||||||
{
|
{
|
||||||
return (uint)bindIndex < Constants.MaxRenderTargets && (_validColorAttachments & (1u << bindIndex)) != 0;
|
return (uint)bindIndex < Constants.MaxRenderTargets && (_validColorAttachments & (1u << bindIndex)) != 0;
|
||||||
|
|
|
@ -1,7 +1,20 @@
|
||||||
using Silk.NET.Vulkan;
|
using Silk.NET.Vulkan;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Vulkan
|
namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
|
[Flags]
|
||||||
|
enum PortabilitySubsetFlags
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
|
||||||
|
VertexBufferAlignment4B = 1,
|
||||||
|
NoTriangleFans = 1 << 1,
|
||||||
|
NoPointMode = 1 << 2,
|
||||||
|
No3DImageView = 1 << 3,
|
||||||
|
NoLodBias = 1 << 4
|
||||||
|
}
|
||||||
|
|
||||||
readonly struct HardwareCapabilities
|
readonly struct HardwareCapabilities
|
||||||
{
|
{
|
||||||
public readonly bool SupportsIndexTypeUint8;
|
public readonly bool SupportsIndexTypeUint8;
|
||||||
|
@ -23,6 +36,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
public readonly uint MaxSubgroupSize;
|
public readonly uint MaxSubgroupSize;
|
||||||
public readonly ShaderStageFlags RequiredSubgroupSizeStages;
|
public readonly ShaderStageFlags RequiredSubgroupSizeStages;
|
||||||
public readonly SampleCountFlags SupportedSampleCounts;
|
public readonly SampleCountFlags SupportedSampleCounts;
|
||||||
|
public readonly PortabilitySubsetFlags PortabilitySubset;
|
||||||
|
|
||||||
public HardwareCapabilities(
|
public HardwareCapabilities(
|
||||||
bool supportsIndexTypeUint8,
|
bool supportsIndexTypeUint8,
|
||||||
|
@ -43,7 +57,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
uint minSubgroupSize,
|
uint minSubgroupSize,
|
||||||
uint maxSubgroupSize,
|
uint maxSubgroupSize,
|
||||||
ShaderStageFlags requiredSubgroupSizeStages,
|
ShaderStageFlags requiredSubgroupSizeStages,
|
||||||
SampleCountFlags supportedSampleCounts)
|
SampleCountFlags supportedSampleCounts,
|
||||||
|
PortabilitySubsetFlags portabilitySubset)
|
||||||
{
|
{
|
||||||
SupportsIndexTypeUint8 = supportsIndexTypeUint8;
|
SupportsIndexTypeUint8 = supportsIndexTypeUint8;
|
||||||
SupportsCustomBorderColor = supportsCustomBorderColor;
|
SupportsCustomBorderColor = supportsCustomBorderColor;
|
||||||
|
@ -64,6 +79,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
MaxSubgroupSize = maxSubgroupSize;
|
MaxSubgroupSize = maxSubgroupSize;
|
||||||
RequiredSubgroupSizeStages = requiredSubgroupSizeStages;
|
RequiredSubgroupSizeStages = requiredSubgroupSizeStages;
|
||||||
SupportedSampleCounts = supportedSampleCounts;
|
SupportedSampleCounts = supportedSampleCounts;
|
||||||
|
PortabilitySubset = portabilitySubset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,13 @@ using VkFormat = Silk.NET.Vulkan.Format;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Vulkan
|
namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
|
enum ComponentType
|
||||||
|
{
|
||||||
|
Float,
|
||||||
|
SignedInteger,
|
||||||
|
UnsignedInteger
|
||||||
|
}
|
||||||
|
|
||||||
class HelperShader : IDisposable
|
class HelperShader : IDisposable
|
||||||
{
|
{
|
||||||
private const int UniformBufferAlignment = 256;
|
private const int UniformBufferAlignment = 256;
|
||||||
|
@ -18,7 +25,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
private readonly ISampler _samplerNearest;
|
private readonly ISampler _samplerNearest;
|
||||||
private readonly IProgram _programColorBlit;
|
private readonly IProgram _programColorBlit;
|
||||||
private readonly IProgram _programColorBlitClearAlpha;
|
private readonly IProgram _programColorBlitClearAlpha;
|
||||||
private readonly IProgram _programColorClear;
|
private readonly IProgram _programColorClearF;
|
||||||
|
private readonly IProgram _programColorClearSI;
|
||||||
|
private readonly IProgram _programColorClearUI;
|
||||||
private readonly IProgram _programStrideChange;
|
private readonly IProgram _programStrideChange;
|
||||||
private readonly IProgram _programConvertIndexBuffer;
|
private readonly IProgram _programConvertIndexBuffer;
|
||||||
private readonly IProgram _programConvertIndirectData;
|
private readonly IProgram _programConvertIndirectData;
|
||||||
|
@ -63,10 +72,22 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
Array.Empty<int>(),
|
Array.Empty<int>(),
|
||||||
Array.Empty<int>());
|
Array.Empty<int>());
|
||||||
|
|
||||||
_programColorClear = gd.CreateProgramWithMinimalLayout(new[]
|
_programColorClearF = gd.CreateProgramWithMinimalLayout(new[]
|
||||||
{
|
{
|
||||||
new ShaderSource(ShaderBinaries.ColorClearVertexShaderSource, colorBlitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
|
new ShaderSource(ShaderBinaries.ColorClearVertexShaderSource, colorBlitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||||
new ShaderSource(ShaderBinaries.ColorClearFragmentShaderSource, colorClearFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv),
|
new ShaderSource(ShaderBinaries.ColorClearFFragmentShaderSource, colorClearFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||||
|
});
|
||||||
|
|
||||||
|
_programColorClearSI = gd.CreateProgramWithMinimalLayout(new[]
|
||||||
|
{
|
||||||
|
new ShaderSource(ShaderBinaries.ColorClearVertexShaderSource, colorBlitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||||
|
new ShaderSource(ShaderBinaries.ColorClearSIFragmentShaderSource, colorClearFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||||
|
});
|
||||||
|
|
||||||
|
_programColorClearUI = gd.CreateProgramWithMinimalLayout(new[]
|
||||||
|
{
|
||||||
|
new ShaderSource(ShaderBinaries.ColorClearVertexShaderSource, colorBlitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||||
|
new ShaderSource(ShaderBinaries.ColorClearUIFragmentShaderSource, colorClearFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||||
});
|
});
|
||||||
|
|
||||||
var strideChangeBindings = new ShaderBindings(
|
var strideChangeBindings = new ShaderBindings(
|
||||||
|
@ -242,6 +263,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
int dstWidth,
|
int dstWidth,
|
||||||
int dstHeight,
|
int dstHeight,
|
||||||
VkFormat dstFormat,
|
VkFormat dstFormat,
|
||||||
|
ComponentType type,
|
||||||
Rectangle<int> scissor)
|
Rectangle<int> scissor)
|
||||||
{
|
{
|
||||||
const int ClearColorBufferSize = 16;
|
const int ClearColorBufferSize = 16;
|
||||||
|
@ -273,7 +295,22 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
scissors[0] = scissor;
|
scissors[0] = scissor;
|
||||||
|
|
||||||
_pipeline.SetProgram(_programColorClear);
|
IProgram program;
|
||||||
|
|
||||||
|
if (type == ComponentType.SignedInteger)
|
||||||
|
{
|
||||||
|
program = _programColorClearSI;
|
||||||
|
}
|
||||||
|
else if (type == ComponentType.UnsignedInteger)
|
||||||
|
{
|
||||||
|
program = _programColorClearUI;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
program = _programColorClearF;
|
||||||
|
}
|
||||||
|
|
||||||
|
_pipeline.SetProgram(program);
|
||||||
_pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, false, dstFormat);
|
_pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, false, dstFormat);
|
||||||
_pipeline.SetRenderTargetColorMasks(new uint[] { componentMask });
|
_pipeline.SetRenderTargetColorMasks(new uint[] { componentMask });
|
||||||
_pipeline.SetViewports(viewports, false);
|
_pipeline.SetViewports(viewports, false);
|
||||||
|
@ -948,7 +985,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
_programColorBlitClearAlpha.Dispose();
|
_programColorBlitClearAlpha.Dispose();
|
||||||
_programColorBlit.Dispose();
|
_programColorBlit.Dispose();
|
||||||
_programColorClear.Dispose();
|
_programColorClearF.Dispose();
|
||||||
|
_programColorClearSI.Dispose();
|
||||||
|
_programColorClearUI.Dispose();
|
||||||
_programStrideChange.Dispose();
|
_programStrideChange.Dispose();
|
||||||
_programConvertIndexBuffer.Dispose();
|
_programConvertIndexBuffer.Dispose();
|
||||||
_programConvertIndirectData.Dispose();
|
_programConvertIndirectData.Dispose();
|
||||||
|
|
104
Ryujinx.Graphics.Vulkan/MoltenVK/MVKConfiguration.cs
Normal file
104
Ryujinx.Graphics.Vulkan/MoltenVK/MVKConfiguration.cs
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Vulkan.MoltenVK
|
||||||
|
{
|
||||||
|
enum MVKConfigLogLevel : int
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Error = 1,
|
||||||
|
Warning = 2,
|
||||||
|
Info = 3,
|
||||||
|
Debug = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
enum MVKConfigTraceVulkanCalls : int
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Enter = 1,
|
||||||
|
EnterExit = 2,
|
||||||
|
Duration = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
enum MVKConfigAutoGPUCaptureScope : int
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Device = 1,
|
||||||
|
Frame = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
enum MVKConfigAdvertiseExtensions : int
|
||||||
|
{
|
||||||
|
All = 0x00000001,
|
||||||
|
MoltenVK = 0x00000002,
|
||||||
|
WSI = 0x00000004,
|
||||||
|
Portability = 0x00000008
|
||||||
|
}
|
||||||
|
|
||||||
|
enum MVKVkSemaphoreSupportStyle : int
|
||||||
|
{
|
||||||
|
MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_SINGLE_QUEUE = 0,
|
||||||
|
MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_METAL_EVENTS_WHERE_SAFE = 1,
|
||||||
|
MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_METAL_EVENTS = 2,
|
||||||
|
MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_CALLBACK = 3,
|
||||||
|
MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_MAX_ENUM = 0x7FFFFFFF
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly struct Bool32
|
||||||
|
{
|
||||||
|
uint Value { get; }
|
||||||
|
|
||||||
|
public Bool32(uint value)
|
||||||
|
{
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bool32(bool value)
|
||||||
|
{
|
||||||
|
Value = value ? 1u : 0u;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator bool(Bool32 val) => val.Value == 1;
|
||||||
|
public static implicit operator Bool32(bool val) => new Bool32(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
struct MVKConfiguration
|
||||||
|
{
|
||||||
|
public Bool32 DebugMode;
|
||||||
|
public Bool32 ShaderConversionFlipVertexY;
|
||||||
|
public Bool32 SynchronousQueueSubmits;
|
||||||
|
public Bool32 PrefillMetalCommandBuffers;
|
||||||
|
public uint MaxActiveMetalCommandBuffersPerQueue;
|
||||||
|
public Bool32 SupportLargeQueryPools;
|
||||||
|
public Bool32 PresentWithCommandBuffer;
|
||||||
|
public Bool32 SwapchainMagFilterUseNearest;
|
||||||
|
public ulong MetalCompileTimeout;
|
||||||
|
public Bool32 PerformanceTracking;
|
||||||
|
public uint PerformanceLoggingFrameCount;
|
||||||
|
public Bool32 DisplayWatermark;
|
||||||
|
public Bool32 SpecializedQueueFamilies;
|
||||||
|
public Bool32 SwitchSystemGPU;
|
||||||
|
public Bool32 FullImageViewSwizzle;
|
||||||
|
public uint DefaultGPUCaptureScopeQueueFamilyIndex;
|
||||||
|
public uint DefaultGPUCaptureScopeQueueIndex;
|
||||||
|
public Bool32 FastMathEnabled;
|
||||||
|
public MVKConfigLogLevel LogLevel;
|
||||||
|
public MVKConfigTraceVulkanCalls TraceVulkanCalls;
|
||||||
|
public Bool32 ForceLowPowerGPU;
|
||||||
|
public Bool32 SemaphoreUseMTLFence;
|
||||||
|
public MVKVkSemaphoreSupportStyle SemaphoreSupportStyle;
|
||||||
|
public MVKConfigAutoGPUCaptureScope AutoGPUCaptureScope;
|
||||||
|
public IntPtr AutoGPUCaptureOutputFilepath;
|
||||||
|
public Bool32 Texture1DAs2D;
|
||||||
|
public Bool32 PreallocateDescriptors;
|
||||||
|
public Bool32 UseCommandPooling;
|
||||||
|
public Bool32 UseMTLHeap;
|
||||||
|
public Bool32 LogActivityPerformanceInline;
|
||||||
|
public uint ApiVersionToAdvertise;
|
||||||
|
public MVKConfigAdvertiseExtensions AdvertiseExtensions;
|
||||||
|
public Bool32 ResumeLostDevice;
|
||||||
|
public Bool32 UseMetalArgumentBuffers;
|
||||||
|
}
|
||||||
|
}
|
31
Ryujinx.Graphics.Vulkan/MoltenVK/MVKInitialization.cs
Normal file
31
Ryujinx.Graphics.Vulkan/MoltenVK/MVKInitialization.cs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
using Silk.NET.Vulkan;
|
||||||
|
using System;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Vulkan.MoltenVK
|
||||||
|
{
|
||||||
|
[SupportedOSPlatform("macos")]
|
||||||
|
public static partial class MVKInitialization
|
||||||
|
{
|
||||||
|
[LibraryImport("libMoltenVK.dylib")]
|
||||||
|
private static partial Result vkGetMoltenVKConfigurationMVK(IntPtr unusedInstance, out MVKConfiguration config, in IntPtr configSize);
|
||||||
|
|
||||||
|
[LibraryImport("libMoltenVK.dylib")]
|
||||||
|
private static partial Result vkSetMoltenVKConfigurationMVK(IntPtr unusedInstance, in MVKConfiguration config, in IntPtr configSize);
|
||||||
|
|
||||||
|
public static void Initialize()
|
||||||
|
{
|
||||||
|
var configSize = (IntPtr)Marshal.SizeOf<MVKConfiguration>();
|
||||||
|
|
||||||
|
vkGetMoltenVKConfigurationMVK(IntPtr.Zero, out MVKConfiguration config, configSize);
|
||||||
|
|
||||||
|
config.UseMetalArgumentBuffers = true;
|
||||||
|
|
||||||
|
config.SemaphoreSupportStyle = MVKVkSemaphoreSupportStyle.MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_SINGLE_QUEUE;
|
||||||
|
config.SynchronousQueueSubmits = false;
|
||||||
|
|
||||||
|
vkSetMoltenVKConfigurationMVK(IntPtr.Zero, config, configSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
using Ryujinx.Graphics.Shader;
|
using Ryujinx.Graphics.Shader;
|
||||||
using Silk.NET.Vulkan;
|
using Silk.NET.Vulkan;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
@ -50,6 +51,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
private Auto<DisposableRenderPass> _renderPass;
|
private Auto<DisposableRenderPass> _renderPass;
|
||||||
private int _writtenAttachmentCount;
|
private int _writtenAttachmentCount;
|
||||||
|
|
||||||
|
private bool _framebufferUsingColorWriteMask;
|
||||||
|
|
||||||
|
private ITexture[] _preMaskColors;
|
||||||
|
private ITexture _preMaskDepthStencil;
|
||||||
|
|
||||||
private readonly DescriptorSetUpdater _descriptorSetUpdater;
|
private readonly DescriptorSetUpdater _descriptorSetUpdater;
|
||||||
|
|
||||||
private IndexBufferState _indexBuffer;
|
private IndexBufferState _indexBuffer;
|
||||||
|
@ -905,22 +911,35 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SignalStateChange();
|
if (_framebufferUsingColorWriteMask)
|
||||||
|
|
||||||
if (writtenAttachments != _writtenAttachmentCount)
|
|
||||||
{
|
{
|
||||||
SignalAttachmentChange();
|
SetRenderTargetsInternal(_preMaskColors, _preMaskDepthStencil, true);
|
||||||
_writtenAttachmentCount = writtenAttachments;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SignalStateChange();
|
||||||
|
|
||||||
|
if (writtenAttachments != _writtenAttachmentCount)
|
||||||
|
{
|
||||||
|
SignalAttachmentChange();
|
||||||
|
_writtenAttachmentCount = writtenAttachments;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetRenderTargetsInternal(ITexture[] colors, ITexture depthStencil, bool filterWriteMasked)
|
||||||
|
{
|
||||||
|
FramebufferParams?.UpdateModifications();
|
||||||
|
CreateFramebuffer(colors, depthStencil, filterWriteMasked);
|
||||||
|
CreateRenderPass();
|
||||||
|
SignalStateChange();
|
||||||
|
SignalAttachmentChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetRenderTargets(ITexture[] colors, ITexture depthStencil)
|
public void SetRenderTargets(ITexture[] colors, ITexture depthStencil)
|
||||||
{
|
{
|
||||||
FramebufferParams?.UpdateModifications();
|
_framebufferUsingColorWriteMask = false;
|
||||||
CreateFramebuffer(colors, depthStencil);
|
SetRenderTargetsInternal(colors, depthStencil, Gd.IsTBDR);
|
||||||
CreateRenderPass();
|
|
||||||
SignalStateChange();
|
|
||||||
SignalAttachmentChange();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetRenderTargetScale(float scale)
|
public void SetRenderTargetScale(float scale)
|
||||||
|
@ -1102,7 +1121,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
int vbSize = vertexBuffer.Buffer.Size;
|
int vbSize = vertexBuffer.Buffer.Size;
|
||||||
|
|
||||||
if (Gd.Vendor == Vendor.Amd && vertexBuffer.Stride > 0)
|
if (Gd.Vendor == Vendor.Amd && !Gd.IsMoltenVk && vertexBuffer.Stride > 0)
|
||||||
{
|
{
|
||||||
// AMD has a bug where if offset + stride * count is greater than
|
// AMD has a bug where if offset + stride * count is greater than
|
||||||
// the size, then the last attribute will have the wrong value.
|
// the size, then the last attribute will have the wrong value.
|
||||||
|
@ -1119,7 +1138,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
buffer.Dispose();
|
buffer.Dispose();
|
||||||
|
|
||||||
if ((vertexBuffer.Stride % FormatExtensions.MaxBufferFormatScalarSize) == 0)
|
if (!Gd.Capabilities.PortabilitySubset.HasFlag(PortabilitySubsetFlags.VertexBufferAlignment4B) &&
|
||||||
|
(vertexBuffer.Stride % FormatExtensions.MaxBufferFormatScalarSize) == 0)
|
||||||
{
|
{
|
||||||
buffer = new VertexBufferState(
|
buffer = new VertexBufferState(
|
||||||
vb,
|
vb,
|
||||||
|
@ -1259,8 +1279,62 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_currentPipelineHandle = 0;
|
_currentPipelineHandle = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateFramebuffer(ITexture[] colors, ITexture depthStencil)
|
private void CreateFramebuffer(ITexture[] colors, ITexture depthStencil, bool filterWriteMasked)
|
||||||
{
|
{
|
||||||
|
if (filterWriteMasked)
|
||||||
|
{
|
||||||
|
// TBDR GPUs don't work properly if the same attachment is bound to multiple targets,
|
||||||
|
// due to each attachment being a copy of the real attachment, rather than a direct write.
|
||||||
|
|
||||||
|
// Just try to remove duplicate attachments.
|
||||||
|
// Save a copy of the array to rebind when mask changes.
|
||||||
|
|
||||||
|
void maskOut()
|
||||||
|
{
|
||||||
|
if (!_framebufferUsingColorWriteMask)
|
||||||
|
{
|
||||||
|
_preMaskColors = colors.ToArray();
|
||||||
|
_preMaskDepthStencil = depthStencil;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If true, then the framebuffer must be recreated when the mask changes.
|
||||||
|
_framebufferUsingColorWriteMask = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for textures that are masked out.
|
||||||
|
|
||||||
|
for (int i = 0; i < colors.Length; i++)
|
||||||
|
{
|
||||||
|
if (colors[i] == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ref var vkBlend = ref _newState.Internal.ColorBlendAttachmentState[i];
|
||||||
|
|
||||||
|
for (int j = 0; j < i; j++)
|
||||||
|
{
|
||||||
|
// Check each binding for a duplicate binding before it.
|
||||||
|
|
||||||
|
if (colors[i] == colors[j])
|
||||||
|
{
|
||||||
|
// Prefer the binding with no write mask.
|
||||||
|
ref var vkBlend2 = ref _newState.Internal.ColorBlendAttachmentState[j];
|
||||||
|
if (vkBlend.ColorWriteMask == 0)
|
||||||
|
{
|
||||||
|
colors[i] = null;
|
||||||
|
maskOut();
|
||||||
|
}
|
||||||
|
else if (vkBlend2.ColorWriteMask == 0)
|
||||||
|
{
|
||||||
|
colors[j] = null;
|
||||||
|
maskOut();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FramebufferParams = new FramebufferParams(Device, colors, depthStencil);
|
FramebufferParams = new FramebufferParams(Device, colors, depthStencil);
|
||||||
UpdatePipelineAttachmentFormats();
|
UpdatePipelineAttachmentFormats();
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,6 +79,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
(int)FramebufferParams.Width,
|
(int)FramebufferParams.Width,
|
||||||
(int)FramebufferParams.Height,
|
(int)FramebufferParams.Height,
|
||||||
FramebufferParams.AttachmentFormats[index],
|
FramebufferParams.AttachmentFormats[index],
|
||||||
|
FramebufferParams.GetAttachmentComponentType(index),
|
||||||
ClearScissor);
|
ClearScissor);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
#version 450 core
|
||||||
|
|
||||||
|
layout (location = 0) in vec4 clear_colour;
|
||||||
|
layout (location = 0) out ivec4 colour;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
colour = floatBitsToInt(clear_colour);
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
#version 450 core
|
||||||
|
|
||||||
|
layout (location = 0) in vec4 clear_colour;
|
||||||
|
layout (location = 0) out uvec4 colour;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
colour = floatBitsToUint(clear_colour);
|
||||||
|
}
|
|
@ -431,7 +431,7 @@ namespace Ryujinx.Graphics.Vulkan.Shaders
|
||||||
0x3C, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
|
0x3C, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
|
||||||
};
|
};
|
||||||
|
|
||||||
public static readonly byte[] ColorClearFragmentShaderSource = new byte[]
|
public static readonly byte[] ColorClearFFragmentShaderSource = new byte[]
|
||||||
{
|
{
|
||||||
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x08, 0x00, 0x0D, 0x00, 0x00, 0x00,
|
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x08, 0x00, 0x0D, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00,
|
||||||
|
@ -459,6 +459,68 @@ namespace Ryujinx.Graphics.Vulkan.Shaders
|
||||||
0x0C, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
|
0x0C, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public static readonly byte[] ColorClearSIFragmentShaderSource = new byte[]
|
||||||
|
{
|
||||||
|
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x08, 0x00, 0x10, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00,
|
||||||
|
0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C, 0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||||
|
0x0F, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00,
|
||||||
|
0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||||
|
0xC2, 0x01, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x63, 0x6F, 0x6C, 0x6F,
|
||||||
|
0x75, 0x72, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x63, 0x6C, 0x65, 0x61,
|
||||||
|
0x72, 0x5F, 0x63, 0x6F, 0x6C, 0x6F, 0x75, 0x72, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
|
||||||
|
0x09, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
|
||||||
|
0x0D, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00,
|
||||||
|
0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||||
|
0x15, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||||
|
0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||||
|
0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
|
||||||
|
0x3B, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
|
||||||
|
0x16, 0x00, 0x03, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00,
|
||||||
|
0x0B, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
|
||||||
|
0x0C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00,
|
||||||
|
0x0C, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00,
|
||||||
|
0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
|
||||||
|
0xF8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00,
|
||||||
|
0x0E, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00,
|
||||||
|
0x0F, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00,
|
||||||
|
0x0F, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
public static readonly byte[] ColorClearUIFragmentShaderSource = new byte[]
|
||||||
|
{
|
||||||
|
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x08, 0x00, 0x10, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00,
|
||||||
|
0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C, 0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||||
|
0x0F, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00,
|
||||||
|
0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||||
|
0xC2, 0x01, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x63, 0x6F, 0x6C, 0x6F,
|
||||||
|
0x75, 0x72, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x63, 0x6C, 0x65, 0x61,
|
||||||
|
0x72, 0x5F, 0x63, 0x6F, 0x6C, 0x6F, 0x75, 0x72, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
|
||||||
|
0x09, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
|
||||||
|
0x0D, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00,
|
||||||
|
0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||||
|
0x15, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||||
|
0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
|
||||||
|
0x3B, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
|
||||||
|
0x16, 0x00, 0x03, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00,
|
||||||
|
0x0B, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
|
||||||
|
0x0C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00,
|
||||||
|
0x0C, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00,
|
||||||
|
0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
|
||||||
|
0xF8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00,
|
||||||
|
0x0E, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00,
|
||||||
|
0x0F, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00,
|
||||||
|
0x0F, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
public static readonly byte[] ColorClearVertexShaderSource = new byte[]
|
public static readonly byte[] ColorClearVertexShaderSource = new byte[]
|
||||||
{
|
{
|
||||||
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x08, 0x00, 0x36, 0x00, 0x00, 0x00,
|
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x08, 0x00, 0x36, 0x00, 0x00, 0x00,
|
||||||
|
|
|
@ -106,7 +106,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
flags |= ImageCreateFlags.CreateCubeCompatibleBit;
|
flags |= ImageCreateFlags.CreateCubeCompatibleBit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == ImageType.Type3D)
|
if (type == ImageType.Type3D && !gd.Capabilities.PortabilitySubset.HasFlag(PortabilitySubsetFlags.No3DImageView))
|
||||||
{
|
{
|
||||||
flags |= ImageCreateFlags.Create2DArrayCompatibleBit;
|
flags |= ImageCreateFlags.Create2DArrayCompatibleBit;
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,8 +94,14 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
var subresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, levels, (uint)firstLayer, layers);
|
var subresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, levels, (uint)firstLayer, layers);
|
||||||
var subresourceRangeDepth = new ImageSubresourceRange(aspectFlagsDepth, (uint)firstLevel, levels, (uint)firstLayer, layers);
|
var subresourceRangeDepth = new ImageSubresourceRange(aspectFlagsDepth, (uint)firstLevel, levels, (uint)firstLayer, layers);
|
||||||
|
|
||||||
unsafe Auto<DisposableImageView> CreateImageView(ComponentMapping cm, ImageSubresourceRange sr, ImageViewType viewType)
|
unsafe Auto<DisposableImageView> CreateImageView(ComponentMapping cm, ImageSubresourceRange sr, ImageViewType viewType, ImageUsageFlags usageFlags = 0)
|
||||||
{
|
{
|
||||||
|
var usage = new ImageViewUsageCreateInfo()
|
||||||
|
{
|
||||||
|
SType = StructureType.ImageViewUsageCreateInfo,
|
||||||
|
Usage = usageFlags
|
||||||
|
};
|
||||||
|
|
||||||
var imageCreateInfo = new ImageViewCreateInfo()
|
var imageCreateInfo = new ImageViewCreateInfo()
|
||||||
{
|
{
|
||||||
SType = StructureType.ImageViewCreateInfo,
|
SType = StructureType.ImageViewCreateInfo,
|
||||||
|
@ -103,7 +109,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
ViewType = viewType,
|
ViewType = viewType,
|
||||||
Format = format,
|
Format = format,
|
||||||
Components = cm,
|
Components = cm,
|
||||||
SubresourceRange = sr
|
SubresourceRange = sr,
|
||||||
|
PNext = usageFlags == 0 ? null : &usage
|
||||||
};
|
};
|
||||||
|
|
||||||
gd.Api.CreateImageView(device, imageCreateInfo, null, out var imageView).ThrowOnError();
|
gd.Api.CreateImageView(device, imageCreateInfo, null, out var imageView).ThrowOnError();
|
||||||
|
@ -124,9 +131,21 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
// Framebuffer attachments also require 3D textures to be bound as 2D array.
|
// Framebuffer attachments also require 3D textures to be bound as 2D array.
|
||||||
if (info.Target == Target.Texture3D)
|
if (info.Target == Target.Texture3D)
|
||||||
{
|
{
|
||||||
subresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, levels, (uint)firstLayer, (uint)info.Depth);
|
if (gd.Capabilities.PortabilitySubset.HasFlag(PortabilitySubsetFlags.No3DImageView))
|
||||||
|
{
|
||||||
|
if (levels == 1 && (info.Format.IsRtColorCompatible() || info.Format.IsDepthOrStencil()))
|
||||||
|
{
|
||||||
|
subresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, levels, (uint)firstLayer, 1);
|
||||||
|
|
||||||
_imageView2dArray = CreateImageView(identityComponentMapping, subresourceRange, ImageViewType.Type2DArray);
|
_imageView2dArray = CreateImageView(identityComponentMapping, subresourceRange, ImageViewType.Type2D, ImageUsageFlags.ColorAttachmentBit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
subresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, levels, (uint)firstLayer, (uint)info.Depth);
|
||||||
|
|
||||||
|
_imageView2dArray = CreateImageView(identityComponentMapping, subresourceRange, ImageViewType.Type2DArray);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Valid = true;
|
Valid = true;
|
||||||
|
@ -353,7 +372,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
|
|
||||||
if (VulkanConfiguration.UseSlowSafeBlitOnAmd &&
|
if (VulkanConfiguration.UseSlowSafeBlitOnAmd &&
|
||||||
_gd.Vendor == Vendor.Amd &&
|
(_gd.Vendor == Vendor.Amd || _gd.IsMoltenVk) &&
|
||||||
src.Info.Target == Target.Texture2D &&
|
src.Info.Target == Target.Texture2D &&
|
||||||
dst.Info.Target == Target.Texture2D &&
|
dst.Info.Target == Target.Texture2D &&
|
||||||
!dst.Info.Format.IsDepthOrStencil())
|
!dst.Info.Format.IsDepthOrStencil())
|
||||||
|
|
|
@ -5,9 +5,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
enum Vendor
|
enum Vendor
|
||||||
{
|
{
|
||||||
Amd,
|
Amd,
|
||||||
|
ImgTec,
|
||||||
Intel,
|
Intel,
|
||||||
Nvidia,
|
Nvidia,
|
||||||
|
ARM,
|
||||||
Qualcomm,
|
Qualcomm,
|
||||||
|
Apple,
|
||||||
Unknown
|
Unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +24,10 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
return id switch
|
return id switch
|
||||||
{
|
{
|
||||||
0x1002 => Vendor.Amd,
|
0x1002 => Vendor.Amd,
|
||||||
|
0x1010 => Vendor.ImgTec,
|
||||||
|
0x106B => Vendor.Apple,
|
||||||
0x10DE => Vendor.Nvidia,
|
0x10DE => Vendor.Nvidia,
|
||||||
|
0x13B5 => Vendor.ARM,
|
||||||
0x8086 => Vendor.Intel,
|
0x8086 => Vendor.Intel,
|
||||||
0x5143 => Vendor.Qualcomm,
|
0x5143 => Vendor.Qualcomm,
|
||||||
_ => Vendor.Unknown
|
_ => Vendor.Unknown
|
||||||
|
@ -34,6 +40,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
0x1002 => "AMD",
|
0x1002 => "AMD",
|
||||||
0x1010 => "ImgTec",
|
0x1010 => "ImgTec",
|
||||||
|
0x106B => "Apple",
|
||||||
0x10DE => "NVIDIA",
|
0x10DE => "NVIDIA",
|
||||||
0x13B5 => "ARM",
|
0x13B5 => "ARM",
|
||||||
0x1AE0 => "Google",
|
0x1AE0 => "Google",
|
||||||
|
|
|
@ -82,9 +82,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
|
|
||||||
_buffer = autoBuffer;
|
_buffer = autoBuffer;
|
||||||
}
|
|
||||||
|
|
||||||
state.Internal.VertexBindingDescriptions[DescriptorIndex].Stride = (uint)_stride;
|
state.Internal.VertexBindingDescriptions[DescriptorIndex].Stride = (uint)stride;
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -389,6 +389,18 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
features2.PNext = &featuresCustomBorderColorSupported;
|
features2.PNext = &featuresCustomBorderColorSupported;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PhysicalDeviceRobustness2FeaturesEXT supportedFeaturesRobustness2 = new PhysicalDeviceRobustness2FeaturesEXT()
|
||||||
|
{
|
||||||
|
SType = StructureType.PhysicalDeviceRobustness2FeaturesExt
|
||||||
|
};
|
||||||
|
|
||||||
|
if (supportedExtensions.Contains("VK_EXT_robustness2"))
|
||||||
|
{
|
||||||
|
supportedFeaturesRobustness2.PNext = features2.PNext;
|
||||||
|
|
||||||
|
features2.PNext = &supportedFeaturesRobustness2;
|
||||||
|
}
|
||||||
|
|
||||||
api.GetPhysicalDeviceFeatures2(physicalDevice, &features2);
|
api.GetPhysicalDeviceFeatures2(physicalDevice, &features2);
|
||||||
|
|
||||||
var supportedFeatures = features2.Features;
|
var supportedFeatures = features2.Features;
|
||||||
|
@ -428,14 +440,17 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
pExtendedFeatures = &featuresTransformFeedback;
|
pExtendedFeatures = &featuresTransformFeedback;
|
||||||
|
|
||||||
var featuresRobustness2 = new PhysicalDeviceRobustness2FeaturesEXT()
|
if (supportedExtensions.Contains("VK_EXT_robustness2"))
|
||||||
{
|
{
|
||||||
SType = StructureType.PhysicalDeviceRobustness2FeaturesExt,
|
var featuresRobustness2 = new PhysicalDeviceRobustness2FeaturesEXT()
|
||||||
PNext = pExtendedFeatures,
|
{
|
||||||
NullDescriptor = true
|
SType = StructureType.PhysicalDeviceRobustness2FeaturesExt,
|
||||||
};
|
PNext = pExtendedFeatures,
|
||||||
|
NullDescriptor = supportedFeaturesRobustness2.NullDescriptor
|
||||||
|
};
|
||||||
|
|
||||||
pExtendedFeatures = &featuresRobustness2;
|
pExtendedFeatures = &featuresRobustness2;
|
||||||
|
}
|
||||||
|
|
||||||
var featuresExtendedDynamicState = new PhysicalDeviceExtendedDynamicStateFeaturesEXT()
|
var featuresExtendedDynamicState = new PhysicalDeviceExtendedDynamicStateFeaturesEXT()
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,6 +3,7 @@ using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.Shader;
|
using Ryujinx.Graphics.Shader;
|
||||||
using Ryujinx.Graphics.Shader.Translation;
|
using Ryujinx.Graphics.Shader.Translation;
|
||||||
|
using Ryujinx.Graphics.Vulkan.MoltenVK;
|
||||||
using Ryujinx.Graphics.Vulkan.Queries;
|
using Ryujinx.Graphics.Vulkan.Queries;
|
||||||
using Silk.NET.Vulkan;
|
using Silk.NET.Vulkan;
|
||||||
using Silk.NET.Vulkan.Extensions.EXT;
|
using Silk.NET.Vulkan.Extensions.EXT;
|
||||||
|
@ -77,6 +78,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
internal bool IsAmdWindows { get; private set; }
|
internal bool IsAmdWindows { get; private set; }
|
||||||
internal bool IsIntelWindows { get; private set; }
|
internal bool IsIntelWindows { get; private set; }
|
||||||
internal bool IsAmdGcn { get; private set; }
|
internal bool IsAmdGcn { get; private set; }
|
||||||
|
internal bool IsMoltenVk { get; private set; }
|
||||||
|
internal bool IsTBDR { get; private set; }
|
||||||
public string GpuVendor { get; private set; }
|
public string GpuVendor { get; private set; }
|
||||||
public string GpuRenderer { get; private set; }
|
public string GpuRenderer { get; private set; }
|
||||||
public string GpuVersion { get; private set; }
|
public string GpuVersion { get; private set; }
|
||||||
|
@ -93,6 +96,14 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
Shaders = new HashSet<ShaderCollection>();
|
Shaders = new HashSet<ShaderCollection>();
|
||||||
Textures = new HashSet<ITexture>();
|
Textures = new HashSet<ITexture>();
|
||||||
Samplers = new HashSet<SamplerHolder>();
|
Samplers = new HashSet<SamplerHolder>();
|
||||||
|
|
||||||
|
if (OperatingSystem.IsMacOS())
|
||||||
|
{
|
||||||
|
MVKInitialization.Initialize();
|
||||||
|
|
||||||
|
// Any device running on MacOS is using MoltenVK, even Intel and AMD vendors.
|
||||||
|
IsMoltenVk = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private unsafe void LoadFeatures(string[] supportedExtensions, uint maxQueueCount, uint queueFamilyIndex)
|
private unsafe void LoadFeatures(string[] supportedExtensions, uint maxQueueCount, uint queueFamilyIndex)
|
||||||
|
@ -161,7 +172,10 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
properties2.PNext = &propertiesTransformFeedback;
|
properties2.PNext = &propertiesTransformFeedback;
|
||||||
}
|
}
|
||||||
|
|
||||||
Api.GetPhysicalDeviceProperties2(_physicalDevice, &properties2);
|
PhysicalDevicePortabilitySubsetPropertiesKHR propertiesPortabilitySubset = new PhysicalDevicePortabilitySubsetPropertiesKHR()
|
||||||
|
{
|
||||||
|
SType = StructureType.PhysicalDevicePortabilitySubsetPropertiesKhr
|
||||||
|
};
|
||||||
|
|
||||||
PhysicalDeviceFeatures2 features2 = new PhysicalDeviceFeatures2()
|
PhysicalDeviceFeatures2 features2 = new PhysicalDeviceFeatures2()
|
||||||
{
|
{
|
||||||
|
@ -183,6 +197,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
SType = StructureType.PhysicalDeviceCustomBorderColorFeaturesExt
|
SType = StructureType.PhysicalDeviceCustomBorderColorFeaturesExt
|
||||||
};
|
};
|
||||||
|
|
||||||
|
PhysicalDevicePortabilitySubsetFeaturesKHR featuresPortabilitySubset = new PhysicalDevicePortabilitySubsetFeaturesKHR()
|
||||||
|
{
|
||||||
|
SType = StructureType.PhysicalDevicePortabilitySubsetFeaturesKhr
|
||||||
|
};
|
||||||
|
|
||||||
if (supportedExtensions.Contains("VK_EXT_robustness2"))
|
if (supportedExtensions.Contains("VK_EXT_robustness2"))
|
||||||
{
|
{
|
||||||
features2.PNext = &featuresRobustness2;
|
features2.PNext = &featuresRobustness2;
|
||||||
|
@ -200,8 +219,31 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
features2.PNext = &featuresCustomBorderColor;
|
features2.PNext = &featuresCustomBorderColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool usePortability = supportedExtensions.Contains("VK_KHR_portability_subset");
|
||||||
|
|
||||||
|
if (usePortability)
|
||||||
|
{
|
||||||
|
propertiesPortabilitySubset.PNext = properties2.PNext;
|
||||||
|
properties2.PNext = &propertiesPortabilitySubset;
|
||||||
|
|
||||||
|
featuresPortabilitySubset.PNext = features2.PNext;
|
||||||
|
features2.PNext = &featuresPortabilitySubset;
|
||||||
|
}
|
||||||
|
|
||||||
|
Api.GetPhysicalDeviceProperties2(_physicalDevice, &properties2);
|
||||||
Api.GetPhysicalDeviceFeatures2(_physicalDevice, &features2);
|
Api.GetPhysicalDeviceFeatures2(_physicalDevice, &features2);
|
||||||
|
|
||||||
|
var portabilityFlags = PortabilitySubsetFlags.None;
|
||||||
|
|
||||||
|
if (usePortability)
|
||||||
|
{
|
||||||
|
portabilityFlags |= propertiesPortabilitySubset.MinVertexInputBindingStrideAlignment > 1 ? PortabilitySubsetFlags.VertexBufferAlignment4B : 0;
|
||||||
|
portabilityFlags |= featuresPortabilitySubset.TriangleFans ? 0 : PortabilitySubsetFlags.NoTriangleFans;
|
||||||
|
portabilityFlags |= featuresPortabilitySubset.PointPolygons ? 0 : PortabilitySubsetFlags.NoPointMode;
|
||||||
|
portabilityFlags |= featuresPortabilitySubset.ImageView2DOn3DImage ? 0 : PortabilitySubsetFlags.No3DImageView;
|
||||||
|
portabilityFlags |= featuresPortabilitySubset.SamplerMipLodBias ? 0 : PortabilitySubsetFlags.NoLodBias;
|
||||||
|
}
|
||||||
|
|
||||||
bool customBorderColorSupported = supportedExtensions.Contains("VK_EXT_custom_border_color") &&
|
bool customBorderColorSupported = supportedExtensions.Contains("VK_EXT_custom_border_color") &&
|
||||||
featuresCustomBorderColor.CustomBorderColors &&
|
featuresCustomBorderColor.CustomBorderColors &&
|
||||||
featuresCustomBorderColor.CustomBorderColorWithoutFormat;
|
featuresCustomBorderColor.CustomBorderColorWithoutFormat;
|
||||||
|
@ -224,7 +266,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
supportedExtensions.Contains(ExtConditionalRendering.ExtensionName),
|
supportedExtensions.Contains(ExtConditionalRendering.ExtensionName),
|
||||||
supportedExtensions.Contains(ExtExtendedDynamicState.ExtensionName),
|
supportedExtensions.Contains(ExtExtendedDynamicState.ExtensionName),
|
||||||
features2.Features.MultiViewport,
|
features2.Features.MultiViewport,
|
||||||
featuresRobustness2.NullDescriptor,
|
featuresRobustness2.NullDescriptor || IsMoltenVk,
|
||||||
supportedExtensions.Contains(KhrPushDescriptor.ExtensionName),
|
supportedExtensions.Contains(KhrPushDescriptor.ExtensionName),
|
||||||
supportsTransformFeedback,
|
supportsTransformFeedback,
|
||||||
propertiesTransformFeedback.TransformFeedbackQueries,
|
propertiesTransformFeedback.TransformFeedbackQueries,
|
||||||
|
@ -232,7 +274,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
propertiesSubgroupSizeControl.MinSubgroupSize,
|
propertiesSubgroupSizeControl.MinSubgroupSize,
|
||||||
propertiesSubgroupSizeControl.MaxSubgroupSize,
|
propertiesSubgroupSizeControl.MaxSubgroupSize,
|
||||||
propertiesSubgroupSizeControl.RequiredSubgroupSizeStages,
|
propertiesSubgroupSizeControl.RequiredSubgroupSizeStages,
|
||||||
supportedSampleCounts);
|
supportedSampleCounts,
|
||||||
|
portabilityFlags);
|
||||||
|
|
||||||
MemoryAllocator = new MemoryAllocator(Api, _device, properties.Limits.MaxMemoryAllocationCount);
|
MemoryAllocator = new MemoryAllocator(Api, _device, properties.Limits.MaxMemoryAllocationCount);
|
||||||
|
|
||||||
|
@ -413,6 +456,36 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
bool supportsR4G4B4A4Format = FormatCapabilities.OptimalFormatsSupport(compressedFormatFeatureFlags,
|
bool supportsR4G4B4A4Format = FormatCapabilities.OptimalFormatsSupport(compressedFormatFeatureFlags,
|
||||||
GAL.Format.R4G4B4A4Unorm);
|
GAL.Format.R4G4B4A4Unorm);
|
||||||
|
|
||||||
|
bool supportsAstcFormats = FormatCapabilities.OptimalFormatsSupport(compressedFormatFeatureFlags,
|
||||||
|
GAL.Format.Astc4x4Unorm,
|
||||||
|
GAL.Format.Astc5x4Unorm,
|
||||||
|
GAL.Format.Astc5x5Unorm,
|
||||||
|
GAL.Format.Astc6x5Unorm,
|
||||||
|
GAL.Format.Astc6x6Unorm,
|
||||||
|
GAL.Format.Astc8x5Unorm,
|
||||||
|
GAL.Format.Astc8x6Unorm,
|
||||||
|
GAL.Format.Astc8x8Unorm,
|
||||||
|
GAL.Format.Astc10x5Unorm,
|
||||||
|
GAL.Format.Astc10x6Unorm,
|
||||||
|
GAL.Format.Astc10x8Unorm,
|
||||||
|
GAL.Format.Astc10x10Unorm,
|
||||||
|
GAL.Format.Astc12x10Unorm,
|
||||||
|
GAL.Format.Astc12x12Unorm,
|
||||||
|
GAL.Format.Astc4x4Srgb,
|
||||||
|
GAL.Format.Astc5x4Srgb,
|
||||||
|
GAL.Format.Astc5x5Srgb,
|
||||||
|
GAL.Format.Astc6x5Srgb,
|
||||||
|
GAL.Format.Astc6x6Srgb,
|
||||||
|
GAL.Format.Astc8x5Srgb,
|
||||||
|
GAL.Format.Astc8x6Srgb,
|
||||||
|
GAL.Format.Astc8x8Srgb,
|
||||||
|
GAL.Format.Astc10x5Srgb,
|
||||||
|
GAL.Format.Astc10x6Srgb,
|
||||||
|
GAL.Format.Astc10x8Srgb,
|
||||||
|
GAL.Format.Astc10x10Srgb,
|
||||||
|
GAL.Format.Astc12x10Srgb,
|
||||||
|
GAL.Format.Astc12x12Srgb);
|
||||||
|
|
||||||
PhysicalDeviceVulkan12Features featuresVk12 = new PhysicalDeviceVulkan12Features()
|
PhysicalDeviceVulkan12Features featuresVk12 = new PhysicalDeviceVulkan12Features()
|
||||||
{
|
{
|
||||||
SType = StructureType.PhysicalDeviceVulkan12Features
|
SType = StructureType.PhysicalDeviceVulkan12Features
|
||||||
|
@ -434,7 +507,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
GpuVendor,
|
GpuVendor,
|
||||||
hasFrontFacingBug: IsIntelWindows,
|
hasFrontFacingBug: IsIntelWindows,
|
||||||
hasVectorIndexingBug: Vendor == Vendor.Qualcomm,
|
hasVectorIndexingBug: Vendor == Vendor.Qualcomm,
|
||||||
supportsAstcCompression: features2.Features.TextureCompressionAstcLdr,
|
needsFragmentOutputSpecialization: IsMoltenVk,
|
||||||
|
reduceShaderPrecision: IsMoltenVk,
|
||||||
|
supportsAstcCompression: features2.Features.TextureCompressionAstcLdr && supportsAstcFormats,
|
||||||
supportsBc123Compression: supportsBc123CompressionFormat,
|
supportsBc123Compression: supportsBc123CompressionFormat,
|
||||||
supportsBc45Compression: supportsBc45CompressionFormat,
|
supportsBc45Compression: supportsBc45CompressionFormat,
|
||||||
supportsBc67Compression: supportsBc67CompressionFormat,
|
supportsBc67Compression: supportsBc67CompressionFormat,
|
||||||
|
@ -515,12 +590,13 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
IsAmdWindows = Vendor == Vendor.Amd && RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
IsAmdWindows = Vendor == Vendor.Amd && RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||||
IsIntelWindows = Vendor == Vendor.Intel && RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
IsIntelWindows = Vendor == Vendor.Intel && RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||||
|
IsTBDR = IsMoltenVk || Vendor == Vendor.Qualcomm || Vendor == Vendor.ARM || Vendor == Vendor.ImgTec;
|
||||||
|
|
||||||
GpuVendor = vendorName;
|
GpuVendor = vendorName;
|
||||||
GpuRenderer = Marshal.PtrToStringAnsi((IntPtr)properties.DeviceName);
|
GpuRenderer = Marshal.PtrToStringAnsi((IntPtr)properties.DeviceName);
|
||||||
GpuVersion = $"Vulkan v{ParseStandardVulkanVersion(properties.ApiVersion)}, Driver v{ParseDriverVersion(ref properties)}";
|
GpuVersion = $"Vulkan v{ParseStandardVulkanVersion(properties.ApiVersion)}, Driver v{ParseDriverVersion(ref properties)}";
|
||||||
|
|
||||||
IsAmdGcn = Vendor == Vendor.Amd && VendorUtils.AmdGcnRegex().IsMatch(GpuRenderer);
|
IsAmdGcn = !IsMoltenVk && Vendor == Vendor.Amd && VendorUtils.AmdGcnRegex().IsMatch(GpuRenderer);
|
||||||
|
|
||||||
Logger.Notice.Print(LogClass.Gpu, $"{GpuVendor} {GpuRenderer} ({GpuVersion})");
|
Logger.Notice.Print(LogClass.Gpu, $"{GpuVendor} {GpuRenderer} ({GpuVersion})");
|
||||||
}
|
}
|
||||||
|
@ -531,6 +607,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
GAL.PrimitiveTopology.Quads => GAL.PrimitiveTopology.Triangles,
|
GAL.PrimitiveTopology.Quads => GAL.PrimitiveTopology.Triangles,
|
||||||
GAL.PrimitiveTopology.QuadStrip => GAL.PrimitiveTopology.TriangleStrip,
|
GAL.PrimitiveTopology.QuadStrip => GAL.PrimitiveTopology.TriangleStrip,
|
||||||
|
GAL.PrimitiveTopology.TriangleFan => Capabilities.PortabilitySubset.HasFlag(PortabilitySubsetFlags.NoTriangleFans) ? GAL.PrimitiveTopology.Triangles : topology,
|
||||||
_ => topology
|
_ => topology
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -540,6 +617,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
return topology switch
|
return topology switch
|
||||||
{
|
{
|
||||||
GAL.PrimitiveTopology.Quads => true,
|
GAL.PrimitiveTopology.Quads => true,
|
||||||
|
GAL.PrimitiveTopology.TriangleFan => Capabilities.PortabilitySubset.HasFlag(PortabilitySubsetFlags.NoTriangleFans),
|
||||||
_ => false
|
_ => false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -553,7 +631,13 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
public bool NeedsVertexBufferAlignment(int attrScalarAlignment, out int alignment)
|
public bool NeedsVertexBufferAlignment(int attrScalarAlignment, out int alignment)
|
||||||
{
|
{
|
||||||
if (Vendor != Vendor.Nvidia)
|
if (Capabilities.PortabilitySubset.HasFlag(PortabilitySubsetFlags.VertexBufferAlignment4B))
|
||||||
|
{
|
||||||
|
alignment = 4;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (Vendor != Vendor.Nvidia)
|
||||||
{
|
{
|
||||||
// Vulkan requires that vertex attributes are globally aligned by their component size,
|
// Vulkan requires that vertex attributes are globally aligned by their component size,
|
||||||
// so buffer strides that don't divide by the largest scalar element are invalid.
|
// so buffer strides that don't divide by the largest scalar element are invalid.
|
||||||
|
|
Loading…
Reference in a new issue