diff options
author | gdk <gab.dark.100@gmail.com> | 2019-10-13 03:02:07 -0300 |
---|---|---|
committer | Thog <thog@protonmail.com> | 2020-01-09 02:13:00 +0100 |
commit | 1876b346fea647e8284a66bb6d62c38801035cff (patch) | |
tree | 6eeff094298cda84d1613dc5ec0691e51d7b35f1 /Ryujinx.Graphics.Gpu/Image/TexturePool.cs | |
parent | f617fb542a0e3d36012d77a4b5acbde7b08902f2 (diff) |
Initial work
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Image/TexturePool.cs')
-rw-r--r-- | Ryujinx.Graphics.Gpu/Image/TexturePool.cs | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/Ryujinx.Graphics.Gpu/Image/TexturePool.cs b/Ryujinx.Graphics.Gpu/Image/TexturePool.cs new file mode 100644 index 00000000..558f4def --- /dev/null +++ b/Ryujinx.Graphics.Gpu/Image/TexturePool.cs @@ -0,0 +1,219 @@ +using Ryujinx.Graphics.GAL; +using Ryujinx.Graphics.GAL.Texture; +using Ryujinx.Graphics.Gpu.Memory; +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace Ryujinx.Graphics.Gpu.Image +{ + class TexturePool : Pool<Texture> + { + private TextureManager _textureManager; + + public LinkedListNode<TexturePool> CacheNode { get; set; } + + private struct TextureContainer + { + public Texture Texture0 { get; set; } + public Texture Texture1 { get; set; } + } + + public TexturePool( + GpuContext context, + TextureManager textureManager, + ulong address, + int maximumId) : base(context, address, maximumId) + { + _textureManager = textureManager; + } + + public override Texture Get(int id) + { + if ((uint)id >= Items.Length) + { + return null; + } + + SynchronizeMemory(); + + Texture texture = Items[id]; + + if (texture == null) + { + ulong address = Address + (ulong)(uint)id * DescriptorSize; + + Span<byte> data = Context.PhysicalMemory.Read(address, DescriptorSize); + + TextureDescriptor descriptor = MemoryMarshal.Cast<byte, TextureDescriptor>(data)[0]; + + TextureInfo info = GetInfo(descriptor); + + // Bad address. We can't add a texture with a invalid address + // to the cache. + if (info.Address == MemoryManager.BadAddress) + { + return null; + } + + texture = _textureManager.FindOrCreateTexture(info, TextureSearchFlags.Sampler); + + texture.IncrementReferenceCount(); + + Items[id] = texture; + } + else + { + // Memory is automatically synchronized on texture creation. + texture.SynchronizeMemory(); + } + + return texture; + } + + protected override void InvalidateRangeImpl(ulong address, ulong size) + { + ulong endAddress = address + size; + + for (; address < endAddress; address += DescriptorSize) + { + int id = (int)((address - Address) / DescriptorSize); + + Texture texture = Items[id]; + + if (texture != null) + { + Span<byte> data = Context.PhysicalMemory.Read(address, DescriptorSize); + + TextureDescriptor descriptor = MemoryMarshal.Cast<byte, TextureDescriptor>(data)[0]; + + // 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.IsPerfectMatch(GetInfo(descriptor), TextureSearchFlags.Strict)) + { + continue; + } + + texture.DecrementReferenceCount(); + + Items[id] = null; + } + } + } + + private TextureInfo GetInfo(TextureDescriptor descriptor) + { + ulong address = Context.MemoryManager.Translate(descriptor.UnpackAddress()); + + int width = descriptor.UnpackWidth(); + int height = descriptor.UnpackHeight(); + int depthOrLayers = descriptor.UnpackDepth(); + int levels = descriptor.UnpackLevels(); + + TextureMsaaMode msaaMode = descriptor.UnpackTextureMsaaMode(); + + int samplesInX = msaaMode.SamplesInX(); + int samplesInY = msaaMode.SamplesInY(); + + int stride = descriptor.UnpackStride(); + + TextureDescriptorType descriptorType = descriptor.UnpackTextureDescriptorType(); + + bool isLinear = descriptorType == TextureDescriptorType.Linear; + + Target target = descriptor.UnpackTextureTarget().Convert((samplesInX | samplesInY) != 1); + + uint format = descriptor.UnpackFormat(); + bool srgb = descriptor.UnpackSrgb(); + + if (!FormatTable.TryGetTextureFormat(format, srgb, out FormatInfo formatInfo)) + { + // TODO: Warning. + + formatInfo = FormatInfo.Default; + } + + int gobBlocksInY = descriptor.UnpackGobBlocksInY(); + int gobBlocksInZ = descriptor.UnpackGobBlocksInZ(); + + int gobBlocksInTileX = descriptor.UnpackGobBlocksInTileX(); + + SwizzleComponent swizzleR = descriptor.UnpackSwizzleR().Convert(); + SwizzleComponent swizzleG = descriptor.UnpackSwizzleG().Convert(); + SwizzleComponent swizzleB = descriptor.UnpackSwizzleB().Convert(); + SwizzleComponent swizzleA = descriptor.UnpackSwizzleA().Convert(); + + DepthStencilMode depthStencilMode = GetDepthStencilMode( + formatInfo.Format, + swizzleR, + swizzleG, + swizzleB, + swizzleA); + + return new TextureInfo( + address, + width, + height, + depthOrLayers, + levels, + samplesInX, + samplesInY, + stride, + isLinear, + gobBlocksInY, + gobBlocksInZ, + gobBlocksInTileX, + target, + formatInfo, + depthStencilMode, + swizzleR, + swizzleG, + swizzleB, + swizzleA); + } + + private static DepthStencilMode GetDepthStencilMode(Format format, params SwizzleComponent[] components) + { + // R = Depth, G = Stencil. + // On 24-bits depth formats, this is inverted (Stencil is R etc). + // NVN setup: + // For depth, A is set to 1.0f, the other components are set to Depth. + // For stencil, all components are set to Stencil. + SwizzleComponent component = components[0]; + + for (int index = 1; index < 4 && !IsRG(component); index++) + { + component = components[index]; + } + + if (!IsRG(component)) + { + return DepthStencilMode.Depth; + } + + if (format == Format.D24X8Unorm || format == Format.D24UnormS8Uint) + { + return component == SwizzleComponent.Red + ? DepthStencilMode.Stencil + : DepthStencilMode.Depth; + } + else + { + return component == SwizzleComponent.Red + ? DepthStencilMode.Depth + : DepthStencilMode.Stencil; + } + } + + private static bool IsRG(SwizzleComponent component) + { + return component == SwizzleComponent.Red || + component == SwizzleComponent.Green; + } + + protected override void Delete(Texture item) + { + item?.DecrementReferenceCount(); + } + } +}
\ No newline at end of file |