|
|
@@ -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();
|