diff --git a/Ryujinx.Graphics/GpuResourceManager.cs b/Ryujinx.Graphics/GpuResourceManager.cs index 134ba36faa..3fdf11711e 100644 --- a/Ryujinx.Graphics/GpuResourceManager.cs +++ b/Ryujinx.Graphics/GpuResourceManager.cs @@ -12,7 +12,7 @@ namespace Ryujinx.Graphics { None, Texture, - TextureMirror, + TextureArrayLayer, ColorBuffer, ZetaBuffer } @@ -74,13 +74,13 @@ namespace Ryujinx.Graphics ImageTypes[Position] = ImageType.Texture; } - public bool TryGetTextureMirorLayer(long Position, out int Layer) + public bool TryGetTextureLayer(long Position, out int LayerIndex) { - if (MirroredTextures.TryGetValue(Position, out Layer)) + if (MirroredTextures.TryGetValue(Position, out LayerIndex)) { ImageType Type = ImageTypes[Position]; - if (Type != ImageType.Texture && Type != ImageType.TextureMirror) + if (Type != ImageType.Texture && Type != ImageType.TextureArrayLayer) { throw new InvalidOperationException(); } @@ -88,14 +88,14 @@ namespace Ryujinx.Graphics return true; } - Layer = -1; + LayerIndex = -1; return false; } - public void SetTextureMirror(long Position, int Layer) + public void SetTextureArrayLayer(long Position, int LayerIndex) { - ImageTypes[Position] = ImageType.TextureMirror; - MirroredTextures[Position] = Layer; + ImageTypes[Position] = ImageType.TextureArrayLayer; + MirroredTextures[Position] = LayerIndex; } private void PrepareSendTexture(NvGpuVmm Vmm, long Position, GalImage NewImage) diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs index b591def8af..da81413334 100644 --- a/Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs +++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs @@ -138,21 +138,20 @@ namespace Ryujinx.Graphics.Graphics3d long GetLayerOffset(GalImage Image, int Layer) { - // FIXME: CALCULATE THE REAL TEXTURE SIZE (GPU SIZE NOT OGL SIZE) // TODO: mip map - return ImageUtils.GetSize(Image) * Layer; + return (ImageUtils.GetGpuSize(Image) / Image.Depth) * Layer; } int SrcLayerIndex = -1; - if (IsSrcLayered && Gpu.ResourceManager.TryGetTextureMirorLayer(SrcKey, out SrcLayerIndex)) + if (IsSrcLayered && Gpu.ResourceManager.TryGetTextureLayer(SrcKey, out SrcLayerIndex) && SrcLayerIndex != 0) { SrcKey = SrcKey - GetLayerOffset(SrcTexture, SrcLayerIndex); } int DstLayerIndex = -1; - if (IsDstLayered && Gpu.ResourceManager.TryGetTextureMirorLayer(DstKey, out DstLayerIndex)) + if (IsDstLayered && Gpu.ResourceManager.TryGetTextureLayer(DstKey, out DstLayerIndex) && DstLayerIndex != 0) { DstKey = DstKey - GetLayerOffset(DstTexture, DstLayerIndex); } @@ -164,7 +163,7 @@ namespace Ryujinx.Graphics.Graphics3d { for (int Layer = 0; Layer < SrcTexture.Depth; Layer++) { - Gpu.ResourceManager.SetTextureMirror(SrcKey + GetLayerOffset(SrcTexture, Layer), Layer); + Gpu.ResourceManager.SetTextureArrayLayer(SrcKey + GetLayerOffset(SrcTexture, Layer), Layer); } SrcLayerIndex = 0; @@ -174,7 +173,7 @@ namespace Ryujinx.Graphics.Graphics3d { for (int Layer = 0; Layer < DstTexture.Depth; Layer++) { - Gpu.ResourceManager.SetTextureMirror(DstKey + GetLayerOffset(DstTexture, Layer), Layer); + Gpu.ResourceManager.SetTextureArrayLayer(DstKey + GetLayerOffset(DstTexture, Layer), Layer); } DstLayerIndex = 0; diff --git a/Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs b/Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs index a0f7a09b58..a5d37accb7 100644 --- a/Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs +++ b/Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs @@ -1,5 +1,6 @@ using ChocolArm64.Memory; using OpenTK.Graphics.OpenGL; +using Ryujinx.Common; using Ryujinx.Graphics.Gal; using Ryujinx.Graphics.Memory; using System; @@ -363,6 +364,91 @@ namespace Ryujinx.Graphics.Texture } } + // from envytools + private static readonly int GobSizeX = 64; + private static readonly int GobSizeY = 8; + private static readonly int GobSizeZ = 1; + + // https://github.com/mesa3d/mesa/blob/master/src/gallium/drivers/nouveau/nvc0/nvc0_miptree.c + // FIXME: the width is never set to anything, maybe there is other variants? + // TODO: miplevels + private static (int TileWidth, int TileHeight, int TileDepth) GetTileDimensions(GalImage Image) + { + (int Width, int Height, int Depth) = GetImageSizeInBlocks(Image); + + int TileWidth = 0; + int TileHeight = 0; + int TileDepth = 0; + + if (Height > 64) + { + TileHeight = 4; + } + else if (Height > 32) + { + TileHeight = 3; + } + else if (Height > 16) + { + TileHeight = 2; + } + else if (Height > 8) + { + TileHeight = 1; + } + + if (Image.TextureTarget == GalTextureTarget.ThreeD) + { + if (TileHeight > 2) + { + TileHeight = 2; + } + + if (Depth > 16 && TileDepth < 2) + { + TileDepth = 5; + } + else if (Depth > 8) + { + TileDepth = 4; + } + else if (Depth > 4) + { + TileDepth = 3; + } + else if (Depth > 2) + { + TileDepth = 2; + } + else if (Depth > 1) + { + TileDepth = 1; + } + } + + return (GobSizeX << TileWidth, GobSizeY << TileHeight, GobSizeZ << TileDepth); + } + + public static int GetGpuSize(GalImage Image, bool forcePitch = false) + { + ImageDescriptor Desc = GetImageDescriptor(Image.Format); + + if (Image.Layout == GalMemoryLayout.Pitch || forcePitch) + { + // TODO: check this + return Image.Width * Image.Height * Image.Depth * Desc.BytesPerPixel; + } + + (int TileWidth, int TileHeight, int TileDepth) = GetTileDimensions(Image); + (int BlockX, int BlockY, int _) = GetImageSizeInBlocks(Image); + + int Pitch = BitUtils.AlignUp(BlockX * Desc.BytesPerPixel, TileWidth); + int Height = BitUtils.AlignUp(BlockY, TileHeight); + int Depth = BitUtils.AlignUp(Image.Depth, TileDepth); + + return BitUtils.AlignUp(Pitch * Height * Depth, (GobSizeX * GobSizeY) << (TileWidth + TileHeight + TileDepth)); + } + public static int GetPitch(GalImageFormat Format, int Width) { ImageDescriptor Desc = GetImageDescriptor(Format);