Compare commits

...

4 Commits

Author SHA1 Message Date
Mary
fe9c49949a vulkan: Enforce Vulkan 1.2+ at instance API level and 1.1+ at device level (#4408)
* vulkan: Enforce Vulkan 1.2+ at instance API level and 1.1+ at device level

This ensure we don't end up trying to initialize with anything currently incompatible.

* Address riperiperi's comment
2023-02-13 22:04:55 +00:00
Mary
052b23c83c vulkan: Do not call vkCmdSetViewport when viewportCount is 0 (#4406)
This fix validation error "VUID-vkCmdSetViewport-viewportCount-arraylength".
2023-02-13 20:32:20 +00:00
riperiperi
e4f68592c3 Fix partial updates for textures. (#4401)
I was forcing some types of texture to partially update when investigating performance with games that stream in data, and noticed that partially loading texture data was really broken on both backends.

Fixes Vulkan texture set by getting the correct expected size for the texture. Fixes partial upload on both backends for both Texture 2D Array and Cubemap using the wrong offset and uploading to the first layer/level for a handle. 3D might also be affected.

This might fix textures randomly having incorrect data in games that render to it - jumbled in the case of OpenGL, and outdated/black in the case of Vulkan. This case typically happens in UE4 games.
2023-02-12 10:30:26 +01:00
Logan Stromberg
1dcd44b94f Treat NpadIdType < 0 as invalid. Filter invalid SupportedPlayers inside IHidServer.SetSupportedNpadIdType(). (#4377)
Co-authored-by: Logan Stromberg <lostromb@microsoft.com>
2023-02-10 12:37:20 -03:00
7 changed files with 57 additions and 20 deletions

View File

@@ -336,24 +336,23 @@ namespace Ryujinx.Graphics.Gpu.Image
if (_loadNeeded[baseHandle + i]) if (_loadNeeded[baseHandle + i])
{ {
var info = GetHandleInformation(baseHandle + i); var info = GetHandleInformation(baseHandle + i);
int offsetIndex = info.Index;
// Only one of these will be greater than 1, as partial sync is only called when there are sub-image views. // Only one of these will be greater than 1, as partial sync is only called when there are sub-image views.
for (int layer = 0; layer < info.Layers; layer++) for (int layer = 0; layer < info.Layers; layer++)
{ {
for (int level = 0; level < info.Levels; level++) for (int level = 0; level < info.Levels; level++)
{ {
int offsetIndex = GetOffsetIndex(info.BaseLayer + layer, info.BaseLevel + level);
int offset = _allOffsets[offsetIndex]; int offset = _allOffsets[offsetIndex];
int endOffset = Math.Min(offset + _sliceSizes[info.BaseLevel + level], (int)Storage.Size); int endOffset = Math.Min(offset + _sliceSizes[info.BaseLevel + level], (int)Storage.Size);
int size = endOffset - offset; int size = endOffset - offset;
ReadOnlySpan<byte> data = _physicalMemory.GetSpan(Storage.Range.GetSlice((ulong)offset, (ulong)size)); ReadOnlySpan<byte> data = _physicalMemory.GetSpan(Storage.Range.GetSlice((ulong)offset, (ulong)size));
SpanOrArray<byte> result = Storage.ConvertToHostCompatibleFormat(data, info.BaseLevel, true); SpanOrArray<byte> result = Storage.ConvertToHostCompatibleFormat(data, info.BaseLevel + level, true);
Storage.SetData(result, info.BaseLayer, info.BaseLevel); Storage.SetData(result, info.BaseLayer + layer, info.BaseLevel + level);
offsetIndex++;
} }
} }
} }

View File

@@ -650,9 +650,7 @@ namespace Ryujinx.Graphics.Vulkan
_newState.DepthWriteEnable = oldDepthWriteEnable; _newState.DepthWriteEnable = oldDepthWriteEnable;
_newState.Topology = oldTopology; _newState.Topology = oldTopology;
DynamicState.Viewports = oldViewports; DynamicState.SetViewports(ref oldViewports, oldViewportsCount);
DynamicState.ViewportsCount = (int)oldViewportsCount;
DynamicState.SetViewportsDirty();
_newState.ViewportsCount = oldViewportsCount; _newState.ViewportsCount = oldViewportsCount;
SignalStateChange(); SignalStateChange();
@@ -1183,6 +1181,8 @@ namespace Ryujinx.Graphics.Vulkan
return Math.Clamp(value, 0f, 1f); return Math.Clamp(value, 0f, 1f);
} }
DynamicState.ViewportsCount = (uint)count;
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
var viewport = viewports[i]; var viewport = viewports[i];
@@ -1196,8 +1196,6 @@ namespace Ryujinx.Graphics.Vulkan
Clamp(viewport.DepthFar))); Clamp(viewport.DepthFar)));
} }
DynamicState.ViewportsCount = count;
float disableTransformF = disableTransform ? 1.0f : 0.0f; float disableTransformF = disableTransform ? 1.0f : 0.0f;
if (SupportBufferUpdater.Data.ViewportInverse.W != disableTransformF || disableTransform) if (SupportBufferUpdater.Data.ViewportInverse.W != disableTransformF || disableTransform)
{ {

View File

@@ -21,7 +21,7 @@ namespace Ryujinx.Graphics.Vulkan
private Array4<float> _blendConstants; private Array4<float> _blendConstants;
public int ViewportsCount; public uint ViewportsCount;
public Array16<Viewport> Viewports; public Array16<Viewport> Viewports;
private enum DirtyFlags private enum DirtyFlags
@@ -88,9 +88,15 @@ namespace Ryujinx.Graphics.Vulkan
_dirty |= DirtyFlags.Viewport; _dirty |= DirtyFlags.Viewport;
} }
public void SetViewportsDirty() public void SetViewports(ref Array16<Viewport> viewports, uint viewportsCount)
{ {
_dirty |= DirtyFlags.Viewport; Viewports = viewports;
ViewportsCount = viewportsCount;
if (ViewportsCount != 0)
{
_dirty |= DirtyFlags.Viewport;
}
} }
public void ForceAllDirty() public void ForceAllDirty()
@@ -155,7 +161,10 @@ namespace Ryujinx.Graphics.Vulkan
private void RecordViewport(Vk api, CommandBuffer commandBuffer) private void RecordViewport(Vk api, CommandBuffer commandBuffer)
{ {
api.CmdSetViewport(commandBuffer, 0, (uint)ViewportsCount, Viewports.AsSpan()); if (ViewportsCount != 0)
{
api.CmdSetViewport(commandBuffer, 0, ViewportsCount, Viewports.AsSpan());
}
} }
} }
} }

View File

@@ -712,7 +712,7 @@ namespace Ryujinx.Graphics.Vulkan
for (int level = 0; level < levels; level++) for (int level = 0; level < levels; level++)
{ {
int mipSize = GetBufferDataLength(Info.GetMipSize(dstLevel + level)); int mipSize = GetBufferDataLength(Info.GetMipSize2D(dstLevel + level) * dstLayers);
int endOffset = offset + mipSize; int endOffset = offset + mipSize;

View File

@@ -14,6 +14,9 @@ namespace Ryujinx.Graphics.Vulkan
public unsafe static class VulkanInitialization public unsafe static class VulkanInitialization
{ {
private const uint InvalidIndex = uint.MaxValue; private const uint InvalidIndex = uint.MaxValue;
private static uint MinimalVulkanVersion = Vk.Version11.Value;
private static uint MinimalInstanceVulkanVersion = Vk.Version12.Value;
private static uint MaximumVulkanVersion = Vk.Version12.Value;
private const string AppName = "Ryujinx.Graphics.Vulkan"; private const string AppName = "Ryujinx.Graphics.Vulkan";
private const int QueuesCount = 2; private const int QueuesCount = 2;
@@ -99,7 +102,7 @@ namespace Ryujinx.Graphics.Vulkan
ApplicationVersion = 1, ApplicationVersion = 1,
PEngineName = (byte*)appName, PEngineName = (byte*)appName,
EngineVersion = 1, EngineVersion = 1,
ApiVersion = Vk.Version12.Value ApiVersion = MaximumVulkanVersion
}; };
IntPtr* ppEnabledExtensions = stackalloc IntPtr[enabledExtensions.Length]; IntPtr* ppEnabledExtensions = stackalloc IntPtr[enabledExtensions.Length];
@@ -224,7 +227,7 @@ namespace Ryujinx.Graphics.Vulkan
ApplicationVersion = 1, ApplicationVersion = 1,
PEngineName = (byte*)appName, PEngineName = (byte*)appName,
EngineVersion = 1, EngineVersion = 1,
ApiVersion = Vk.Version12.Value ApiVersion = MaximumVulkanVersion
}; };
var instanceCreateInfo = new InstanceCreateInfo var instanceCreateInfo = new InstanceCreateInfo
@@ -239,6 +242,27 @@ namespace Ryujinx.Graphics.Vulkan
api.CreateInstance(in instanceCreateInfo, null, out var instance).ThrowOnError(); api.CreateInstance(in instanceCreateInfo, null, out var instance).ThrowOnError();
// 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; uint physicalDeviceCount;
@@ -259,6 +283,11 @@ namespace Ryujinx.Graphics.Vulkan
var physicalDevice = physicalDevices[i]; var physicalDevice = physicalDevices[i];
api.GetPhysicalDeviceProperties(physicalDevice, out var properties); api.GetPhysicalDeviceProperties(physicalDevice, out var properties);
if (properties.ApiVersion < MinimalVulkanVersion)
{
continue;
}
devices[i] = new DeviceInfo( devices[i] = new DeviceInfo(
StringFromIdPair(properties.VendorID, properties.DeviceID), StringFromIdPair(properties.VendorID, properties.DeviceID),
VendorUtils.GetNameFromId(properties.VendorID), VendorUtils.GetNameFromId(properties.VendorID),

View File

@@ -38,7 +38,9 @@ namespace Ryujinx.HLE.HOS.Services.Hid.HidServer
public static bool IsValidNpadIdType(NpadIdType npadIdType) public static bool IsValidNpadIdType(NpadIdType npadIdType)
{ {
return npadIdType <= NpadIdType.Player8 || npadIdType == NpadIdType.Handheld || npadIdType == NpadIdType.Unknown; return (npadIdType >= NpadIdType.Player1 && npadIdType <= NpadIdType.Player8) ||
npadIdType == NpadIdType.Handheld ||
npadIdType == NpadIdType.Unknown;
} }
} }
} }

View File

@@ -722,7 +722,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
for (int i = 0; i < supportedPlayerIds.Length; ++i) for (int i = 0; i < supportedPlayerIds.Length; ++i)
{ {
if (supportedPlayerIds[i] >= 0) if (HidUtils.IsValidNpadIdType(supportedPlayerIds[i]))
{ {
context.Device.Hid.Npads.SetSupportedPlayer(HidUtils.GetIndexFromNpadIdType(supportedPlayerIds[i])); context.Device.Hid.Npads.SetSupportedPlayer(HidUtils.GetIndexFromNpadIdType(supportedPlayerIds[i]));
} }
@@ -1101,7 +1101,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
if (deviceType < NpadStyleIndex.System || deviceType >= NpadStyleIndex.FullKey) if (deviceType < NpadStyleIndex.System || deviceType >= NpadStyleIndex.FullKey)
{ {
if (npadIdType >= (NpadIdType.Player8 + 1) && npadIdType != NpadIdType.Handheld && npadIdType != NpadIdType.Unknown) if (!HidUtils.IsValidNpadIdType(npadIdType))
{ {
return ResultCode.InvalidNpadIdType; return ResultCode.InvalidNpadIdType;
} }