Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
c95be55091 | ||
|
63dedbda86 | ||
|
c532118d94 | ||
|
52d6f2e656 |
@@ -44,7 +44,7 @@
|
|||||||
<PackageVersion Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta11" />
|
<PackageVersion Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta11" />
|
||||||
<PackageVersion Include="SPB" Version="0.0.4-build28" />
|
<PackageVersion Include="SPB" Version="0.0.4-build28" />
|
||||||
<PackageVersion Include="System.Drawing.Common" Version="7.0.0" />
|
<PackageVersion Include="System.Drawing.Common" Version="7.0.0" />
|
||||||
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.27.0" />
|
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.28.1" />
|
||||||
<PackageVersion Include="System.IO.Hashing" Version="7.0.0" />
|
<PackageVersion Include="System.IO.Hashing" Version="7.0.0" />
|
||||||
<PackageVersion Include="System.Management" Version="7.0.0" />
|
<PackageVersion Include="System.Management" Version="7.0.0" />
|
||||||
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
|
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
|
||||||
|
@@ -38,4 +38,25 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
Src1AlphaGl = 0xc902,
|
Src1AlphaGl = 0xc902,
|
||||||
OneMinusSrc1AlphaGl = 0xc903
|
OneMinusSrc1AlphaGl = 0xc903
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class BlendFactorExtensions
|
||||||
|
{
|
||||||
|
public static bool IsDualSource(this BlendFactor factor)
|
||||||
|
{
|
||||||
|
switch (factor)
|
||||||
|
{
|
||||||
|
case BlendFactor.Src1Color:
|
||||||
|
case BlendFactor.Src1ColorGl:
|
||||||
|
case BlendFactor.Src1Alpha:
|
||||||
|
case BlendFactor.Src1AlphaGl:
|
||||||
|
case BlendFactor.OneMinusSrc1Color:
|
||||||
|
case BlendFactor.OneMinusSrc1ColorGl:
|
||||||
|
case BlendFactor.OneMinusSrc1Alpha:
|
||||||
|
case BlendFactor.OneMinusSrc1AlphaGl:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@@ -328,5 +328,19 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
Signal();
|
Signal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the dual-source blend enabled state.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="enabled">True if blending is enabled and using dual-source blend</param>
|
||||||
|
public void SetDualSourceBlendEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
if (enabled != _graphics.DualSourceBlendEnable)
|
||||||
|
{
|
||||||
|
_graphics.DualSourceBlendEnable = enabled;
|
||||||
|
|
||||||
|
Signal();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1183,6 +1183,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
bool blendIndependent = _state.State.BlendIndependent;
|
bool blendIndependent = _state.State.BlendIndependent;
|
||||||
ColorF blendConstant = _state.State.BlendConstant;
|
ColorF blendConstant = _state.State.BlendConstant;
|
||||||
|
|
||||||
|
bool dualSourceBlendEnabled = false;
|
||||||
|
|
||||||
if (blendIndependent)
|
if (blendIndependent)
|
||||||
{
|
{
|
||||||
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
||||||
@@ -1200,6 +1202,15 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
FilterBlendFactor(blend.AlphaSrcFactor, index),
|
FilterBlendFactor(blend.AlphaSrcFactor, index),
|
||||||
FilterBlendFactor(blend.AlphaDstFactor, index));
|
FilterBlendFactor(blend.AlphaDstFactor, index));
|
||||||
|
|
||||||
|
if (enable &&
|
||||||
|
(blend.ColorSrcFactor.IsDualSource() ||
|
||||||
|
blend.ColorDstFactor.IsDualSource() ||
|
||||||
|
blend.AlphaSrcFactor.IsDualSource() ||
|
||||||
|
blend.AlphaDstFactor.IsDualSource()))
|
||||||
|
{
|
||||||
|
dualSourceBlendEnabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
_pipeline.BlendDescriptors[index] = descriptor;
|
_pipeline.BlendDescriptors[index] = descriptor;
|
||||||
_context.Renderer.Pipeline.SetBlendState(index, descriptor);
|
_context.Renderer.Pipeline.SetBlendState(index, descriptor);
|
||||||
}
|
}
|
||||||
@@ -1219,12 +1230,23 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
FilterBlendFactor(blend.AlphaSrcFactor, 0),
|
FilterBlendFactor(blend.AlphaSrcFactor, 0),
|
||||||
FilterBlendFactor(blend.AlphaDstFactor, 0));
|
FilterBlendFactor(blend.AlphaDstFactor, 0));
|
||||||
|
|
||||||
|
if (enable &&
|
||||||
|
(blend.ColorSrcFactor.IsDualSource() ||
|
||||||
|
blend.ColorDstFactor.IsDualSource() ||
|
||||||
|
blend.AlphaSrcFactor.IsDualSource() ||
|
||||||
|
blend.AlphaDstFactor.IsDualSource()))
|
||||||
|
{
|
||||||
|
dualSourceBlendEnabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
||||||
{
|
{
|
||||||
_pipeline.BlendDescriptors[index] = descriptor;
|
_pipeline.BlendDescriptors[index] = descriptor;
|
||||||
_context.Renderer.Pipeline.SetBlendState(index, descriptor);
|
_context.Renderer.Pipeline.SetBlendState(index, descriptor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_currentSpecState.SetDualSourceBlendEnabled(dualSourceBlendEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -141,6 +141,12 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
return _oldSpecState.GraphicsState.HasConstantBufferDrawParameters;
|
return _oldSpecState.GraphicsState.HasConstantBufferDrawParameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public bool QueryDualSourceBlendEnable()
|
||||||
|
{
|
||||||
|
return _oldSpecState.GraphicsState.DualSourceBlendEnable;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public InputTopology QueryPrimitiveTopology()
|
public InputTopology QueryPrimitiveTopology()
|
||||||
{
|
{
|
||||||
|
@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
private const ushort FileFormatVersionMajor = 1;
|
private const ushort FileFormatVersionMajor = 1;
|
||||||
private const ushort FileFormatVersionMinor = 2;
|
private const ushort FileFormatVersionMinor = 2;
|
||||||
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
||||||
private const uint CodeGenVersion = 4368;
|
private const uint CodeGenVersion = 4404;
|
||||||
|
|
||||||
private const string SharedTocFileName = "shared.toc";
|
private const string SharedTocFileName = "shared.toc";
|
||||||
private const string SharedDataFileName = "shared.data";
|
private const string SharedDataFileName = "shared.data";
|
||||||
|
@@ -157,6 +157,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
return _state.GraphicsState.HasUnalignedStorageBuffer || _state.ComputeState.HasUnalignedStorageBuffer;
|
return _state.GraphicsState.HasUnalignedStorageBuffer || _state.ComputeState.HasUnalignedStorageBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public bool QueryDualSourceBlendEnable()
|
||||||
|
{
|
||||||
|
return _state.GraphicsState.DualSourceBlendEnable;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public InputTopology QueryPrimitiveTopology()
|
public InputTopology QueryPrimitiveTopology()
|
||||||
{
|
{
|
||||||
|
@@ -92,6 +92,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Array8<AttributeType> FragmentOutputTypes;
|
public Array8<AttributeType> FragmentOutputTypes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates whether dual source blend is enabled.
|
||||||
|
/// </summary>
|
||||||
|
public bool DualSourceBlendEnable;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new GPU graphics state.
|
/// Creates a new GPU graphics state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -111,6 +116,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
/// <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>
|
/// <param name="fragmentOutputTypes">Type of the fragment shader outputs</param>
|
||||||
|
/// <param name="dualSourceBlendEnable">Type of the vertex attributes consumed by the shader</param>
|
||||||
public GpuChannelGraphicsState(
|
public GpuChannelGraphicsState(
|
||||||
bool earlyZForce,
|
bool earlyZForce,
|
||||||
PrimitiveTopology topology,
|
PrimitiveTopology topology,
|
||||||
@@ -127,7 +133,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
ref Array32<AttributeType> attributeTypes,
|
ref Array32<AttributeType> attributeTypes,
|
||||||
bool hasConstantBufferDrawParameters,
|
bool hasConstantBufferDrawParameters,
|
||||||
bool hasUnalignedStorageBuffer,
|
bool hasUnalignedStorageBuffer,
|
||||||
ref Array8<AttributeType> fragmentOutputTypes)
|
ref Array8<AttributeType> fragmentOutputTypes,
|
||||||
|
bool dualSourceBlendEnable)
|
||||||
{
|
{
|
||||||
EarlyZForce = earlyZForce;
|
EarlyZForce = earlyZForce;
|
||||||
Topology = topology;
|
Topology = topology;
|
||||||
@@ -145,6 +152,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
HasConstantBufferDrawParameters = hasConstantBufferDrawParameters;
|
HasConstantBufferDrawParameters = hasConstantBufferDrawParameters;
|
||||||
HasUnalignedStorageBuffer = hasUnalignedStorageBuffer;
|
HasUnalignedStorageBuffer = hasUnalignedStorageBuffer;
|
||||||
FragmentOutputTypes = fragmentOutputTypes;
|
FragmentOutputTypes = fragmentOutputTypes;
|
||||||
|
DualSourceBlendEnable = dualSourceBlendEnable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -535,6 +535,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (graphicsState.DualSourceBlendEnable != GraphicsState.DualSourceBlendEnable)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return Matches(channel, ref poolState, checkTextures, isCompute: false);
|
return Matches(channel, ref poolState, checkTextures, isCompute: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -833,31 +833,13 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
(BlendingFactorSrc)blend.AlphaSrcFactor.Convert(),
|
(BlendingFactorSrc)blend.AlphaSrcFactor.Convert(),
|
||||||
(BlendingFactorDest)blend.AlphaDstFactor.Convert());
|
(BlendingFactorDest)blend.AlphaDstFactor.Convert());
|
||||||
|
|
||||||
static bool IsDualSource(BlendFactor factor)
|
|
||||||
{
|
|
||||||
switch (factor)
|
|
||||||
{
|
|
||||||
case BlendFactor.Src1Color:
|
|
||||||
case BlendFactor.Src1ColorGl:
|
|
||||||
case BlendFactor.Src1Alpha:
|
|
||||||
case BlendFactor.Src1AlphaGl:
|
|
||||||
case BlendFactor.OneMinusSrc1Color:
|
|
||||||
case BlendFactor.OneMinusSrc1ColorGl:
|
|
||||||
case BlendFactor.OneMinusSrc1Alpha:
|
|
||||||
case BlendFactor.OneMinusSrc1AlphaGl:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
EnsureFramebuffer();
|
EnsureFramebuffer();
|
||||||
|
|
||||||
_framebuffer.SetDualSourceBlend(
|
_framebuffer.SetDualSourceBlend(
|
||||||
IsDualSource(blend.ColorSrcFactor) ||
|
blend.ColorSrcFactor.IsDualSource() ||
|
||||||
IsDualSource(blend.ColorDstFactor) ||
|
blend.ColorDstFactor.IsDualSource() ||
|
||||||
IsDualSource(blend.AlphaSrcFactor) ||
|
blend.AlphaSrcFactor.IsDualSource() ||
|
||||||
IsDualSource(blend.AlphaDstFactor));
|
blend.AlphaDstFactor.IsDualSource());
|
||||||
|
|
||||||
if (_blendConstant != blend.BlendConstant)
|
if (_blendConstant != blend.BlendConstant)
|
||||||
{
|
{
|
||||||
|
@@ -612,6 +612,19 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
int usedAttributes = context.Config.UsedOutputAttributes;
|
int usedAttributes = context.Config.UsedOutputAttributes;
|
||||||
|
|
||||||
|
if (context.Config.Stage == ShaderStage.Fragment && context.Config.GpuAccessor.QueryDualSourceBlendEnable())
|
||||||
|
{
|
||||||
|
int firstOutput = BitOperations.TrailingZeroCount(usedAttributes);
|
||||||
|
int mask = 3 << firstOutput;
|
||||||
|
|
||||||
|
if ((usedAttributes & mask) == mask)
|
||||||
|
{
|
||||||
|
usedAttributes &= ~mask;
|
||||||
|
DeclareOutputDualSourceBlendAttribute(context, firstOutput);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while (usedAttributes != 0)
|
while (usedAttributes != 0)
|
||||||
{
|
{
|
||||||
int index = BitOperations.TrailingZeroCount(usedAttributes);
|
int index = BitOperations.TrailingZeroCount(usedAttributes);
|
||||||
@@ -690,6 +703,15 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void DeclareOutputDualSourceBlendAttribute(CodeGenContext context, int attr)
|
||||||
|
{
|
||||||
|
string name = $"{DefaultNames.OAttributePrefix}{attr}";
|
||||||
|
string name2 = $"{DefaultNames.OAttributePrefix}{(attr + 1)}";
|
||||||
|
|
||||||
|
context.AppendLine($"layout (location = {attr}, index = 0) out vec4 {name};");
|
||||||
|
context.AppendLine($"layout (location = {attr}, index = 1) out vec4 {name2};");
|
||||||
|
}
|
||||||
|
|
||||||
private static void DeclareUsedOutputAttributesPerPatch(CodeGenContext context, HashSet<int> attrs)
|
private static void DeclareUsedOutputAttributesPerPatch(CodeGenContext context, HashSet<int> attrs)
|
||||||
{
|
{
|
||||||
foreach (int attr in attrs.Order())
|
foreach (int attr in attrs.Order())
|
||||||
|
@@ -6,6 +6,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
using static Spv.Specification;
|
using static Spv.Specification;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
@@ -622,8 +623,28 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
else if (attr >= AttributeConsts.FragmentOutputColorBase && attr < AttributeConsts.FragmentOutputColorEnd)
|
else if (attr >= AttributeConsts.FragmentOutputColorBase && attr < AttributeConsts.FragmentOutputColorEnd)
|
||||||
{
|
{
|
||||||
int location = (attr - AttributeConsts.FragmentOutputColorBase) / 16;
|
int location = (attr - AttributeConsts.FragmentOutputColorBase) / 16;
|
||||||
|
|
||||||
|
if (context.Config.Stage == ShaderStage.Fragment && context.Config.GpuAccessor.QueryDualSourceBlendEnable())
|
||||||
|
{
|
||||||
|
int firstLocation = BitOperations.TrailingZeroCount(context.Config.UsedOutputAttributes);
|
||||||
|
int index = location - firstLocation;
|
||||||
|
int mask = 3 << firstLocation;
|
||||||
|
|
||||||
|
if ((uint)index < 2 && (context.Config.UsedOutputAttributes & mask) == mask)
|
||||||
|
{
|
||||||
|
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)firstLocation);
|
||||||
|
context.Decorate(spvVar, Decoration.Index, (LiteralInteger)index);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location);
|
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!isOutAttr)
|
if (!isOutAttr)
|
||||||
{
|
{
|
||||||
|
@@ -205,6 +205,15 @@ namespace Ryujinx.Graphics.Shader
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queries dual source blend state.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if blending is enabled with a dual source blend equation, false otherwise</returns>
|
||||||
|
bool QueryDualSourceBlendEnable()
|
||||||
|
{
|
||||||
|
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>
|
||||||
|
@@ -9,21 +9,18 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
private ulong MaxDeviceMemoryUsageEstimate = 16UL * 1024 * 1024 * 1024;
|
private ulong MaxDeviceMemoryUsageEstimate = 16UL * 1024 * 1024 * 1024;
|
||||||
|
|
||||||
private readonly Vk _api;
|
private readonly Vk _api;
|
||||||
private readonly PhysicalDevice _physicalDevice;
|
private readonly VulkanPhysicalDevice _physicalDevice;
|
||||||
private readonly Device _device;
|
private readonly Device _device;
|
||||||
private readonly List<MemoryAllocatorBlockList> _blockLists;
|
private readonly List<MemoryAllocatorBlockList> _blockLists;
|
||||||
private readonly int _blockAlignment;
|
private readonly int _blockAlignment;
|
||||||
private readonly PhysicalDeviceMemoryProperties _physicalDeviceMemoryProperties;
|
|
||||||
|
|
||||||
public MemoryAllocator(Vk api, PhysicalDevice physicalDevice, Device device, uint maxMemoryAllocationCount)
|
public MemoryAllocator(Vk api, VulkanPhysicalDevice physicalDevice, Device device)
|
||||||
{
|
{
|
||||||
_api = api;
|
_api = api;
|
||||||
_physicalDevice = physicalDevice;
|
_physicalDevice = physicalDevice;
|
||||||
_device = device;
|
_device = device;
|
||||||
_blockLists = new List<MemoryAllocatorBlockList>();
|
_blockLists = new List<MemoryAllocatorBlockList>();
|
||||||
_blockAlignment = (int)Math.Min(int.MaxValue, MaxDeviceMemoryUsageEstimate / (ulong)maxMemoryAllocationCount);
|
_blockAlignment = (int)Math.Min(int.MaxValue, MaxDeviceMemoryUsageEstimate / (ulong)_physicalDevice.PhysicalDeviceProperties.Limits.MaxMemoryAllocationCount);
|
||||||
|
|
||||||
_api.GetPhysicalDeviceMemoryProperties(_physicalDevice, out _physicalDeviceMemoryProperties);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public MemoryAllocation AllocateDeviceMemory(
|
public MemoryAllocation AllocateDeviceMemory(
|
||||||
@@ -64,9 +61,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
uint memoryTypeBits,
|
uint memoryTypeBits,
|
||||||
MemoryPropertyFlags flags)
|
MemoryPropertyFlags flags)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < _physicalDeviceMemoryProperties.MemoryTypeCount; i++)
|
for (int i = 0; i < _physicalDevice.PhysicalDeviceMemoryProperties.MemoryTypeCount; i++)
|
||||||
{
|
{
|
||||||
var type = _physicalDeviceMemoryProperties.MemoryTypes[i];
|
var type = _physicalDevice.PhysicalDeviceMemoryProperties.MemoryTypes[i];
|
||||||
|
|
||||||
if ((memoryTypeBits & (1 << i)) != 0)
|
if ((memoryTypeBits & (1 << i)) != 0)
|
||||||
{
|
{
|
||||||
@@ -80,15 +77,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsDeviceMemoryShared(Vk api, PhysicalDevice physicalDevice)
|
public static bool IsDeviceMemoryShared(VulkanPhysicalDevice physicalDevice)
|
||||||
{
|
{
|
||||||
// The device is regarded as having shared memory if all heaps have the device local bit.
|
for (int i = 0; i < physicalDevice.PhysicalDeviceMemoryProperties.MemoryHeapCount; i++)
|
||||||
|
|
||||||
api.GetPhysicalDeviceMemoryProperties(physicalDevice, out var properties);
|
|
||||||
|
|
||||||
for (int i = 0; i < properties.MemoryHeapCount; i++)
|
|
||||||
{
|
{
|
||||||
if (!properties.MemoryHeaps[i].Flags.HasFlag(MemoryHeapFlags.DeviceLocalBit))
|
if (!physicalDevice.PhysicalDeviceMemoryProperties.MemoryHeaps[i].Flags.HasFlag(MemoryHeapFlags.DeviceLocalBit))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@@ -47,36 +47,24 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
KhrSwapchain.ExtensionName
|
KhrSwapchain.ExtensionName
|
||||||
};
|
};
|
||||||
|
|
||||||
internal static Instance CreateInstance(Vk api, GraphicsDebugLevel logLevel, string[] requiredExtensions)
|
internal static VulkanInstance CreateInstance(Vk api, GraphicsDebugLevel logLevel, string[] requiredExtensions)
|
||||||
{
|
{
|
||||||
var enabledLayers = new List<string>();
|
var enabledLayers = new List<string>();
|
||||||
|
|
||||||
|
var instanceExtensions = VulkanInstance.GetInstanceExtensions(api);
|
||||||
|
var instanceLayers = VulkanInstance.GetInstanceLayers(api);
|
||||||
|
|
||||||
void AddAvailableLayer(string layerName)
|
void AddAvailableLayer(string layerName)
|
||||||
{
|
{
|
||||||
uint layerPropertiesCount;
|
if (instanceLayers.Contains(layerName))
|
||||||
|
|
||||||
api.EnumerateInstanceLayerProperties(&layerPropertiesCount, null).ThrowOnError();
|
|
||||||
|
|
||||||
LayerProperties[] layerProperties = new LayerProperties[layerPropertiesCount];
|
|
||||||
|
|
||||||
fixed (LayerProperties* pLayerProperties = layerProperties)
|
|
||||||
{
|
|
||||||
api.EnumerateInstanceLayerProperties(&layerPropertiesCount, layerProperties).ThrowOnError();
|
|
||||||
|
|
||||||
for (int i = 0; i < layerPropertiesCount; i++)
|
|
||||||
{
|
|
||||||
string currentLayerName = Marshal.PtrToStringAnsi((IntPtr)pLayerProperties[i].LayerName);
|
|
||||||
|
|
||||||
if (currentLayerName == layerName)
|
|
||||||
{
|
{
|
||||||
enabledLayers.Add(layerName);
|
enabledLayers.Add(layerName);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
}
|
{
|
||||||
|
|
||||||
Logger.Warning?.Print(LogClass.Gpu, $"Missing layer {layerName}");
|
Logger.Warning?.Print(LogClass.Gpu, $"Missing layer {layerName}");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (logLevel != GraphicsDebugLevel.None)
|
if (logLevel != GraphicsDebugLevel.None)
|
||||||
{
|
{
|
||||||
@@ -85,7 +73,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
var enabledExtensions = requiredExtensions;
|
var enabledExtensions = requiredExtensions;
|
||||||
|
|
||||||
if (api.IsInstanceExtensionPresent("VK_EXT_debug_utils"))
|
if (instanceExtensions.Contains("VK_EXT_debug_utils"))
|
||||||
{
|
{
|
||||||
enabledExtensions = enabledExtensions.Append(ExtDebugUtils.ExtensionName).ToArray();
|
enabledExtensions = enabledExtensions.Append(ExtDebugUtils.ExtensionName).ToArray();
|
||||||
}
|
}
|
||||||
@@ -124,7 +112,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
EnabledLayerCount = (uint)enabledLayers.Count
|
EnabledLayerCount = (uint)enabledLayers.Count
|
||||||
};
|
};
|
||||||
|
|
||||||
api.CreateInstance(in instanceCreateInfo, null, out var instance).ThrowOnError();
|
Result result = VulkanInstance.Create(api, ref instanceCreateInfo, out var instance);
|
||||||
|
|
||||||
Marshal.FreeHGlobal(appName);
|
Marshal.FreeHGlobal(appName);
|
||||||
|
|
||||||
@@ -138,21 +126,14 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
Marshal.FreeHGlobal(ppEnabledLayers[i]);
|
Marshal.FreeHGlobal(ppEnabledLayers[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result.ThrowOnError();
|
||||||
|
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static PhysicalDevice FindSuitablePhysicalDevice(Vk api, Instance instance, SurfaceKHR surface, string preferredGpuId)
|
internal static VulkanPhysicalDevice FindSuitablePhysicalDevice(Vk api, VulkanInstance instance, SurfaceKHR surface, string preferredGpuId)
|
||||||
{
|
{
|
||||||
uint physicalDeviceCount;
|
instance.EnumeratePhysicalDevices(out var physicalDevices).ThrowOnError();
|
||||||
|
|
||||||
api.EnumeratePhysicalDevices(instance, &physicalDeviceCount, null).ThrowOnError();
|
|
||||||
|
|
||||||
PhysicalDevice[] physicalDevices = new PhysicalDevice[physicalDeviceCount];
|
|
||||||
|
|
||||||
fixed (PhysicalDevice* pPhysicalDevices = physicalDevices)
|
|
||||||
{
|
|
||||||
api.EnumeratePhysicalDevices(instance, &physicalDeviceCount, pPhysicalDevices).ThrowOnError();
|
|
||||||
}
|
|
||||||
|
|
||||||
// First we try to pick the the user preferred GPU.
|
// First we try to pick the the user preferred GPU.
|
||||||
for (int i = 0; i < physicalDevices.Length; i++)
|
for (int i = 0; i < physicalDevices.Length; i++)
|
||||||
@@ -198,76 +179,41 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
EnabledLayerCount = 0
|
EnabledLayerCount = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
api.CreateInstance(in instanceCreateInfo, null, out var instance).ThrowOnError();
|
Result result = VulkanInstance.Create(api, ref instanceCreateInfo, out var rawInstance);
|
||||||
|
|
||||||
// We ensure that vkEnumerateInstanceVersion is present (added in 1.1).
|
|
||||||
// If the instance doesn't support it, no device is going to be 1.1 compatible.
|
|
||||||
if (api.GetInstanceProcAddr(instance, "vkEnumerateInstanceVersion") == IntPtr.Zero)
|
|
||||||
{
|
|
||||||
api.DestroyInstance(instance, null);
|
|
||||||
|
|
||||||
return Array.Empty<DeviceInfo>();
|
|
||||||
}
|
|
||||||
|
|
||||||
// We currently assume that the instance is compatible with Vulkan 1.2
|
|
||||||
// TODO: Remove this once we relax our initialization codepaths.
|
|
||||||
uint instanceApiVerison = 0;
|
|
||||||
api.EnumerateInstanceVersion(ref instanceApiVerison).ThrowOnError();
|
|
||||||
|
|
||||||
if (instanceApiVerison < MinimalInstanceVulkanVersion)
|
|
||||||
{
|
|
||||||
api.DestroyInstance(instance, null);
|
|
||||||
|
|
||||||
return Array.Empty<DeviceInfo>();
|
|
||||||
}
|
|
||||||
|
|
||||||
Marshal.FreeHGlobal(appName);
|
Marshal.FreeHGlobal(appName);
|
||||||
|
|
||||||
uint physicalDeviceCount;
|
result.ThrowOnError();
|
||||||
|
|
||||||
api.EnumeratePhysicalDevices(instance, &physicalDeviceCount, null).ThrowOnError();
|
using VulkanInstance instance = rawInstance;
|
||||||
|
|
||||||
PhysicalDevice[] physicalDevices = new PhysicalDevice[physicalDeviceCount];
|
// We currently assume that the instance is compatible with Vulkan 1.2
|
||||||
|
// TODO: Remove this once we relax our initialization codepaths.
|
||||||
fixed (PhysicalDevice* pPhysicalDevices = physicalDevices)
|
if (instance.InstanceVersion < MinimalInstanceVulkanVersion)
|
||||||
{
|
{
|
||||||
api.EnumeratePhysicalDevices(instance, &physicalDeviceCount, pPhysicalDevices).ThrowOnError();
|
return Array.Empty<DeviceInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceInfo[] devices = new DeviceInfo[physicalDevices.Length];
|
instance.EnumeratePhysicalDevices(out VulkanPhysicalDevice[] physicalDevices).ThrowOnError();
|
||||||
|
|
||||||
for (int i = 0; i < physicalDevices.Length; i++)
|
List<DeviceInfo> deviceInfos = new List<DeviceInfo>();
|
||||||
|
|
||||||
|
foreach (VulkanPhysicalDevice physicalDevice in physicalDevices)
|
||||||
{
|
{
|
||||||
var physicalDevice = physicalDevices[i];
|
if (physicalDevice.PhysicalDeviceProperties.ApiVersion < MinimalVulkanVersion)
|
||||||
api.GetPhysicalDeviceProperties(physicalDevice, out var properties);
|
|
||||||
|
|
||||||
if (properties.ApiVersion < MinimalVulkanVersion)
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
devices[i] = new DeviceInfo(
|
deviceInfos.Add(physicalDevice.ToDeviceInfo());
|
||||||
StringFromIdPair(properties.VendorID, properties.DeviceID),
|
|
||||||
VendorUtils.GetNameFromId(properties.VendorID),
|
|
||||||
Marshal.PtrToStringAnsi((IntPtr)properties.DeviceName),
|
|
||||||
properties.DeviceType == PhysicalDeviceType.DiscreteGpu);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
api.DestroyInstance(instance, null);
|
return deviceInfos.ToArray();
|
||||||
|
|
||||||
return devices;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string StringFromIdPair(uint vendorId, uint deviceId)
|
private static bool IsPreferredAndSuitableDevice(Vk api, VulkanPhysicalDevice physicalDevice, SurfaceKHR surface, string preferredGpuId)
|
||||||
{
|
{
|
||||||
return $"0x{vendorId:X}_0x{deviceId:X}";
|
if (physicalDevice.Id != preferredGpuId)
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsPreferredAndSuitableDevice(Vk api, PhysicalDevice physicalDevice, SurfaceKHR surface, string preferredGpuId)
|
|
||||||
{
|
|
||||||
api.GetPhysicalDeviceProperties(physicalDevice, out var properties);
|
|
||||||
|
|
||||||
if (StringFromIdPair(properties.VendorID, properties.DeviceID) != preferredGpuId)
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -275,68 +221,47 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
return IsSuitableDevice(api, physicalDevice, surface);
|
return IsSuitableDevice(api, physicalDevice, surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsSuitableDevice(Vk api, PhysicalDevice physicalDevice, SurfaceKHR surface)
|
private static bool IsSuitableDevice(Vk api, VulkanPhysicalDevice physicalDevice, SurfaceKHR surface)
|
||||||
{
|
{
|
||||||
int extensionMatches = 0;
|
int extensionMatches = 0;
|
||||||
uint propertiesCount;
|
|
||||||
|
|
||||||
api.EnumerateDeviceExtensionProperties(physicalDevice, (byte*)null, &propertiesCount, null).ThrowOnError();
|
foreach (string requiredExtension in _requiredExtensions)
|
||||||
|
|
||||||
ExtensionProperties[] extensionProperties = new ExtensionProperties[propertiesCount];
|
|
||||||
|
|
||||||
fixed (ExtensionProperties* pExtensionProperties = extensionProperties)
|
|
||||||
{
|
{
|
||||||
api.EnumerateDeviceExtensionProperties(physicalDevice, (byte*)null, &propertiesCount, pExtensionProperties).ThrowOnError();
|
if (physicalDevice.IsDeviceExtensionPresent(requiredExtension))
|
||||||
|
|
||||||
for (int i = 0; i < propertiesCount; i++)
|
|
||||||
{
|
|
||||||
string extensionName = Marshal.PtrToStringAnsi((IntPtr)pExtensionProperties[i].ExtensionName);
|
|
||||||
|
|
||||||
if (_requiredExtensions.Contains(extensionName))
|
|
||||||
{
|
{
|
||||||
extensionMatches++;
|
extensionMatches++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return extensionMatches == _requiredExtensions.Length && FindSuitableQueueFamily(api, physicalDevice, surface, out _) != InvalidIndex;
|
return extensionMatches == _requiredExtensions.Length && FindSuitableQueueFamily(api, physicalDevice, surface, out _) != InvalidIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static uint FindSuitableQueueFamily(Vk api, PhysicalDevice physicalDevice, SurfaceKHR surface, out uint queueCount)
|
internal static uint FindSuitableQueueFamily(Vk api, VulkanPhysicalDevice physicalDevice, SurfaceKHR surface, out uint queueCount)
|
||||||
{
|
{
|
||||||
const QueueFlags RequiredFlags = QueueFlags.GraphicsBit | QueueFlags.ComputeBit;
|
const QueueFlags RequiredFlags = QueueFlags.GraphicsBit | QueueFlags.ComputeBit;
|
||||||
|
|
||||||
var khrSurface = new KhrSurface(api.Context);
|
var khrSurface = new KhrSurface(api.Context);
|
||||||
|
|
||||||
uint propertiesCount;
|
for (uint index = 0; index < physicalDevice.QueueFamilyProperties.Length; index++)
|
||||||
|
|
||||||
api.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, &propertiesCount, null);
|
|
||||||
|
|
||||||
QueueFamilyProperties[] properties = new QueueFamilyProperties[propertiesCount];
|
|
||||||
|
|
||||||
fixed (QueueFamilyProperties* pProperties = properties)
|
|
||||||
{
|
{
|
||||||
api.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, &propertiesCount, pProperties);
|
ref QueueFamilyProperties property = ref physicalDevice.QueueFamilyProperties[index];
|
||||||
}
|
|
||||||
|
|
||||||
for (uint index = 0; index < propertiesCount; index++)
|
khrSurface.GetPhysicalDeviceSurfaceSupport(physicalDevice.PhysicalDevice, index, surface, out var surfaceSupported).ThrowOnError();
|
||||||
|
|
||||||
|
if (property.QueueFlags.HasFlag(RequiredFlags) && surfaceSupported)
|
||||||
{
|
{
|
||||||
var queueFlags = properties[index].QueueFlags;
|
queueCount = property.QueueCount;
|
||||||
|
|
||||||
khrSurface.GetPhysicalDeviceSurfaceSupport(physicalDevice, index, surface, out var surfaceSupported).ThrowOnError();
|
|
||||||
|
|
||||||
if (queueFlags.HasFlag(RequiredFlags) && surfaceSupported)
|
|
||||||
{
|
|
||||||
queueCount = properties[index].QueueCount;
|
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
queueCount = 0;
|
queueCount = 0;
|
||||||
|
|
||||||
return InvalidIndex;
|
return InvalidIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Device CreateDevice(Vk api, PhysicalDevice physicalDevice, uint queueFamilyIndex, string[] supportedExtensions, uint queueCount)
|
internal static Device CreateDevice(Vk api, VulkanPhysicalDevice physicalDevice, uint queueFamilyIndex, uint queueCount)
|
||||||
{
|
{
|
||||||
if (queueCount > QueuesCount)
|
if (queueCount > QueuesCount)
|
||||||
{
|
{
|
||||||
@@ -358,8 +283,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
PQueuePriorities = queuePriorities
|
PQueuePriorities = queuePriorities
|
||||||
};
|
};
|
||||||
|
|
||||||
api.GetPhysicalDeviceProperties(physicalDevice, out var properties);
|
bool useRobustBufferAccess = VendorUtils.FromId(physicalDevice.PhysicalDeviceProperties.VendorID) == Vendor.Nvidia;
|
||||||
bool useRobustBufferAccess = VendorUtils.FromId(properties.VendorID) == Vendor.Nvidia;
|
|
||||||
|
|
||||||
PhysicalDeviceFeatures2 features2 = new PhysicalDeviceFeatures2()
|
PhysicalDeviceFeatures2 features2 = new PhysicalDeviceFeatures2()
|
||||||
{
|
{
|
||||||
@@ -380,7 +304,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
PNext = features2.PNext
|
PNext = features2.PNext
|
||||||
};
|
};
|
||||||
|
|
||||||
if (supportedExtensions.Contains("VK_EXT_custom_border_color"))
|
if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_custom_border_color"))
|
||||||
{
|
{
|
||||||
features2.PNext = &supportedFeaturesCustomBorderColor;
|
features2.PNext = &supportedFeaturesCustomBorderColor;
|
||||||
}
|
}
|
||||||
@@ -391,7 +315,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
PNext = features2.PNext
|
PNext = features2.PNext
|
||||||
};
|
};
|
||||||
|
|
||||||
if (supportedExtensions.Contains("VK_EXT_primitive_topology_list_restart"))
|
if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_primitive_topology_list_restart"))
|
||||||
{
|
{
|
||||||
features2.PNext = &supportedFeaturesPrimitiveTopologyListRestart;
|
features2.PNext = &supportedFeaturesPrimitiveTopologyListRestart;
|
||||||
}
|
}
|
||||||
@@ -402,7 +326,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
PNext = features2.PNext
|
PNext = features2.PNext
|
||||||
};
|
};
|
||||||
|
|
||||||
if (supportedExtensions.Contains(ExtTransformFeedback.ExtensionName))
|
if (physicalDevice.IsDeviceExtensionPresent(ExtTransformFeedback.ExtensionName))
|
||||||
{
|
{
|
||||||
features2.PNext = &supportedFeaturesTransformFeedback;
|
features2.PNext = &supportedFeaturesTransformFeedback;
|
||||||
}
|
}
|
||||||
@@ -412,14 +336,14 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
SType = StructureType.PhysicalDeviceRobustness2FeaturesExt
|
SType = StructureType.PhysicalDeviceRobustness2FeaturesExt
|
||||||
};
|
};
|
||||||
|
|
||||||
if (supportedExtensions.Contains("VK_EXT_robustness2"))
|
if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_robustness2"))
|
||||||
{
|
{
|
||||||
supportedFeaturesRobustness2.PNext = features2.PNext;
|
supportedFeaturesRobustness2.PNext = features2.PNext;
|
||||||
|
|
||||||
features2.PNext = &supportedFeaturesRobustness2;
|
features2.PNext = &supportedFeaturesRobustness2;
|
||||||
}
|
}
|
||||||
|
|
||||||
api.GetPhysicalDeviceFeatures2(physicalDevice, &features2);
|
api.GetPhysicalDeviceFeatures2(physicalDevice.PhysicalDevice, &features2);
|
||||||
|
|
||||||
var supportedFeatures = features2.Features;
|
var supportedFeatures = features2.Features;
|
||||||
|
|
||||||
@@ -452,7 +376,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
PhysicalDeviceTransformFeedbackFeaturesEXT featuresTransformFeedback;
|
PhysicalDeviceTransformFeedbackFeaturesEXT featuresTransformFeedback;
|
||||||
|
|
||||||
if (supportedExtensions.Contains(ExtTransformFeedback.ExtensionName))
|
if (physicalDevice.IsDeviceExtensionPresent(ExtTransformFeedback.ExtensionName))
|
||||||
{
|
{
|
||||||
featuresTransformFeedback = new PhysicalDeviceTransformFeedbackFeaturesEXT()
|
featuresTransformFeedback = new PhysicalDeviceTransformFeedbackFeaturesEXT()
|
||||||
{
|
{
|
||||||
@@ -466,7 +390,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
PhysicalDevicePrimitiveTopologyListRestartFeaturesEXT featuresPrimitiveTopologyListRestart;
|
PhysicalDevicePrimitiveTopologyListRestartFeaturesEXT featuresPrimitiveTopologyListRestart;
|
||||||
|
|
||||||
if (supportedExtensions.Contains("VK_EXT_primitive_topology_list_restart"))
|
if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_primitive_topology_list_restart"))
|
||||||
{
|
{
|
||||||
featuresPrimitiveTopologyListRestart = new PhysicalDevicePrimitiveTopologyListRestartFeaturesEXT()
|
featuresPrimitiveTopologyListRestart = new PhysicalDevicePrimitiveTopologyListRestartFeaturesEXT()
|
||||||
{
|
{
|
||||||
@@ -481,7 +405,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
PhysicalDeviceRobustness2FeaturesEXT featuresRobustness2;
|
PhysicalDeviceRobustness2FeaturesEXT featuresRobustness2;
|
||||||
|
|
||||||
if (supportedExtensions.Contains("VK_EXT_robustness2"))
|
if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_robustness2"))
|
||||||
{
|
{
|
||||||
featuresRobustness2 = new PhysicalDeviceRobustness2FeaturesEXT()
|
featuresRobustness2 = new PhysicalDeviceRobustness2FeaturesEXT()
|
||||||
{
|
{
|
||||||
@@ -497,7 +421,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
SType = StructureType.PhysicalDeviceExtendedDynamicStateFeaturesExt,
|
SType = StructureType.PhysicalDeviceExtendedDynamicStateFeaturesExt,
|
||||||
PNext = pExtendedFeatures,
|
PNext = pExtendedFeatures,
|
||||||
ExtendedDynamicState = supportedExtensions.Contains(ExtExtendedDynamicState.ExtensionName)
|
ExtendedDynamicState = physicalDevice.IsDeviceExtensionPresent(ExtExtendedDynamicState.ExtensionName)
|
||||||
};
|
};
|
||||||
|
|
||||||
pExtendedFeatures = &featuresExtendedDynamicState;
|
pExtendedFeatures = &featuresExtendedDynamicState;
|
||||||
@@ -515,16 +439,16 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
SType = StructureType.PhysicalDeviceVulkan12Features,
|
SType = StructureType.PhysicalDeviceVulkan12Features,
|
||||||
PNext = pExtendedFeatures,
|
PNext = pExtendedFeatures,
|
||||||
DescriptorIndexing = supportedExtensions.Contains("VK_EXT_descriptor_indexing"),
|
DescriptorIndexing = physicalDevice.IsDeviceExtensionPresent("VK_EXT_descriptor_indexing"),
|
||||||
DrawIndirectCount = supportedExtensions.Contains(KhrDrawIndirectCount.ExtensionName),
|
DrawIndirectCount = physicalDevice.IsDeviceExtensionPresent(KhrDrawIndirectCount.ExtensionName),
|
||||||
UniformBufferStandardLayout = supportedExtensions.Contains("VK_KHR_uniform_buffer_standard_layout")
|
UniformBufferStandardLayout = physicalDevice.IsDeviceExtensionPresent("VK_KHR_uniform_buffer_standard_layout")
|
||||||
};
|
};
|
||||||
|
|
||||||
pExtendedFeatures = &featuresVk12;
|
pExtendedFeatures = &featuresVk12;
|
||||||
|
|
||||||
PhysicalDeviceIndexTypeUint8FeaturesEXT featuresIndexU8;
|
PhysicalDeviceIndexTypeUint8FeaturesEXT featuresIndexU8;
|
||||||
|
|
||||||
if (supportedExtensions.Contains("VK_EXT_index_type_uint8"))
|
if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_index_type_uint8"))
|
||||||
{
|
{
|
||||||
featuresIndexU8 = new PhysicalDeviceIndexTypeUint8FeaturesEXT()
|
featuresIndexU8 = new PhysicalDeviceIndexTypeUint8FeaturesEXT()
|
||||||
{
|
{
|
||||||
@@ -538,7 +462,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
PhysicalDeviceFragmentShaderInterlockFeaturesEXT featuresFragmentShaderInterlock;
|
PhysicalDeviceFragmentShaderInterlockFeaturesEXT featuresFragmentShaderInterlock;
|
||||||
|
|
||||||
if (supportedExtensions.Contains("VK_EXT_fragment_shader_interlock"))
|
if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_fragment_shader_interlock"))
|
||||||
{
|
{
|
||||||
featuresFragmentShaderInterlock = new PhysicalDeviceFragmentShaderInterlockFeaturesEXT()
|
featuresFragmentShaderInterlock = new PhysicalDeviceFragmentShaderInterlockFeaturesEXT()
|
||||||
{
|
{
|
||||||
@@ -552,7 +476,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
PhysicalDeviceSubgroupSizeControlFeaturesEXT featuresSubgroupSizeControl;
|
PhysicalDeviceSubgroupSizeControlFeaturesEXT featuresSubgroupSizeControl;
|
||||||
|
|
||||||
if (supportedExtensions.Contains("VK_EXT_subgroup_size_control"))
|
if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_subgroup_size_control"))
|
||||||
{
|
{
|
||||||
featuresSubgroupSizeControl = new PhysicalDeviceSubgroupSizeControlFeaturesEXT()
|
featuresSubgroupSizeControl = new PhysicalDeviceSubgroupSizeControlFeaturesEXT()
|
||||||
{
|
{
|
||||||
@@ -566,7 +490,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
PhysicalDeviceCustomBorderColorFeaturesEXT featuresCustomBorderColor;
|
PhysicalDeviceCustomBorderColorFeaturesEXT featuresCustomBorderColor;
|
||||||
|
|
||||||
if (supportedExtensions.Contains("VK_EXT_custom_border_color") &&
|
if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_custom_border_color") &&
|
||||||
supportedFeaturesCustomBorderColor.CustomBorderColors &&
|
supportedFeaturesCustomBorderColor.CustomBorderColors &&
|
||||||
supportedFeaturesCustomBorderColor.CustomBorderColorWithoutFormat)
|
supportedFeaturesCustomBorderColor.CustomBorderColorWithoutFormat)
|
||||||
{
|
{
|
||||||
@@ -581,7 +505,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
pExtendedFeatures = &featuresCustomBorderColor;
|
pExtendedFeatures = &featuresCustomBorderColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
var enabledExtensions = _requiredExtensions.Union(_desirableExtensions.Intersect(supportedExtensions)).ToArray();
|
var enabledExtensions = _requiredExtensions.Union(_desirableExtensions.Intersect(physicalDevice.DeviceExtensions)).ToArray();
|
||||||
|
|
||||||
IntPtr* ppEnabledExtensions = stackalloc IntPtr[enabledExtensions.Length];
|
IntPtr* ppEnabledExtensions = stackalloc IntPtr[enabledExtensions.Length];
|
||||||
|
|
||||||
@@ -601,7 +525,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
PEnabledFeatures = &features
|
PEnabledFeatures = &features
|
||||||
};
|
};
|
||||||
|
|
||||||
api.CreateDevice(physicalDevice, in deviceCreateInfo, null, out var device).ThrowOnError();
|
api.CreateDevice(physicalDevice.PhysicalDevice, in deviceCreateInfo, null, out var device).ThrowOnError();
|
||||||
|
|
||||||
for (int i = 0; i < enabledExtensions.Length; i++)
|
for (int i = 0; i < enabledExtensions.Length; i++)
|
||||||
{
|
{
|
||||||
@@ -610,21 +534,5 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string[] GetSupportedExtensions(Vk api, PhysicalDevice physicalDevice)
|
|
||||||
{
|
|
||||||
uint propertiesCount;
|
|
||||||
|
|
||||||
api.EnumerateDeviceExtensionProperties(physicalDevice, (byte*)null, &propertiesCount, null).ThrowOnError();
|
|
||||||
|
|
||||||
ExtensionProperties[] extensionProperties = new ExtensionProperties[propertiesCount];
|
|
||||||
|
|
||||||
fixed (ExtensionProperties* pExtensionProperties = extensionProperties)
|
|
||||||
{
|
|
||||||
api.EnumerateDeviceExtensionProperties(physicalDevice, (byte*)null, &propertiesCount, pExtensionProperties).ThrowOnError();
|
|
||||||
}
|
|
||||||
|
|
||||||
return extensionProperties.Select(x => Marshal.PtrToStringAnsi((IntPtr)x.ExtensionName)).ToArray();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
127
Ryujinx.Graphics.Vulkan/VulkanInstance.cs
Normal file
127
Ryujinx.Graphics.Vulkan/VulkanInstance.cs
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
using Ryujinx.Common.Utilities;
|
||||||
|
using Silk.NET.Core;
|
||||||
|
using Silk.NET.Vulkan;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Vulkan
|
||||||
|
{
|
||||||
|
class VulkanInstance : IDisposable
|
||||||
|
{
|
||||||
|
private readonly Vk _api;
|
||||||
|
public readonly Instance Instance;
|
||||||
|
public readonly Version32 InstanceVersion;
|
||||||
|
|
||||||
|
private bool _disposed;
|
||||||
|
|
||||||
|
private VulkanInstance(Vk api, Instance instance)
|
||||||
|
{
|
||||||
|
_api = api;
|
||||||
|
Instance = instance;
|
||||||
|
|
||||||
|
if (api.GetInstanceProcAddr(instance, "vkEnumerateInstanceVersion") == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
InstanceVersion = Vk.Version10;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint rawInstanceVersion = 0;
|
||||||
|
|
||||||
|
if (api.EnumerateInstanceVersion(ref rawInstanceVersion) != Result.Success)
|
||||||
|
{
|
||||||
|
rawInstanceVersion = Vk.Version11.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
InstanceVersion = (Version32)rawInstanceVersion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Result Create(Vk api, ref InstanceCreateInfo createInfo, out VulkanInstance instance)
|
||||||
|
{
|
||||||
|
instance = null;
|
||||||
|
|
||||||
|
Instance rawInstance = default;
|
||||||
|
|
||||||
|
Result result = api.CreateInstance(SpanHelpers.AsReadOnlySpan(ref createInfo), ReadOnlySpan<AllocationCallbacks>.Empty, SpanHelpers.AsSpan(ref rawInstance));
|
||||||
|
|
||||||
|
if (result == Result.Success)
|
||||||
|
{
|
||||||
|
instance = new VulkanInstance(api, rawInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result EnumeratePhysicalDevices(out VulkanPhysicalDevice[] physicalDevices)
|
||||||
|
{
|
||||||
|
physicalDevices = null;
|
||||||
|
|
||||||
|
uint physicalDeviceCount = 0;
|
||||||
|
|
||||||
|
Result result = _api.EnumeratePhysicalDevices(Instance, SpanHelpers.AsSpan(ref physicalDeviceCount), Span<PhysicalDevice>.Empty);
|
||||||
|
|
||||||
|
if (result != Result.Success)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
PhysicalDevice[] rawPhysicalDevices = new PhysicalDevice[physicalDeviceCount];
|
||||||
|
|
||||||
|
result = _api.EnumeratePhysicalDevices(Instance, SpanHelpers.AsSpan(ref physicalDeviceCount), rawPhysicalDevices);
|
||||||
|
|
||||||
|
if (result != Result.Success)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
physicalDevices = rawPhysicalDevices.Select(x => new VulkanPhysicalDevice(_api, x)).ToArray();
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IReadOnlySet<string> GetInstanceExtensions(Vk api)
|
||||||
|
{
|
||||||
|
uint propertiesCount = 0;
|
||||||
|
|
||||||
|
api.EnumerateInstanceExtensionProperties(ReadOnlySpan<byte>.Empty, SpanHelpers.AsSpan(ref propertiesCount), Span<ExtensionProperties>.Empty).ThrowOnError();
|
||||||
|
|
||||||
|
ExtensionProperties[] extensionProperties = new ExtensionProperties[propertiesCount];
|
||||||
|
|
||||||
|
api.EnumerateInstanceExtensionProperties(ReadOnlySpan<byte>.Empty, SpanHelpers.AsSpan(ref propertiesCount), extensionProperties).ThrowOnError();
|
||||||
|
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
return extensionProperties.Select(x => Marshal.PtrToStringAnsi((IntPtr)x.ExtensionName)).ToImmutableHashSet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IReadOnlySet<string> GetInstanceLayers(Vk api)
|
||||||
|
{
|
||||||
|
uint propertiesCount = 0;
|
||||||
|
|
||||||
|
api.EnumerateInstanceLayerProperties(SpanHelpers.AsSpan(ref propertiesCount), Span<LayerProperties>.Empty).ThrowOnError();
|
||||||
|
|
||||||
|
LayerProperties[] layerProperties = new LayerProperties[propertiesCount];
|
||||||
|
|
||||||
|
api.EnumerateInstanceLayerProperties(SpanHelpers.AsSpan(ref propertiesCount), layerProperties).ThrowOnError();
|
||||||
|
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
return layerProperties.Select(x => Marshal.PtrToStringAnsi((IntPtr)x.LayerName)).ToImmutableHashSet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (!_disposed)
|
||||||
|
{
|
||||||
|
_api.DestroyInstance(Instance, ReadOnlySpan<AllocationCallbacks>.Empty);
|
||||||
|
|
||||||
|
_disposed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
70
Ryujinx.Graphics.Vulkan/VulkanPhysicalDevice.cs
Normal file
70
Ryujinx.Graphics.Vulkan/VulkanPhysicalDevice.cs
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
using Ryujinx.Common.Utilities;
|
||||||
|
using Ryujinx.Graphics.GAL;
|
||||||
|
using Silk.NET.Vulkan;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Vulkan
|
||||||
|
{
|
||||||
|
readonly struct VulkanPhysicalDevice
|
||||||
|
{
|
||||||
|
public readonly PhysicalDevice PhysicalDevice;
|
||||||
|
public readonly PhysicalDeviceFeatures PhysicalDeviceFeatures;
|
||||||
|
public readonly PhysicalDeviceProperties PhysicalDeviceProperties;
|
||||||
|
public readonly PhysicalDeviceMemoryProperties PhysicalDeviceMemoryProperties;
|
||||||
|
public readonly QueueFamilyProperties[] QueueFamilyProperties;
|
||||||
|
public readonly string DeviceName;
|
||||||
|
public readonly IReadOnlySet<string> DeviceExtensions;
|
||||||
|
|
||||||
|
public VulkanPhysicalDevice(Vk api, PhysicalDevice physicalDevice)
|
||||||
|
{
|
||||||
|
PhysicalDevice = physicalDevice;
|
||||||
|
PhysicalDeviceFeatures = api.GetPhysicalDeviceFeature(PhysicalDevice);
|
||||||
|
|
||||||
|
api.GetPhysicalDeviceProperties(PhysicalDevice, out var physicalDeviceProperties);
|
||||||
|
PhysicalDeviceProperties = physicalDeviceProperties;
|
||||||
|
|
||||||
|
api.GetPhysicalDeviceMemoryProperties(PhysicalDevice, out PhysicalDeviceMemoryProperties);
|
||||||
|
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
DeviceName = Marshal.PtrToStringAnsi((IntPtr)physicalDeviceProperties.DeviceName);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint propertiesCount = 0;
|
||||||
|
|
||||||
|
api.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, SpanHelpers.AsSpan(ref propertiesCount), Span<QueueFamilyProperties>.Empty);
|
||||||
|
|
||||||
|
QueueFamilyProperties = new QueueFamilyProperties[propertiesCount];
|
||||||
|
|
||||||
|
api.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, SpanHelpers.AsSpan(ref propertiesCount), QueueFamilyProperties);
|
||||||
|
|
||||||
|
api.EnumerateDeviceExtensionProperties(PhysicalDevice, Span<byte>.Empty, SpanHelpers.AsSpan(ref propertiesCount), Span<ExtensionProperties>.Empty).ThrowOnError();
|
||||||
|
|
||||||
|
ExtensionProperties[] extensionProperties = new ExtensionProperties[propertiesCount];
|
||||||
|
|
||||||
|
api.EnumerateDeviceExtensionProperties(PhysicalDevice, Span<byte>.Empty, SpanHelpers.AsSpan(ref propertiesCount), extensionProperties).ThrowOnError();
|
||||||
|
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
DeviceExtensions = extensionProperties.Select(x => Marshal.PtrToStringAnsi((IntPtr)x.ExtensionName)).ToImmutableHashSet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Id => $"0x{PhysicalDeviceProperties.VendorID:X}_0x{PhysicalDeviceProperties.DeviceID:X}";
|
||||||
|
|
||||||
|
public bool IsDeviceExtensionPresent(string extension) => DeviceExtensions.Contains(extension);
|
||||||
|
|
||||||
|
public DeviceInfo ToDeviceInfo()
|
||||||
|
{
|
||||||
|
return new DeviceInfo(
|
||||||
|
Id,
|
||||||
|
VendorUtils.GetNameFromId(PhysicalDeviceProperties.VendorID),
|
||||||
|
DeviceName,
|
||||||
|
PhysicalDeviceProperties.DeviceType == PhysicalDeviceType.DiscreteGpu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -17,9 +17,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
public sealed class VulkanRenderer : IRenderer
|
public sealed class VulkanRenderer : IRenderer
|
||||||
{
|
{
|
||||||
private Instance _instance;
|
private VulkanInstance _instance;
|
||||||
private SurfaceKHR _surface;
|
private SurfaceKHR _surface;
|
||||||
private PhysicalDevice _physicalDevice;
|
private VulkanPhysicalDevice _physicalDevice;
|
||||||
private Device _device;
|
private Device _device;
|
||||||
private WindowBase _window;
|
private WindowBase _window;
|
||||||
|
|
||||||
@@ -106,33 +106,31 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private unsafe void LoadFeatures(string[] supportedExtensions, uint maxQueueCount, uint queueFamilyIndex)
|
private unsafe void LoadFeatures(uint maxQueueCount, uint queueFamilyIndex)
|
||||||
{
|
{
|
||||||
FormatCapabilities = new FormatCapabilities(Api, _physicalDevice);
|
FormatCapabilities = new FormatCapabilities(Api, _physicalDevice.PhysicalDevice);
|
||||||
|
|
||||||
var supportedFeatures = Api.GetPhysicalDeviceFeature(_physicalDevice);
|
if (Api.TryGetDeviceExtension(_instance.Instance, _device, out ExtConditionalRendering conditionalRenderingApi))
|
||||||
|
|
||||||
if (Api.TryGetDeviceExtension(_instance, _device, out ExtConditionalRendering conditionalRenderingApi))
|
|
||||||
{
|
{
|
||||||
ConditionalRenderingApi = conditionalRenderingApi;
|
ConditionalRenderingApi = conditionalRenderingApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Api.TryGetDeviceExtension(_instance, _device, out ExtExtendedDynamicState extendedDynamicStateApi))
|
if (Api.TryGetDeviceExtension(_instance.Instance, _device, out ExtExtendedDynamicState extendedDynamicStateApi))
|
||||||
{
|
{
|
||||||
ExtendedDynamicStateApi = extendedDynamicStateApi;
|
ExtendedDynamicStateApi = extendedDynamicStateApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Api.TryGetDeviceExtension(_instance, _device, out KhrPushDescriptor pushDescriptorApi))
|
if (Api.TryGetDeviceExtension(_instance.Instance, _device, out KhrPushDescriptor pushDescriptorApi))
|
||||||
{
|
{
|
||||||
PushDescriptorApi = pushDescriptorApi;
|
PushDescriptorApi = pushDescriptorApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Api.TryGetDeviceExtension(_instance, _device, out ExtTransformFeedback transformFeedbackApi))
|
if (Api.TryGetDeviceExtension(_instance.Instance, _device, out ExtTransformFeedback transformFeedbackApi))
|
||||||
{
|
{
|
||||||
TransformFeedbackApi = transformFeedbackApi;
|
TransformFeedbackApi = transformFeedbackApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Api.TryGetDeviceExtension(_instance, _device, out KhrDrawIndirectCount drawIndirectCountApi))
|
if (Api.TryGetDeviceExtension(_instance.Instance, _device, out KhrDrawIndirectCount drawIndirectCountApi))
|
||||||
{
|
{
|
||||||
DrawIndirectCountApi = drawIndirectCountApi;
|
DrawIndirectCountApi = drawIndirectCountApi;
|
||||||
}
|
}
|
||||||
@@ -154,7 +152,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
SType = StructureType.PhysicalDeviceBlendOperationAdvancedPropertiesExt
|
SType = StructureType.PhysicalDeviceBlendOperationAdvancedPropertiesExt
|
||||||
};
|
};
|
||||||
|
|
||||||
bool supportsBlendOperationAdvanced = supportedExtensions.Contains("VK_EXT_blend_operation_advanced");
|
bool supportsBlendOperationAdvanced = _physicalDevice.IsDeviceExtensionPresent("VK_EXT_blend_operation_advanced");
|
||||||
|
|
||||||
if (supportsBlendOperationAdvanced)
|
if (supportsBlendOperationAdvanced)
|
||||||
{
|
{
|
||||||
@@ -167,14 +165,14 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
SType = StructureType.PhysicalDeviceSubgroupSizeControlPropertiesExt
|
SType = StructureType.PhysicalDeviceSubgroupSizeControlPropertiesExt
|
||||||
};
|
};
|
||||||
|
|
||||||
bool supportsSubgroupSizeControl = supportedExtensions.Contains("VK_EXT_subgroup_size_control");
|
bool supportsSubgroupSizeControl = _physicalDevice.IsDeviceExtensionPresent("VK_EXT_subgroup_size_control");
|
||||||
|
|
||||||
if (supportsSubgroupSizeControl)
|
if (supportsSubgroupSizeControl)
|
||||||
{
|
{
|
||||||
properties2.PNext = &propertiesSubgroupSizeControl;
|
properties2.PNext = &propertiesSubgroupSizeControl;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool supportsTransformFeedback = supportedExtensions.Contains(ExtTransformFeedback.ExtensionName);
|
bool supportsTransformFeedback = _physicalDevice.IsDeviceExtensionPresent(ExtTransformFeedback.ExtensionName);
|
||||||
|
|
||||||
PhysicalDeviceTransformFeedbackPropertiesEXT propertiesTransformFeedback = new PhysicalDeviceTransformFeedbackPropertiesEXT()
|
PhysicalDeviceTransformFeedbackPropertiesEXT propertiesTransformFeedback = new PhysicalDeviceTransformFeedbackPropertiesEXT()
|
||||||
{
|
{
|
||||||
@@ -222,30 +220,30 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
SType = StructureType.PhysicalDevicePortabilitySubsetFeaturesKhr
|
SType = StructureType.PhysicalDevicePortabilitySubsetFeaturesKhr
|
||||||
};
|
};
|
||||||
|
|
||||||
if (supportedExtensions.Contains("VK_EXT_primitive_topology_list_restart"))
|
if (_physicalDevice.IsDeviceExtensionPresent("VK_EXT_primitive_topology_list_restart"))
|
||||||
{
|
{
|
||||||
features2.PNext = &featuresPrimitiveTopologyListRestart;
|
features2.PNext = &featuresPrimitiveTopologyListRestart;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (supportedExtensions.Contains("VK_EXT_robustness2"))
|
if (_physicalDevice.IsDeviceExtensionPresent("VK_EXT_robustness2"))
|
||||||
{
|
{
|
||||||
featuresRobustness2.PNext = features2.PNext;
|
featuresRobustness2.PNext = features2.PNext;
|
||||||
features2.PNext = &featuresRobustness2;
|
features2.PNext = &featuresRobustness2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (supportedExtensions.Contains("VK_KHR_shader_float16_int8"))
|
if (_physicalDevice.IsDeviceExtensionPresent("VK_KHR_shader_float16_int8"))
|
||||||
{
|
{
|
||||||
featuresShaderInt8.PNext = features2.PNext;
|
featuresShaderInt8.PNext = features2.PNext;
|
||||||
features2.PNext = &featuresShaderInt8;
|
features2.PNext = &featuresShaderInt8;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (supportedExtensions.Contains("VK_EXT_custom_border_color"))
|
if (_physicalDevice.IsDeviceExtensionPresent("VK_EXT_custom_border_color"))
|
||||||
{
|
{
|
||||||
featuresCustomBorderColor.PNext = features2.PNext;
|
featuresCustomBorderColor.PNext = features2.PNext;
|
||||||
features2.PNext = &featuresCustomBorderColor;
|
features2.PNext = &featuresCustomBorderColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool usePortability = supportedExtensions.Contains("VK_KHR_portability_subset");
|
bool usePortability = _physicalDevice.IsDeviceExtensionPresent("VK_KHR_portability_subset");
|
||||||
|
|
||||||
if (usePortability)
|
if (usePortability)
|
||||||
{
|
{
|
||||||
@@ -256,8 +254,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
features2.PNext = &featuresPortabilitySubset;
|
features2.PNext = &featuresPortabilitySubset;
|
||||||
}
|
}
|
||||||
|
|
||||||
Api.GetPhysicalDeviceProperties2(_physicalDevice, &properties2);
|
Api.GetPhysicalDeviceProperties2(_physicalDevice.PhysicalDevice, &properties2);
|
||||||
Api.GetPhysicalDeviceFeatures2(_physicalDevice, &features2);
|
Api.GetPhysicalDeviceFeatures2(_physicalDevice.PhysicalDevice, &features2);
|
||||||
|
|
||||||
var portabilityFlags = PortabilitySubsetFlags.None;
|
var portabilityFlags = PortabilitySubsetFlags.None;
|
||||||
uint vertexBufferAlignment = 1;
|
uint vertexBufferAlignment = 1;
|
||||||
@@ -272,7 +270,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
portabilityFlags |= featuresPortabilitySubset.SamplerMipLodBias ? 0 : PortabilitySubsetFlags.NoLodBias;
|
portabilityFlags |= featuresPortabilitySubset.SamplerMipLodBias ? 0 : PortabilitySubsetFlags.NoLodBias;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool supportsCustomBorderColor = supportedExtensions.Contains("VK_EXT_custom_border_color") &&
|
bool supportsCustomBorderColor = _physicalDevice.IsDeviceExtensionPresent("VK_EXT_custom_border_color") &&
|
||||||
featuresCustomBorderColor.CustomBorderColors &&
|
featuresCustomBorderColor.CustomBorderColors &&
|
||||||
featuresCustomBorderColor.CustomBorderColorWithoutFormat;
|
featuresCustomBorderColor.CustomBorderColorWithoutFormat;
|
||||||
|
|
||||||
@@ -284,30 +282,30 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
properties.Limits.FramebufferStencilSampleCounts;
|
properties.Limits.FramebufferStencilSampleCounts;
|
||||||
|
|
||||||
Capabilities = new HardwareCapabilities(
|
Capabilities = new HardwareCapabilities(
|
||||||
supportedExtensions.Contains("VK_EXT_index_type_uint8"),
|
_physicalDevice.IsDeviceExtensionPresent("VK_EXT_index_type_uint8"),
|
||||||
supportsCustomBorderColor,
|
supportsCustomBorderColor,
|
||||||
supportsBlendOperationAdvanced,
|
supportsBlendOperationAdvanced,
|
||||||
propertiesBlendOperationAdvanced.AdvancedBlendCorrelatedOverlap,
|
propertiesBlendOperationAdvanced.AdvancedBlendCorrelatedOverlap,
|
||||||
propertiesBlendOperationAdvanced.AdvancedBlendNonPremultipliedSrcColor,
|
propertiesBlendOperationAdvanced.AdvancedBlendNonPremultipliedSrcColor,
|
||||||
propertiesBlendOperationAdvanced.AdvancedBlendNonPremultipliedDstColor,
|
propertiesBlendOperationAdvanced.AdvancedBlendNonPremultipliedDstColor,
|
||||||
supportedExtensions.Contains(KhrDrawIndirectCount.ExtensionName),
|
_physicalDevice.IsDeviceExtensionPresent(KhrDrawIndirectCount.ExtensionName),
|
||||||
supportedExtensions.Contains("VK_EXT_fragment_shader_interlock"),
|
_physicalDevice.IsDeviceExtensionPresent("VK_EXT_fragment_shader_interlock"),
|
||||||
supportedExtensions.Contains("VK_NV_geometry_shader_passthrough"),
|
_physicalDevice.IsDeviceExtensionPresent("VK_NV_geometry_shader_passthrough"),
|
||||||
supportsSubgroupSizeControl,
|
supportsSubgroupSizeControl,
|
||||||
featuresShaderInt8.ShaderInt8,
|
featuresShaderInt8.ShaderInt8,
|
||||||
supportedExtensions.Contains("VK_EXT_shader_stencil_export"),
|
_physicalDevice.IsDeviceExtensionPresent("VK_EXT_shader_stencil_export"),
|
||||||
supportedExtensions.Contains(ExtConditionalRendering.ExtensionName),
|
_physicalDevice.IsDeviceExtensionPresent(ExtConditionalRendering.ExtensionName),
|
||||||
supportedExtensions.Contains(ExtExtendedDynamicState.ExtensionName),
|
_physicalDevice.IsDeviceExtensionPresent(ExtExtendedDynamicState.ExtensionName),
|
||||||
features2.Features.MultiViewport,
|
features2.Features.MultiViewport,
|
||||||
featuresRobustness2.NullDescriptor || IsMoltenVk,
|
featuresRobustness2.NullDescriptor || IsMoltenVk,
|
||||||
supportedExtensions.Contains(KhrPushDescriptor.ExtensionName),
|
_physicalDevice.IsDeviceExtensionPresent(KhrPushDescriptor.ExtensionName),
|
||||||
featuresPrimitiveTopologyListRestart.PrimitiveTopologyListRestart,
|
featuresPrimitiveTopologyListRestart.PrimitiveTopologyListRestart,
|
||||||
featuresPrimitiveTopologyListRestart.PrimitiveTopologyPatchListRestart,
|
featuresPrimitiveTopologyListRestart.PrimitiveTopologyPatchListRestart,
|
||||||
supportsTransformFeedback,
|
supportsTransformFeedback,
|
||||||
propertiesTransformFeedback.TransformFeedbackQueries,
|
propertiesTransformFeedback.TransformFeedbackQueries,
|
||||||
features2.Features.OcclusionQueryPrecise,
|
features2.Features.OcclusionQueryPrecise,
|
||||||
supportedFeatures.PipelineStatisticsQuery,
|
_physicalDevice.PhysicalDeviceFeatures.PipelineStatisticsQuery,
|
||||||
supportedFeatures.GeometryShader,
|
_physicalDevice.PhysicalDeviceFeatures.GeometryShader,
|
||||||
propertiesSubgroupSizeControl.MinSubgroupSize,
|
propertiesSubgroupSizeControl.MinSubgroupSize,
|
||||||
propertiesSubgroupSizeControl.MaxSubgroupSize,
|
propertiesSubgroupSizeControl.MaxSubgroupSize,
|
||||||
propertiesSubgroupSizeControl.RequiredSubgroupSizeStages,
|
propertiesSubgroupSizeControl.RequiredSubgroupSizeStages,
|
||||||
@@ -315,9 +313,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
portabilityFlags,
|
portabilityFlags,
|
||||||
vertexBufferAlignment);
|
vertexBufferAlignment);
|
||||||
|
|
||||||
IsSharedMemory = MemoryAllocator.IsDeviceMemoryShared(Api, _physicalDevice);
|
IsSharedMemory = MemoryAllocator.IsDeviceMemoryShared(_physicalDevice);
|
||||||
|
|
||||||
MemoryAllocator = new MemoryAllocator(Api, _physicalDevice, _device, properties.Limits.MaxMemoryAllocationCount);
|
MemoryAllocator = new MemoryAllocator(Api, _physicalDevice, _device);
|
||||||
|
|
||||||
CommandBufferPool = new CommandBufferPool(Api, _device, Queue, QueueLock, queueFamilyIndex);
|
CommandBufferPool = new CommandBufferPool(Api, _device, Queue, QueueLock, queueFamilyIndex);
|
||||||
|
|
||||||
@@ -345,22 +343,21 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
Api = api;
|
Api = api;
|
||||||
|
|
||||||
_instance = VulkanInitialization.CreateInstance(api, logLevel, _getRequiredExtensions());
|
_instance = VulkanInitialization.CreateInstance(api, logLevel, _getRequiredExtensions());
|
||||||
_debugMessenger = new VulkanDebugMessenger(api, _instance, logLevel);
|
_debugMessenger = new VulkanDebugMessenger(api, _instance.Instance, logLevel);
|
||||||
|
|
||||||
if (api.TryGetInstanceExtension(_instance, out KhrSurface surfaceApi))
|
if (api.TryGetInstanceExtension(_instance.Instance, out KhrSurface surfaceApi))
|
||||||
{
|
{
|
||||||
SurfaceApi = surfaceApi;
|
SurfaceApi = surfaceApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
_surface = _getSurface(_instance, api);
|
_surface = _getSurface(_instance.Instance, api);
|
||||||
_physicalDevice = VulkanInitialization.FindSuitablePhysicalDevice(api, _instance, _surface, _preferredGpuId);
|
_physicalDevice = VulkanInitialization.FindSuitablePhysicalDevice(api, _instance, _surface, _preferredGpuId);
|
||||||
|
|
||||||
var queueFamilyIndex = VulkanInitialization.FindSuitableQueueFamily(api, _physicalDevice, _surface, out uint maxQueueCount);
|
var queueFamilyIndex = VulkanInitialization.FindSuitableQueueFamily(api, _physicalDevice, _surface, out uint maxQueueCount);
|
||||||
var supportedExtensions = VulkanInitialization.GetSupportedExtensions(api, _physicalDevice);
|
|
||||||
|
|
||||||
_device = VulkanInitialization.CreateDevice(api, _physicalDevice, queueFamilyIndex, supportedExtensions, maxQueueCount);
|
_device = VulkanInitialization.CreateDevice(api, _physicalDevice, queueFamilyIndex, maxQueueCount);
|
||||||
|
|
||||||
if (api.TryGetDeviceExtension(_instance, _device, out KhrSwapchain swapchainApi))
|
if (api.TryGetDeviceExtension(_instance.Instance, _device, out KhrSwapchain swapchainApi))
|
||||||
{
|
{
|
||||||
SwapchainApi = swapchainApi;
|
SwapchainApi = swapchainApi;
|
||||||
}
|
}
|
||||||
@@ -369,9 +366,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
Queue = queue;
|
Queue = queue;
|
||||||
QueueLock = new object();
|
QueueLock = new object();
|
||||||
|
|
||||||
LoadFeatures(supportedExtensions, maxQueueCount, queueFamilyIndex);
|
LoadFeatures(maxQueueCount, queueFamilyIndex);
|
||||||
|
|
||||||
_window = new Window(this, _surface, _physicalDevice, _device);
|
_window = new Window(this, _surface, _physicalDevice.PhysicalDevice, _device);
|
||||||
|
|
||||||
_initialized = true;
|
_initialized = true;
|
||||||
}
|
}
|
||||||
@@ -536,10 +533,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
PNext = &featuresVk12
|
PNext = &featuresVk12
|
||||||
};
|
};
|
||||||
|
|
||||||
Api.GetPhysicalDeviceFeatures2(_physicalDevice, &features2);
|
Api.GetPhysicalDeviceFeatures2(_physicalDevice.PhysicalDevice, &features2);
|
||||||
Api.GetPhysicalDeviceProperties(_physicalDevice, out var properties);
|
|
||||||
|
|
||||||
var limits = properties.Limits;
|
var limits = _physicalDevice.PhysicalDeviceProperties.Limits;
|
||||||
|
|
||||||
return new Capabilities(
|
return new Capabilities(
|
||||||
api: TargetApi.Vulkan,
|
api: TargetApi.Vulkan,
|
||||||
@@ -623,7 +619,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
private unsafe void PrintGpuInformation()
|
private unsafe void PrintGpuInformation()
|
||||||
{
|
{
|
||||||
Api.GetPhysicalDeviceProperties(_physicalDevice, out var properties);
|
var properties = _physicalDevice.PhysicalDeviceProperties;
|
||||||
|
|
||||||
string vendorName = VendorUtils.GetNameFromId(properties.VendorID);
|
string vendorName = VendorUtils.GetNameFromId(properties.VendorID);
|
||||||
|
|
||||||
@@ -807,14 +803,14 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
sampler.Dispose();
|
sampler.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
SurfaceApi.DestroySurface(_instance, _surface, null);
|
SurfaceApi.DestroySurface(_instance.Instance, _surface, null);
|
||||||
|
|
||||||
Api.DestroyDevice(_device, null);
|
Api.DestroyDevice(_device, null);
|
||||||
|
|
||||||
_debugMessenger.Dispose();
|
_debugMessenger.Dispose();
|
||||||
|
|
||||||
// Last step destroy the instance
|
// Last step destroy the instance
|
||||||
Api.DestroyInstance(_instance, null);
|
_instance.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -405,7 +405,16 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
// Once everything is loaded, we can load cheats.
|
// Once everything is loaded, we can load cheats.
|
||||||
device.Configuration.VirtualFileSystem.ModLoader.LoadCheats(programId, tamperInfo, device.TamperMachine);
|
device.Configuration.VirtualFileSystem.ModLoader.LoadCheats(programId, tamperInfo, device.TamperMachine);
|
||||||
|
|
||||||
return new ProcessResult(metaLoader, applicationControlProperties, diskCacheEnabled, allowCodeMemoryForJit, processContextFactory.DiskCacheLoadState, process.Pid, meta.MainThreadPriority, meta.MainThreadStackSize);
|
return new ProcessResult(
|
||||||
|
metaLoader,
|
||||||
|
applicationControlProperties,
|
||||||
|
diskCacheEnabled,
|
||||||
|
allowCodeMemoryForJit,
|
||||||
|
processContextFactory.DiskCacheLoadState,
|
||||||
|
process.Pid,
|
||||||
|
meta.MainThreadPriority,
|
||||||
|
meta.MainThreadStackSize,
|
||||||
|
device.System.State.DesiredTitleLanguage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Result LoadIntoMemory(KProcess process, IExecutable image, ulong baseAddress)
|
public static Result LoadIntoMemory(KProcess process, IExecutable image, ulong baseAddress)
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
using LibHac.Ns;
|
using LibHac.Ns;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Cpu;
|
using Ryujinx.Cpu;
|
||||||
|
using Ryujinx.HLE.HOS.SystemState;
|
||||||
using Ryujinx.HLE.Loaders.Processes.Extensions;
|
using Ryujinx.HLE.Loaders.Processes.Extensions;
|
||||||
using Ryujinx.Horizon.Common;
|
using Ryujinx.Horizon.Common;
|
||||||
|
|
||||||
@@ -9,7 +10,7 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
{
|
{
|
||||||
public struct ProcessResult
|
public struct ProcessResult
|
||||||
{
|
{
|
||||||
public static ProcessResult Failed => new(null, new ApplicationControlProperty(), false, false, null, 0, 0, 0);
|
public static ProcessResult Failed => new(null, new ApplicationControlProperty(), false, false, null, 0, 0, 0, TitleLanguage.AmericanEnglish);
|
||||||
|
|
||||||
private readonly byte _mainThreadPriority;
|
private readonly byte _mainThreadPriority;
|
||||||
private readonly uint _mainThreadStackSize;
|
private readonly uint _mainThreadStackSize;
|
||||||
@@ -35,7 +36,8 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
IDiskCacheLoadState diskCacheLoadState,
|
IDiskCacheLoadState diskCacheLoadState,
|
||||||
ulong pid,
|
ulong pid,
|
||||||
byte mainThreadPriority,
|
byte mainThreadPriority,
|
||||||
uint mainThreadStackSize)
|
uint mainThreadStackSize,
|
||||||
|
TitleLanguage titleLanguage)
|
||||||
{
|
{
|
||||||
_mainThreadPriority = mainThreadPriority;
|
_mainThreadPriority = mainThreadPriority;
|
||||||
_mainThreadStackSize = mainThreadStackSize;
|
_mainThreadStackSize = mainThreadStackSize;
|
||||||
@@ -50,7 +52,17 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
{
|
{
|
||||||
ulong programId = metaLoader.GetProgramId();
|
ulong programId = metaLoader.GetProgramId();
|
||||||
|
|
||||||
|
if (ApplicationControlProperties.Title.ItemsRo.Length > 0)
|
||||||
|
{
|
||||||
|
var langIndex = ApplicationControlProperties.Title.ItemsRo.Length > (int)titleLanguage ? (int)titleLanguage : 0;
|
||||||
|
|
||||||
|
Name = ApplicationControlProperties.Title[langIndex].NameString.ToString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
Name = metaLoader.GetProgramName();
|
Name = metaLoader.GetProgramName();
|
||||||
|
}
|
||||||
|
|
||||||
ProgramId = programId;
|
ProgramId = programId;
|
||||||
ProgramIdText = $"{programId:x16}";
|
ProgramIdText = $"{programId:x16}";
|
||||||
Is64Bit = metaLoader.IsProgram64Bit();
|
Is64Bit = metaLoader.IsProgram64Bit();
|
||||||
|
Reference in New Issue
Block a user