Handle mismatching texture size with copy dependencies (#4364)
* Handle mismatching texture size with copy dependencies * Create copy and render textures with the minimum possible size * Only align width for comparisons, assume that height is always exact * Fix IsExactMatch size check * Allow sampler and copy textures to match textures with larger width * Delete texture ChangeSize related code * Move AdjustSize to TextureInfo and give it a better name, adjust usages * Fix GetMinimumWidthInGob when minimumWidth > width * Only update render targets that are actually cleared for clear Avoids creating textures with incorrect sizes * Delete UpdateRenderTargetState method that is not needed anymore Clears now only ever sets the render targets that will be cleared rather than all of them
This commit is contained in:
parent
59755818ef
commit
96cf242bcf
12 changed files with 271 additions and 406 deletions
|
@ -380,42 +380,37 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
/// </summary>
|
||||
/// <param name="lhs">Texture information of the texture view</param>
|
||||
/// <param name="rhs">Texture information of the texture view to match against</param>
|
||||
/// <param name="exact">Indicates if the sizes must be exactly equal</param>
|
||||
/// <param name="level">Mipmap level of the texture view in relation to this texture</param>
|
||||
/// <returns>The view compatibility level of the view sizes</returns>
|
||||
public static TextureViewCompatibility ViewSizeMatches(TextureInfo lhs, TextureInfo rhs, int level)
|
||||
public static TextureViewCompatibility ViewSizeMatches(TextureInfo lhs, TextureInfo rhs, bool exact, int level)
|
||||
{
|
||||
Size size = GetAlignedSize(lhs, level);
|
||||
Size lhsAlignedSize = GetAlignedSize(lhs, level);
|
||||
Size rhsAlignedSize = GetAlignedSize(rhs);
|
||||
|
||||
Size otherSize = GetAlignedSize(rhs);
|
||||
Size lhsSize = GetSizeInBlocks(lhs, level);
|
||||
Size rhsSize = GetSizeInBlocks(rhs);
|
||||
|
||||
TextureViewCompatibility result = TextureViewCompatibility.Full;
|
||||
|
||||
// For copies, we can copy a subset of the 3D texture slices,
|
||||
// so the depth may be different in this case.
|
||||
if (rhs.Target == Target.Texture3D && size.Depth != otherSize.Depth)
|
||||
if (rhs.Target == Target.Texture3D && lhsSize.Depth != rhsSize.Depth)
|
||||
{
|
||||
result = TextureViewCompatibility.CopyOnly;
|
||||
}
|
||||
|
||||
if (size.Width == otherSize.Width && size.Height == otherSize.Height)
|
||||
// Some APIs align the width for copy and render target textures,
|
||||
// so the width may not match in this case for different uses of the same texture.
|
||||
// To account for this, we compare the aligned width here.
|
||||
// We expect height to always match exactly, if the texture is the same.
|
||||
if (lhsAlignedSize.Width == rhsAlignedSize.Width && lhsSize.Height == rhsSize.Height)
|
||||
{
|
||||
if (level > 0 && result == TextureViewCompatibility.Full)
|
||||
{
|
||||
// A resize should not change the aligned size of the largest mip.
|
||||
// If it would, then create a copy dependency rather than a full view.
|
||||
|
||||
Size mip0SizeLhs = GetAlignedSize(lhs);
|
||||
Size mip0SizeRhs = GetLargestAlignedSize(rhs, level);
|
||||
|
||||
if (mip0SizeLhs.Width != mip0SizeRhs.Width || mip0SizeLhs.Height != mip0SizeRhs.Height)
|
||||
{
|
||||
result = TextureViewCompatibility.CopyOnly;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return (exact && lhsSize.Width != rhsSize.Width) || lhsSize.Width < rhsSize.Width
|
||||
? TextureViewCompatibility.CopyOnly
|
||||
: result;
|
||||
}
|
||||
else if (lhs.IsLinear && rhs.IsLinear)
|
||||
else if (lhs.IsLinear && rhs.IsLinear && lhsSize.Height == rhsSize.Height)
|
||||
{
|
||||
// Copy between linear textures with matching stride.
|
||||
int stride = BitUtils.AlignUp(Math.Max(1, lhs.Stride >> level), Constants.StrideAlignment);
|
||||
|
@ -454,57 +449,33 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
/// </summary>
|
||||
/// <param name="lhs">Texture information to compare</param>
|
||||
/// <param name="rhs">Texture information to compare with</param>
|
||||
/// <returns>True if the size matches, false otherwise</returns>
|
||||
public static bool SizeMatches(TextureInfo lhs, TextureInfo rhs)
|
||||
{
|
||||
return SizeMatches(lhs, rhs, alignSizes: false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the texture sizes of the supplied texture informations match the given level
|
||||
/// </summary>
|
||||
/// <param name="lhs">Texture information to compare</param>
|
||||
/// <param name="rhs">Texture information to compare with</param>
|
||||
/// <param name="level">Mipmap level of this texture to compare with</param>
|
||||
/// <returns>True if the size matches with the level, false otherwise</returns>
|
||||
public static bool SizeMatches(TextureInfo lhs, TextureInfo rhs, int level)
|
||||
{
|
||||
return Math.Max(1, lhs.Width >> level) == rhs.Width &&
|
||||
Math.Max(1, lhs.Height >> level) == rhs.Height &&
|
||||
Math.Max(1, lhs.GetDepth() >> level) == rhs.GetDepth();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the texture sizes of the supplied texture informations match.
|
||||
/// </summary>
|
||||
/// <param name="lhs">Texture information to compare</param>
|
||||
/// <param name="rhs">Texture information to compare with</param>
|
||||
/// <param name="alignSizes">True to align the sizes according to the texture layout for comparison</param>
|
||||
/// <param name="lhsLevel">Mip level of the lhs texture. Aligned sizes are compared for the largest mip</param>
|
||||
/// <param name="exact">Indicates if the size must be exactly equal between the textures, or if <paramref name="rhs"/> is allowed to be larger</param>
|
||||
/// <returns>True if the sizes matches, false otherwise</returns>
|
||||
public static bool SizeMatches(TextureInfo lhs, TextureInfo rhs, bool alignSizes, int lhsLevel = 0)
|
||||
public static bool SizeMatches(TextureInfo lhs, TextureInfo rhs, bool exact)
|
||||
{
|
||||
if (lhs.GetLayers() != rhs.GetLayers())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isTextureBuffer = lhs.Target == Target.TextureBuffer || rhs.Target == Target.TextureBuffer;
|
||||
Size lhsSize = GetSizeInBlocks(lhs);
|
||||
Size rhsSize = GetSizeInBlocks(rhs);
|
||||
|
||||
if (alignSizes && !isTextureBuffer)
|
||||
if (exact || lhs.IsLinear || rhs.IsLinear)
|
||||
{
|
||||
Size size0 = GetLargestAlignedSize(lhs, lhsLevel);
|
||||
Size size1 = GetLargestAlignedSize(rhs, lhsLevel);
|
||||
|
||||
return size0.Width == size1.Width &&
|
||||
size0.Height == size1.Height &&
|
||||
size0.Depth == size1.Depth;
|
||||
return lhsSize.Width == rhsSize.Width &&
|
||||
lhsSize.Height == rhsSize.Height &&
|
||||
lhsSize.Depth == rhsSize.Depth;
|
||||
}
|
||||
else
|
||||
{
|
||||
return lhs.Width == rhs.Width &&
|
||||
lhs.Height == rhs.Height &&
|
||||
lhs.GetDepth() == rhs.GetDepth();
|
||||
Size lhsAlignedSize = GetAlignedSize(lhs);
|
||||
Size rhsAlignedSize = GetAlignedSize(rhs);
|
||||
|
||||
return lhsAlignedSize.Width == rhsAlignedSize.Width &&
|
||||
lhsSize.Width >= rhsSize.Width &&
|
||||
lhsSize.Height == rhsSize.Height &&
|
||||
lhsSize.Depth == rhsSize.Depth;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -543,22 +514,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the aligned sizes of the specified texture information, shifted to the largest mip from a given level.
|
||||
/// The alignment depends on the texture layout and format bytes per pixel.
|
||||
/// </summary>
|
||||
/// <param name="info">Texture information to calculate the aligned size from</param>
|
||||
/// <param name="level">Mipmap level for texture views. Shifts the aligned size to represent the largest mip level</param>
|
||||
/// <returns>The aligned texture size of the largest mip level</returns>
|
||||
public static Size GetLargestAlignedSize(TextureInfo info, int level)
|
||||
{
|
||||
int width = info.Width << level;
|
||||
int height = info.Height << level;
|
||||
int depth = info.GetDepth() << level;
|
||||
|
||||
return GetAlignedSize(info, width, height, depth);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the aligned sizes of the specified texture information.
|
||||
/// The alignment depends on the texture layout and format bytes per pixel.
|
||||
|
@ -575,6 +530,25 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
return GetAlignedSize(info, width, height, depth);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size in blocks for the given texture information.
|
||||
/// For non-compressed formats, that's the same as the regular size.
|
||||
/// </summary>
|
||||
/// <param name="info">Texture information to calculate the aligned size from</param>
|
||||
/// <param name="level">Mipmap level for texture views</param>
|
||||
/// <returns>The texture size in blocks</returns>
|
||||
public static Size GetSizeInBlocks(TextureInfo info, int level = 0)
|
||||
{
|
||||
int width = Math.Max(1, info.Width >> level);
|
||||
int height = Math.Max(1, info.Height >> level);
|
||||
int depth = Math.Max(1, info.GetDepth() >> level);
|
||||
|
||||
return new Size(
|
||||
BitUtils.DivRoundUp(width, info.FormatInfo.BlockWidth),
|
||||
BitUtils.DivRoundUp(height, info.FormatInfo.BlockHeight),
|
||||
depth);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if it's possible to create a view with the layout of the second texture information from the first.
|
||||
/// The layout information is composed of the Stride for linear textures, or GOB block size
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue