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:
gdkchan 2023-02-08 04:48:09 -03:00 committed by GitHub
parent 59755818ef
commit 96cf242bcf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 271 additions and 406 deletions

View file

@ -1,5 +1,7 @@
using Ryujinx.Common;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Texture;
using System;
namespace Ryujinx.Graphics.Gpu.Image
{
@ -292,5 +294,88 @@ namespace Ryujinx.Graphics.Gpu.Image
layerSize);
}
}
/// <summary>
/// Creates texture information for a given mipmap level of the specified parent texture and this information.
/// </summary>
/// <param name="parent">The parent texture</param>
/// <param name="firstLevel">The first level of the texture view</param>
/// <returns>The adjusted texture information with the new size</returns>
public TextureInfo CreateInfoForLevelView(Texture parent, int firstLevel)
{
// When the texture is used as view of another texture, we must
// ensure that the sizes are valid, otherwise data uploads would fail
// (and the size wouldn't match the real size used on the host API).
// Given a parent texture from where the view is created, we have the
// following rules:
// - The view size must be equal to the parent size, divided by (2 ^ l),
// where l is the first mipmap level of the view. The division result must
// be rounded down, and the result must be clamped to 1.
// - If the parent format is compressed, and the view format isn't, the
// view size is calculated as above, but the width and height of the
// view must be also divided by the compressed format block width and height.
// - If the parent format is not compressed, and the view is, the view
// size is calculated as described on the first point, but the width and height
// of the view must be also multiplied by the block width and height.
int width = Math.Max(1, parent.Info.Width >> firstLevel);
int height = Math.Max(1, parent.Info.Height >> firstLevel);
if (parent.Info.FormatInfo.IsCompressed && !FormatInfo.IsCompressed)
{
width = BitUtils.DivRoundUp(width, parent.Info.FormatInfo.BlockWidth);
height = BitUtils.DivRoundUp(height, parent.Info.FormatInfo.BlockHeight);
}
else if (!parent.Info.FormatInfo.IsCompressed && FormatInfo.IsCompressed)
{
width *= FormatInfo.BlockWidth;
height *= FormatInfo.BlockHeight;
}
int depthOrLayers;
if (Target == Target.Texture3D)
{
depthOrLayers = Math.Max(1, parent.Info.DepthOrLayers >> firstLevel);
}
else
{
depthOrLayers = DepthOrLayers;
}
// 2D and 2D multisample textures are not considered compatible.
// This specific case is required for copies, where the source texture might be multisample.
// In this case, we inherit the parent texture multisample state.
Target target = Target;
int samplesInX = SamplesInX;
int samplesInY = SamplesInY;
if (target == Target.Texture2D && parent.Target == Target.Texture2DMultisample)
{
target = Target.Texture2DMultisample;
samplesInX = parent.Info.SamplesInX;
samplesInY = parent.Info.SamplesInY;
}
return new TextureInfo(
GpuAddress,
width,
height,
depthOrLayers,
Levels,
samplesInX,
samplesInY,
Stride,
IsLinear,
GobBlocksInY,
GobBlocksInZ,
GobBlocksInTileX,
target,
FormatInfo,
DepthStencilMode,
SwizzleR,
SwizzleG,
SwizzleB,
SwizzleA);
}
}
}