Add XML documentation to Ryujinx.Graphics.Gpu.Image
This commit is contained in:
parent
53bbc1311f
commit
32764f9560
24 changed files with 1133 additions and 61 deletions
|
@ -3,17 +3,31 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Ryujinx.Graphics.Gpu.Image
|
||||
{
|
||||
/// <summary>
|
||||
/// A texture cache that automatically removes older textures that are not used for some time.
|
||||
/// The cache works with a rotated list with a fixed size. When new textures are added, the
|
||||
/// old ones at the bottom of the list are deleted.
|
||||
/// </summary>
|
||||
class AutoDeleteCache : IEnumerable<Texture>
|
||||
{
|
||||
private const int MaxCapacity = 2048;
|
||||
|
||||
private LinkedList<Texture> _textures;
|
||||
private readonly LinkedList<Texture> _textures;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the automatic deletion cache.
|
||||
/// </summary>
|
||||
public AutoDeleteCache()
|
||||
{
|
||||
_textures = new LinkedList<Texture>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new texture to the cache, even if the texture added is already on the cache.
|
||||
/// Using this method is only recommended if you know that the texture is not yet on the cache,
|
||||
/// otherwise it would store the same texture more than once.
|
||||
/// </summary>
|
||||
/// <param name="texture">The texture to be added to the cache</param>
|
||||
public void Add(Texture texture)
|
||||
{
|
||||
texture.IncrementReferenceCount();
|
||||
|
@ -32,6 +46,12 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new texture to the cache, or just moves it to the top of the list if the
|
||||
/// texture is already on the cache. Moving the texture to the top of the list prevents
|
||||
/// it from being deleted, as the textures on the bottom of the list are deleted when new ones are added.
|
||||
/// </summary>
|
||||
/// <param name="texture">The texture to be added, or moved to the top</param>
|
||||
public void Lift(Texture texture)
|
||||
{
|
||||
if (texture.CacheNode != null)
|
||||
|
|
|
@ -2,20 +2,48 @@ using Ryujinx.Graphics.GAL;
|
|||
|
||||
namespace Ryujinx.Graphics.Gpu.Image
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents texture format information.
|
||||
/// </summary>
|
||||
struct FormatInfo
|
||||
{
|
||||
private static FormatInfo _rgba8 = new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4);
|
||||
|
||||
public static FormatInfo Default => _rgba8;
|
||||
/// <summary>
|
||||
/// A default, generic RGBA8 texture format.
|
||||
/// </summary>
|
||||
public static FormatInfo Default { get; } = new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4);
|
||||
|
||||
/// <summary>
|
||||
/// The format of the texture data.
|
||||
/// </summary>
|
||||
public Format Format { get; }
|
||||
|
||||
public int BlockWidth { get; }
|
||||
public int BlockHeight { get; }
|
||||
/// <summary>
|
||||
/// The block width for compressed formats. Must be 1 for non-compressed formats.
|
||||
/// </summary>
|
||||
public int BlockWidth { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The block height for compressed formats. Must be 1 for non-compressed formats.
|
||||
/// </summary>
|
||||
public int BlockHeight { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of bytes occupied by a single pixel in memory of the texture data.
|
||||
/// </summary>
|
||||
public int BytesPerPixel { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whenever or not the texture format is a compressed format. Determined from block size.
|
||||
/// </summary>
|
||||
public bool IsCompressed => (BlockWidth | BlockHeight) != 1;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs the texture format info structure.
|
||||
/// </summary>
|
||||
/// <param name="format">The format of the texture data</param>
|
||||
/// <param name="blockWidth">The block width for compressed formats. Must be 1 for non-compressed formats</param>
|
||||
/// <param name="blockHeight">The block height for compressed formats. Must be 1 for non-compressed formats</param>
|
||||
/// <param name="bytesPerPixel">The number of bytes occupied by a single pixel in memory of the texture data</param>
|
||||
public FormatInfo(
|
||||
Format format,
|
||||
int blockWidth,
|
||||
|
|
|
@ -3,6 +3,9 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Ryujinx.Graphics.Gpu.Image
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains format tables, for texture and vertex attribute formats.
|
||||
/// </summary>
|
||||
static class FormatTable
|
||||
{
|
||||
private static Dictionary<uint, FormatInfo> _textureFormats = new Dictionary<uint, FormatInfo>()
|
||||
|
@ -186,6 +189,13 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
{ 0x36000000, Format.R10G10B10A2Sscaled }
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Try getting the texture format from a encoded format integer from the Maxwell texture descriptor.
|
||||
/// </summary>
|
||||
/// <param name="encoded">The encoded format integer from the texture descriptor</param>
|
||||
/// <param name="isSrgb">Indicates if the format is a sRGB format</param>
|
||||
/// <param name="format">The output texture format</param>
|
||||
/// <returns>True if the format is valid, false otherwise</returns>
|
||||
public static bool TryGetTextureFormat(uint encoded, bool isSrgb, out FormatInfo format)
|
||||
{
|
||||
encoded |= (isSrgb ? 1u << 19 : 0u);
|
||||
|
@ -193,6 +203,12 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
return _textureFormats.TryGetValue(encoded, out format);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try getting the vertex attribute format from a encoded format integer from Maxwell attribute registers.
|
||||
/// </summary>
|
||||
/// <param name="encoded">The encoded format integer from the attribute registers</param>
|
||||
/// <param name="format">The output vertex attribute format</param>
|
||||
/// <returns>True if the format is valid, false otherwise</returns>
|
||||
public static bool TryGetAttribFormat(uint encoded, out Format format)
|
||||
{
|
||||
return _attribFormats.TryGetValue(encoded, out format);
|
||||
|
|
|
@ -3,6 +3,10 @@ using System;
|
|||
|
||||
namespace Ryujinx.Graphics.Gpu.Image
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a pool of GPU resources, such as samplers or textures.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">GPU resource type</typeparam>
|
||||
abstract class Pool<T> : IDisposable
|
||||
{
|
||||
protected const int DescriptorSize = 0x20;
|
||||
|
@ -11,10 +15,21 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
|
||||
protected T[] Items;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum ID value of resources on the pool (inclusive).
|
||||
/// The maximum amount of resources on the pool is equal to this value plus one.
|
||||
/// </summary>
|
||||
public int MaximumId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The address of the pool in guest memory.
|
||||
/// </summary>
|
||||
public ulong Address { get; }
|
||||
public ulong Size { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The size of the pool in bytes.
|
||||
/// </summary>
|
||||
public ulong Size { get; }
|
||||
|
||||
public Pool(GpuContext context, ulong address, int maximumId)
|
||||
{
|
||||
|
@ -31,8 +46,18 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
Size = size;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the GPU resource with the given ID.
|
||||
/// </summary>
|
||||
/// <param name="id">ID of the resource. This is effectively a zero-based index</param>
|
||||
/// <returns>The GPU resource with the given ID</returns>
|
||||
public abstract T Get(int id);
|
||||
|
||||
/// <summary>
|
||||
/// Synchronizes host memory with guest memory.
|
||||
/// This causes a invalidation of pool entries,
|
||||
/// if a modification of entries by the CPU is detected.
|
||||
/// </summary>
|
||||
public void SynchronizeMemory()
|
||||
{
|
||||
(ulong, ulong)[] modifiedRanges = Context.PhysicalMemory.GetModifiedRanges(Address, Size, ResourceName.TexturePool);
|
||||
|
@ -57,6 +82,13 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invalidates a range of memory of the GPU resource pool.
|
||||
/// Entries that falls inside the speicified range will be invalidated,
|
||||
/// causing all the data to be reloaded from guest memory.
|
||||
/// </summary>
|
||||
/// <param name="address">The start address of the range to invalidate</param>
|
||||
/// <param name="size">The size of the range to invalidate</param>
|
||||
public void InvalidateRange(ulong address, ulong size)
|
||||
{
|
||||
ulong endAddress = address + size;
|
||||
|
@ -80,6 +112,8 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
endAddress = texturePoolEndAddress;
|
||||
}
|
||||
|
||||
size = endAddress - address;
|
||||
|
||||
InvalidateRangeImpl(address, size);
|
||||
}
|
||||
|
||||
|
@ -87,6 +121,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
|
||||
protected abstract void Delete(T item);
|
||||
|
||||
/// <summary>
|
||||
/// Performs the disposal of all resources stored on the pool.
|
||||
/// It's an error to try using the pool after disposal.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
if (Items != null)
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
namespace Ryujinx.Graphics.Gpu.Image
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a filter used with texture minification linear filtering.
|
||||
/// This feature is only supported on NVIDIA GPUs.
|
||||
/// </summary>
|
||||
enum ReductionFilter
|
||||
{
|
||||
Average,
|
||||
|
|
|
@ -3,10 +3,21 @@ using System;
|
|||
|
||||
namespace Ryujinx.Graphics.Gpu.Image
|
||||
{
|
||||
/// <summary>
|
||||
/// Cached sampler entry for sampler pools.
|
||||
/// </summary>
|
||||
class Sampler : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Host sampler object.
|
||||
/// </summary>
|
||||
public ISampler HostSampler { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the cached sampler.
|
||||
/// </summary>
|
||||
/// <param name="context">The GPU context the sampler belongs to</param>
|
||||
/// <param name="descriptor">The Maxwell sampler descriptor</param>
|
||||
public Sampler(GpuContext context, SamplerDescriptor descriptor)
|
||||
{
|
||||
MinFilter minFilter = descriptor.UnpackMinFilter();
|
||||
|
@ -42,6 +53,9 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
maxAnisotropy));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes the host sampler object.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
HostSampler.Dispose();
|
||||
|
|
|
@ -2,6 +2,10 @@ using Ryujinx.Graphics.GAL;
|
|||
|
||||
namespace Ryujinx.Graphics.Gpu.Image
|
||||
{
|
||||
/// <summary>
|
||||
/// Maxwell sampler descriptor structure.
|
||||
/// This structure defines the sampler descriptor as it is packed on the GPU sampler pool region.
|
||||
/// </summary>
|
||||
struct SamplerDescriptor
|
||||
{
|
||||
private static readonly float[] _f5ToF32ConversionLut = new float[]
|
||||
|
@ -56,41 +60,81 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
public uint BorderColorB;
|
||||
public uint BorderColorA;
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the texture wrap mode along the X axis.
|
||||
/// </summary>
|
||||
/// <returns>The texture wrap mode enum</returns>
|
||||
public AddressMode UnpackAddressU()
|
||||
{
|
||||
return (AddressMode)(Word0 & 7);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
/// Unpacks the texture wrap mode along the Y axis.
|
||||
/// </summary>
|
||||
/// <returns>The texture wrap mode enum</returns>
|
||||
public AddressMode UnpackAddressV()
|
||||
{
|
||||
return (AddressMode)((Word0 >> 3) & 7);
|
||||
}
|
||||
|
||||
// <summary>
|
||||
/// Unpacks the texture wrap mode along the Z axis.
|
||||
/// </summary>
|
||||
/// <returns>The texture wrap mode enum</returns>
|
||||
public AddressMode UnpackAddressP()
|
||||
{
|
||||
return (AddressMode)((Word0 >> 6) & 7);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the compare mode used for depth comparison on the shader, for
|
||||
/// depth buffer texture.
|
||||
/// This is only relevant for shaders with shadow samplers.
|
||||
/// </summary>
|
||||
/// <returns>The depth comparison mode enum</returns>
|
||||
public CompareMode UnpackCompareMode()
|
||||
{
|
||||
return (CompareMode)((Word0 >> 9) & 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the compare operation used for depth comparison on the shader, for
|
||||
/// depth buffer texture.
|
||||
/// This is only relevant for shaders with shadow samplers.
|
||||
/// </summary>
|
||||
/// <returns>The depth comparison operation enum</returns>
|
||||
public CompareOp UnpackCompareOp()
|
||||
{
|
||||
return (CompareOp)(((Word0 >> 10) & 7) + 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks and converts the maximum anisotropy value used for texture anisotropic filtering.
|
||||
/// </summary>
|
||||
/// <returns>The maximum anisotropy</returns>
|
||||
public float UnpackMaxAnisotropy()
|
||||
{
|
||||
return _maxAnisotropyLut[(Word0 >> 20) & 7];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the texture magnification filter.
|
||||
/// This defines the filtering used when the texture covers an area on the screen
|
||||
/// that is larger than the texture size.
|
||||
/// </summary>
|
||||
/// <returns>The magnification filter</returns>
|
||||
public MagFilter UnpackMagFilter()
|
||||
{
|
||||
return (MagFilter)(Word1 & 3);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the texture minification filter.
|
||||
/// This defines the filtering used when the texture covers an area on the screen
|
||||
/// that is smaller than the texture size.
|
||||
/// </summary>
|
||||
/// <returns>The minification filter</returns>
|
||||
public MinFilter UnpackMinFilter()
|
||||
{
|
||||
SamplerMinFilter minFilter = (SamplerMinFilter)((Word1 >> 4) & 3);
|
||||
|
@ -99,6 +143,13 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
return ConvertFilter(minFilter, mipFilter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts two minification and filter enum, to a single minification enum,
|
||||
/// including mipmap filtering information, as expected from the host API.
|
||||
/// </summary>
|
||||
/// <param name="minFilter">The minification filter</param>
|
||||
/// <param name="mipFilter">The mipmap level filter</param>
|
||||
/// <returns>The combined, host API compatible filter enum</returns>
|
||||
private static MinFilter ConvertFilter(SamplerMinFilter minFilter, SamplerMipFilter mipFilter)
|
||||
{
|
||||
switch (mipFilter)
|
||||
|
@ -131,11 +182,22 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
return MinFilter.Nearest;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the reduction filter, used with texture minification linear filtering.
|
||||
/// This describes how the final value will be computed from neighbouring pixels.
|
||||
/// </summary>
|
||||
/// <returns>The reduction filter</returns>
|
||||
public ReductionFilter UnpackReductionFilter()
|
||||
{
|
||||
return (ReductionFilter)((Word1 >> 10) & 3);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the level-of-detail bias value.
|
||||
/// This is a bias added to the level-of-detail value as computed by the GPU, used to select
|
||||
/// which mipmap level to use from a given texture.
|
||||
/// </summary>
|
||||
/// <returns>The level-of-detail bias value</returns>
|
||||
public float UnpackMipLodBias()
|
||||
{
|
||||
int fixedValue = (int)(Word1 >> 12) & 0x1fff;
|
||||
|
@ -145,16 +207,28 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
return fixedValue * Frac8ToF32;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the level-of-detail snap value.
|
||||
/// </summary>
|
||||
/// <returns>The level-of-detail snap value</returns>
|
||||
public float UnpackLodSnap()
|
||||
{
|
||||
return _f5ToF32ConversionLut[(Word1 >> 26) & 0x1f];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the minimum level-of-detail value.
|
||||
/// </summary>
|
||||
/// <returns>The minimum level-of-detail value</returns>
|
||||
public float UnpackMinLod()
|
||||
{
|
||||
return (Word2 & 0xfff) * Frac8ToF32;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the maximum level-of-detail value.
|
||||
/// </summary>
|
||||
/// <returns>The maximum level-of-detail value</returns>
|
||||
public float UnpackMaxLod()
|
||||
{
|
||||
return ((Word2 >> 12) & 0xfff) * Frac8ToF32;
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
namespace Ryujinx.Graphics.Gpu.Image
|
||||
{
|
||||
/// <summary>
|
||||
/// Sampler texture minification filter.
|
||||
/// </summary>
|
||||
enum SamplerMinFilter
|
||||
{
|
||||
Nearest = 1,
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
namespace Ryujinx.Graphics.Gpu.Image
|
||||
{
|
||||
/// <summary>
|
||||
/// Sampler texture mipmap level filter.
|
||||
/// </summary>
|
||||
enum SamplerMipFilter
|
||||
{
|
||||
None = 1,
|
||||
|
|
|
@ -3,12 +3,26 @@ using System.Runtime.InteropServices;
|
|||
|
||||
namespace Ryujinx.Graphics.Gpu.Image
|
||||
{
|
||||
/// <summary>
|
||||
/// Sampler pool.
|
||||
/// </summary>
|
||||
class SamplerPool : Pool<Sampler>
|
||||
{
|
||||
private int _sequenceNumber;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new instance of the sampler pool.
|
||||
/// </summary>
|
||||
/// <param name="context">GPU context that the sampler pool belongs to</param>
|
||||
/// <param name="address">Address of the sampler pool in guest memory</param>
|
||||
/// <param name="maximumId">Maximum sampler ID of the sampler pool (equal to maximum samplers minus one)</param>
|
||||
public SamplerPool(GpuContext context, ulong address, int maximumId) : base(context, address, maximumId) { }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sampler with the given ID.
|
||||
/// </summary>
|
||||
/// <param name="id">ID of the sampler. This is effectively a zero-based index</param>
|
||||
/// <returns>The sampler with the given ID</returns>
|
||||
public override Sampler Get(int id)
|
||||
{
|
||||
if ((uint)id >= Items.Length)
|
||||
|
@ -41,6 +55,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
return sampler;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of the sampler pool range invalidation.
|
||||
/// </summary>
|
||||
/// <param name="address">Start address of the range of the sampler pool</param>
|
||||
/// <param name="size">Size of the range being invalidated</param>
|
||||
protected override void InvalidateRangeImpl(ulong address, ulong size)
|
||||
{
|
||||
ulong endAddress = address + size;
|
||||
|
@ -60,6 +79,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a given sampler pool entry.
|
||||
/// The host memory used by the sampler is released by the driver.
|
||||
/// </summary>
|
||||
/// <param name="item">The entry to be deleted</param>
|
||||
protected override void Delete(Sampler item)
|
||||
{
|
||||
item?.Dispose();
|
||||
|
|
|
@ -10,14 +10,23 @@ using System.Diagnostics;
|
|||
|
||||
namespace Ryujinx.Graphics.Gpu.Image
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a cached GPU texture.
|
||||
/// </summary>
|
||||
class Texture : IRange<Texture>
|
||||
{
|
||||
private GpuContext _context;
|
||||
|
||||
private SizeInfo _sizeInfo;
|
||||
|
||||
/// <summary>
|
||||
/// Texture format.
|
||||
/// </summary>
|
||||
public Format Format => Info.FormatInfo.Format;
|
||||
|
||||
/// <summary>
|
||||
/// Texture information.
|
||||
/// </summary>
|
||||
public TextureInfo Info { get; private set; }
|
||||
|
||||
private int _depth;
|
||||
|
@ -34,21 +43,48 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
|
||||
private List<Texture> _views;
|
||||
|
||||
/// <summary>
|
||||
/// Host texture.
|
||||
/// </summary>
|
||||
public ITexture HostTexture { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Intrusive linked list node used on the auto deletion texture cache.
|
||||
/// </summary>
|
||||
public LinkedListNode<Texture> CacheNode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Texture data modified by the GPU.
|
||||
/// </summary>
|
||||
public bool Modified { get; set; }
|
||||
|
||||
public ulong Address => Info.Address;
|
||||
/// <summary>
|
||||
/// Start address of the texture in guest memory.
|
||||
/// </summary>
|
||||
public ulong Address => Info.Address;
|
||||
|
||||
/// <summary>
|
||||
/// End address of the texture in guest memory.
|
||||
/// </summary>
|
||||
public ulong EndAddress => Info.Address + Size;
|
||||
|
||||
/// <summary>
|
||||
/// Texture size in bytes.
|
||||
/// </summary>
|
||||
public ulong Size => (ulong)_sizeInfo.TotalSize;
|
||||
|
||||
private int _referenceCount;
|
||||
|
||||
private int _sequenceNumber;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new instance of the cached GPU texture.
|
||||
/// </summary>
|
||||
/// <param name="context">GPU context that the texture belongs to</param>
|
||||
/// <param name="info">Texture information</param>
|
||||
/// <param name="sizeInfo">Size information of the texture</param>
|
||||
/// <param name="firstLayer">The first layer of the texture, or 0 if the texture has no parent</param>
|
||||
/// <param name="firstLevel">The first mipmap level of the texture, or 0 if the texture has no parent</param>
|
||||
private Texture(
|
||||
GpuContext context,
|
||||
TextureInfo info,
|
||||
|
@ -64,6 +100,12 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
_hasData = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new instance of the cached GPU texture.
|
||||
/// </summary>
|
||||
/// <param name="context">GPU context that the texture belongs to</param>
|
||||
/// <param name="info">Texture information</param>
|
||||
/// <param name="sizeInfo">Size information of the texture</param>
|
||||
public Texture(GpuContext context, TextureInfo info, SizeInfo sizeInfo)
|
||||
{
|
||||
InitializeTexture(context, info, sizeInfo);
|
||||
|
@ -73,6 +115,14 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
HostTexture = _context.Renderer.CreateTexture(createInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Common texture initialization method.
|
||||
/// This sets the context, info and sizeInfo fields.
|
||||
/// Other fields are initialized with their default values.
|
||||
/// </summary>
|
||||
/// <param name="context">GPU context that the texture belongs to</param>
|
||||
/// <param name="info">Texture information</param>
|
||||
/// <param name="sizeInfo">Size information of the texture</param>
|
||||
private void InitializeTexture(GpuContext context, TextureInfo info, SizeInfo sizeInfo)
|
||||
{
|
||||
_context = context;
|
||||
|
@ -85,6 +135,17 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
_views = new List<Texture>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a texture view from this texture.
|
||||
/// A texture view is defined as a child texture, from a sub-range of their parent texture.
|
||||
/// For example, the initial layer and mipmap level of the view can be defined, so the texture
|
||||
/// will start at the given layer/level of the parent texture.
|
||||
/// </summary>
|
||||
/// <param name="info">Child texture information</param>
|
||||
/// <param name="sizeInfo">Child texture size information</param>
|
||||
/// <param name="firstLayer">Start layer of the child texture on the parent texture</param>
|
||||
/// <param name="firstLevel">Start mipmap level of the child texture on the parent texture</param>
|
||||
/// <returns>The child texture</returns>
|
||||
public Texture CreateView(TextureInfo info, SizeInfo sizeInfo, int firstLayer, int firstLevel)
|
||||
{
|
||||
Texture texture = new Texture(
|
||||
|
@ -103,6 +164,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
return texture;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a child texture to this texture.
|
||||
/// </summary>
|
||||
/// <param name="texture">The child texture</param>
|
||||
private void AddView(Texture texture)
|
||||
{
|
||||
_views.Add(texture);
|
||||
|
@ -110,6 +175,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
texture._viewStorage = this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a child texture from this texture.
|
||||
/// </summary>
|
||||
/// <param name="texture">The child texture</param>
|
||||
private void RemoveView(Texture texture)
|
||||
{
|
||||
_views.Remove(texture);
|
||||
|
@ -119,6 +188,14 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
DeleteIfNotUsed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes the texture size.
|
||||
/// This operation may also change the size of all mipmap levels, including from the parent
|
||||
/// and other possible child textures, to ensure that all sizes are consistent.
|
||||
/// </summary>
|
||||
/// <param name="width">The new texture width</param>
|
||||
/// <param name="height">The new texture height</param>
|
||||
/// <param name="depthOrLayers">The new texture depth (for 3D textures) or layers (for layered textures)</param>
|
||||
public void ChangeSize(int width, int height, int depthOrLayers)
|
||||
{
|
||||
width <<= _firstLevel;
|
||||
|
@ -155,6 +232,14 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recreates the texture storage (or view, in the case of child textures) of this texture.
|
||||
/// This allows recreating the texture with a new size.
|
||||
/// A copy is automatically performed from the old to the new texture.
|
||||
/// </summary>
|
||||
/// <param name="width">The new texture width</param>
|
||||
/// <param name="height">The new texture height</param>
|
||||
/// <param name="depthOrLayers">The new texture depth (for 3D textures) or layers (for layered textures)</param>
|
||||
private void RecreateStorageOrView(int width, int height, int depthOrLayers)
|
||||
{
|
||||
SetInfo(new TextureInfo(
|
||||
|
@ -194,6 +279,13 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Synchronizes guest and host memory.
|
||||
/// This will overwrite the texture data with the texture data on the guest memory, if a CPU
|
||||
/// modification is detected.
|
||||
/// Be aware that this can cause texture data written by the GPU to be lost, this is just a
|
||||
/// one way copy (from CPU owned to GPU owned memory).
|
||||
/// </summary>
|
||||
public void SynchronizeMemory()
|
||||
{
|
||||
if (_sequenceNumber == _context.SequenceNumber && _hasData)
|
||||
|
@ -266,6 +358,14 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
_hasData = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flushes the texture data.
|
||||
/// This causes the texture data to be written back to guest memory.
|
||||
/// If the texture was written by the GPU, this includes all modification made by the GPU
|
||||
/// up to this point.
|
||||
/// Be aware that this is a expensive operation, avoid calling it unless strictly needed.
|
||||
/// This may cause data corruption if the memory is already being used for something else on the CPU side.
|
||||
/// </summary>
|
||||
public void Flush()
|
||||
{
|
||||
Span<byte> data = HostTexture.GetData();
|
||||
|
@ -302,6 +402,13 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
_context.PhysicalMemory.Write(Address, data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a comparison of this texture information, with the specified texture information.
|
||||
/// This performs a strict comparison, used to check if two textures are equal.
|
||||
/// </summary>
|
||||
/// <param name="info">Texture information to compare with</param>
|
||||
/// <param name="flags">Comparison flags</param>
|
||||
/// <returns>True if the textures are strictly equal or similar, false otherwise</returns>
|
||||
public bool IsPerfectMatch(TextureInfo info, TextureSearchFlags flags)
|
||||
{
|
||||
if (!FormatMatches(info, (flags & TextureSearchFlags.Strict) != 0))
|
||||
|
@ -344,6 +451,12 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
return Info.Address == info.Address && Info.Levels == info.Levels;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the texture format matches with the specified texture information.
|
||||
/// </summary>
|
||||
/// <param name="info">Texture information to compare with</param>
|
||||
/// <param name="strict">True to perform a strict comparison (formats must be exactly equal)</param>
|
||||
/// <returns>True if the format matches, with the given comparison rules</returns>
|
||||
private bool FormatMatches(TextureInfo info, bool strict)
|
||||
{
|
||||
// D32F and R32F texture have the same representation internally,
|
||||
|
@ -356,6 +469,13 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
return Info.FormatInfo.Format == info.FormatInfo.Format;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the texture layout specified matches with this texture layout.
|
||||
/// The layout information is composed of the Stride for linear textures, or GOB block size
|
||||
/// for block linear textures.
|
||||
/// </summary>
|
||||
/// <param name="info">Texture information to compare with</param>
|
||||
/// <returns>True if the layout matches, false otherwise</returns>
|
||||
private bool LayoutMatches(TextureInfo info)
|
||||
{
|
||||
if (Info.IsLinear != info.IsLinear)
|
||||
|
@ -376,11 +496,23 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the texture sizes of the supplied texture information matches this texture.
|
||||
/// </summary>
|
||||
/// <param name="info">Texture information to compare with</param>
|
||||
/// <returns>True if the size matches, false otherwise</returns>
|
||||
public bool SizeMatches(TextureInfo info)
|
||||
{
|
||||
return SizeMatches(info, alignSizes: false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the texture sizes of the supplied texture information matches the given level of
|
||||
/// this texture.
|
||||
/// </summary>
|
||||
/// <param name="info">Texture information to compare with</param>
|
||||
/// <param name="level">Mipmap level of this texture to compare with</param>
|
||||
/// <returns>True if the size matches with the level, false otherwise</returns>
|
||||
public bool SizeMatches(TextureInfo info, int level)
|
||||
{
|
||||
return Math.Max(1, Info.Width >> level) == info.Width &&
|
||||
|
@ -388,6 +520,12 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
Math.Max(1, Info.GetDepth() >> level) == info.GetDepth();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the texture sizes of the supplied texture information matches this texture.
|
||||
/// </summary>
|
||||
/// <param name="info">Texture information to compare with</param>
|
||||
/// <param name="alignSizes">True to align the sizes according to the texture layout for comparison</param>
|
||||
/// <returns>True if the sizes matches, false otherwise</returns>
|
||||
private bool SizeMatches(TextureInfo info, bool alignSizes)
|
||||
{
|
||||
if (Info.GetLayers() != info.GetLayers())
|
||||
|
@ -412,6 +550,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the texture shader sampling parameters matches.
|
||||
/// </summary>
|
||||
/// <param name="info">Texture information to compare with</param>
|
||||
/// <returns>True if the texture shader sampling parameters matches, false otherwise</returns>
|
||||
private bool SamplerParamsMatches(TextureInfo info)
|
||||
{
|
||||
return Info.DepthStencilMode == info.DepthStencilMode &&
|
||||
|
@ -421,6 +564,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
Info.SwizzleA == info.SwizzleA;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the texture target and samples count (for multisampled textures) matches.
|
||||
/// </summary>
|
||||
/// <param name="info">Texture information to compare with</param>
|
||||
/// <returns>True if the texture target and samples count matches, false otherwise</returns>
|
||||
private bool TargetAndSamplesCompatible(TextureInfo info)
|
||||
{
|
||||
return Info.Target == info.Target &&
|
||||
|
@ -428,6 +576,14 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
Info.SamplesInY == info.SamplesInY;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if it's possible to create a view, with the given parameters, from this texture.
|
||||
/// </summary>
|
||||
/// <param name="info">Texture view information</param>
|
||||
/// <param name="size">Texture view size</param>
|
||||
/// <param name="firstLayer">Texture view initial layer on this texture</param>
|
||||
/// <param name="firstLevel">Texture view first mipmap level on this texture</param>
|
||||
/// <returns>True if a view with the given parameters can be created from this texture, false otherwise</returns>
|
||||
public bool IsViewCompatible(
|
||||
TextureInfo info,
|
||||
ulong size,
|
||||
|
@ -437,6 +593,15 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
return IsViewCompatible(info, size, isCopy: false, out firstLayer, out firstLevel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if it's possible to create a view, with the given parameters, from this texture.
|
||||
/// </summary>
|
||||
/// <param name="info">Texture view information</param>
|
||||
/// <param name="size">Texture view size</param>
|
||||
/// <param name="isCopy">True to check for copy compability, instead of view compatibility</param>
|
||||
/// <param name="firstLayer">Texture view initial layer on this texture</param>
|
||||
/// <param name="firstLevel">Texture view first mipmap level on this texture</param>
|
||||
/// <returns>True if a view with the given parameters can be created from this texture, false otherwise</returns>
|
||||
public bool IsViewCompatible(
|
||||
TextureInfo info,
|
||||
ulong size,
|
||||
|
@ -484,6 +649,14 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
Info.SamplesInY == info.SamplesInY;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check it's possible to create a view with the specified layout.
|
||||
/// The layout information is composed of the Stride for linear textures, or GOB block size
|
||||
/// for block linear textures.
|
||||
/// </summary>
|
||||
/// <param name="info">Texture information of the texture view</param>
|
||||
/// <param name="level">Start level of the texture view, in relation with this texture</param>
|
||||
/// <returns>True if the layout is compatible, false otherwise</returns>
|
||||
private bool ViewLayoutCompatible(TextureInfo info, int level)
|
||||
{
|
||||
if (Info.IsLinear != info.IsLinear)
|
||||
|
@ -520,11 +693,26 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the view format is compatible with this texture format.
|
||||
/// In general, the formats are considered compatible if the bytes per pixel value is equal,
|
||||
/// but there are more complex rules for some formats, like compressed or depth-stencil formats.
|
||||
/// This follows the host API copy compatibility rules.
|
||||
/// </summary>
|
||||
/// <param name="info">Texture information of the texture view</param>
|
||||
/// <returns>True if the formats are compatible, false otherwise</returns>
|
||||
private bool ViewFormatCompatible(TextureInfo info)
|
||||
{
|
||||
return TextureCompatibility.FormatCompatible(Info.FormatInfo, info.FormatInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the size of a given texture view is compatible with this texture.
|
||||
/// </summary>
|
||||
/// <param name="info">Texture information of the texture view</param>
|
||||
/// <param name="level">Mipmap level of the texture view in relation to this texture</param>
|
||||
/// <param name="isCopy">True to check for copy compatibility rather than view compatibility</param>
|
||||
/// <returns>True if the sizes are compatible, false otherwise</returns>
|
||||
private bool ViewSizeMatches(TextureInfo info, int level, bool isCopy)
|
||||
{
|
||||
Size size = GetAlignedSize(Info, level);
|
||||
|
@ -542,6 +730,14 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
size.Height == otherSize.Height;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the target of the specified texture view information is compatible with this
|
||||
/// texture.
|
||||
/// This follows the host API target compatibility rules.
|
||||
/// </summary>
|
||||
/// <param name="info">Texture information of the texture view</param>
|
||||
/// <param name="isCopy">True to check for copy rather than view compatibility</param>
|
||||
/// <returns>True if the targets are compatible, false otherwise</returns>
|
||||
private bool ViewTargetCompatible(TextureInfo info, bool isCopy)
|
||||
{
|
||||
switch (Info.Target)
|
||||
|
@ -576,6 +772,13 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the aligned sizes of the specified texture information.
|
||||
/// The alignment depends on the texture layout and format bytes per pixel.
|
||||
/// </summary>
|
||||
/// <param name="info">Texture information to calculate the aligned size from</param>
|
||||
/// <param name="level">Mipmap level for texture views</param>
|
||||
/// <returns>The aligned texture size</returns>
|
||||
private static Size GetAlignedSize(TextureInfo info, int level = 0)
|
||||
{
|
||||
int width = Math.Max(1, info.Width >> level);
|
||||
|
@ -614,6 +817,13 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a texture of the specified target type from this texture.
|
||||
/// This can be used to get an array texture from a non-array texture and vice-versa.
|
||||
/// If this texture and the requested targets are equal, then this texture Host texture is returned directly.
|
||||
/// </summary>
|
||||
/// <param name="target">The desired target type</param>
|
||||
/// <returns>A view of this texture with the requested target, or null if the target is invalid for this texture</returns>
|
||||
public ITexture GetTargetTexture(Target target)
|
||||
{
|
||||
if (target == Info.Target)
|
||||
|
@ -655,6 +865,13 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if this texture and the specified target have the same number of dimensions.
|
||||
/// For the purposes of this comparison, 2D and 2D Multisample textures are not considered to have
|
||||
/// the same number of dimensions. Same for Cubemap and 3D textures.
|
||||
/// </summary>
|
||||
/// <param name="target">The target to compare with</param>
|
||||
/// <returns>True if both targets have the same number of dimensions, false otherwise</returns>
|
||||
private bool IsSameDimensionsTarget(Target target)
|
||||
{
|
||||
switch (Info.Target)
|
||||
|
@ -686,6 +903,13 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replaces view texture information.
|
||||
/// This should only be used for child textures with a parent.
|
||||
/// </summary>
|
||||
/// <param name="parent">The parent texture</param>
|
||||
/// <param name="info">The new view texture information</param>
|
||||
/// <param name="hostTexture">The new host texture</param>
|
||||
public void ReplaceView(Texture parent, TextureInfo info, ITexture hostTexture)
|
||||
{
|
||||
ReplaceStorage(hostTexture);
|
||||
|
@ -695,6 +919,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
SetInfo(info);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the internal texture information structure.
|
||||
/// </summary>
|
||||
/// <param name="info">The new texture information</param>
|
||||
private void SetInfo(TextureInfo info)
|
||||
{
|
||||
Info = info;
|
||||
|
@ -703,6 +931,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
_layers = info.GetLayers();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replaces the host texture, while disposing of the old one if needed.
|
||||
/// </summary>
|
||||
/// <param name="hostTexture">The new host texture</param>
|
||||
private void ReplaceStorage(ITexture hostTexture)
|
||||
{
|
||||
DisposeTextures();
|
||||
|
@ -710,16 +942,29 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
HostTexture = hostTexture;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the texture overlaps with a memory range.
|
||||
/// </summary>
|
||||
/// <param name="address">Start address of the range</param>
|
||||
/// <param name="size">Size of the range</param>
|
||||
/// <returns>True if the texture overlaps with the range, false otherwise</returns>
|
||||
public bool OverlapsWith(ulong address, ulong size)
|
||||
{
|
||||
return Address < address + size && address < EndAddress;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Increments the texture reference count.
|
||||
/// </summary>
|
||||
public void IncrementReferenceCount()
|
||||
{
|
||||
_referenceCount++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decrements the texture reference count.
|
||||
/// When the reference count hits zero, the texture may be deleted and can't be used anymore.
|
||||
/// </summary>
|
||||
public void DecrementReferenceCount()
|
||||
{
|
||||
int newRefCount = --_referenceCount;
|
||||
|
@ -739,6 +984,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
DeleteIfNotUsed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delete the texture if it is not used anymore.
|
||||
/// The texture is considered unused when the reference count is zero,
|
||||
/// and it has no child views.
|
||||
/// </summary>
|
||||
private void DeleteIfNotUsed()
|
||||
{
|
||||
// We can delete the texture as long it is not being used
|
||||
|
@ -751,6 +1001,9 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs texture disposal, deleting the texture.
|
||||
/// </summary>
|
||||
private void DisposeTextures()
|
||||
{
|
||||
HostTexture.Dispose();
|
||||
|
|
|
@ -2,17 +2,44 @@ using Ryujinx.Graphics.GAL;
|
|||
|
||||
namespace Ryujinx.Graphics.Gpu.Image
|
||||
{
|
||||
/// <summary>
|
||||
/// Texture binding information.
|
||||
/// This is used for textures that needs to be accessed from shaders.
|
||||
/// </summary>
|
||||
struct TextureBindingInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Shader sampler target type.
|
||||
/// </summary>
|
||||
public Target Target { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Shader texture handle.
|
||||
/// This is a index into the texture constant buffer.
|
||||
/// </summary>
|
||||
public int Handle { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the texture is a bindless texture.
|
||||
/// For those textures, Handle is ignored.
|
||||
/// </summary>
|
||||
public bool IsBindless { get; }
|
||||
|
||||
public int CbufSlot { get; }
|
||||
/// <summary>
|
||||
/// Constant buffer slot with the bindless texture handle, for bindless texture.
|
||||
/// </summary>
|
||||
public int CbufSlot { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Constant buffer offset of the bindless texture handle, for bindless texture.
|
||||
/// </summary>
|
||||
public int CbufOffset { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructs the texture binding information structure.
|
||||
/// </summary>
|
||||
/// <param name="target">The shader sampler target type</param>
|
||||
/// <param name="handle">The shader texture handle (read index into the texture constant buffer)</param>
|
||||
public TextureBindingInfo(Target target, int handle)
|
||||
{
|
||||
Target = target;
|
||||
|
@ -24,6 +51,12 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
CbufOffset = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs the bindless texture binding information structure.
|
||||
/// </summary>
|
||||
/// <param name="target">The shader sampler target type</param>
|
||||
/// <param name="cbufSlot">Constant buffer slot where the bindless texture handle is located</param>
|
||||
/// <param name="cbufOffset">Constant buffer offset of the bindless texture handle</param>
|
||||
public TextureBindingInfo(Target target, int cbufSlot, int cbufOffset)
|
||||
{
|
||||
Target = target;
|
||||
|
|
|
@ -6,6 +6,9 @@ using System.Runtime.InteropServices;
|
|||
|
||||
namespace Ryujinx.Graphics.Gpu.Image
|
||||
{
|
||||
/// <summary>
|
||||
/// Texture bindings manager.
|
||||
/// </summary>
|
||||
class TextureBindingsManager
|
||||
{
|
||||
private GpuContext _context;
|
||||
|
@ -37,6 +40,12 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
|
||||
private bool _rebind;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new instance of the texture bindings manager.
|
||||
/// </summary>
|
||||
/// <param name="context">The GPU context that the texture bindings manager belongs to</param>
|
||||
/// <param name="texturePoolCache">Texture pools cache used to get texture pools from</param>
|
||||
/// <param name="isCompute">True if the bindings manager is used for the compute engine</param>
|
||||
public TextureBindingsManager(GpuContext context, TexturePoolCache texturePoolCache, bool isCompute)
|
||||
{
|
||||
_context = context;
|
||||
|
@ -52,6 +61,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
_imageState = new TextureStatePerStage[stages][];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Binds textures for a given shader stage.
|
||||
/// </summary>
|
||||
/// <param name="stage">Shader stage number, or 0 for compute shaders</param>
|
||||
/// <param name="bindings">Texture bindings</param>
|
||||
public void SetTextures(int stage, TextureBindingInfo[] bindings)
|
||||
{
|
||||
_textureBindings[stage] = bindings;
|
||||
|
@ -59,6 +73,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
_textureState[stage] = new TextureStatePerStage[bindings.Length];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Binds images for a given shader stage.
|
||||
/// </summary>
|
||||
/// <param name="stage">Shader stage number, or 0 for compute shaders</param>
|
||||
/// <param name="bindings">Image bindings</param>
|
||||
public void SetImages(int stage, TextureBindingInfo[] bindings)
|
||||
{
|
||||
_imageBindings[stage] = bindings;
|
||||
|
@ -66,11 +85,22 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
_imageState[stage] = new TextureStatePerStage[bindings.Length];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the textures constant buffer index.
|
||||
/// The constant buffer specified holds the texture handles.
|
||||
/// </summary>
|
||||
/// <param name="index">Constant buffer index</param>
|
||||
public void SetTextureBufferIndex(int index)
|
||||
{
|
||||
_textureBufferIndex = index;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the current texture sampler pool to be used.
|
||||
/// </summary>
|
||||
/// <param name="gpuVa">Start GPU virtual address of the pool</param>
|
||||
/// <param name="maximumId">Maximum ID of the pool (total count minus one)</param>
|
||||
/// <param name="samplerIndex">Type of the sampler pool indexing used for bound samplers</param>
|
||||
public void SetSamplerPool(ulong gpuVa, int maximumId, SamplerIndex samplerIndex)
|
||||
{
|
||||
ulong address = _context.MemoryManager.Translate(gpuVa);
|
||||
|
@ -90,6 +120,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
_samplerIndex = samplerIndex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the current texture pool to be used.
|
||||
/// </summary>
|
||||
/// <param name="gpuVa">Start GPU virtual address of the pool</param>
|
||||
/// <param name="maximumId">Maximum ID of the pool (total count minus one)</param>
|
||||
public void SetTexturePool(ulong gpuVa, int maximumId)
|
||||
{
|
||||
ulong address = _context.MemoryManager.Translate(gpuVa);
|
||||
|
@ -98,6 +133,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
_texturePoolMaximumId = maximumId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that the bindings are visible to the host GPU.
|
||||
/// This actually performs the binding using the host graphics API.
|
||||
/// </summary>
|
||||
public void CommitBindings()
|
||||
{
|
||||
TexturePool texturePool = _texturePoolCache.FindOrCreate(
|
||||
|
@ -123,6 +162,13 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
_rebind = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that the texture bindings are visible to the host GPU.
|
||||
/// This actually performs the binding using the host graphics API.
|
||||
/// </summary>
|
||||
/// <param name="pool">The current texture pool</param>
|
||||
/// <param name="stage">The shader stage using the textures to be bound</param>
|
||||
/// <param name="stageIndex">The stage number of the specified shader stage</param>
|
||||
private void CommitTextureBindings(TexturePool pool, ShaderStage stage, int stageIndex)
|
||||
{
|
||||
if (_textureBindings[stageIndex] == null)
|
||||
|
@ -194,6 +240,13 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that the image bindings are visible to the host GPU.
|
||||
/// This actually performs the binding using the host graphics API.
|
||||
/// </summary>
|
||||
/// <param name="pool">The current texture pool</param>
|
||||
/// <param name="stage">The shader stage using the textures to be bound</param>
|
||||
/// <param name="stageIndex">The stage number of the specified shader stage</param>
|
||||
private void CommitImageBindings(TexturePool pool, ShaderStage stage, int stageIndex)
|
||||
{
|
||||
if (_imageBindings[stageIndex] == null)
|
||||
|
@ -222,6 +275,13 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the texture descriptor for a given texture handle.
|
||||
/// </summary>
|
||||
/// <param name="state">The current GPU state</param>
|
||||
/// <param name="stageIndex">The stage number where the texture is bound</param>
|
||||
/// <param name="handle">The texture handle</param>
|
||||
/// <returns>The texture descriptor for the specified texture</returns>
|
||||
public TextureDescriptor GetTextureDescriptor(GpuState state, int stageIndex, int handle)
|
||||
{
|
||||
int packedId = ReadPackedId(stageIndex, handle);
|
||||
|
@ -237,7 +297,14 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
return texturePool.GetDescriptor(textureId);
|
||||
}
|
||||
|
||||
private int ReadPackedId(int stage, int wordOffset)
|
||||
/// <summary>
|
||||
/// Reads a packed texture and sampler ID (basically, the real texture handle)
|
||||
/// from the texture constant buffer.
|
||||
/// </summary>
|
||||
/// <param name="stageIndex">The number of the shader stage where the texture is bound</param>
|
||||
/// <param name="wordOffset">A word offset of the handle on the buffer (the "fake" shader handle)</param>
|
||||
/// <returns>The packed texture and sampler ID (the real texture handle)</returns>
|
||||
private int ReadPackedId(int stageIndex, int wordOffset)
|
||||
{
|
||||
ulong address;
|
||||
|
||||
|
@ -249,7 +316,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
}
|
||||
else
|
||||
{
|
||||
address = bufferManager.GetGraphicsUniformBufferAddress(stage, _textureBufferIndex);
|
||||
address = bufferManager.GetGraphicsUniformBufferAddress(stageIndex, _textureBufferIndex);
|
||||
}
|
||||
|
||||
address += (uint)wordOffset * 4;
|
||||
|
@ -257,16 +324,31 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
return BitConverter.ToInt32(_context.PhysicalMemory.Read(address, 4));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the texture ID from the real texture handle.
|
||||
/// </summary>
|
||||
/// <param name="packedId">The real texture handle</param>
|
||||
/// <returns>The texture ID</returns>
|
||||
private static int UnpackTextureId(int packedId)
|
||||
{
|
||||
return (packedId >> 0) & 0xfffff;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the sampler ID from the real texture handle.
|
||||
/// </summary>
|
||||
/// <param name="packedId">The real texture handle</param>
|
||||
/// <returns>The sampler ID</returns>
|
||||
private static int UnpackSamplerId(int packedId)
|
||||
{
|
||||
return (packedId >> 20) & 0xfff;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invalidates a range of memory on all GPU resource pools (both texture and sampler pools).
|
||||
/// </summary>
|
||||
/// <param name="address">Start address of the range to invalidate</param>
|
||||
/// <param name="size">Size of the range to invalidate</param>
|
||||
public void InvalidatePoolRange(ulong address, ulong size)
|
||||
{
|
||||
_samplerPool?.InvalidateRange(address, size);
|
||||
|
@ -274,6 +356,9 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
_texturePoolCache.InvalidateRange(address, size);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Force all bound textures and images to be rebound the next time CommitBindings is called.
|
||||
/// </summary>
|
||||
public void Rebind()
|
||||
{
|
||||
_rebind = true;
|
||||
|
|
|
@ -2,6 +2,9 @@ using Ryujinx.Graphics.GAL;
|
|||
|
||||
namespace Ryujinx.Graphics.Gpu.Image
|
||||
{
|
||||
/// <summary>
|
||||
/// Texture format compatibility checks.
|
||||
/// </summary>
|
||||
static class TextureCompatibility
|
||||
{
|
||||
private enum FormatClass
|
||||
|
@ -19,6 +22,12 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
Bc7
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if two formats are compatible, according to the host API copy format compatibility rules.
|
||||
/// </summary>
|
||||
/// <param name="lhs">First comparand</param>
|
||||
/// <param name="rhs">Second comparand</param>
|
||||
/// <returns>True if the formats are compatible, false otherwise</returns>
|
||||
public static bool FormatCompatible(FormatInfo lhs, FormatInfo rhs)
|
||||
{
|
||||
if (IsDsFormat(lhs.Format) || IsDsFormat(rhs.Format))
|
||||
|
@ -44,6 +53,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the texture format class, for compressed textures, or Unclassified otherwise.
|
||||
/// </summary>
|
||||
/// <param name="format">The format</param>
|
||||
/// <returns>Format class</returns>
|
||||
private static FormatClass GetFormatClass(Format format)
|
||||
{
|
||||
switch (format)
|
||||
|
@ -77,6 +91,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
return FormatClass.Unclassified;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the format is a depth-stencil texture format.
|
||||
/// </summary>
|
||||
/// <param name="format">Format to check</param>
|
||||
/// <returns>True if the format is a depth-stencil format (including depth only), false otherwise</returns>
|
||||
private static bool IsDsFormat(Format format)
|
||||
{
|
||||
switch (format)
|
||||
|
|
|
@ -2,6 +2,9 @@ using Ryujinx.Graphics.GAL;
|
|||
|
||||
namespace Ryujinx.Graphics.Gpu.Image
|
||||
{
|
||||
/// <summary>
|
||||
/// Texture swizzle color component.
|
||||
/// </summary>
|
||||
enum TextureComponent
|
||||
{
|
||||
Zero = 0,
|
||||
|
@ -15,6 +18,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
|
||||
static class TextureComponentConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts the texture swizzle color component enum to the respective Graphics Abstraction Layer enum.
|
||||
/// </summary>
|
||||
/// <param name="component">Texture swizzle color component</param>
|
||||
/// <returns>Converted enum</returns>
|
||||
public static SwizzleComponent Convert(this TextureComponent component)
|
||||
{
|
||||
switch (component)
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
namespace Ryujinx.Graphics.Gpu.Image
|
||||
{
|
||||
/// <summary>
|
||||
/// Maxwell texture descriptor, as stored on the GPU texture pool memory region.
|
||||
/// </summary>
|
||||
struct TextureDescriptor
|
||||
{
|
||||
public uint Word0;
|
||||
|
@ -11,111 +14,213 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
public uint Word6;
|
||||
public uint Word7;
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks Maxwell texture format integer.
|
||||
/// </summary>
|
||||
/// <returns>The texture format integer</returns>
|
||||
public uint UnpackFormat()
|
||||
{
|
||||
return Word0 & 0x8007ffff;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the swizzle component for the texture red color channel.
|
||||
/// </summary>
|
||||
/// <returns>The swizzle component</returns>
|
||||
public TextureComponent UnpackSwizzleR()
|
||||
{
|
||||
return(TextureComponent)((Word0 >> 19) & 7);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the swizzle component for the texture green color channel.
|
||||
/// </summary>
|
||||
/// <returns>The swizzle component</returns>
|
||||
public TextureComponent UnpackSwizzleG()
|
||||
{
|
||||
return(TextureComponent)((Word0 >> 22) & 7);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the swizzle component for the texture blue color channel.
|
||||
/// </summary>
|
||||
/// <returns>The swizzle component</returns>
|
||||
public TextureComponent UnpackSwizzleB()
|
||||
{
|
||||
return(TextureComponent)((Word0 >> 25) & 7);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the swizzle component for the texture alpha color channel.
|
||||
/// </summary>
|
||||
/// <returns>The swizzle component</returns>
|
||||
public TextureComponent UnpackSwizzleA()
|
||||
{
|
||||
return(TextureComponent)((Word0 >> 28) & 7);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the 40-bits texture GPU virtual address.
|
||||
/// </summary>
|
||||
/// <returns>The GPU virtual address</returns>
|
||||
public ulong UnpackAddress()
|
||||
{
|
||||
return Word1 | ((ulong)(Word2 & 0xffff) << 32);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks texture descriptor type for this texture descriptor.
|
||||
/// This defines the texture layout, among other things.
|
||||
/// </summary>
|
||||
/// <returns>The texture descriptor type</returns>
|
||||
public TextureDescriptorType UnpackTextureDescriptorType()
|
||||
{
|
||||
return (TextureDescriptorType)((Word2 >> 21) & 7);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the texture stride (bytes per line) for linear textures only.
|
||||
/// Always 32-bytes aligned.
|
||||
/// </summary>
|
||||
/// <returns>The linear texture stride</returns>
|
||||
public int UnpackStride()
|
||||
{
|
||||
return (int)(Word3 & 0xffff) << 5;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the GOB block size in X (width) for block linear textures.
|
||||
/// Must be always 1, ignored by the GPU.
|
||||
/// </summary>
|
||||
/// <returns>THe GOB block X size</returns>
|
||||
public int UnpackGobBlocksInX()
|
||||
{
|
||||
return 1 << (int)(Word3 & 7);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the GOB block size in Y (height) for block linear textures.
|
||||
/// Must be always a power of 2, with a maximum value of 32.
|
||||
/// </summary>
|
||||
/// <returns>THe GOB block Y size</returns>
|
||||
public int UnpackGobBlocksInY()
|
||||
{
|
||||
return 1 << (int)((Word3 >> 3) & 7);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the GOB block size in Z (depth) for block linear textures.
|
||||
/// Must be always a power of 2, with a maximum value of 32.
|
||||
/// Must be 1 for any texture target other than 3D textures.
|
||||
/// </summary>
|
||||
/// <returns>The GOB block Z size</returns>
|
||||
public int UnpackGobBlocksInZ()
|
||||
{
|
||||
return 1 << (int)((Word3 >> 6) & 7);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Number of GOB blocks per tile in the X direction.
|
||||
/// This is only used for sparse textures, should be 1 otherwise.
|
||||
/// </summary>
|
||||
/// <returns>The number of GOB blocks per tile</returns>
|
||||
public int UnpackGobBlocksInTileX()
|
||||
{
|
||||
return 1 << (int)((Word3 >> 10) & 7);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the number of mipmap levels of the texture.
|
||||
/// </summary>
|
||||
/// <returns>The number of mipmap levels</returns>
|
||||
public int UnpackLevels()
|
||||
{
|
||||
return (int)(Word3 >> 28) + 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpack the base level texture width size.
|
||||
/// </summary>
|
||||
/// <returns>The texture width</returns>
|
||||
public int UnpackWidth()
|
||||
{
|
||||
return (int)(Word4 & 0xffff) + 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the texture sRGB format flag.
|
||||
/// </summary>
|
||||
/// <returns>True if the texture is sRGB, false otherwise</returns>
|
||||
public bool UnpackSrgb()
|
||||
{
|
||||
return (Word4 & (1 << 22)) != 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the texture target.
|
||||
/// </summary>
|
||||
/// <returns>The texture target</returns>
|
||||
public TextureTarget UnpackTextureTarget()
|
||||
{
|
||||
return (TextureTarget)((Word4 >> 23) & 0xf);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpack the base level texture height size, or array layers for 1D array textures.
|
||||
/// Should be ignored for 1D or buffer textures.
|
||||
/// </summary>
|
||||
/// <returns>The texture height or layers count</returns>
|
||||
public int UnpackHeight()
|
||||
{
|
||||
return (int)(Word5 & 0xffff) + 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpack the base level texture depth size, number of array layers or cubemap faces.
|
||||
/// The meaning of this value depends on the texture target.
|
||||
/// </summary>
|
||||
/// <returns>The texture depth, layer or faces count</returns>
|
||||
public int UnpackDepth()
|
||||
{
|
||||
return (int)((Word5 >> 16) & 0x3fff) + 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the texture coordinates normalized flag.
|
||||
/// When this is true, texture coordinates are expected to be in the [0, 1] range on the shader.
|
||||
/// WHen this is false, texture coordinates are expected to be in the [0, W], [0, H] and [0, D] range.
|
||||
/// It must be set to false (by the guest driver) for rectangle textures.
|
||||
/// </summary>
|
||||
/// <returns>The texture coordinates normalized flag</returns>
|
||||
public bool UnpackTextureCoordNormalized()
|
||||
{
|
||||
return (Word5 & (1 << 31)) != 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the base mipmap level of the texture.
|
||||
/// </summary>
|
||||
/// <returns>The base mipmap level of the texture</returns>
|
||||
public int UnpackBaseLevel()
|
||||
{
|
||||
return (int)(Word7 & 0xf);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the maximum mipmap level (inclusive) of the texture.
|
||||
/// Usually equal to Levels minus 1.
|
||||
/// </summary>
|
||||
/// <returns>The maximum mipmap level (inclusive) of the texture</returns>
|
||||
public int UnpackMaxLevelInclusive()
|
||||
{
|
||||
return (int)((Word7 >> 4) & 0xf);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the multisampled texture samples count in each direction.
|
||||
/// Must be ignored for non-multisample textures.
|
||||
/// </summary>
|
||||
/// <returns>The multisample counts enum</returns>
|
||||
public TextureMsaaMode UnpackTextureMsaaMode()
|
||||
{
|
||||
return (TextureMsaaMode)((Word7 >> 8) & 0xf);
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
namespace Ryujinx.Graphics.Gpu.Image
|
||||
{
|
||||
/// <summary>
|
||||
/// The texture descriptor type.
|
||||
/// This specifies the texture memory layout.
|
||||
/// The texture descriptor structure depends on the type.
|
||||
/// </summary>
|
||||
enum TextureDescriptorType
|
||||
{
|
||||
Buffer,
|
||||
|
|
|
@ -2,35 +2,131 @@ using Ryujinx.Graphics.GAL;
|
|||
|
||||
namespace Ryujinx.Graphics.Gpu.Image
|
||||
{
|
||||
/// <summary>
|
||||
/// Texture information.
|
||||
/// </summary>
|
||||
struct TextureInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Address of the texture in guest memory.
|
||||
/// </summary>
|
||||
public ulong Address { get; }
|
||||
|
||||
public int Width { get; }
|
||||
public int Height { get; }
|
||||
public int DepthOrLayers { get; }
|
||||
public int Levels { get; }
|
||||
public int SamplesInX { get; }
|
||||
public int SamplesInY { get; }
|
||||
public int Stride { get; }
|
||||
public bool IsLinear { get; }
|
||||
public int GobBlocksInY { get; }
|
||||
public int GobBlocksInZ { get; }
|
||||
public int GobBlocksInTileX { get; }
|
||||
/// <summary>
|
||||
/// The width of the texture.
|
||||
/// </summary>
|
||||
public int Width { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The height of the texture, or layers count for 1D array textures.
|
||||
/// </summary>
|
||||
public int Height { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The depth of the texture (for 3D textures), or layers count for array textures.
|
||||
/// </summary>
|
||||
public int DepthOrLayers { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of mipmap levels of the texture.
|
||||
/// </summary>
|
||||
public int Levels { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of samples in the X direction for multisampled textures.
|
||||
/// </summary>
|
||||
public int SamplesInX { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of samples in the Y direction for multisampled textures.
|
||||
/// </summary>
|
||||
public int SamplesInY { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of bytes per line for linear textures.
|
||||
/// </summary>
|
||||
public int Stride { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whenever or not the texture is a linear texture.
|
||||
/// </summary>
|
||||
public bool IsLinear { get; }
|
||||
|
||||
/// <summary>
|
||||
/// GOB blocks in the Y direction, for block linear textures.
|
||||
/// </summary>
|
||||
public int GobBlocksInY { get; }
|
||||
|
||||
/// <summary>
|
||||
/// GOB blocks in the Z direction, for block linear textures.
|
||||
/// </summary>
|
||||
public int GobBlocksInZ { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of GOB blocks per tile in the X direction, for block linear textures.
|
||||
/// </summary>
|
||||
public int GobBlocksInTileX { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Total number of samples for multisampled textures.
|
||||
/// </summary>
|
||||
public int Samples => SamplesInX * SamplesInY;
|
||||
|
||||
/// <summary>
|
||||
/// Texture target type.
|
||||
/// </summary>
|
||||
public Target Target { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Texture format information.
|
||||
/// </summary>
|
||||
public FormatInfo FormatInfo { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Depth-stencil mode of the texture. This defines whenever the depth or stencil value is read from shaders,
|
||||
/// for depth-stencil texture formats.
|
||||
/// </summary>
|
||||
public DepthStencilMode DepthStencilMode { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Texture swizzle for the red color channel.
|
||||
/// </summary>
|
||||
public SwizzleComponent SwizzleR { get; }
|
||||
/// <summary>
|
||||
/// Texture swizzle for the green color channel.
|
||||
/// </summary>
|
||||
public SwizzleComponent SwizzleG { get; }
|
||||
/// <summary>
|
||||
/// Texture swizzle for the blue color channel.
|
||||
/// </summary>
|
||||
public SwizzleComponent SwizzleB { get; }
|
||||
/// <summary>
|
||||
/// Texture swizzle for the alpha color channel.
|
||||
/// </summary>
|
||||
public SwizzleComponent SwizzleA { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructs the texture information structure.
|
||||
/// </summary>
|
||||
/// <param name="address">The address of the texture</param>
|
||||
/// <param name="width">The width of the texture</param>
|
||||
/// <param name="height">The height or the texture</param>
|
||||
/// <param name="depthOrLayers">The depth or layers count of the texture</param>
|
||||
/// <param name="levels">The amount if mipmap levels of the texture</param>
|
||||
/// <param name="samplesInX">The number of samples in the X direction for multisample textures, should be 1 otherwise</param>
|
||||
/// <param name="samplesInY">The number of samples in the Y direction for multisample textures, should be 1 otherwise</param>
|
||||
/// <param name="stride">The stride for linear textures</param>
|
||||
/// <param name="isLinear">Whenever the texture is linear or block linear</param>
|
||||
/// <param name="gobBlocksInY">Number of GOB blocks in the Y direction</param>
|
||||
/// <param name="gobBlocksInZ">Number of GOB blocks in the Z direction</param>
|
||||
/// <param name="gobBlocksInTileX">Number of GOB blocks per tile in the X direction</param>
|
||||
/// <param name="target">Texture target type</param>
|
||||
/// <param name="formatInfo">Texture format information</param>
|
||||
/// <param name="depthStencilMode">Depth-stencil mode</param>
|
||||
/// <param name="swizzleR">Swizzle for the red color channel</param>
|
||||
/// <param name="swizzleG">Swizzle for the green color channel</param>
|
||||
/// <param name="swizzleB">Swizzle for the blue color channel</param>
|
||||
/// <param name="swizzleA">Swizzle for the alpha color channel</param>
|
||||
public TextureInfo(
|
||||
ulong address,
|
||||
int width,
|
||||
|
@ -73,11 +169,21 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
SwizzleA = swizzleA;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the real texture depth.
|
||||
/// Returns 1 for any target other than 3D textures.
|
||||
/// </summary>
|
||||
/// <returns>Texture depth</returns>
|
||||
public int GetDepth()
|
||||
{
|
||||
return Target == Target.Texture3D ? DepthOrLayers : 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of layers of the texture.
|
||||
/// Returns 1 for non-array textures, 6 for cubemap textures, and layer faces for cubemap array textures.
|
||||
/// </summary>
|
||||
/// <returns>The number of texture layers</returns>
|
||||
public int GetLayers()
|
||||
{
|
||||
if (Target == Target.Texture2DArray || Target == Target.Texture2DMultisampleArray)
|
||||
|
|
|
@ -8,28 +8,37 @@ using System;
|
|||
|
||||
namespace Ryujinx.Graphics.Gpu.Image
|
||||
{
|
||||
/// <summary>
|
||||
/// Texture manager.
|
||||
/// </summary>
|
||||
class TextureManager
|
||||
{
|
||||
private const int OverlapsBufferInitialCapacity = 10;
|
||||
private const int OverlapsBufferMaxCapacity = 10000;
|
||||
|
||||
private GpuContext _context;
|
||||
private readonly GpuContext _context;
|
||||
|
||||
private TextureBindingsManager _cpBindingsManager;
|
||||
private TextureBindingsManager _gpBindingsManager;
|
||||
private readonly TextureBindingsManager _cpBindingsManager;
|
||||
private readonly TextureBindingsManager _gpBindingsManager;
|
||||
|
||||
private Texture[] _rtColors;
|
||||
private Texture _rtDepthStencil;
|
||||
private readonly Texture[] _rtColors;
|
||||
|
||||
private ITexture[] _rtHostColors;
|
||||
private ITexture _rtHostDs;
|
||||
private Texture _rtDepthStencil;
|
||||
|
||||
private RangeList<Texture> _textures;
|
||||
private readonly ITexture[] _rtHostColors;
|
||||
|
||||
private ITexture _rtHostDs;
|
||||
|
||||
private readonly RangeList<Texture> _textures;
|
||||
|
||||
private Texture[] _textureOverlaps;
|
||||
|
||||
private AutoDeleteCache _cache;
|
||||
private readonly AutoDeleteCache _cache;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new instance of the texture manager.
|
||||
/// </summary>
|
||||
/// <param name="context">The GPU context that the texture manager belongs to</param>
|
||||
public TextureManager(GpuContext context)
|
||||
{
|
||||
_context = context;
|
||||
|
@ -50,66 +59,126 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
_cache = new AutoDeleteCache();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets texture bindings on the compute pipeline.
|
||||
/// </summary>
|
||||
/// <param name="bindings">The texture bindings</param>
|
||||
public void SetComputeTextures(TextureBindingInfo[] bindings)
|
||||
{
|
||||
_cpBindingsManager.SetTextures(0, bindings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets texture bindings on the graphics pipeline.
|
||||
/// </summary>
|
||||
/// <param name="stage">The index of the shader stage to bind the textures</param>
|
||||
/// <param name="bindings">The texture bindings</param>
|
||||
public void SetGraphicsTextures(int stage, TextureBindingInfo[] bindings)
|
||||
{
|
||||
_gpBindingsManager.SetTextures(stage, bindings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets image bindings on the compute pipeline.
|
||||
/// </summary>
|
||||
/// <param name="bindings">The image bindings</param>
|
||||
public void SetComputeImages(TextureBindingInfo[] bindings)
|
||||
{
|
||||
_cpBindingsManager.SetImages(0, bindings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets image bindings on the graphics pipeline.
|
||||
/// </summary>
|
||||
/// <param name="stage">The index of the shader stage to bind the images</param>
|
||||
/// <param name="bindings">The image bindings</param>
|
||||
public void SetGraphicsImages(int stage, TextureBindingInfo[] bindings)
|
||||
{
|
||||
_gpBindingsManager.SetImages(stage, bindings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the texture constant buffer index on the compute pipeline.
|
||||
/// </summary>
|
||||
/// <param name="index">The texture constant buffer index</param>
|
||||
public void SetComputeTextureBufferIndex(int index)
|
||||
{
|
||||
_cpBindingsManager.SetTextureBufferIndex(index);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the texture constant buffer index on the graphics pipeline.
|
||||
/// </summary>
|
||||
/// <param name="index">The texture constant buffer index</param>
|
||||
public void SetGraphicsTextureBufferIndex(int index)
|
||||
{
|
||||
_gpBindingsManager.SetTextureBufferIndex(index);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the current sampler pool on the compute pipeline.
|
||||
/// </summary>
|
||||
/// <param name="gpuVa">The start GPU virtual address of the sampler pool</param>
|
||||
/// <param name="maximumId">The maximum ID of the sampler pool</param>
|
||||
/// <param name="samplerIndex">The indexing type of the sampler</param>
|
||||
public void SetComputeSamplerPool(ulong gpuVa, int maximumId, SamplerIndex samplerIndex)
|
||||
{
|
||||
_cpBindingsManager.SetSamplerPool(gpuVa, maximumId, samplerIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the current sampler pool on the graphics pipeline.
|
||||
/// </summary>
|
||||
/// <param name="gpuVa">The start GPU virtual address of the sampler pool</param>
|
||||
/// <param name="maximumId">The maximum ID of the sampler pool</param>
|
||||
/// <param name="samplerIndex">The indexing type of the sampler</param>
|
||||
public void SetGraphicsSamplerPool(ulong gpuVa, int maximumId, SamplerIndex samplerIndex)
|
||||
{
|
||||
_gpBindingsManager.SetSamplerPool(gpuVa, maximumId, samplerIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the current texture pool on the compute pipeline.
|
||||
/// </summary>
|
||||
/// <param name="gpuVa">The start GPU virtual address of the texture pool</param>
|
||||
/// <param name="maximumId">The maximum ID of the texture pool</param>
|
||||
public void SetComputeTexturePool(ulong gpuVa, int maximumId)
|
||||
{
|
||||
_cpBindingsManager.SetTexturePool(gpuVa, maximumId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the current texture pool on the graphics pipeline.
|
||||
/// </summary>
|
||||
/// <param name="gpuVa">The start GPU virtual address of the texture pool</param>
|
||||
/// <param name="maximumId">The maximum ID of the texture pool</param>
|
||||
public void SetGraphicsTexturePool(ulong gpuVa, int maximumId)
|
||||
{
|
||||
_gpBindingsManager.SetTexturePool(gpuVa, maximumId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the render target color buffer.
|
||||
/// </summary>
|
||||
/// <param name="index">The index of the color buffer to set (up to 8)</param>
|
||||
/// <param name="color">The color buffer texture</param>
|
||||
public void SetRenderTargetColor(int index, Texture color)
|
||||
{
|
||||
_rtColors[index] = color;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the render target depth-stencil buffer.
|
||||
/// </summary>
|
||||
/// <param name="depthStencil">The depth-stencil buffer texture</param>
|
||||
public void SetRenderTargetDepthStencil(Texture depthStencil)
|
||||
{
|
||||
_rtDepthStencil = depthStencil;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Commits bindings on the compute pipeline.
|
||||
/// </summary>
|
||||
public void CommitComputeBindings()
|
||||
{
|
||||
// Every time we switch between graphics and compute work,
|
||||
|
@ -121,6 +190,9 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
_gpBindingsManager.Rebind();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Commits bindings on the graphics pipeline.
|
||||
/// </summary>
|
||||
public void CommitGraphicsBindings()
|
||||
{
|
||||
_gpBindingsManager.CommitBindings();
|
||||
|
@ -128,11 +200,21 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
UpdateRenderTargets();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a texture descriptor used on the graphics pipeline.
|
||||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="stageIndex">Index of the shader stage where the texture is bound</param>
|
||||
/// <param name="handle">Shader "fake" handle of the texture</param>
|
||||
/// <returns>The texture descriptor</returns>
|
||||
public TextureDescriptor GetGraphicsTextureDescriptor(GpuState state, int stageIndex, int handle)
|
||||
{
|
||||
return _gpBindingsManager.GetTextureDescriptor(state, stageIndex, handle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update host framebuffer attachments based on currently bound render target buffers.
|
||||
/// </summary>
|
||||
private void UpdateRenderTargets()
|
||||
{
|
||||
bool anyChanged = false;
|
||||
|
@ -162,6 +244,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to find a existing texture, or create a new one if not found.
|
||||
/// </summary>
|
||||
/// <param name="copyTexture">Copy texture to find or create</param>
|
||||
/// <returns>The texture</returns>
|
||||
public Texture FindOrCreateTexture(CopyTexture copyTexture)
|
||||
{
|
||||
ulong address = _context.MemoryManager.Translate(copyTexture.Address.Pack());
|
||||
|
@ -210,6 +297,13 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
return texture;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to find a existing texture, or create a new one if not found.
|
||||
/// </summary>
|
||||
/// <param name="colorState">Color buffer texture to find or create</param>
|
||||
/// <param name="samplesInX">Number of samples in the X direction, for MSAA</param>
|
||||
/// <param name="samplesInY">Number of samples in the Y direction, for MSAA</param>
|
||||
/// <returns>The texture</returns>
|
||||
public Texture FindOrCreateTexture(RtColorState colorState, int samplesInX, int samplesInY)
|
||||
{
|
||||
ulong address = _context.MemoryManager.Translate(colorState.Address.Pack());
|
||||
|
@ -286,6 +380,14 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
return texture;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to find a existing texture, or create a new one if not found.
|
||||
/// </summary>
|
||||
/// <param name="dsState">Depth-stencil buffer texture to find or create</param>
|
||||
/// <param name="size">Size of the depth-stencil texture</param>
|
||||
/// <param name="samplesInX">Number of samples in the X direction, for MSAA</param>
|
||||
/// <param name="samplesInY">Number of samples in the Y direction, for MSAA</param>
|
||||
/// <returns>The texture</returns>
|
||||
public Texture FindOrCreateTexture(RtDepthStencilState dsState, Size3D size, int samplesInX, int samplesInY)
|
||||
{
|
||||
ulong address = _context.MemoryManager.Translate(dsState.Address.Pack());
|
||||
|
@ -327,6 +429,12 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
return texture;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to find a existing texture, or create a new one if not found.
|
||||
/// </summary>
|
||||
/// <param name="info">Texture information of the texture to be found or created</param>
|
||||
/// <param name="flags">The texture search flags, defines texture comparison rules</param>
|
||||
/// <returns>The texture</returns>
|
||||
public Texture FindOrCreateTexture(TextureInfo info, TextureSearchFlags flags = TextureSearchFlags.None)
|
||||
{
|
||||
bool isSamplerTexture = (flags & TextureSearchFlags.Sampler) != 0;
|
||||
|
@ -480,6 +588,9 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
return texture;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resizes the temporary buffer used for range list intersection results, if it has grown too much.
|
||||
/// </summary>
|
||||
private void ShrinkOverlapsBufferIfNeeded()
|
||||
{
|
||||
if (_textureOverlaps.Length > OverlapsBufferMaxCapacity)
|
||||
|
@ -488,6 +599,14 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adjusts the size of the texture information for a given mipmap level,
|
||||
/// based on the size of a parent texture.
|
||||
/// </summary>
|
||||
/// <param name="parent">The parent texture</param>
|
||||
/// <param name="info">The texture information to be adjusted</param>
|
||||
/// <param name="firstLevel">The first level of the texture view</param>
|
||||
/// <returns>The adjusted texture information with the new size</returns>
|
||||
private static TextureInfo AdjustSizes(Texture parent, TextureInfo info, int firstLevel)
|
||||
{
|
||||
// When the texture is used as view of another texture, we must
|
||||
|
@ -551,6 +670,14 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
info.SwizzleA);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets a texture creation information from texture information.
|
||||
/// This can be used to create new host textures.
|
||||
/// </summary>
|
||||
/// <param name="info">Texture information</param>
|
||||
/// <param name="caps">GPU capabilities</param>
|
||||
/// <returns>The texture creation information</returns>
|
||||
public static TextureCreateInfo GetCreateInfo(TextureInfo info, Capabilities caps)
|
||||
{
|
||||
FormatInfo formatInfo = info.FormatInfo;
|
||||
|
@ -590,6 +717,9 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
info.SwizzleA);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flushes all the textures in the cache that have been modified since the last call.
|
||||
/// </summary>
|
||||
public void Flush()
|
||||
{
|
||||
foreach (Texture texture in _cache)
|
||||
|
@ -603,6 +733,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flushes textures in the cache inside a given range that have been modified since the last call.
|
||||
/// </summary>
|
||||
/// <param name="address">The range start address</param>
|
||||
/// <param name="size">The range size</param>
|
||||
public void Flush(ulong address, ulong size)
|
||||
{
|
||||
foreach (Texture texture in _cache)
|
||||
|
@ -616,6 +751,12 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a texture from the cache.
|
||||
/// This only removes the texture from the internal list, not from the auto-deletion cache.
|
||||
/// It may still have live references after the removal.
|
||||
/// </summary>
|
||||
/// <param name="texture">The texture to be removed</param>
|
||||
public void RemoveTextureFromCache(Texture texture)
|
||||
{
|
||||
_textures.Remove(texture);
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
namespace Ryujinx.Graphics.Gpu.Image
|
||||
{
|
||||
/// <summary>
|
||||
/// Multisampled texture samples count.
|
||||
/// </summary>
|
||||
enum TextureMsaaMode
|
||||
{
|
||||
Ms1x1 = 0,
|
||||
|
@ -11,43 +14,55 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
|
||||
static class TextureMsaaModeConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the total number of samples from the MSAA mode.
|
||||
/// </summary>
|
||||
/// <param name="msaaMode">The MSAA mode</param>
|
||||
/// <returns>The total number of samples</returns>
|
||||
public static int SamplesCount(this TextureMsaaMode msaaMode)
|
||||
{
|
||||
switch (msaaMode)
|
||||
return msaaMode switch
|
||||
{
|
||||
case TextureMsaaMode.Ms2x1: return 2;
|
||||
case TextureMsaaMode.Ms2x2: return 4;
|
||||
case TextureMsaaMode.Ms4x2: return 8;
|
||||
case TextureMsaaMode.Ms4x4: return 16;
|
||||
}
|
||||
|
||||
return 1;
|
||||
TextureMsaaMode.Ms2x1 => 2,
|
||||
TextureMsaaMode.Ms2x2 => 4,
|
||||
TextureMsaaMode.Ms4x2 => 8,
|
||||
TextureMsaaMode.Ms4x4 => 16,
|
||||
_ => 1
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number of samples in the X direction from the MSAA mode.
|
||||
/// </summary>
|
||||
/// <param name="msaaMode">The MSAA mode</param>
|
||||
/// <returns>The number of samples in the X direction</returns>
|
||||
public static int SamplesInX(this TextureMsaaMode msaaMode)
|
||||
{
|
||||
switch (msaaMode)
|
||||
return msaaMode switch
|
||||
{
|
||||
case TextureMsaaMode.Ms2x1: return 2;
|
||||
case TextureMsaaMode.Ms2x2: return 2;
|
||||
case TextureMsaaMode.Ms4x2: return 4;
|
||||
case TextureMsaaMode.Ms4x4: return 4;
|
||||
}
|
||||
|
||||
return 1;
|
||||
TextureMsaaMode.Ms2x1 => 2,
|
||||
TextureMsaaMode.Ms2x2 => 2,
|
||||
TextureMsaaMode.Ms4x2 => 4,
|
||||
TextureMsaaMode.Ms4x4 => 4,
|
||||
_ => 1
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number of samples in the Y direction from the MSAA mode.
|
||||
/// </summary>
|
||||
/// <param name="msaaMode">The MSAA mode</param>
|
||||
/// <returns>The number of samples in the Y direction</returns>
|
||||
public static int SamplesInY(this TextureMsaaMode msaaMode)
|
||||
{
|
||||
switch (msaaMode)
|
||||
return msaaMode switch
|
||||
{
|
||||
case TextureMsaaMode.Ms2x1: return 1;
|
||||
case TextureMsaaMode.Ms2x2: return 2;
|
||||
case TextureMsaaMode.Ms4x2: return 2;
|
||||
case TextureMsaaMode.Ms4x4: return 4;
|
||||
}
|
||||
|
||||
return 1;
|
||||
TextureMsaaMode.Ms2x1 => 1,
|
||||
TextureMsaaMode.Ms2x2 => 2,
|
||||
TextureMsaaMode.Ms4x2 => 2,
|
||||
TextureMsaaMode.Ms4x4 => 4,
|
||||
_ => 1
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,17 +7,31 @@ using System.Runtime.InteropServices;
|
|||
|
||||
namespace Ryujinx.Graphics.Gpu.Image
|
||||
{
|
||||
/// <summary>
|
||||
/// Texture pool.
|
||||
/// </summary>
|
||||
class TexturePool : Pool<Texture>
|
||||
{
|
||||
public LinkedListNode<TexturePool> CacheNode { get; set; }
|
||||
|
||||
private int _sequenceNumber;
|
||||
|
||||
public TexturePool(
|
||||
GpuContext context,
|
||||
ulong address,
|
||||
int maximumId) : base(context, address, maximumId) { }
|
||||
/// <summary>
|
||||
/// Intrusive linked list node used on the texture pool cache.
|
||||
/// </summary>
|
||||
public LinkedListNode<TexturePool> CacheNode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new instance of the texture pool.
|
||||
/// </summary>
|
||||
/// <param name="context">GPU context that the texture pool belongs to</param>
|
||||
/// <param name="address">Address of the texture pool in guest memory</param>
|
||||
/// <param name="maximumId">Maximum texture ID of the texture pool (equal to maximum textures minus one)</param>
|
||||
public TexturePool(GpuContext context, ulong address, int maximumId) : base(context, address, maximumId) { }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the texture with the given ID.
|
||||
/// </summary>
|
||||
/// <param name="id">ID of the texture. This is effectively a zero-based index</param>
|
||||
/// <returns>The texture with the given ID</returns>
|
||||
public override Texture Get(int id)
|
||||
{
|
||||
if ((uint)id >= Items.Length)
|
||||
|
@ -62,6 +76,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
return texture;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the texture descriptor from a given texture ID.
|
||||
/// </summary>
|
||||
/// <param name="id">ID of the texture. This is effectively a zero-based index</param>
|
||||
/// <returns>The texture descriptor</returns>
|
||||
public TextureDescriptor GetDescriptor(int id)
|
||||
{
|
||||
ulong address = Address + (ulong)(uint)id * DescriptorSize;
|
||||
|
@ -71,6 +90,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
return MemoryMarshal.Cast<byte, TextureDescriptor>(data)[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of the texture pool range invalidation.
|
||||
/// </summary>
|
||||
/// <param name="address">Start address of the range of the texture pool</param>
|
||||
/// <param name="size">Size of the range being invalidated</param>
|
||||
protected override void InvalidateRangeImpl(ulong address, ulong size)
|
||||
{
|
||||
ulong endAddress = address + size;
|
||||
|
@ -101,6 +125,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets texture information from a texture descriptor.
|
||||
/// </summary>
|
||||
/// <param name="descriptor">The texture descriptor</param>
|
||||
/// <returns>The texture information</returns>
|
||||
private TextureInfo GetInfo(TextureDescriptor descriptor)
|
||||
{
|
||||
ulong address = Context.MemoryManager.Translate(descriptor.UnpackAddress());
|
||||
|
@ -172,6 +201,13 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
swizzleA);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the texture depth-stencil mode, based on the swizzle components of each color channel.
|
||||
/// The depth-stencil mode is determined based on how the driver sets those parameters.
|
||||
/// </summary>
|
||||
/// <param name="format">The format of the texture</param>
|
||||
/// <param name="components">The texture swizzle components</param>
|
||||
/// <returns>The depth-stencil mode</returns>
|
||||
private static DepthStencilMode GetDepthStencilMode(Format format, params SwizzleComponent[] components)
|
||||
{
|
||||
// R = Depth, G = Stencil.
|
||||
|
@ -205,12 +241,22 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the swizzle component is equal to the red or green channels.
|
||||
/// </summary>
|
||||
/// <param name="component">The swizzle component to check</param>
|
||||
/// <returns>True if the swizzle component is equal to the red or blue, false otherwise</returns>
|
||||
private static bool IsRG(SwizzleComponent component)
|
||||
{
|
||||
return component == SwizzleComponent.Red ||
|
||||
component == SwizzleComponent.Green;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decrements the reference count of the texture.
|
||||
/// This indicates that the texture pool is not using it anymore.
|
||||
/// </summary>
|
||||
/// <param name="item">The texture to be deleted</param>
|
||||
protected override void Delete(Texture item)
|
||||
{
|
||||
item?.DecrementReferenceCount();
|
||||
|
|
|
@ -2,6 +2,11 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Ryujinx.Graphics.Gpu.Image
|
||||
{
|
||||
/// <summary>
|
||||
/// Texture pool cache.
|
||||
/// This can keep multiple texture pools, and return the current one as needed.
|
||||
/// It is useful for applications that uses multiple texture pools.
|
||||
/// </summary>
|
||||
class TexturePoolCache
|
||||
{
|
||||
private const int MaxCapacity = 4;
|
||||
|
@ -10,6 +15,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
|
||||
private LinkedList<TexturePool> _pools;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new instance of the texture pool.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
public TexturePoolCache(GpuContext context)
|
||||
{
|
||||
_context = context;
|
||||
|
@ -17,6 +26,12 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
_pools = new LinkedList<TexturePool>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds a cache texture pool, or creates a new one if not found.
|
||||
/// </summary>
|
||||
/// <param name="address">Start address of the texture pool</param>
|
||||
/// <param name="maximumId">Maximum ID of the texture pool</param>
|
||||
/// <returns>The found or newly created texture pool</returns>
|
||||
public TexturePool FindOrCreate(ulong address, int maximumId)
|
||||
{
|
||||
TexturePool pool;
|
||||
|
@ -58,6 +73,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
return pool;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invalidates a memory range of all intersecting texture pools on the cache.
|
||||
/// </summary>
|
||||
/// <param name="address">Start address of the range to invalidate</param>
|
||||
/// <param name="size">Size of the range to invalidate</param>
|
||||
public void InvalidateRange(ulong address, ulong size)
|
||||
{
|
||||
for (LinkedListNode<TexturePool> node = _pools.First; node != null; node = node.Next)
|
||||
|
|
|
@ -2,6 +2,9 @@ using System;
|
|||
|
||||
namespace Ryujinx.Graphics.Gpu.Image
|
||||
{
|
||||
/// <summary>
|
||||
/// Texture search flags, defines texture information comparison rules.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
enum TextureSearchFlags
|
||||
{
|
||||
|
|
|
@ -2,6 +2,9 @@ using Ryujinx.Graphics.GAL;
|
|||
|
||||
namespace Ryujinx.Graphics.Gpu.Image
|
||||
{
|
||||
/// <summary>
|
||||
/// Texture target.
|
||||
/// </summary>
|
||||
enum TextureTarget
|
||||
{
|
||||
Texture1D,
|
||||
|
@ -17,6 +20,12 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
|
||||
static class TextureTargetConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts the texture target enum to a host compatible, Graphics Abstraction Layer enum.
|
||||
/// </summary>
|
||||
/// <param name="target">The target enum to convert</param>
|
||||
/// <param name="isMultisample">True if the texture is a multisampled texture</param>
|
||||
/// <returns>The host compatible texture target</returns>
|
||||
public static Target Convert(this TextureTarget target, bool isMultisample)
|
||||
{
|
||||
if (isMultisample)
|
||||
|
|
Reference in a new issue