mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2025-09-13 21:45:11 +00:00
This was a missed change that would resolve Image Usage validation error that is created fairly frequently. ``VUID-VkImageViewCreateInfo-pNext-02662(ERROR / SPEC): msgNum: -55646969 - Validation Error: [ VUID-VkImageViewCreateInfo-pNext-02662 ] Object 0: handle = 0x260b9d1f6b8, type = VK_OBJECT_TYPE_IMAGE; | MessageID = 0xfcaee507 | vkCreateImageView(): pCreateInfo->pNext<VkImageViewUsageCreateInfo>.usage (VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_STORAGE_BIT) must not include any bits that were not set in VkImageCreateInfo::usage (VK_IMAGE_USAGE_TRANSFER_SRC_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT|VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) of the image. The Vulkan spec states: If the pNext chain includes a VkImageViewUsageCreateInfo structure, and image was not created with a VkImageStencilUsageCreateInfo structure included in the pNext chain of VkImageCreateInfo, its usage member must not include any bits that were not set in the usage member of the VkImageCreateInfo structure used to create image (https://vulkan.lunarg.com/doc/view/1.3.290.0/windows/1.3-extensions/vkspec.html#VUID-VkImageViewCreateInfo-pNext-02662) Objects: 1 [0] 0x260b9d1f6b8, type: 10, name: NULL ``
234 lines
8.1 KiB
C#
234 lines
8.1 KiB
C#
using Ryujinx.Common.Logging;
|
|
using Ryujinx.Graphics.GAL;
|
|
using Silk.NET.Vulkan;
|
|
using System;
|
|
using Format = Ryujinx.Graphics.GAL.Format;
|
|
using VkFormat = Silk.NET.Vulkan.Format;
|
|
|
|
namespace Ryujinx.Graphics.Vulkan
|
|
{
|
|
class FormatCapabilities
|
|
{
|
|
private static readonly GAL.Format[] _scaledFormats = {
|
|
GAL.Format.R8Uscaled,
|
|
GAL.Format.R8Sscaled,
|
|
GAL.Format.R16Uscaled,
|
|
GAL.Format.R16Sscaled,
|
|
GAL.Format.R8G8Uscaled,
|
|
GAL.Format.R8G8Sscaled,
|
|
GAL.Format.R16G16Uscaled,
|
|
GAL.Format.R16G16Sscaled,
|
|
GAL.Format.R8G8B8Uscaled,
|
|
GAL.Format.R8G8B8Sscaled,
|
|
GAL.Format.R16G16B16Uscaled,
|
|
GAL.Format.R16G16B16Sscaled,
|
|
GAL.Format.R8G8B8A8Uscaled,
|
|
GAL.Format.R8G8B8A8Sscaled,
|
|
GAL.Format.R16G16B16A16Uscaled,
|
|
GAL.Format.R16G16B16A16Sscaled,
|
|
GAL.Format.R10G10B10A2Uscaled,
|
|
GAL.Format.R10G10B10A2Sscaled,
|
|
};
|
|
|
|
private static readonly GAL.Format[] _intFormats = {
|
|
GAL.Format.R8Uint,
|
|
GAL.Format.R8Sint,
|
|
GAL.Format.R16Uint,
|
|
GAL.Format.R16Sint,
|
|
GAL.Format.R8G8Uint,
|
|
GAL.Format.R8G8Sint,
|
|
GAL.Format.R16G16Uint,
|
|
GAL.Format.R16G16Sint,
|
|
GAL.Format.R8G8B8Uint,
|
|
GAL.Format.R8G8B8Sint,
|
|
GAL.Format.R16G16B16Uint,
|
|
GAL.Format.R16G16B16Sint,
|
|
GAL.Format.R8G8B8A8Uint,
|
|
GAL.Format.R8G8B8A8Sint,
|
|
GAL.Format.R16G16B16A16Uint,
|
|
GAL.Format.R16G16B16A16Sint,
|
|
GAL.Format.R10G10B10A2Uint,
|
|
GAL.Format.R10G10B10A2Sint,
|
|
};
|
|
|
|
private readonly FormatFeatureFlags[] _bufferTable;
|
|
private readonly FormatFeatureFlags[] _optimalTable;
|
|
|
|
private readonly Vk _api;
|
|
private readonly PhysicalDevice _physicalDevice;
|
|
|
|
public FormatCapabilities(Vk api, PhysicalDevice physicalDevice)
|
|
{
|
|
_api = api;
|
|
_physicalDevice = physicalDevice;
|
|
|
|
int totalFormats = Enum.GetNames(typeof(Format)).Length;
|
|
|
|
_bufferTable = new FormatFeatureFlags[totalFormats];
|
|
_optimalTable = new FormatFeatureFlags[totalFormats];
|
|
}
|
|
|
|
public bool BufferFormatsSupport(FormatFeatureFlags flags, params ReadOnlySpan<Format> formats)
|
|
{
|
|
foreach (Format format in formats)
|
|
{
|
|
if (!BufferFormatSupports(flags, format))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public bool OptimalFormatsSupport(FormatFeatureFlags flags, params ReadOnlySpan<Format> formats)
|
|
{
|
|
foreach (Format format in formats)
|
|
{
|
|
if (!OptimalFormatSupports(flags, format))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public bool BufferFormatSupports(FormatFeatureFlags flags, Format format)
|
|
{
|
|
var formatFeatureFlags = _bufferTable[(int)format];
|
|
|
|
if (formatFeatureFlags == 0)
|
|
{
|
|
_api.GetPhysicalDeviceFormatProperties(_physicalDevice, FormatTable.GetFormat(format), out var fp);
|
|
formatFeatureFlags = fp.BufferFeatures;
|
|
_bufferTable[(int)format] = formatFeatureFlags;
|
|
}
|
|
|
|
return (formatFeatureFlags & flags) == flags;
|
|
}
|
|
|
|
public bool SupportsScaledVertexFormats()
|
|
{
|
|
// We want to check is all scaled formats are supported,
|
|
// but if the integer variant is not supported either,
|
|
// then the format is likely not supported at all,
|
|
// we ignore formats that are entirely unsupported here.
|
|
|
|
for (int i = 0; i < _scaledFormats.Length; i++)
|
|
{
|
|
if (!BufferFormatSupports(FormatFeatureFlags.VertexBufferBit, _scaledFormats[i]) &&
|
|
BufferFormatSupports(FormatFeatureFlags.VertexBufferBit, _intFormats[i]))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public bool BufferFormatSupports(FormatFeatureFlags flags, VkFormat format)
|
|
{
|
|
_api.GetPhysicalDeviceFormatProperties(_physicalDevice, format, out var fp);
|
|
|
|
return (fp.BufferFeatures & flags) == flags;
|
|
}
|
|
|
|
public bool OptimalFormatSupports(FormatFeatureFlags flags, Format format)
|
|
{
|
|
var formatFeatureFlags = _optimalTable[(int)format];
|
|
|
|
if (formatFeatureFlags == 0)
|
|
{
|
|
_api.GetPhysicalDeviceFormatProperties(_physicalDevice, FormatTable.GetFormat(format), out var fp);
|
|
formatFeatureFlags = fp.OptimalTilingFeatures;
|
|
_optimalTable[(int)format] = formatFeatureFlags;
|
|
}
|
|
|
|
return (formatFeatureFlags & flags) == flags;
|
|
}
|
|
|
|
public VkFormat ConvertToVkFormat(Format srcFormat, bool storageFeatureFlagRequired)
|
|
{
|
|
var format = FormatTable.GetFormat(srcFormat);
|
|
|
|
var requiredFeatures = FormatFeatureFlags.SampledImageBit |
|
|
FormatFeatureFlags.TransferSrcBit |
|
|
FormatFeatureFlags.TransferDstBit;
|
|
|
|
if (srcFormat.IsDepthOrStencil())
|
|
{
|
|
requiredFeatures |= FormatFeatureFlags.DepthStencilAttachmentBit;
|
|
}
|
|
else if (srcFormat.IsRtColorCompatible())
|
|
{
|
|
requiredFeatures |= FormatFeatureFlags.ColorAttachmentBit;
|
|
}
|
|
|
|
if (srcFormat.IsImageCompatible() && storageFeatureFlagRequired)
|
|
{
|
|
requiredFeatures |= FormatFeatureFlags.StorageImageBit;
|
|
}
|
|
|
|
if (!OptimalFormatSupports(requiredFeatures, srcFormat) || (IsD24S8(srcFormat) && VulkanConfiguration.ForceD24S8Unsupported))
|
|
{
|
|
// The format is not supported. Can we convert it to a higher precision format?
|
|
if (IsD24S8(srcFormat))
|
|
{
|
|
format = VkFormat.D32SfloatS8Uint;
|
|
}
|
|
else if (srcFormat == Format.R4G4B4A4Unorm)
|
|
{
|
|
format = VkFormat.R4G4B4A4UnormPack16;
|
|
}
|
|
else
|
|
{
|
|
Logger.Error?.Print(LogClass.Gpu, $"Format {srcFormat} is not supported by the host.");
|
|
}
|
|
}
|
|
|
|
return format;
|
|
}
|
|
|
|
public VkFormat ConvertToVertexVkFormat(Format srcFormat)
|
|
{
|
|
var format = FormatTable.GetFormat(srcFormat);
|
|
|
|
if (!BufferFormatSupports(FormatFeatureFlags.VertexBufferBit, srcFormat) ||
|
|
(IsRGB16IntFloat(srcFormat) && VulkanConfiguration.ForceRGB16IntFloatUnsupported))
|
|
{
|
|
// The format is not supported. Can we convert it to an alternative format?
|
|
switch (srcFormat)
|
|
{
|
|
case Format.R16G16B16Float:
|
|
format = VkFormat.R16G16B16A16Sfloat;
|
|
break;
|
|
case Format.R16G16B16Sint:
|
|
format = VkFormat.R16G16B16A16Sint;
|
|
break;
|
|
case Format.R16G16B16Uint:
|
|
format = VkFormat.R16G16B16A16Uint;
|
|
break;
|
|
default:
|
|
Logger.Error?.Print(LogClass.Gpu, $"Format {srcFormat} is not supported by the host.");
|
|
break;
|
|
}
|
|
}
|
|
|
|
return format;
|
|
}
|
|
|
|
public static bool IsD24S8(Format format)
|
|
{
|
|
return format == Format.D24UnormS8Uint || format == Format.S8UintD24Unorm || format == Format.X8UintD24Unorm;
|
|
}
|
|
|
|
private static bool IsRGB16IntFloat(Format format)
|
|
{
|
|
return format == Format.R16G16B16Float ||
|
|
format == Format.R16G16B16Sint ||
|
|
format == Format.R16G16B16Uint;
|
|
}
|
|
}
|
|
}
|