aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Ryujinx.Graphics.Gpu/Image/FormatTable.cs30
-rw-r--r--src/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs20
-rw-r--r--src/Ryujinx.Graphics.Gpu/Image/TexturePool.cs2
3 files changed, 47 insertions, 5 deletions
diff --git a/src/Ryujinx.Graphics.Gpu/Image/FormatTable.cs b/src/Ryujinx.Graphics.Gpu/Image/FormatTable.cs
index 1b517e63f..0af0725a2 100644
--- a/src/Ryujinx.Graphics.Gpu/Image/FormatTable.cs
+++ b/src/Ryujinx.Graphics.Gpu/Image/FormatTable.cs
@@ -651,9 +651,35 @@ namespace Ryujinx.Graphics.Gpu.Image
651 /// <returns>True if the format is valid, false otherwise</returns> 651 /// <returns>True if the format is valid, false otherwise</returns>
652 public static bool TryGetTextureFormat(uint encoded, bool isSrgb, out FormatInfo format) 652 public static bool TryGetTextureFormat(uint encoded, bool isSrgb, out FormatInfo format)
653 { 653 {
654 encoded |= (isSrgb ? 1u << 19 : 0u); 654 bool isPacked = (encoded & 0x80000000u) != 0;
655 if (isPacked)
656 {
657 encoded &= ~0x80000000u;
658 }
655 659
656 return _textureFormats.TryGetValue((TextureFormat)encoded, out format); 660 encoded |= isSrgb ? 1u << 19 : 0u;
661
662 bool found = _textureFormats.TryGetValue((TextureFormat)encoded, out format);
663
664 if (found && isPacked && !format.Format.IsDepthOrStencil())
665 {
666 // If the packed flag is set, then the components of the pixel are tightly packed into the
667 // GPU registers on the shader.
668 // We can get the same behaviour by aliasing the texture as a format with the same amount of
669 // bytes per pixel, but only a single or the lowest possible number of components.
670
671 format = format.BytesPerPixel switch
672 {
673 1 => new FormatInfo(Format.R8Unorm, 1, 1, 1, 1),
674 2 => new FormatInfo(Format.R16Unorm, 1, 1, 2, 1),
675 4 => new FormatInfo(Format.R32Float, 1, 1, 4, 1),
676 8 => new FormatInfo(Format.R32G32Float, 1, 1, 8, 2),
677 16 => new FormatInfo(Format.R32G32B32A32Float, 1, 1, 16, 4),
678 _ => format,
679 };
680 }
681
682 return found;
657 } 683 }
658 684
659 /// <summary> 685 /// <summary>
diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs
index 5af0471c0..eef38948d 100644
--- a/src/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs
+++ b/src/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs
@@ -2,6 +2,8 @@ using Ryujinx.Common;
2using Ryujinx.Graphics.GAL; 2using Ryujinx.Graphics.GAL;
3using Ryujinx.Graphics.Texture; 3using Ryujinx.Graphics.Texture;
4using System; 4using System;
5using System.Diagnostics;
6using System.Numerics;
5 7
6namespace Ryujinx.Graphics.Gpu.Image 8namespace Ryujinx.Graphics.Gpu.Image
7{ 9{
@@ -339,7 +341,20 @@ namespace Ryujinx.Graphics.Gpu.Image
339 341
340 if (lhs.FormatInfo.BytesPerPixel != rhs.FormatInfo.BytesPerPixel && IsIncompatibleFormatAliasingAllowed(lhs.FormatInfo, rhs.FormatInfo)) 342 if (lhs.FormatInfo.BytesPerPixel != rhs.FormatInfo.BytesPerPixel && IsIncompatibleFormatAliasingAllowed(lhs.FormatInfo, rhs.FormatInfo))
341 { 343 {
342 alignedWidthMatches = lhsSize.Width * lhs.FormatInfo.BytesPerPixel == rhsSize.Width * rhs.FormatInfo.BytesPerPixel; 344 // If the formats are incompatible, but the texture strides match,
345 // we might allow them to be copy compatible depending on the format.
346 // The strides are aligned because the format with higher bytes per pixel
347 // might need a bit of padding at the end due to one width not being a multiple of the other.
348
349 Debug.Assert((1 << BitOperations.Log2((uint)lhs.FormatInfo.BytesPerPixel)) == lhs.FormatInfo.BytesPerPixel);
350 Debug.Assert((1 << BitOperations.Log2((uint)rhs.FormatInfo.BytesPerPixel)) == rhs.FormatInfo.BytesPerPixel);
351
352 int alignment = Math.Max(lhs.FormatInfo.BytesPerPixel, rhs.FormatInfo.BytesPerPixel);
353
354 int lhsStride = BitUtils.AlignUp(lhsSize.Width * lhs.FormatInfo.BytesPerPixel, alignment);
355 int rhsStride = BitUtils.AlignUp(rhsSize.Width * rhs.FormatInfo.BytesPerPixel, alignment);
356
357 alignedWidthMatches = lhsStride == rhsStride;
343 } 358 }
344 359
345 TextureViewCompatibility result = TextureViewCompatibility.Full; 360 TextureViewCompatibility result = TextureViewCompatibility.Full;
@@ -718,7 +733,8 @@ namespace Ryujinx.Graphics.Gpu.Image
718 (lhsFormat, rhsFormat) = (rhsFormat, lhsFormat); 733 (lhsFormat, rhsFormat) = (rhsFormat, lhsFormat);
719 } 734 }
720 735
721 return lhsFormat.Format == Format.R8Unorm && rhsFormat.Format == Format.R8G8B8A8Unorm; 736 return (lhsFormat.Format == Format.R8G8B8A8Unorm && rhsFormat.Format == Format.R32G32B32A32Float) ||
737 (lhsFormat.Format == Format.R8Unorm && rhsFormat.Format == Format.R8G8B8A8Unorm);
722 } 738 }
723 739
724 /// <summary> 740 /// <summary>
diff --git a/src/Ryujinx.Graphics.Gpu/Image/TexturePool.cs b/src/Ryujinx.Graphics.Gpu/Image/TexturePool.cs
index 0fdb6cd64..a4035577d 100644
--- a/src/Ryujinx.Graphics.Gpu/Image/TexturePool.cs
+++ b/src/Ryujinx.Graphics.Gpu/Image/TexturePool.cs
@@ -430,7 +430,7 @@ namespace Ryujinx.Graphics.Gpu.Image
430 430
431 if (!FormatTable.TryGetTextureFormat(format, srgb, out FormatInfo formatInfo)) 431 if (!FormatTable.TryGetTextureFormat(format, srgb, out FormatInfo formatInfo))
432 { 432 {
433 if (gpuVa != 0 && (int)format > 0) 433 if (gpuVa != 0 && format != 0)
434 { 434 {
435 Logger.Error?.Print(LogClass.Gpu, $"Invalid texture format 0x{format:X} (sRGB: {srgb})."); 435 Logger.Error?.Print(LogClass.Gpu, $"Invalid texture format 0x{format:X} (sRGB: {srgb}).");
436 } 436 }