aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Graphics.Gpu/Image
diff options
context:
space:
mode:
Diffstat (limited to 'src/Ryujinx.Graphics.Gpu/Image')
-rw-r--r--src/Ryujinx.Graphics.Gpu/Image/Texture.cs6
-rw-r--r--src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs92
-rw-r--r--src/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs78
-rw-r--r--src/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs9
-rw-r--r--src/Ryujinx.Graphics.Gpu/Image/TextureInfo.cs34
-rw-r--r--src/Ryujinx.Graphics.Gpu/Image/TextureViewCompatibility.cs1
6 files changed, 114 insertions, 106 deletions
diff --git a/src/Ryujinx.Graphics.Gpu/Image/Texture.cs b/src/Ryujinx.Graphics.Gpu/Image/Texture.cs
index 0427d09b..a7af1aad 100644
--- a/src/Ryujinx.Graphics.Gpu/Image/Texture.cs
+++ b/src/Ryujinx.Graphics.Gpu/Image/Texture.cs
@@ -1170,6 +1170,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="caps">Host GPU capabilities</param>
/// <param name="firstLayer">Texture view initial layer on this texture</param>
/// <param name="firstLevel">Texture view first mipmap level on this texture</param>
+ /// <param name="flags">Texture search flags</param>
/// <returns>The level of compatiblilty a view with the given parameters created from this texture has</returns>
public TextureViewCompatibility IsViewCompatible(
TextureInfo info,
@@ -1178,11 +1179,12 @@ namespace Ryujinx.Graphics.Gpu.Image
int layerSize,
Capabilities caps,
out int firstLayer,
- out int firstLevel)
+ out int firstLevel,
+ TextureSearchFlags flags = TextureSearchFlags.None)
{
TextureViewCompatibility result = TextureViewCompatibility.Full;
- result = TextureCompatibility.PropagateViewCompatibility(result, TextureCompatibility.ViewFormatCompatible(Info, info, caps));
+ result = TextureCompatibility.PropagateViewCompatibility(result, TextureCompatibility.ViewFormatCompatible(Info, info, caps, flags));
if (result != TextureViewCompatibility.Incompatible)
{
result = TextureCompatibility.PropagateViewCompatibility(result, TextureCompatibility.ViewTargetCompatible(Info, info, ref caps));
diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
index 49191239..bccd3fd7 100644
--- a/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
+++ b/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
@@ -569,7 +569,7 @@ namespace Ryujinx.Graphics.Gpu.Image
Texture texture = null;
- TextureMatchQuality bestQuality = TextureMatchQuality.NoMatch;
+ long bestSequence = 0;
for (int index = 0; index < sameAddressOverlapsCount; index++)
{
@@ -601,17 +601,12 @@ namespace Ryujinx.Graphics.Gpu.Image
continue;
}
}
- }
- if (matchQuality == TextureMatchQuality.Perfect)
- {
- texture = overlap;
- break;
- }
- else if (matchQuality > bestQuality)
- {
- texture = overlap;
- bestQuality = matchQuality;
+ if (texture == null || overlap.Group.ModifiedSequence - bestSequence > 0)
+ {
+ texture = overlap;
+ bestSequence = overlap.Group.ModifiedSequence;
+ }
}
}
@@ -664,6 +659,7 @@ namespace Ryujinx.Graphics.Gpu.Image
int fullyCompatible = 0;
// Evaluate compatibility of overlaps, add temporary references
+ int preferredOverlap = -1;
for (int index = 0; index < overlapsCount; index++)
{
@@ -675,17 +671,26 @@ namespace Ryujinx.Graphics.Gpu.Image
sizeInfo.LayerSize,
_context.Capabilities,
out int firstLayer,
- out int firstLevel);
+ out int firstLevel,
+ flags);
- if (overlapCompatibility == TextureViewCompatibility.Full)
+ if (overlapCompatibility >= TextureViewCompatibility.FormatAlias)
{
if (overlap.IsView)
{
- overlapCompatibility = TextureViewCompatibility.CopyOnly;
+ overlapCompatibility = overlapCompatibility == TextureViewCompatibility.FormatAlias ?
+ TextureViewCompatibility.Incompatible :
+ TextureViewCompatibility.CopyOnly;
}
else
{
fullyCompatible++;
+
+ if (preferredOverlap == -1 || overlap.Group.ModifiedSequence - bestSequence > 0)
+ {
+ preferredOverlap = index;
+ bestSequence = overlap.Group.ModifiedSequence;
+ }
}
}
@@ -695,37 +700,50 @@ namespace Ryujinx.Graphics.Gpu.Image
// Search through the overlaps to find a compatible view and establish any copy dependencies.
- for (int index = 0; index < overlapsCount; index++)
+ if (preferredOverlap != -1)
{
- Texture overlap = _textureOverlaps[index];
- OverlapInfo oInfo = _overlapInfo[index];
+ Texture overlap = _textureOverlaps[preferredOverlap];
+ OverlapInfo oInfo = _overlapInfo[preferredOverlap];
+
+ bool aliased = oInfo.Compatibility == TextureViewCompatibility.FormatAlias;
- if (oInfo.Compatibility == TextureViewCompatibility.Full)
+ if (!isSamplerTexture)
{
- if (!isSamplerTexture)
- {
- // If this is not a sampler texture, the size might be different from the requested size,
- // so we need to make sure the texture information has the correct size for this base texture,
- // before creating the view.
- info = info.CreateInfoForLevelView(overlap, oInfo.FirstLevel);
- }
+ // If this is not a sampler texture, the size might be different from the requested size,
+ // so we need to make sure the texture information has the correct size for this base texture,
+ // before creating the view.
- texture = overlap.CreateView(info, sizeInfo, range.Value, oInfo.FirstLayer, oInfo.FirstLevel);
- texture.SynchronizeMemory();
- break;
+ info = info.CreateInfoForLevelView(overlap, oInfo.FirstLevel, aliased);
+ }
+ else if (aliased)
+ {
+ // The format must be changed to match the parent.
+ info = info.CreateInfoWithFormat(overlap.Info.FormatInfo);
}
- else if (oInfo.Compatibility == TextureViewCompatibility.CopyOnly && fullyCompatible == 0)
+
+ texture = overlap.CreateView(info, sizeInfo, range.Value, oInfo.FirstLayer, oInfo.FirstLevel);
+ texture.SynchronizeMemory();
+ }
+ else
+ {
+ for (int index = 0; index < overlapsCount; index++)
{
- // Only copy compatible. If there's another choice for a FULLY compatible texture, choose that instead.
+ Texture overlap = _textureOverlaps[index];
+ OverlapInfo oInfo = _overlapInfo[index];
+
+ if (oInfo.Compatibility == TextureViewCompatibility.CopyOnly && fullyCompatible == 0)
+ {
+ // Only copy compatible. If there's another choice for a FULLY compatible texture, choose that instead.
- texture = new Texture(_context, _physicalMemory, info, sizeInfo, range.Value, scaleMode);
+ texture = new Texture(_context, _physicalMemory, info, sizeInfo, range.Value, scaleMode);
- texture.InitializeGroup(true, true, new List<TextureIncompatibleOverlap>());
- texture.InitializeData(false, false);
+ texture.InitializeGroup(true, true, new List<TextureIncompatibleOverlap>());
+ texture.InitializeData(false, false);
- overlap.SynchronizeMemory();
- overlap.CreateCopyDependency(texture, oInfo.FirstLayer, oInfo.FirstLevel, true);
- break;
+ overlap.SynchronizeMemory();
+ overlap.CreateCopyDependency(texture, oInfo.FirstLayer, oInfo.FirstLevel, true);
+ break;
+ }
}
}
@@ -740,7 +758,7 @@ namespace Ryujinx.Graphics.Gpu.Image
Texture overlap = _textureOverlaps[index];
OverlapInfo oInfo = _overlapInfo[index];
- if (oInfo.Compatibility <= TextureViewCompatibility.LayoutIncompatible)
+ if (oInfo.Compatibility <= TextureViewCompatibility.LayoutIncompatible || oInfo.Compatibility == TextureViewCompatibility.FormatAlias)
{
if (!overlap.IsView && texture.DataOverlaps(overlap, oInfo.Compatibility))
{
diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs
index 5d846222..85ad0bb0 100644
--- a/src/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs
+++ b/src/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs
@@ -291,22 +291,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <returns>The minimum compatibility level of two provided view compatibility results</returns>
public static TextureViewCompatibility PropagateViewCompatibility(TextureViewCompatibility first, TextureViewCompatibility second)
{
- if (first == TextureViewCompatibility.Incompatible || second == TextureViewCompatibility.Incompatible)
- {
- return TextureViewCompatibility.Incompatible;
- }
- else if (first == TextureViewCompatibility.LayoutIncompatible || second == TextureViewCompatibility.LayoutIncompatible)
- {
- return TextureViewCompatibility.LayoutIncompatible;
- }
- else if (first == TextureViewCompatibility.CopyOnly || second == TextureViewCompatibility.CopyOnly)
- {
- return TextureViewCompatibility.CopyOnly;
- }
- else
- {
- return TextureViewCompatibility.Full;
- }
+ return (TextureViewCompatibility)Math.Min((int)first, (int)second);
}
/// <summary>
@@ -628,15 +613,21 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="lhs">Texture information of the texture view</param>
/// <param name="rhs">Texture information of the texture view</param>
/// <param name="caps">Host GPU capabilities</param>
+ /// <param name="flags">Texture search flags</param>
/// <returns>The view compatibility level of the texture formats</returns>
- public static TextureViewCompatibility ViewFormatCompatible(TextureInfo lhs, TextureInfo rhs, Capabilities caps)
+ public static TextureViewCompatibility ViewFormatCompatible(TextureInfo lhs, TextureInfo rhs, Capabilities caps, TextureSearchFlags flags)
{
FormatInfo lhsFormat = lhs.FormatInfo;
FormatInfo rhsFormat = rhs.FormatInfo;
if (lhsFormat.Format.IsDepthOrStencil() || rhsFormat.Format.IsDepthOrStencil())
{
- return lhsFormat.Format == rhsFormat.Format ? TextureViewCompatibility.Full : TextureViewCompatibility.Incompatible;
+ return FormatMatches(lhs, rhs, flags.HasFlag(TextureSearchFlags.ForSampler), flags.HasFlag(TextureSearchFlags.DepthAlias)) switch
+ {
+ TextureMatchQuality.Perfect => TextureViewCompatibility.Full,
+ TextureMatchQuality.FormatAlias => TextureViewCompatibility.FormatAlias,
+ _ => TextureViewCompatibility.Incompatible
+ };
}
if (IsFormatHostIncompatible(lhs, caps) || IsFormatHostIncompatible(rhs, caps))
@@ -755,49 +746,6 @@ namespace Ryujinx.Graphics.Gpu.Image
}
/// <summary>
- /// Checks if a swizzle component in two textures functionally match, taking into account if the components are defined.
- /// </summary>
- /// <param name="lhs">Texture information to compare</param>
- /// <param name="rhs">Texture information to compare with</param>
- /// <param name="swizzleLhs">Swizzle component for the first texture</param>
- /// <param name="swizzleRhs">Swizzle component for the second texture</param>
- /// <param name="component">Component index, starting at 0 for red</param>
- /// <returns>True if the swizzle components functionally match, false othersize</returns>
- private static bool SwizzleComponentMatches(TextureInfo lhs, TextureInfo rhs, SwizzleComponent swizzleLhs, SwizzleComponent swizzleRhs, int component)
- {
- int lhsComponents = lhs.FormatInfo.Components;
- int rhsComponents = rhs.FormatInfo.Components;
-
- if (lhsComponents == 4 && rhsComponents == 4)
- {
- return swizzleLhs == swizzleRhs;
- }
-
- // Swizzles after the number of components a format defines are "undefined".
- // We allow these to not be equal under certain circumstances.
- // This can only happen when there are less than 4 components in a format.
- // It tends to happen when float depth textures are sampled.
-
- bool lhsDefined = (swizzleLhs - SwizzleComponent.Red) < lhsComponents;
- bool rhsDefined = (swizzleRhs - SwizzleComponent.Red) < rhsComponents;
-
- if (lhsDefined == rhsDefined)
- {
- // If both are undefined, return true. Otherwise just check if they're equal.
- return lhsDefined ? swizzleLhs == swizzleRhs : true;
- }
- else
- {
- SwizzleComponent defined = lhsDefined ? swizzleLhs : swizzleRhs;
- SwizzleComponent undefined = lhsDefined ? swizzleRhs : swizzleLhs;
-
- // Undefined swizzle can be matched by a forced value (0, 1), exact equality, or expected value.
- // For example, R___ matches R001, RGBA but not RBGA.
- return defined == undefined || defined < SwizzleComponent.Red || defined == SwizzleComponent.Red + component;
- }
- }
-
- /// <summary>
/// Checks if the texture shader sampling parameters of two texture informations match.
/// </summary>
/// <param name="lhs">Texture information to compare</param>
@@ -806,10 +754,10 @@ namespace Ryujinx.Graphics.Gpu.Image
public static bool SamplerParamsMatches(TextureInfo lhs, TextureInfo rhs)
{
return lhs.DepthStencilMode == rhs.DepthStencilMode &&
- SwizzleComponentMatches(lhs, rhs, lhs.SwizzleR, rhs.SwizzleR, 0) &&
- SwizzleComponentMatches(lhs, rhs, lhs.SwizzleG, rhs.SwizzleG, 1) &&
- SwizzleComponentMatches(lhs, rhs, lhs.SwizzleB, rhs.SwizzleB, 2) &&
- SwizzleComponentMatches(lhs, rhs, lhs.SwizzleA, rhs.SwizzleA, 3);
+ lhs.SwizzleR == rhs.SwizzleR &&
+ lhs.SwizzleG == rhs.SwizzleG &&
+ lhs.SwizzleB == rhs.SwizzleB &&
+ lhs.SwizzleA == rhs.SwizzleA;
}
/// <summary>
diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs
index b36b16e9..2fa1e79e 100644
--- a/src/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs
+++ b/src/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs
@@ -68,6 +68,11 @@ namespace Ryujinx.Graphics.Gpu.Image
/// </summary>
public bool HasIncompatibleOverlaps => _incompatibleOverlaps.Count > 0;
+ /// <summary>
+ /// Number indicating the order this texture group was modified relative to others.
+ /// </summary>
+ public long ModifiedSequence { get; private set; }
+
private readonly GpuContext _context;
private readonly PhysicalMemory _physicalMemory;
@@ -664,6 +669,8 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="texture">The texture that has been modified</param>
public void SignalModified(Texture texture)
{
+ ModifiedSequence = _context.GetModifiedSequence();
+
ClearIncompatibleOverlaps(texture);
EvaluateRelevantHandles(texture, (baseHandle, regionCount, split) =>
@@ -684,6 +691,8 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="bound">True if this texture is being bound, false if unbound</param>
public void SignalModifying(Texture texture, bool bound)
{
+ ModifiedSequence = _context.GetModifiedSequence();
+
ClearIncompatibleOverlaps(texture);
EvaluateRelevantHandles(texture, (baseHandle, regionCount, split) =>
diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureInfo.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureInfo.cs
index a7ee12bc..1994d226 100644
--- a/src/Ryujinx.Graphics.Gpu/Image/TextureInfo.cs
+++ b/src/Ryujinx.Graphics.Gpu/Image/TextureInfo.cs
@@ -300,8 +300,9 @@ namespace Ryujinx.Graphics.Gpu.Image
/// </summary>
/// <param name="parent">The parent texture</param>
/// <param name="firstLevel">The first level of the texture view</param>
+ /// <param name="parentFormat">True if the parent format should be inherited</param>
/// <returns>The adjusted texture information with the new size</returns>
- public TextureInfo CreateInfoForLevelView(Texture parent, int firstLevel)
+ public TextureInfo CreateInfoForLevelView(Texture parent, int firstLevel, bool parentFormat)
{
// When the texture is used as view of another texture, we must
// ensure that the sizes are valid, otherwise data uploads would fail
@@ -370,7 +371,36 @@ namespace Ryujinx.Graphics.Gpu.Image
GobBlocksInZ,
GobBlocksInTileX,
target,
- FormatInfo,
+ parentFormat ? parent.Info.FormatInfo : FormatInfo,
+ DepthStencilMode,
+ SwizzleR,
+ SwizzleG,
+ SwizzleB,
+ SwizzleA);
+ }
+
+ /// <summary>
+ /// Creates texture information for a given format and this information.
+ /// </summary>
+ /// <param name="formatInfo">Format for the new texture info</param>
+ /// <returns>New info with the specified format</returns>
+ public TextureInfo CreateInfoWithFormat(FormatInfo formatInfo)
+ {
+ return new TextureInfo(
+ GpuAddress,
+ Width,
+ Height,
+ DepthOrLayers,
+ Levels,
+ SamplesInX,
+ SamplesInY,
+ Stride,
+ IsLinear,
+ GobBlocksInY,
+ GobBlocksInZ,
+ GobBlocksInTileX,
+ Target,
+ formatInfo,
DepthStencilMode,
SwizzleR,
SwizzleG,
diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureViewCompatibility.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureViewCompatibility.cs
index b89936eb..dfa688c4 100644
--- a/src/Ryujinx.Graphics.Gpu/Image/TextureViewCompatibility.cs
+++ b/src/Ryujinx.Graphics.Gpu/Image/TextureViewCompatibility.cs
@@ -9,6 +9,7 @@
Incompatible = 0,
LayoutIncompatible,
CopyOnly,
+ FormatAlias,
Full
}
}