219 lines
7 KiB
C#
219 lines
7 KiB
C#
|
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();
|
||
|
}
|
||
|
}
|
||
|
}
|