From 32764f95602611e9daa50362330d760e8ed83fda Mon Sep 17 00:00:00 2001 From: gdkchan Date: Sun, 29 Dec 2019 20:26:37 -0300 Subject: [PATCH] Add XML documentation to Ryujinx.Graphics.Gpu.Image --- Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs | 22 +- Ryujinx.Graphics.Gpu/Image/FormatInfo.cs | 38 ++- Ryujinx.Graphics.Gpu/Image/FormatTable.cs | 16 ++ Ryujinx.Graphics.Gpu/Image/Pool.cs | 40 ++- Ryujinx.Graphics.Gpu/Image/ReductionFilter.cs | 4 + Ryujinx.Graphics.Gpu/Image/Sampler.cs | 14 + .../Image/SamplerDescriptor.cs | 74 +++++ .../Image/SamplerMinFilter.cs | 3 + .../Image/SamplerMipFilter.cs | 3 + Ryujinx.Graphics.Gpu/Image/SamplerPool.cs | 24 ++ Ryujinx.Graphics.Gpu/Image/Texture.cs | 255 +++++++++++++++++- .../Image/TextureBindingInfo.cs | 35 ++- .../Image/TextureBindingsManager.cs | 89 +++++- .../Image/TextureCompatibility.cs | 19 ++ .../Image/TextureComponent.cs | 8 + .../Image/TextureDescriptor.cs | 105 ++++++++ .../Image/TextureDescriptorType.cs | 5 + Ryujinx.Graphics.Gpu/Image/TextureInfo.cs | 128 ++++++++- Ryujinx.Graphics.Gpu/Image/TextureManager.cs | 159 ++++++++++- Ryujinx.Graphics.Gpu/Image/TextureMsaaMode.cs | 63 +++-- Ryujinx.Graphics.Gpu/Image/TexturePool.cs | 58 +++- .../Image/TexturePoolCache.cs | 20 ++ .../Image/TextureSearchFlags.cs | 3 + Ryujinx.Graphics.Gpu/Image/TextureTarget.cs | 9 + 24 files changed, 1133 insertions(+), 61 deletions(-) diff --git a/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs b/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs index 33ed78818..fc30d03c7 100644 --- a/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs +++ b/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs @@ -3,17 +3,31 @@ using System.Collections.Generic; namespace Ryujinx.Graphics.Gpu.Image { + /// + /// 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. + /// class AutoDeleteCache : IEnumerable { private const int MaxCapacity = 2048; - private LinkedList _textures; + private readonly LinkedList _textures; + /// + /// Creates a new instance of the automatic deletion cache. + /// public AutoDeleteCache() { _textures = new LinkedList(); } + /// + /// 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. + /// + /// The texture to be added to the cache public void Add(Texture texture) { texture.IncrementReferenceCount(); @@ -32,6 +46,12 @@ namespace Ryujinx.Graphics.Gpu.Image } } + /// + /// 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. + /// + /// The texture to be added, or moved to the top public void Lift(Texture texture) { if (texture.CacheNode != null) diff --git a/Ryujinx.Graphics.Gpu/Image/FormatInfo.cs b/Ryujinx.Graphics.Gpu/Image/FormatInfo.cs index a728c66e1..4f73bfa86 100644 --- a/Ryujinx.Graphics.Gpu/Image/FormatInfo.cs +++ b/Ryujinx.Graphics.Gpu/Image/FormatInfo.cs @@ -2,20 +2,48 @@ using Ryujinx.Graphics.GAL; namespace Ryujinx.Graphics.Gpu.Image { + /// + /// Represents texture format information. + /// struct FormatInfo { - private static FormatInfo _rgba8 = new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4); - - public static FormatInfo Default => _rgba8; + /// + /// A default, generic RGBA8 texture format. + /// + public static FormatInfo Default { get; } = new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4); + /// + /// The format of the texture data. + /// public Format Format { get; } - public int BlockWidth { get; } - public int BlockHeight { get; } + /// + /// The block width for compressed formats. Must be 1 for non-compressed formats. + /// + public int BlockWidth { get; } + + /// + /// The block height for compressed formats. Must be 1 for non-compressed formats. + /// + public int BlockHeight { get; } + + /// + /// The number of bytes occupied by a single pixel in memory of the texture data. + /// public int BytesPerPixel { get; } + /// + /// Whenever or not the texture format is a compressed format. Determined from block size. + /// public bool IsCompressed => (BlockWidth | BlockHeight) != 1; + /// + /// Constructs the texture format info structure. + /// + /// The format of the texture data + /// The block width for compressed formats. Must be 1 for non-compressed formats + /// The block height for compressed formats. Must be 1 for non-compressed formats + /// The number of bytes occupied by a single pixel in memory of the texture data public FormatInfo( Format format, int blockWidth, diff --git a/Ryujinx.Graphics.Gpu/Image/FormatTable.cs b/Ryujinx.Graphics.Gpu/Image/FormatTable.cs index baff2e4fc..468a1ed5c 100644 --- a/Ryujinx.Graphics.Gpu/Image/FormatTable.cs +++ b/Ryujinx.Graphics.Gpu/Image/FormatTable.cs @@ -3,6 +3,9 @@ using System.Collections.Generic; namespace Ryujinx.Graphics.Gpu.Image { + /// + /// Contains format tables, for texture and vertex attribute formats. + /// static class FormatTable { private static Dictionary _textureFormats = new Dictionary() @@ -186,6 +189,13 @@ namespace Ryujinx.Graphics.Gpu.Image { 0x36000000, Format.R10G10B10A2Sscaled } }; + /// + /// Try getting the texture format from a encoded format integer from the Maxwell texture descriptor. + /// + /// The encoded format integer from the texture descriptor + /// Indicates if the format is a sRGB format + /// The output texture format + /// True if the format is valid, false otherwise 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); } + /// + /// Try getting the vertex attribute format from a encoded format integer from Maxwell attribute registers. + /// + /// The encoded format integer from the attribute registers + /// The output vertex attribute format + /// True if the format is valid, false otherwise public static bool TryGetAttribFormat(uint encoded, out Format format) { return _attribFormats.TryGetValue(encoded, out format); diff --git a/Ryujinx.Graphics.Gpu/Image/Pool.cs b/Ryujinx.Graphics.Gpu/Image/Pool.cs index 5ce8d7f68..bb55d40e1 100644 --- a/Ryujinx.Graphics.Gpu/Image/Pool.cs +++ b/Ryujinx.Graphics.Gpu/Image/Pool.cs @@ -3,6 +3,10 @@ using System; namespace Ryujinx.Graphics.Gpu.Image { + /// + /// Represents a pool of GPU resources, such as samplers or textures. + /// + /// GPU resource type abstract class Pool : IDisposable { protected const int DescriptorSize = 0x20; @@ -11,10 +15,21 @@ namespace Ryujinx.Graphics.Gpu.Image protected T[] Items; + /// + /// 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. + /// public int MaximumId { get; } + /// + /// The address of the pool in guest memory. + /// public ulong Address { get; } - public ulong Size { get; } + + /// + /// The size of the pool in bytes. + /// + public ulong Size { get; } public Pool(GpuContext context, ulong address, int maximumId) { @@ -31,8 +46,18 @@ namespace Ryujinx.Graphics.Gpu.Image Size = size; } + /// + /// Gets the GPU resource with the given ID. + /// + /// ID of the resource. This is effectively a zero-based index + /// The GPU resource with the given ID public abstract T Get(int id); + /// + /// Synchronizes host memory with guest memory. + /// This causes a invalidation of pool entries, + /// if a modification of entries by the CPU is detected. + /// public void SynchronizeMemory() { (ulong, ulong)[] modifiedRanges = Context.PhysicalMemory.GetModifiedRanges(Address, Size, ResourceName.TexturePool); @@ -57,6 +82,13 @@ namespace Ryujinx.Graphics.Gpu.Image } } + /// + /// 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. + /// + /// The start address of the range to invalidate + /// The size of the range to invalidate 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); + /// + /// Performs the disposal of all resources stored on the pool. + /// It's an error to try using the pool after disposal. + /// public void Dispose() { if (Items != null) diff --git a/Ryujinx.Graphics.Gpu/Image/ReductionFilter.cs b/Ryujinx.Graphics.Gpu/Image/ReductionFilter.cs index f14a17f2e..94b3f5425 100644 --- a/Ryujinx.Graphics.Gpu/Image/ReductionFilter.cs +++ b/Ryujinx.Graphics.Gpu/Image/ReductionFilter.cs @@ -1,5 +1,9 @@ namespace Ryujinx.Graphics.Gpu.Image { + /// + /// Represents a filter used with texture minification linear filtering. + /// This feature is only supported on NVIDIA GPUs. + /// enum ReductionFilter { Average, diff --git a/Ryujinx.Graphics.Gpu/Image/Sampler.cs b/Ryujinx.Graphics.Gpu/Image/Sampler.cs index 80790bd51..23c6160e3 100644 --- a/Ryujinx.Graphics.Gpu/Image/Sampler.cs +++ b/Ryujinx.Graphics.Gpu/Image/Sampler.cs @@ -3,10 +3,21 @@ using System; namespace Ryujinx.Graphics.Gpu.Image { + /// + /// Cached sampler entry for sampler pools. + /// class Sampler : IDisposable { + /// + /// Host sampler object. + /// public ISampler HostSampler { get; } + /// + /// Creates a new instance of the cached sampler. + /// + /// The GPU context the sampler belongs to + /// The Maxwell sampler descriptor public Sampler(GpuContext context, SamplerDescriptor descriptor) { MinFilter minFilter = descriptor.UnpackMinFilter(); @@ -42,6 +53,9 @@ namespace Ryujinx.Graphics.Gpu.Image maxAnisotropy)); } + /// + /// Disposes the host sampler object. + /// public void Dispose() { HostSampler.Dispose(); diff --git a/Ryujinx.Graphics.Gpu/Image/SamplerDescriptor.cs b/Ryujinx.Graphics.Gpu/Image/SamplerDescriptor.cs index 00b4ecb46..80b1b70fd 100644 --- a/Ryujinx.Graphics.Gpu/Image/SamplerDescriptor.cs +++ b/Ryujinx.Graphics.Gpu/Image/SamplerDescriptor.cs @@ -2,6 +2,10 @@ using Ryujinx.Graphics.GAL; namespace Ryujinx.Graphics.Gpu.Image { + /// + /// Maxwell sampler descriptor structure. + /// This structure defines the sampler descriptor as it is packed on the GPU sampler pool region. + /// struct SamplerDescriptor { private static readonly float[] _f5ToF32ConversionLut = new float[] @@ -56,41 +60,81 @@ namespace Ryujinx.Graphics.Gpu.Image public uint BorderColorB; public uint BorderColorA; + /// + /// Unpacks the texture wrap mode along the X axis. + /// + /// The texture wrap mode enum public AddressMode UnpackAddressU() { return (AddressMode)(Word0 & 7); } + // + /// Unpacks the texture wrap mode along the Y axis. + /// + /// The texture wrap mode enum public AddressMode UnpackAddressV() { return (AddressMode)((Word0 >> 3) & 7); } + // + /// Unpacks the texture wrap mode along the Z axis. + /// + /// The texture wrap mode enum public AddressMode UnpackAddressP() { return (AddressMode)((Word0 >> 6) & 7); } + /// + /// Unpacks the compare mode used for depth comparison on the shader, for + /// depth buffer texture. + /// This is only relevant for shaders with shadow samplers. + /// + /// The depth comparison mode enum public CompareMode UnpackCompareMode() { return (CompareMode)((Word0 >> 9) & 1); } + /// + /// Unpacks the compare operation used for depth comparison on the shader, for + /// depth buffer texture. + /// This is only relevant for shaders with shadow samplers. + /// + /// The depth comparison operation enum public CompareOp UnpackCompareOp() { return (CompareOp)(((Word0 >> 10) & 7) + 1); } + /// + /// Unpacks and converts the maximum anisotropy value used for texture anisotropic filtering. + /// + /// The maximum anisotropy public float UnpackMaxAnisotropy() { return _maxAnisotropyLut[(Word0 >> 20) & 7]; } + /// + /// 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. + /// + /// The magnification filter public MagFilter UnpackMagFilter() { return (MagFilter)(Word1 & 3); } + /// + /// 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. + /// + /// The minification filter public MinFilter UnpackMinFilter() { SamplerMinFilter minFilter = (SamplerMinFilter)((Word1 >> 4) & 3); @@ -99,6 +143,13 @@ namespace Ryujinx.Graphics.Gpu.Image return ConvertFilter(minFilter, mipFilter); } + /// + /// Converts two minification and filter enum, to a single minification enum, + /// including mipmap filtering information, as expected from the host API. + /// + /// The minification filter + /// The mipmap level filter + /// The combined, host API compatible filter enum private static MinFilter ConvertFilter(SamplerMinFilter minFilter, SamplerMipFilter mipFilter) { switch (mipFilter) @@ -131,11 +182,22 @@ namespace Ryujinx.Graphics.Gpu.Image return MinFilter.Nearest; } + /// + /// Unpacks the reduction filter, used with texture minification linear filtering. + /// This describes how the final value will be computed from neighbouring pixels. + /// + /// The reduction filter public ReductionFilter UnpackReductionFilter() { return (ReductionFilter)((Word1 >> 10) & 3); } + /// + /// 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. + /// + /// The level-of-detail bias value public float UnpackMipLodBias() { int fixedValue = (int)(Word1 >> 12) & 0x1fff; @@ -145,16 +207,28 @@ namespace Ryujinx.Graphics.Gpu.Image return fixedValue * Frac8ToF32; } + /// + /// Unpacks the level-of-detail snap value. + /// + /// The level-of-detail snap value public float UnpackLodSnap() { return _f5ToF32ConversionLut[(Word1 >> 26) & 0x1f]; } + /// + /// Unpacks the minimum level-of-detail value. + /// + /// The minimum level-of-detail value public float UnpackMinLod() { return (Word2 & 0xfff) * Frac8ToF32; } + /// + /// Unpacks the maximum level-of-detail value. + /// + /// The maximum level-of-detail value public float UnpackMaxLod() { return ((Word2 >> 12) & 0xfff) * Frac8ToF32; diff --git a/Ryujinx.Graphics.Gpu/Image/SamplerMinFilter.cs b/Ryujinx.Graphics.Gpu/Image/SamplerMinFilter.cs index b3274b649..17beb1293 100644 --- a/Ryujinx.Graphics.Gpu/Image/SamplerMinFilter.cs +++ b/Ryujinx.Graphics.Gpu/Image/SamplerMinFilter.cs @@ -1,5 +1,8 @@ namespace Ryujinx.Graphics.Gpu.Image { + /// + /// Sampler texture minification filter. + /// enum SamplerMinFilter { Nearest = 1, diff --git a/Ryujinx.Graphics.Gpu/Image/SamplerMipFilter.cs b/Ryujinx.Graphics.Gpu/Image/SamplerMipFilter.cs index 0bc9eb92c..319d41960 100644 --- a/Ryujinx.Graphics.Gpu/Image/SamplerMipFilter.cs +++ b/Ryujinx.Graphics.Gpu/Image/SamplerMipFilter.cs @@ -1,5 +1,8 @@ namespace Ryujinx.Graphics.Gpu.Image { + /// + /// Sampler texture mipmap level filter. + /// enum SamplerMipFilter { None = 1, diff --git a/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs b/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs index 555551095..f10f800cd 100644 --- a/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs +++ b/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs @@ -3,12 +3,26 @@ using System.Runtime.InteropServices; namespace Ryujinx.Graphics.Gpu.Image { + /// + /// Sampler pool. + /// class SamplerPool : Pool { private int _sequenceNumber; + /// + /// Constructs a new instance of the sampler pool. + /// + /// GPU context that the sampler pool belongs to + /// Address of the sampler pool in guest memory + /// Maximum sampler ID of the sampler pool (equal to maximum samplers minus one) public SamplerPool(GpuContext context, ulong address, int maximumId) : base(context, address, maximumId) { } + /// + /// Gets the sampler with the given ID. + /// + /// ID of the sampler. This is effectively a zero-based index + /// The sampler with the given ID public override Sampler Get(int id) { if ((uint)id >= Items.Length) @@ -41,6 +55,11 @@ namespace Ryujinx.Graphics.Gpu.Image return sampler; } + /// + /// Implementation of the sampler pool range invalidation. + /// + /// Start address of the range of the sampler pool + /// Size of the range being invalidated protected override void InvalidateRangeImpl(ulong address, ulong size) { ulong endAddress = address + size; @@ -60,6 +79,11 @@ namespace Ryujinx.Graphics.Gpu.Image } } + /// + /// Deletes a given sampler pool entry. + /// The host memory used by the sampler is released by the driver. + /// + /// The entry to be deleted protected override void Delete(Sampler item) { item?.Dispose(); diff --git a/Ryujinx.Graphics.Gpu/Image/Texture.cs b/Ryujinx.Graphics.Gpu/Image/Texture.cs index 544c49af5..9e5bea908 100644 --- a/Ryujinx.Graphics.Gpu/Image/Texture.cs +++ b/Ryujinx.Graphics.Gpu/Image/Texture.cs @@ -10,14 +10,23 @@ using System.Diagnostics; namespace Ryujinx.Graphics.Gpu.Image { + /// + /// Represents a cached GPU texture. + /// class Texture : IRange { private GpuContext _context; private SizeInfo _sizeInfo; + /// + /// Texture format. + /// public Format Format => Info.FormatInfo.Format; + /// + /// Texture information. + /// public TextureInfo Info { get; private set; } private int _depth; @@ -34,21 +43,48 @@ namespace Ryujinx.Graphics.Gpu.Image private List _views; + /// + /// Host texture. + /// public ITexture HostTexture { get; private set; } + /// + /// Intrusive linked list node used on the auto deletion texture cache. + /// public LinkedListNode CacheNode { get; set; } + /// + /// Texture data modified by the GPU. + /// public bool Modified { get; set; } - public ulong Address => Info.Address; + /// + /// Start address of the texture in guest memory. + /// + public ulong Address => Info.Address; + + /// + /// End address of the texture in guest memory. + /// public ulong EndAddress => Info.Address + Size; + /// + /// Texture size in bytes. + /// public ulong Size => (ulong)_sizeInfo.TotalSize; private int _referenceCount; private int _sequenceNumber; + /// + /// Constructs a new instance of the cached GPU texture. + /// + /// GPU context that the texture belongs to + /// Texture information + /// Size information of the texture + /// The first layer of the texture, or 0 if the texture has no parent + /// The first mipmap level of the texture, or 0 if the texture has no parent private Texture( GpuContext context, TextureInfo info, @@ -64,6 +100,12 @@ namespace Ryujinx.Graphics.Gpu.Image _hasData = true; } + /// + /// Constructs a new instance of the cached GPU texture. + /// + /// GPU context that the texture belongs to + /// Texture information + /// Size information of the texture 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); } + /// + /// Common texture initialization method. + /// This sets the context, info and sizeInfo fields. + /// Other fields are initialized with their default values. + /// + /// GPU context that the texture belongs to + /// Texture information + /// Size information of the texture private void InitializeTexture(GpuContext context, TextureInfo info, SizeInfo sizeInfo) { _context = context; @@ -85,6 +135,17 @@ namespace Ryujinx.Graphics.Gpu.Image _views = new List(); } + /// + /// 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. + /// + /// Child texture information + /// Child texture size information + /// Start layer of the child texture on the parent texture + /// Start mipmap level of the child texture on the parent texture + /// The child texture 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; } + /// + /// Adds a child texture to this texture. + /// + /// The child texture private void AddView(Texture texture) { _views.Add(texture); @@ -110,6 +175,10 @@ namespace Ryujinx.Graphics.Gpu.Image texture._viewStorage = this; } + /// + /// Removes a child texture from this texture. + /// + /// The child texture private void RemoveView(Texture texture) { _views.Remove(texture); @@ -119,6 +188,14 @@ namespace Ryujinx.Graphics.Gpu.Image DeleteIfNotUsed(); } + /// + /// 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. + /// + /// The new texture width + /// The new texture height + /// The new texture depth (for 3D textures) or layers (for layered textures) public void ChangeSize(int width, int height, int depthOrLayers) { width <<= _firstLevel; @@ -155,6 +232,14 @@ namespace Ryujinx.Graphics.Gpu.Image } } + /// + /// 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. + /// + /// The new texture width + /// The new texture height + /// The new texture depth (for 3D textures) or layers (for layered textures) private void RecreateStorageOrView(int width, int height, int depthOrLayers) { SetInfo(new TextureInfo( @@ -194,6 +279,13 @@ namespace Ryujinx.Graphics.Gpu.Image } } + /// + /// 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). + /// public void SynchronizeMemory() { if (_sequenceNumber == _context.SequenceNumber && _hasData) @@ -266,6 +358,14 @@ namespace Ryujinx.Graphics.Gpu.Image _hasData = true; } + /// + /// 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. + /// public void Flush() { Span data = HostTexture.GetData(); @@ -302,6 +402,13 @@ namespace Ryujinx.Graphics.Gpu.Image _context.PhysicalMemory.Write(Address, data); } + /// + /// 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. + /// + /// Texture information to compare with + /// Comparison flags + /// True if the textures are strictly equal or similar, false otherwise 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; } + /// + /// Checks if the texture format matches with the specified texture information. + /// + /// Texture information to compare with + /// True to perform a strict comparison (formats must be exactly equal) + /// True if the format matches, with the given comparison rules 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; } + /// + /// 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. + /// + /// Texture information to compare with + /// True if the layout matches, false otherwise private bool LayoutMatches(TextureInfo info) { if (Info.IsLinear != info.IsLinear) @@ -376,11 +496,23 @@ namespace Ryujinx.Graphics.Gpu.Image } } + /// + /// Checks if the texture sizes of the supplied texture information matches this texture. + /// + /// Texture information to compare with + /// True if the size matches, false otherwise public bool SizeMatches(TextureInfo info) { return SizeMatches(info, alignSizes: false); } + /// + /// Checks if the texture sizes of the supplied texture information matches the given level of + /// this texture. + /// + /// Texture information to compare with + /// Mipmap level of this texture to compare with + /// True if the size matches with the level, false otherwise 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(); } + /// + /// Checks if the texture sizes of the supplied texture information matches this texture. + /// + /// Texture information to compare with + /// True to align the sizes according to the texture layout for comparison + /// True if the sizes matches, false otherwise private bool SizeMatches(TextureInfo info, bool alignSizes) { if (Info.GetLayers() != info.GetLayers()) @@ -412,6 +550,11 @@ namespace Ryujinx.Graphics.Gpu.Image } } + /// + /// Checks if the texture shader sampling parameters matches. + /// + /// Texture information to compare with + /// True if the texture shader sampling parameters matches, false otherwise private bool SamplerParamsMatches(TextureInfo info) { return Info.DepthStencilMode == info.DepthStencilMode && @@ -421,6 +564,11 @@ namespace Ryujinx.Graphics.Gpu.Image Info.SwizzleA == info.SwizzleA; } + /// + /// Check if the texture target and samples count (for multisampled textures) matches. + /// + /// Texture information to compare with + /// True if the texture target and samples count matches, false otherwise private bool TargetAndSamplesCompatible(TextureInfo info) { return Info.Target == info.Target && @@ -428,6 +576,14 @@ namespace Ryujinx.Graphics.Gpu.Image Info.SamplesInY == info.SamplesInY; } + /// + /// Check if it's possible to create a view, with the given parameters, from this texture. + /// + /// Texture view information + /// Texture view size + /// Texture view initial layer on this texture + /// Texture view first mipmap level on this texture + /// True if a view with the given parameters can be created from this texture, false otherwise 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); } + /// + /// Check if it's possible to create a view, with the given parameters, from this texture. + /// + /// Texture view information + /// Texture view size + /// True to check for copy compability, instead of view compatibility + /// Texture view initial layer on this texture + /// Texture view first mipmap level on this texture + /// True if a view with the given parameters can be created from this texture, false otherwise public bool IsViewCompatible( TextureInfo info, ulong size, @@ -484,6 +649,14 @@ namespace Ryujinx.Graphics.Gpu.Image Info.SamplesInY == info.SamplesInY; } + /// + /// 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. + /// + /// Texture information of the texture view + /// Start level of the texture view, in relation with this texture + /// True if the layout is compatible, false otherwise private bool ViewLayoutCompatible(TextureInfo info, int level) { if (Info.IsLinear != info.IsLinear) @@ -520,11 +693,26 @@ namespace Ryujinx.Graphics.Gpu.Image } } + /// + /// 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. + /// + /// Texture information of the texture view + /// True if the formats are compatible, false otherwise private bool ViewFormatCompatible(TextureInfo info) { return TextureCompatibility.FormatCompatible(Info.FormatInfo, info.FormatInfo); } + /// + /// Checks if the size of a given texture view is compatible with this texture. + /// + /// Texture information of the texture view + /// Mipmap level of the texture view in relation to this texture + /// True to check for copy compatibility rather than view compatibility + /// True if the sizes are compatible, false otherwise 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; } + /// + /// Check if the target of the specified texture view information is compatible with this + /// texture. + /// This follows the host API target compatibility rules. + /// + /// Texture information of the texture view + /// True to check for copy rather than view compatibility + /// True if the targets are compatible, false otherwise private bool ViewTargetCompatible(TextureInfo info, bool isCopy) { switch (Info.Target) @@ -576,6 +772,13 @@ namespace Ryujinx.Graphics.Gpu.Image return false; } + /// + /// Gets the aligned sizes of the specified texture information. + /// The alignment depends on the texture layout and format bytes per pixel. + /// + /// Texture information to calculate the aligned size from + /// Mipmap level for texture views + /// The aligned texture size 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 } } + /// + /// 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. + /// + /// The desired target type + /// A view of this texture with the requested target, or null if the target is invalid for this texture public ITexture GetTargetTexture(Target target) { if (target == Info.Target) @@ -655,6 +865,13 @@ namespace Ryujinx.Graphics.Gpu.Image return null; } + /// + /// 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. + /// + /// The target to compare with + /// True if both targets have the same number of dimensions, false otherwise private bool IsSameDimensionsTarget(Target target) { switch (Info.Target) @@ -686,6 +903,13 @@ namespace Ryujinx.Graphics.Gpu.Image return false; } + /// + /// Replaces view texture information. + /// This should only be used for child textures with a parent. + /// + /// The parent texture + /// The new view texture information + /// The new host texture public void ReplaceView(Texture parent, TextureInfo info, ITexture hostTexture) { ReplaceStorage(hostTexture); @@ -695,6 +919,10 @@ namespace Ryujinx.Graphics.Gpu.Image SetInfo(info); } + /// + /// Sets the internal texture information structure. + /// + /// The new texture information private void SetInfo(TextureInfo info) { Info = info; @@ -703,6 +931,10 @@ namespace Ryujinx.Graphics.Gpu.Image _layers = info.GetLayers(); } + /// + /// Replaces the host texture, while disposing of the old one if needed. + /// + /// The new host texture private void ReplaceStorage(ITexture hostTexture) { DisposeTextures(); @@ -710,16 +942,29 @@ namespace Ryujinx.Graphics.Gpu.Image HostTexture = hostTexture; } + /// + /// Checks if the texture overlaps with a memory range. + /// + /// Start address of the range + /// Size of the range + /// True if the texture overlaps with the range, false otherwise public bool OverlapsWith(ulong address, ulong size) { return Address < address + size && address < EndAddress; } + /// + /// Increments the texture reference count. + /// public void IncrementReferenceCount() { _referenceCount++; } + /// + /// Decrements the texture reference count. + /// When the reference count hits zero, the texture may be deleted and can't be used anymore. + /// public void DecrementReferenceCount() { int newRefCount = --_referenceCount; @@ -739,6 +984,11 @@ namespace Ryujinx.Graphics.Gpu.Image DeleteIfNotUsed(); } + /// + /// 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. + /// private void DeleteIfNotUsed() { // We can delete the texture as long it is not being used @@ -751,6 +1001,9 @@ namespace Ryujinx.Graphics.Gpu.Image } } + /// + /// Performs texture disposal, deleting the texture. + /// private void DisposeTextures() { HostTexture.Dispose(); diff --git a/Ryujinx.Graphics.Gpu/Image/TextureBindingInfo.cs b/Ryujinx.Graphics.Gpu/Image/TextureBindingInfo.cs index cf922ac5a..94225406e 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureBindingInfo.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureBindingInfo.cs @@ -2,17 +2,44 @@ using Ryujinx.Graphics.GAL; namespace Ryujinx.Graphics.Gpu.Image { + /// + /// Texture binding information. + /// This is used for textures that needs to be accessed from shaders. + /// struct TextureBindingInfo { + /// + /// Shader sampler target type. + /// public Target Target { get; } + /// + /// Shader texture handle. + /// This is a index into the texture constant buffer. + /// public int Handle { get; } + /// + /// Indicates if the texture is a bindless texture. + /// For those textures, Handle is ignored. + /// public bool IsBindless { get; } - public int CbufSlot { get; } + /// + /// Constant buffer slot with the bindless texture handle, for bindless texture. + /// + public int CbufSlot { get; } + + /// + /// Constant buffer offset of the bindless texture handle, for bindless texture. + /// public int CbufOffset { get; } + /// + /// Constructs the texture binding information structure. + /// + /// The shader sampler target type + /// The shader texture handle (read index into the texture constant buffer) public TextureBindingInfo(Target target, int handle) { Target = target; @@ -24,6 +51,12 @@ namespace Ryujinx.Graphics.Gpu.Image CbufOffset = 0; } + /// + /// Constructs the bindless texture binding information structure. + /// + /// The shader sampler target type + /// Constant buffer slot where the bindless texture handle is located + /// Constant buffer offset of the bindless texture handle public TextureBindingInfo(Target target, int cbufSlot, int cbufOffset) { Target = target; diff --git a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs index 0ea7aec27..4d50c46e3 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs @@ -6,6 +6,9 @@ using System.Runtime.InteropServices; namespace Ryujinx.Graphics.Gpu.Image { + /// + /// Texture bindings manager. + /// class TextureBindingsManager { private GpuContext _context; @@ -37,6 +40,12 @@ namespace Ryujinx.Graphics.Gpu.Image private bool _rebind; + /// + /// Constructs a new instance of the texture bindings manager. + /// + /// The GPU context that the texture bindings manager belongs to + /// Texture pools cache used to get texture pools from + /// True if the bindings manager is used for the compute engine public TextureBindingsManager(GpuContext context, TexturePoolCache texturePoolCache, bool isCompute) { _context = context; @@ -52,6 +61,11 @@ namespace Ryujinx.Graphics.Gpu.Image _imageState = new TextureStatePerStage[stages][]; } + /// + /// Binds textures for a given shader stage. + /// + /// Shader stage number, or 0 for compute shaders + /// Texture bindings 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]; } + /// + /// Binds images for a given shader stage. + /// + /// Shader stage number, or 0 for compute shaders + /// Image bindings 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]; } + /// + /// Sets the textures constant buffer index. + /// The constant buffer specified holds the texture handles. + /// + /// Constant buffer index public void SetTextureBufferIndex(int index) { _textureBufferIndex = index; } + /// + /// Sets the current texture sampler pool to be used. + /// + /// Start GPU virtual address of the pool + /// Maximum ID of the pool (total count minus one) + /// Type of the sampler pool indexing used for bound samplers 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; } + /// + /// Sets the current texture pool to be used. + /// + /// Start GPU virtual address of the pool + /// Maximum ID of the pool (total count minus one) public void SetTexturePool(ulong gpuVa, int maximumId) { ulong address = _context.MemoryManager.Translate(gpuVa); @@ -98,6 +133,10 @@ namespace Ryujinx.Graphics.Gpu.Image _texturePoolMaximumId = maximumId; } + /// + /// Ensures that the bindings are visible to the host GPU. + /// This actually performs the binding using the host graphics API. + /// public void CommitBindings() { TexturePool texturePool = _texturePoolCache.FindOrCreate( @@ -123,6 +162,13 @@ namespace Ryujinx.Graphics.Gpu.Image _rebind = false; } + /// + /// Ensures that the texture bindings are visible to the host GPU. + /// This actually performs the binding using the host graphics API. + /// + /// The current texture pool + /// The shader stage using the textures to be bound + /// The stage number of the specified shader stage private void CommitTextureBindings(TexturePool pool, ShaderStage stage, int stageIndex) { if (_textureBindings[stageIndex] == null) @@ -194,6 +240,13 @@ namespace Ryujinx.Graphics.Gpu.Image } } + /// + /// Ensures that the image bindings are visible to the host GPU. + /// This actually performs the binding using the host graphics API. + /// + /// The current texture pool + /// The shader stage using the textures to be bound + /// The stage number of the specified shader stage private void CommitImageBindings(TexturePool pool, ShaderStage stage, int stageIndex) { if (_imageBindings[stageIndex] == null) @@ -222,6 +275,13 @@ namespace Ryujinx.Graphics.Gpu.Image } } + /// + /// Gets the texture descriptor for a given texture handle. + /// + /// The current GPU state + /// The stage number where the texture is bound + /// The texture handle + /// The texture descriptor for the specified texture 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) + /// + /// Reads a packed texture and sampler ID (basically, the real texture handle) + /// from the texture constant buffer. + /// + /// The number of the shader stage where the texture is bound + /// A word offset of the handle on the buffer (the "fake" shader handle) + /// The packed texture and sampler ID (the real texture handle) + 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)); } + /// + /// Unpacks the texture ID from the real texture handle. + /// + /// The real texture handle + /// The texture ID private static int UnpackTextureId(int packedId) { return (packedId >> 0) & 0xfffff; } + /// + /// Unpacks the sampler ID from the real texture handle. + /// + /// The real texture handle + /// The sampler ID private static int UnpackSamplerId(int packedId) { return (packedId >> 20) & 0xfff; } + /// + /// Invalidates a range of memory on all GPU resource pools (both texture and sampler pools). + /// + /// Start address of the range to invalidate + /// Size of the range to invalidate public void InvalidatePoolRange(ulong address, ulong size) { _samplerPool?.InvalidateRange(address, size); @@ -274,6 +356,9 @@ namespace Ryujinx.Graphics.Gpu.Image _texturePoolCache.InvalidateRange(address, size); } + /// + /// Force all bound textures and images to be rebound the next time CommitBindings is called. + /// public void Rebind() { _rebind = true; diff --git a/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs b/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs index 524721647..5b8696209 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs @@ -2,6 +2,9 @@ using Ryujinx.Graphics.GAL; namespace Ryujinx.Graphics.Gpu.Image { + /// + /// Texture format compatibility checks. + /// static class TextureCompatibility { private enum FormatClass @@ -19,6 +22,12 @@ namespace Ryujinx.Graphics.Gpu.Image Bc7 } + /// + /// Checks if two formats are compatible, according to the host API copy format compatibility rules. + /// + /// First comparand + /// Second comparand + /// True if the formats are compatible, false otherwise public static bool FormatCompatible(FormatInfo lhs, FormatInfo rhs) { if (IsDsFormat(lhs.Format) || IsDsFormat(rhs.Format)) @@ -44,6 +53,11 @@ namespace Ryujinx.Graphics.Gpu.Image } } + /// + /// Gets the texture format class, for compressed textures, or Unclassified otherwise. + /// + /// The format + /// Format class private static FormatClass GetFormatClass(Format format) { switch (format) @@ -77,6 +91,11 @@ namespace Ryujinx.Graphics.Gpu.Image return FormatClass.Unclassified; } + /// + /// Checks if the format is a depth-stencil texture format. + /// + /// Format to check + /// True if the format is a depth-stencil format (including depth only), false otherwise private static bool IsDsFormat(Format format) { switch (format) diff --git a/Ryujinx.Graphics.Gpu/Image/TextureComponent.cs b/Ryujinx.Graphics.Gpu/Image/TextureComponent.cs index db9b9dae6..359069bcf 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureComponent.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureComponent.cs @@ -2,6 +2,9 @@ using Ryujinx.Graphics.GAL; namespace Ryujinx.Graphics.Gpu.Image { + /// + /// Texture swizzle color component. + /// enum TextureComponent { Zero = 0, @@ -15,6 +18,11 @@ namespace Ryujinx.Graphics.Gpu.Image static class TextureComponentConverter { + /// + /// Converts the texture swizzle color component enum to the respective Graphics Abstraction Layer enum. + /// + /// Texture swizzle color component + /// Converted enum public static SwizzleComponent Convert(this TextureComponent component) { switch (component) diff --git a/Ryujinx.Graphics.Gpu/Image/TextureDescriptor.cs b/Ryujinx.Graphics.Gpu/Image/TextureDescriptor.cs index 6d1f0fb18..5dbd1a082 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureDescriptor.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureDescriptor.cs @@ -1,5 +1,8 @@ namespace Ryujinx.Graphics.Gpu.Image { + /// + /// Maxwell texture descriptor, as stored on the GPU texture pool memory region. + /// struct TextureDescriptor { public uint Word0; @@ -11,111 +14,213 @@ namespace Ryujinx.Graphics.Gpu.Image public uint Word6; public uint Word7; + /// + /// Unpacks Maxwell texture format integer. + /// + /// The texture format integer public uint UnpackFormat() { return Word0 & 0x8007ffff; } + /// + /// Unpacks the swizzle component for the texture red color channel. + /// + /// The swizzle component public TextureComponent UnpackSwizzleR() { return(TextureComponent)((Word0 >> 19) & 7); } + /// + /// Unpacks the swizzle component for the texture green color channel. + /// + /// The swizzle component public TextureComponent UnpackSwizzleG() { return(TextureComponent)((Word0 >> 22) & 7); } + /// + /// Unpacks the swizzle component for the texture blue color channel. + /// + /// The swizzle component public TextureComponent UnpackSwizzleB() { return(TextureComponent)((Word0 >> 25) & 7); } + /// + /// Unpacks the swizzle component for the texture alpha color channel. + /// + /// The swizzle component public TextureComponent UnpackSwizzleA() { return(TextureComponent)((Word0 >> 28) & 7); } + /// + /// Unpacks the 40-bits texture GPU virtual address. + /// + /// The GPU virtual address public ulong UnpackAddress() { return Word1 | ((ulong)(Word2 & 0xffff) << 32); } + /// + /// Unpacks texture descriptor type for this texture descriptor. + /// This defines the texture layout, among other things. + /// + /// The texture descriptor type public TextureDescriptorType UnpackTextureDescriptorType() { return (TextureDescriptorType)((Word2 >> 21) & 7); } + /// + /// Unpacks the texture stride (bytes per line) for linear textures only. + /// Always 32-bytes aligned. + /// + /// The linear texture stride public int UnpackStride() { return (int)(Word3 & 0xffff) << 5; } + /// + /// Unpacks the GOB block size in X (width) for block linear textures. + /// Must be always 1, ignored by the GPU. + /// + /// THe GOB block X size public int UnpackGobBlocksInX() { return 1 << (int)(Word3 & 7); } + /// + /// 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. + /// + /// THe GOB block Y size public int UnpackGobBlocksInY() { return 1 << (int)((Word3 >> 3) & 7); } + /// + /// 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. + /// + /// The GOB block Z size public int UnpackGobBlocksInZ() { return 1 << (int)((Word3 >> 6) & 7); } + /// + /// Number of GOB blocks per tile in the X direction. + /// This is only used for sparse textures, should be 1 otherwise. + /// + /// The number of GOB blocks per tile public int UnpackGobBlocksInTileX() { return 1 << (int)((Word3 >> 10) & 7); } + /// + /// Unpacks the number of mipmap levels of the texture. + /// + /// The number of mipmap levels public int UnpackLevels() { return (int)(Word3 >> 28) + 1; } + /// + /// Unpack the base level texture width size. + /// + /// The texture width public int UnpackWidth() { return (int)(Word4 & 0xffff) + 1; } + /// + /// Unpacks the texture sRGB format flag. + /// + /// True if the texture is sRGB, false otherwise public bool UnpackSrgb() { return (Word4 & (1 << 22)) != 0; } + /// + /// Unpacks the texture target. + /// + /// The texture target public TextureTarget UnpackTextureTarget() { return (TextureTarget)((Word4 >> 23) & 0xf); } + /// + /// Unpack the base level texture height size, or array layers for 1D array textures. + /// Should be ignored for 1D or buffer textures. + /// + /// The texture height or layers count public int UnpackHeight() { return (int)(Word5 & 0xffff) + 1; } + /// + /// Unpack the base level texture depth size, number of array layers or cubemap faces. + /// The meaning of this value depends on the texture target. + /// + /// The texture depth, layer or faces count public int UnpackDepth() { return (int)((Word5 >> 16) & 0x3fff) + 1; } + /// + /// 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. + /// + /// The texture coordinates normalized flag public bool UnpackTextureCoordNormalized() { return (Word5 & (1 << 31)) != 0; } + /// + /// Unpacks the base mipmap level of the texture. + /// + /// The base mipmap level of the texture public int UnpackBaseLevel() { return (int)(Word7 & 0xf); } + /// + /// Unpacks the maximum mipmap level (inclusive) of the texture. + /// Usually equal to Levels minus 1. + /// + /// The maximum mipmap level (inclusive) of the texture public int UnpackMaxLevelInclusive() { return (int)((Word7 >> 4) & 0xf); } + /// + /// Unpacks the multisampled texture samples count in each direction. + /// Must be ignored for non-multisample textures. + /// + /// The multisample counts enum public TextureMsaaMode UnpackTextureMsaaMode() { return (TextureMsaaMode)((Word7 >> 8) & 0xf); diff --git a/Ryujinx.Graphics.Gpu/Image/TextureDescriptorType.cs b/Ryujinx.Graphics.Gpu/Image/TextureDescriptorType.cs index 6f6048a61..8e7d40bbe 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureDescriptorType.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureDescriptorType.cs @@ -1,5 +1,10 @@ namespace Ryujinx.Graphics.Gpu.Image { + /// + /// The texture descriptor type. + /// This specifies the texture memory layout. + /// The texture descriptor structure depends on the type. + /// enum TextureDescriptorType { Buffer, diff --git a/Ryujinx.Graphics.Gpu/Image/TextureInfo.cs b/Ryujinx.Graphics.Gpu/Image/TextureInfo.cs index 19110dcf6..784ff0e97 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureInfo.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureInfo.cs @@ -2,35 +2,131 @@ using Ryujinx.Graphics.GAL; namespace Ryujinx.Graphics.Gpu.Image { + /// + /// Texture information. + /// struct TextureInfo { + /// + /// Address of the texture in guest memory. + /// 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; } + /// + /// The width of the texture. + /// + public int Width { get; } + /// + /// The height of the texture, or layers count for 1D array textures. + /// + public int Height { get; } + + /// + /// The depth of the texture (for 3D textures), or layers count for array textures. + /// + public int DepthOrLayers { get; } + + /// + /// The number of mipmap levels of the texture. + /// + public int Levels { get; } + + /// + /// The number of samples in the X direction for multisampled textures. + /// + public int SamplesInX { get; } + + /// + /// The number of samples in the Y direction for multisampled textures. + /// + public int SamplesInY { get; } + + /// + /// The number of bytes per line for linear textures. + /// + public int Stride { get; } + + /// + /// Indicates whenever or not the texture is a linear texture. + /// + public bool IsLinear { get; } + + /// + /// GOB blocks in the Y direction, for block linear textures. + /// + public int GobBlocksInY { get; } + + /// + /// GOB blocks in the Z direction, for block linear textures. + /// + public int GobBlocksInZ { get; } + + /// + /// Number of GOB blocks per tile in the X direction, for block linear textures. + /// + public int GobBlocksInTileX { get; } + + /// + /// Total number of samples for multisampled textures. + /// public int Samples => SamplesInX * SamplesInY; + /// + /// Texture target type. + /// public Target Target { get; } + /// + /// Texture format information. + /// public FormatInfo FormatInfo { get; } + /// + /// Depth-stencil mode of the texture. This defines whenever the depth or stencil value is read from shaders, + /// for depth-stencil texture formats. + /// public DepthStencilMode DepthStencilMode { get; } + /// + /// Texture swizzle for the red color channel. + /// public SwizzleComponent SwizzleR { get; } + /// + /// Texture swizzle for the green color channel. + /// public SwizzleComponent SwizzleG { get; } + /// + /// Texture swizzle for the blue color channel. + /// public SwizzleComponent SwizzleB { get; } + /// + /// Texture swizzle for the alpha color channel. + /// public SwizzleComponent SwizzleA { get; } + /// + /// Constructs the texture information structure. + /// + /// The address of the texture + /// The width of the texture + /// The height or the texture + /// The depth or layers count of the texture + /// The amount if mipmap levels of the texture + /// The number of samples in the X direction for multisample textures, should be 1 otherwise + /// The number of samples in the Y direction for multisample textures, should be 1 otherwise + /// The stride for linear textures + /// Whenever the texture is linear or block linear + /// Number of GOB blocks in the Y direction + /// Number of GOB blocks in the Z direction + /// Number of GOB blocks per tile in the X direction + /// Texture target type + /// Texture format information + /// Depth-stencil mode + /// Swizzle for the red color channel + /// Swizzle for the green color channel + /// Swizzle for the blue color channel + /// Swizzle for the alpha color channel public TextureInfo( ulong address, int width, @@ -73,11 +169,21 @@ namespace Ryujinx.Graphics.Gpu.Image SwizzleA = swizzleA; } + /// + /// Gets the real texture depth. + /// Returns 1 for any target other than 3D textures. + /// + /// Texture depth public int GetDepth() { return Target == Target.Texture3D ? DepthOrLayers : 1; } + /// + /// 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. + /// + /// The number of texture layers public int GetLayers() { if (Target == Target.Texture2DArray || Target == Target.Texture2DMultisampleArray) diff --git a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs index 6e1b8c60a..4f6d5e588 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs @@ -8,28 +8,37 @@ using System; namespace Ryujinx.Graphics.Gpu.Image { + /// + /// Texture manager. + /// 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 _textures; + private readonly ITexture[] _rtHostColors; + + private ITexture _rtHostDs; + + private readonly RangeList _textures; private Texture[] _textureOverlaps; - private AutoDeleteCache _cache; + private readonly AutoDeleteCache _cache; + /// + /// Constructs a new instance of the texture manager. + /// + /// The GPU context that the texture manager belongs to public TextureManager(GpuContext context) { _context = context; @@ -50,66 +59,126 @@ namespace Ryujinx.Graphics.Gpu.Image _cache = new AutoDeleteCache(); } + /// + /// Sets texture bindings on the compute pipeline. + /// + /// The texture bindings public void SetComputeTextures(TextureBindingInfo[] bindings) { _cpBindingsManager.SetTextures(0, bindings); } + /// + /// Sets texture bindings on the graphics pipeline. + /// + /// The index of the shader stage to bind the textures + /// The texture bindings public void SetGraphicsTextures(int stage, TextureBindingInfo[] bindings) { _gpBindingsManager.SetTextures(stage, bindings); } + /// + /// Sets image bindings on the compute pipeline. + /// + /// The image bindings public void SetComputeImages(TextureBindingInfo[] bindings) { _cpBindingsManager.SetImages(0, bindings); } + /// + /// Sets image bindings on the graphics pipeline. + /// + /// The index of the shader stage to bind the images + /// The image bindings public void SetGraphicsImages(int stage, TextureBindingInfo[] bindings) { _gpBindingsManager.SetImages(stage, bindings); } + /// + /// Sets the texture constant buffer index on the compute pipeline. + /// + /// The texture constant buffer index public void SetComputeTextureBufferIndex(int index) { _cpBindingsManager.SetTextureBufferIndex(index); } + /// + /// Sets the texture constant buffer index on the graphics pipeline. + /// + /// The texture constant buffer index public void SetGraphicsTextureBufferIndex(int index) { _gpBindingsManager.SetTextureBufferIndex(index); } + /// + /// Sets the current sampler pool on the compute pipeline. + /// + /// The start GPU virtual address of the sampler pool + /// The maximum ID of the sampler pool + /// The indexing type of the sampler public void SetComputeSamplerPool(ulong gpuVa, int maximumId, SamplerIndex samplerIndex) { _cpBindingsManager.SetSamplerPool(gpuVa, maximumId, samplerIndex); } + /// + /// Sets the current sampler pool on the graphics pipeline. + /// + /// The start GPU virtual address of the sampler pool + /// The maximum ID of the sampler pool + /// The indexing type of the sampler public void SetGraphicsSamplerPool(ulong gpuVa, int maximumId, SamplerIndex samplerIndex) { _gpBindingsManager.SetSamplerPool(gpuVa, maximumId, samplerIndex); } + /// + /// Sets the current texture pool on the compute pipeline. + /// + /// The start GPU virtual address of the texture pool + /// The maximum ID of the texture pool public void SetComputeTexturePool(ulong gpuVa, int maximumId) { _cpBindingsManager.SetTexturePool(gpuVa, maximumId); } + /// + /// Sets the current texture pool on the graphics pipeline. + /// + /// The start GPU virtual address of the texture pool + /// The maximum ID of the texture pool public void SetGraphicsTexturePool(ulong gpuVa, int maximumId) { _gpBindingsManager.SetTexturePool(gpuVa, maximumId); } + /// + /// Sets the render target color buffer. + /// + /// The index of the color buffer to set (up to 8) + /// The color buffer texture public void SetRenderTargetColor(int index, Texture color) { _rtColors[index] = color; } + /// + /// Sets the render target depth-stencil buffer. + /// + /// The depth-stencil buffer texture public void SetRenderTargetDepthStencil(Texture depthStencil) { _rtDepthStencil = depthStencil; } + /// + /// Commits bindings on the compute pipeline. + /// public void CommitComputeBindings() { // Every time we switch between graphics and compute work, @@ -121,6 +190,9 @@ namespace Ryujinx.Graphics.Gpu.Image _gpBindingsManager.Rebind(); } + /// + /// Commits bindings on the graphics pipeline. + /// public void CommitGraphicsBindings() { _gpBindingsManager.CommitBindings(); @@ -128,11 +200,21 @@ namespace Ryujinx.Graphics.Gpu.Image UpdateRenderTargets(); } + /// + /// Gets a texture descriptor used on the graphics pipeline. + /// + /// Current GPU state + /// Index of the shader stage where the texture is bound + /// Shader "fake" handle of the texture + /// The texture descriptor public TextureDescriptor GetGraphicsTextureDescriptor(GpuState state, int stageIndex, int handle) { return _gpBindingsManager.GetTextureDescriptor(state, stageIndex, handle); } + /// + /// Update host framebuffer attachments based on currently bound render target buffers. + /// private void UpdateRenderTargets() { bool anyChanged = false; @@ -162,6 +244,11 @@ namespace Ryujinx.Graphics.Gpu.Image } } + /// + /// Tries to find a existing texture, or create a new one if not found. + /// + /// Copy texture to find or create + /// The texture public Texture FindOrCreateTexture(CopyTexture copyTexture) { ulong address = _context.MemoryManager.Translate(copyTexture.Address.Pack()); @@ -210,6 +297,13 @@ namespace Ryujinx.Graphics.Gpu.Image return texture; } + /// + /// Tries to find a existing texture, or create a new one if not found. + /// + /// Color buffer texture to find or create + /// Number of samples in the X direction, for MSAA + /// Number of samples in the Y direction, for MSAA + /// The texture 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; } + /// + /// Tries to find a existing texture, or create a new one if not found. + /// + /// Depth-stencil buffer texture to find or create + /// Size of the depth-stencil texture + /// Number of samples in the X direction, for MSAA + /// Number of samples in the Y direction, for MSAA + /// The texture 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; } + /// + /// Tries to find a existing texture, or create a new one if not found. + /// + /// Texture information of the texture to be found or created + /// The texture search flags, defines texture comparison rules + /// The texture 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; } + /// + /// Resizes the temporary buffer used for range list intersection results, if it has grown too much. + /// private void ShrinkOverlapsBufferIfNeeded() { if (_textureOverlaps.Length > OverlapsBufferMaxCapacity) @@ -488,6 +599,14 @@ namespace Ryujinx.Graphics.Gpu.Image } } + /// + /// Adjusts the size of the texture information for a given mipmap level, + /// based on the size of a parent texture. + /// + /// The parent texture + /// The texture information to be adjusted + /// The first level of the texture view + /// The adjusted texture information with the new size 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); } + + /// + /// Gets a texture creation information from texture information. + /// This can be used to create new host textures. + /// + /// Texture information + /// GPU capabilities + /// The texture creation information public static TextureCreateInfo GetCreateInfo(TextureInfo info, Capabilities caps) { FormatInfo formatInfo = info.FormatInfo; @@ -590,6 +717,9 @@ namespace Ryujinx.Graphics.Gpu.Image info.SwizzleA); } + /// + /// Flushes all the textures in the cache that have been modified since the last call. + /// public void Flush() { foreach (Texture texture in _cache) @@ -603,6 +733,11 @@ namespace Ryujinx.Graphics.Gpu.Image } } + /// + /// Flushes textures in the cache inside a given range that have been modified since the last call. + /// + /// The range start address + /// The range size public void Flush(ulong address, ulong size) { foreach (Texture texture in _cache) @@ -616,6 +751,12 @@ namespace Ryujinx.Graphics.Gpu.Image } } + /// + /// 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. + /// + /// The texture to be removed public void RemoveTextureFromCache(Texture texture) { _textures.Remove(texture); diff --git a/Ryujinx.Graphics.Gpu/Image/TextureMsaaMode.cs b/Ryujinx.Graphics.Gpu/Image/TextureMsaaMode.cs index 134210671..0461888f1 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureMsaaMode.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureMsaaMode.cs @@ -1,5 +1,8 @@ namespace Ryujinx.Graphics.Gpu.Image { + /// + /// Multisampled texture samples count. + /// enum TextureMsaaMode { Ms1x1 = 0, @@ -11,43 +14,55 @@ namespace Ryujinx.Graphics.Gpu.Image static class TextureMsaaModeConverter { + /// + /// Returns the total number of samples from the MSAA mode. + /// + /// The MSAA mode + /// The total number of samples 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 + }; } + /// + /// Returns the number of samples in the X direction from the MSAA mode. + /// + /// The MSAA mode + /// The number of samples in the X direction 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 + }; } + /// + /// Returns the number of samples in the Y direction from the MSAA mode. + /// + /// The MSAA mode + /// The number of samples in the Y direction 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 + }; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics.Gpu/Image/TexturePool.cs b/Ryujinx.Graphics.Gpu/Image/TexturePool.cs index f6fa50692..91f6338f3 100644 --- a/Ryujinx.Graphics.Gpu/Image/TexturePool.cs +++ b/Ryujinx.Graphics.Gpu/Image/TexturePool.cs @@ -7,17 +7,31 @@ using System.Runtime.InteropServices; namespace Ryujinx.Graphics.Gpu.Image { + /// + /// Texture pool. + /// class TexturePool : Pool { - public LinkedListNode CacheNode { get; set; } - private int _sequenceNumber; - public TexturePool( - GpuContext context, - ulong address, - int maximumId) : base(context, address, maximumId) { } + /// + /// Intrusive linked list node used on the texture pool cache. + /// + public LinkedListNode CacheNode { get; set; } + /// + /// Constructs a new instance of the texture pool. + /// + /// GPU context that the texture pool belongs to + /// Address of the texture pool in guest memory + /// Maximum texture ID of the texture pool (equal to maximum textures minus one) + public TexturePool(GpuContext context, ulong address, int maximumId) : base(context, address, maximumId) { } + + /// + /// Gets the texture with the given ID. + /// + /// ID of the texture. This is effectively a zero-based index + /// The texture with the given ID public override Texture Get(int id) { if ((uint)id >= Items.Length) @@ -62,6 +76,11 @@ namespace Ryujinx.Graphics.Gpu.Image return texture; } + /// + /// Gets the texture descriptor from a given texture ID. + /// + /// ID of the texture. This is effectively a zero-based index + /// The texture descriptor public TextureDescriptor GetDescriptor(int id) { ulong address = Address + (ulong)(uint)id * DescriptorSize; @@ -71,6 +90,11 @@ namespace Ryujinx.Graphics.Gpu.Image return MemoryMarshal.Cast(data)[0]; } + /// + /// Implementation of the texture pool range invalidation. + /// + /// Start address of the range of the texture pool + /// Size of the range being invalidated protected override void InvalidateRangeImpl(ulong address, ulong size) { ulong endAddress = address + size; @@ -101,6 +125,11 @@ namespace Ryujinx.Graphics.Gpu.Image } } + /// + /// Gets texture information from a texture descriptor. + /// + /// The texture descriptor + /// The texture information private TextureInfo GetInfo(TextureDescriptor descriptor) { ulong address = Context.MemoryManager.Translate(descriptor.UnpackAddress()); @@ -172,6 +201,13 @@ namespace Ryujinx.Graphics.Gpu.Image swizzleA); } + /// + /// 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. + /// + /// The format of the texture + /// The texture swizzle components + /// The depth-stencil mode private static DepthStencilMode GetDepthStencilMode(Format format, params SwizzleComponent[] components) { // R = Depth, G = Stencil. @@ -205,12 +241,22 @@ namespace Ryujinx.Graphics.Gpu.Image } } + /// + /// Checks if the swizzle component is equal to the red or green channels. + /// + /// The swizzle component to check + /// True if the swizzle component is equal to the red or blue, false otherwise private static bool IsRG(SwizzleComponent component) { return component == SwizzleComponent.Red || component == SwizzleComponent.Green; } + /// + /// Decrements the reference count of the texture. + /// This indicates that the texture pool is not using it anymore. + /// + /// The texture to be deleted protected override void Delete(Texture item) { item?.DecrementReferenceCount(); diff --git a/Ryujinx.Graphics.Gpu/Image/TexturePoolCache.cs b/Ryujinx.Graphics.Gpu/Image/TexturePoolCache.cs index 9ab7e292d..6c249ca65 100644 --- a/Ryujinx.Graphics.Gpu/Image/TexturePoolCache.cs +++ b/Ryujinx.Graphics.Gpu/Image/TexturePoolCache.cs @@ -2,6 +2,11 @@ using System.Collections.Generic; namespace Ryujinx.Graphics.Gpu.Image { + /// + /// 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. + /// class TexturePoolCache { private const int MaxCapacity = 4; @@ -10,6 +15,10 @@ namespace Ryujinx.Graphics.Gpu.Image private LinkedList _pools; + /// + /// Constructs a new instance of the texture pool. + /// + /// public TexturePoolCache(GpuContext context) { _context = context; @@ -17,6 +26,12 @@ namespace Ryujinx.Graphics.Gpu.Image _pools = new LinkedList(); } + /// + /// Finds a cache texture pool, or creates a new one if not found. + /// + /// Start address of the texture pool + /// Maximum ID of the texture pool + /// The found or newly created texture pool public TexturePool FindOrCreate(ulong address, int maximumId) { TexturePool pool; @@ -58,6 +73,11 @@ namespace Ryujinx.Graphics.Gpu.Image return pool; } + /// + /// Invalidates a memory range of all intersecting texture pools on the cache. + /// + /// Start address of the range to invalidate + /// Size of the range to invalidate public void InvalidateRange(ulong address, ulong size) { for (LinkedListNode node = _pools.First; node != null; node = node.Next) diff --git a/Ryujinx.Graphics.Gpu/Image/TextureSearchFlags.cs b/Ryujinx.Graphics.Gpu/Image/TextureSearchFlags.cs index a5c951b53..daf726f1d 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureSearchFlags.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureSearchFlags.cs @@ -2,6 +2,9 @@ using System; namespace Ryujinx.Graphics.Gpu.Image { + /// + /// Texture search flags, defines texture information comparison rules. + /// [Flags] enum TextureSearchFlags { diff --git a/Ryujinx.Graphics.Gpu/Image/TextureTarget.cs b/Ryujinx.Graphics.Gpu/Image/TextureTarget.cs index 96a814c62..301fc87b2 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureTarget.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureTarget.cs @@ -2,6 +2,9 @@ using Ryujinx.Graphics.GAL; namespace Ryujinx.Graphics.Gpu.Image { + /// + /// Texture target. + /// enum TextureTarget { Texture1D, @@ -17,6 +20,12 @@ namespace Ryujinx.Graphics.Gpu.Image static class TextureTargetConverter { + /// + /// Converts the texture target enum to a host compatible, Graphics Abstraction Layer enum. + /// + /// The target enum to convert + /// True if the texture is a multisampled texture + /// The host compatible texture target public static Target Convert(this TextureTarget target, bool isMultisample) { if (isMultisample)