Fix mipmap base level being ignored for sampled textures and images (#1911)

* Fix mipmap base level being ignored for sampled textures and images

* Fix layer size and max level for textures

* Missing XML doc + reorder comments
This commit is contained in:
gdkchan 2021-01-15 15:14:00 -03:00 committed by GitHub
parent 1e5b37c94f
commit 3bad321d2b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 159 additions and 54 deletions

View file

@ -1,6 +1,8 @@
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.Graphics.Texture;
using System;
using System.Collections.Generic;
namespace Ryujinx.Graphics.Gpu.Image
@ -50,7 +52,7 @@ namespace Ryujinx.Graphics.Gpu.Image
{
TextureDescriptor descriptor = GetDescriptor(id);
TextureInfo info = GetInfo(descriptor);
TextureInfo info = GetInfo(descriptor, out int layerSize);
// Bad address. We can't add a texture with a invalid address
// to the cache.
@ -59,7 +61,7 @@ namespace Ryujinx.Graphics.Gpu.Image
return null;
}
texture = Context.Methods.TextureManager.FindOrCreateTexture(info, TextureSearchFlags.ForSampler);
texture = Context.Methods.TextureManager.FindOrCreateTexture(info, TextureSearchFlags.ForSampler, layerSize);
texture.IncrementReferenceCount();
@ -121,7 +123,7 @@ namespace Ryujinx.Graphics.Gpu.Image
// If the descriptors are the same, the texture is the same,
// we don't need to remove as it was not modified. Just continue.
if (texture.IsExactMatch(GetInfo(descriptor), TextureSearchFlags.Strict) != TextureMatchQuality.NoMatch)
if (texture.IsExactMatch(GetInfo(descriptor, out _), TextureSearchFlags.Strict) != TextureMatchQuality.NoMatch)
{
continue;
}
@ -137,10 +139,12 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Gets texture information from a texture descriptor.
/// </summary>
/// <param name="descriptor">The texture descriptor</param>
/// <param name="layerSize">Layer size for textures using a sub-range of mipmap levels, otherwise 0</param>
/// <returns>The texture information</returns>
private TextureInfo GetInfo(TextureDescriptor descriptor)
private TextureInfo GetInfo(TextureDescriptor descriptor, out int layerSize)
{
ulong address = Context.MemoryManager.Translate(descriptor.UnpackAddress());
bool addressIsValid = address != MemoryManager.PteUnmapped;
int width = descriptor.UnpackWidth();
int height = descriptor.UnpackHeight();
@ -181,7 +185,7 @@ namespace Ryujinx.Graphics.Gpu.Image
if (!FormatTable.TryGetTextureFormat(format, srgb, out FormatInfo formatInfo))
{
if ((long)address > 0L && (int)format > 0)
if (addressIsValid && (int)format > 0)
{
Logger.Error?.Print(LogClass.Gpu, $"Invalid texture format 0x{format:X} (sRGB: {srgb}).");
}
@ -194,6 +198,53 @@ namespace Ryujinx.Graphics.Gpu.Image
int gobBlocksInTileX = descriptor.UnpackGobBlocksInTileX();
layerSize = 0;
int minLod = descriptor.UnpackBaseLevel();
int maxLod = descriptor.UnpackMaxLevelInclusive();
// Linear textures don't support mipmaps, so we don't handle this case here.
if ((minLod != 0 || maxLod + 1 != levels) && target != Target.TextureBuffer && !isLinear && addressIsValid)
{
int depth = TextureInfo.GetDepth(target, depthOrLayers);
int layers = TextureInfo.GetLayers(target, depthOrLayers);
SizeInfo sizeInfo = SizeCalculator.GetBlockLinearTextureSize(
width,
height,
depth,
levels,
layers,
formatInfo.BlockWidth,
formatInfo.BlockHeight,
formatInfo.BytesPerPixel,
gobBlocksInY,
gobBlocksInZ,
gobBlocksInTileX);
layerSize = sizeInfo.LayerSize;
if (minLod != 0)
{
// If the base level is not zero, we additionally add the mip level offset
// to the address, this allows the texture manager to find the base level from the
// address if there is a overlapping texture on the cache that can contain the new texture.
address += (ulong)sizeInfo.GetMipOffset(minLod);
width = Math.Max(1, width >> minLod);
height = Math.Max(1, height >> minLod);
if (target == Target.Texture3D)
{
depthOrLayers = Math.Max(1, depthOrLayers >> minLod);
}
(gobBlocksInY, gobBlocksInZ) = SizeCalculator.GetMipGobBlockSizes(height, depth, formatInfo.BlockHeight, gobBlocksInY, gobBlocksInZ);
}
levels = (maxLod - minLod) + 1;
}
SwizzleComponent swizzleR = descriptor.UnpackSwizzleR().Convert();
SwizzleComponent swizzleG = descriptor.UnpackSwizzleG().Convert();
SwizzleComponent swizzleB = descriptor.UnpackSwizzleB().Convert();