diff options
| author | TSR Berry <20988865+TSRBerry@users.noreply.github.com> | 2023-04-08 01:22:00 +0200 |
|---|---|---|
| committer | Mary <thog@protonmail.com> | 2023-04-27 23:51:14 +0200 |
| commit | cee712105850ac3385cd0091a923438167433f9f (patch) | |
| tree | 4a5274b21d8b7f938c0d0ce18736d3f2993b11b1 /Ryujinx.Graphics.Gpu/Image/TexturePool.cs | |
| parent | cd124bda587ef09668a971fa1cac1c3f0cfc9f21 (diff) | |
Move solution and projects to src
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Image/TexturePool.cs')
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Image/TexturePool.cs | 603 |
1 files changed, 0 insertions, 603 deletions
diff --git a/Ryujinx.Graphics.Gpu/Image/TexturePool.cs b/Ryujinx.Graphics.Gpu/Image/TexturePool.cs deleted file mode 100644 index 5277e789..00000000 --- a/Ryujinx.Graphics.Gpu/Image/TexturePool.cs +++ /dev/null @@ -1,603 +0,0 @@ -using Ryujinx.Common.Logging; -using Ryujinx.Graphics.GAL; -using Ryujinx.Graphics.Gpu.Memory; -using Ryujinx.Graphics.Texture; -using Ryujinx.Memory.Range; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Threading; - -namespace Ryujinx.Graphics.Gpu.Image -{ - /// <summary> - /// Texture pool. - /// </summary> - class TexturePool : Pool<Texture, TextureDescriptor>, IPool<TexturePool> - { - /// <summary> - /// A request to dereference a texture from a pool. - /// </summary> - private struct DereferenceRequest - { - /// <summary> - /// Whether the dereference is due to a mapping change or not. - /// </summary> - public readonly bool IsRemapped; - - /// <summary> - /// The texture being dereferenced. - /// </summary> - public readonly Texture Texture; - - /// <summary> - /// The ID of the pool entry this reference belonged to. - /// </summary> - public readonly int ID; - - /// <summary> - /// Create a dereference request for a texture with a specific pool ID, and remapped flag. - /// </summary> - /// <param name="isRemapped">Whether the dereference is due to a mapping change or not</param> - /// <param name="texture">The texture being dereferenced</param> - /// <param name="id">The ID of the pool entry, used to restore remapped textures</param> - private DereferenceRequest(bool isRemapped, Texture texture, int id) - { - IsRemapped = isRemapped; - Texture = texture; - ID = id; - } - - /// <summary> - /// Create a dereference request for a texture removal. - /// </summary> - /// <param name="texture">The texture being removed</param> - /// <returns>A texture removal dereference request</returns> - public static DereferenceRequest Remove(Texture texture) - { - return new DereferenceRequest(false, texture, 0); - } - - /// <summary> - /// Create a dereference request for a texture remapping with a specific pool ID. - /// </summary> - /// <param name="texture">The texture being remapped</param> - /// <param name="id">The ID of the pool entry, used to restore remapped textures</param> - /// <returns>A remap dereference request</returns> - public static DereferenceRequest Remap(Texture texture, int id) - { - return new DereferenceRequest(true, texture, id); - } - } - - private readonly GpuChannel _channel; - private readonly ConcurrentQueue<DereferenceRequest> _dereferenceQueue = new ConcurrentQueue<DereferenceRequest>(); - private TextureDescriptor _defaultDescriptor; - - /// <summary> - /// Linked list node used on the texture pool cache. - /// </summary> - public LinkedListNode<TexturePool> CacheNode { get; set; } - - /// <summary> - /// Timestamp used by the texture pool cache, updated on every use of this texture pool. - /// </summary> - public ulong CacheTimestamp { get; set; } - - /// <summary> - /// Creates a new instance of the texture pool. - /// </summary> - /// <param name="context">GPU context that the texture pool belongs to</param> - /// <param name="channel">GPU channel 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, GpuChannel channel, ulong address, int maximumId) : base(context, channel.MemoryManager.Physical, address, maximumId) - { - _channel = channel; - } - - /// <summary> - /// Gets the texture descripor and texture with the given ID with no bounds check or synchronization. - /// </summary> - /// <param name="id">ID of the texture. This is effectively a zero-based index</param> - /// <param name="texture">The texture with the given ID</param> - /// <returns>The texture descriptor with the given ID</returns> - private ref readonly TextureDescriptor GetInternal(int id, out Texture texture) - { - texture = Items[id]; - - ref readonly TextureDescriptor descriptor = ref GetDescriptorRef(id); - - if (texture == null) - { - texture = PhysicalMemory.TextureCache.FindShortCache(descriptor); - - if (texture == null) - { - TextureInfo info = GetInfo(descriptor, out int layerSize); - - // The dereference queue can put our texture back on the cache. - if ((texture = ProcessDereferenceQueue(id)) != null) - { - return ref descriptor; - } - - texture = PhysicalMemory.TextureCache.FindOrCreateTexture(_channel.MemoryManager, TextureSearchFlags.ForSampler, info, layerSize); - - // If this happens, then the texture address is invalid, we can't add it to the cache. - if (texture == null) - { - return ref descriptor; - } - } - else - { - texture.SynchronizeMemory(); - } - - Items[id] = texture; - - texture.IncrementReferenceCount(this, id, descriptor.UnpackAddress()); - - DescriptorCache[id] = descriptor; - } - else - { - // On the path above (texture not yet in the pool), memory is automatically synchronized on texture creation. - texture.SynchronizeMemory(); - } - - return ref descriptor; - } - - /// <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) - { - return null; - } - - if (SequenceNumber != Context.SequenceNumber) - { - SequenceNumber = Context.SequenceNumber; - - SynchronizeMemory(); - } - - GetInternal(id, out Texture texture); - - return texture; - } - - /// <summary> - /// Gets the texture descriptor and texture with the given ID. - /// </summary> - /// <remarks> - /// This method assumes that the pool has been manually synchronized before doing binding. - /// </remarks> - /// <param name="id">ID of the texture. This is effectively a zero-based index</param> - /// <param name="texture">The texture with the given ID</param> - /// <returns>The texture descriptor with the given ID</returns> - public ref readonly TextureDescriptor GetForBinding(int id, out Texture texture) - { - if ((uint)id >= Items.Length) - { - texture = null; - return ref _defaultDescriptor; - } - - // When getting for binding, assume the pool has already been synchronized. - - return ref GetInternal(id, out texture); - } - - /// <summary> - /// Checks if the pool was modified, and returns the last sequence number where a modification was detected. - /// </summary> - /// <returns>A number that increments each time a modification is detected</returns> - public int CheckModified() - { - if (SequenceNumber != Context.SequenceNumber) - { - SequenceNumber = Context.SequenceNumber; - - SynchronizeMemory(); - } - - return ModifiedSequenceNumber; - } - - /// <summary> - /// Forcibly remove a texture from this pool's items. - /// If deferred, the dereference will be queued to occur on the render thread. - /// </summary> - /// <param name="texture">The texture being removed</param> - /// <param name="id">The ID of the texture in this pool</param> - /// <param name="deferred">If true, queue the dereference to happen on the render thread, otherwise dereference immediately</param> - public void ForceRemove(Texture texture, int id, bool deferred) - { - var previous = Interlocked.Exchange(ref Items[id], null); - - if (deferred) - { - if (previous != null) - { - _dereferenceQueue.Enqueue(DereferenceRequest.Remove(texture)); - } - } - else - { - texture.DecrementReferenceCount(); - } - } - - /// <summary> - /// Queues a request to update a texture's mapping. - /// Mapping is updated later to avoid deleting the texture if it is still sparsely mapped. - /// </summary> - /// <param name="texture">Texture with potential mapping change</param> - /// <param name="id">ID in cache of texture with potential mapping change</param> - public void QueueUpdateMapping(Texture texture, int id) - { - if (Interlocked.Exchange(ref Items[id], null) == texture) - { - _dereferenceQueue.Enqueue(DereferenceRequest.Remap(texture, id)); - } - } - - /// <summary> - /// Process the dereference queue, decrementing the reference count for each texture in it. - /// This is used to ensure that texture disposal happens on the render thread. - /// </summary> - /// <param name="id">The ID of the entry that triggered this method</param> - /// <returns>Texture that matches the entry ID if it has been readded to the cache.</returns> - private Texture ProcessDereferenceQueue(int id = -1) - { - while (_dereferenceQueue.TryDequeue(out DereferenceRequest request)) - { - Texture texture = request.Texture; - - // Unmapped storage textures can swap their ranges. The texture must be storage with no views or dependencies. - // TODO: Would need to update ranges on views, or guarantee that ones where the range changes can be instantly deleted. - - if (request.IsRemapped && texture.Group.Storage == texture && !texture.HasViews && !texture.Group.HasCopyDependencies) - { - // Has the mapping for this texture changed? - ref readonly TextureDescriptor descriptor = ref GetDescriptorRef(request.ID); - - ulong address = descriptor.UnpackAddress(); - - MultiRange range = _channel.MemoryManager.GetPhysicalRegions(address, texture.Size); - - // If the texture is not mapped at all, delete its reference. - - if (range.Count == 1 && range.GetSubRange(0).Address == MemoryManager.PteUnmapped) - { - texture.DecrementReferenceCount(); - continue; - } - - Items[request.ID] = texture; - - // Create a new pool reference, as the last one was removed on unmap. - - texture.IncrementReferenceCount(this, request.ID, address); - texture.DecrementReferenceCount(); - - // Refetch the range. Changes since the last check could have been lost - // as the cache entry was not restored (required to queue mapping change). - - range = _channel.MemoryManager.GetPhysicalRegions(address, texture.Size); - - if (!range.Equals(texture.Range)) - { - // Part of the texture was mapped or unmapped. Replace the range and regenerate tracking handles. - if (!_channel.MemoryManager.Physical.TextureCache.UpdateMapping(texture, range)) - { - // Texture could not be remapped due to a collision, just delete it. - if (Interlocked.Exchange(ref Items[request.ID], null) != null) - { - // If this is null, a request was already queued to decrement reference. - texture.DecrementReferenceCount(this, request.ID); - } - continue; - } - } - - if (request.ID == id) - { - return texture; - } - } - else - { - texture.DecrementReferenceCount(); - } - } - - return null; - } - - /// <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) - { - ProcessDereferenceQueue(); - - ulong endAddress = address + size; - - for (; address < endAddress; address += DescriptorSize) - { - int id = (int)((address - Address) / DescriptorSize); - - Texture texture = Items[id]; - - if (texture != null) - { - ref TextureDescriptor cachedDescriptor = ref DescriptorCache[id]; - ref readonly TextureDescriptor descriptor = ref GetDescriptorRefAddress(address); - - // If the descriptors are the same, the texture is the same, - // we don't need to remove as it was not modified. Just continue. - if (descriptor.Equals(ref cachedDescriptor)) - { - continue; - } - - if (texture.HasOneReference()) - { - _channel.MemoryManager.Physical.TextureCache.AddShortCache(texture, ref cachedDescriptor); - } - - if (Interlocked.Exchange(ref Items[id], null) != null) - { - texture.DecrementReferenceCount(this, id); - } - } - } - } - - /// <summary> - /// Gets texture information from a texture descriptor. - /// </summary> - /// <param name="descriptor">The texture descriptor</param> - /// <param name="layerSize">Layer size for textures using a sub-range of mipmap levels, otherwise 0</param> - /// <returns>The texture information</returns> - private TextureInfo GetInfo(in TextureDescriptor descriptor, out int layerSize) - { - int depthOrLayers = descriptor.UnpackDepth(); - int levels = descriptor.UnpackLevels(); - - TextureMsaaMode msaaMode = descriptor.UnpackTextureMsaaMode(); - - int samplesInX = msaaMode.SamplesInX(); - int samplesInY = msaaMode.SamplesInY(); - - int stride = descriptor.UnpackStride(); - - TextureDescriptorType descriptorType = descriptor.UnpackTextureDescriptorType(); - - bool isLinear = descriptorType == TextureDescriptorType.Linear; - - Target target = descriptor.UnpackTextureTarget().Convert((samplesInX | samplesInY) != 1); - - int width = target == Target.TextureBuffer ? descriptor.UnpackBufferTextureWidth() : descriptor.UnpackWidth(); - int height = descriptor.UnpackHeight(); - - if (target == Target.Texture2DMultisample || target == Target.Texture2DMultisampleArray) - { - // This is divided back before the backend texture is created. - width *= samplesInX; - height *= samplesInY; - } - - // We use 2D targets for 1D textures as that makes texture cache - // management easier. We don't know the target for render target - // and copies, so those would normally use 2D targets, which are - // not compatible with 1D targets. By doing that we also allow those - // to match when looking for compatible textures on the cache. - if (target == Target.Texture1D) - { - target = Target.Texture2D; - height = 1; - } - else if (target == Target.Texture1DArray) - { - target = Target.Texture2DArray; - height = 1; - } - - uint format = descriptor.UnpackFormat(); - bool srgb = descriptor.UnpackSrgb(); - - ulong gpuVa = descriptor.UnpackAddress(); - - if (!FormatTable.TryGetTextureFormat(format, srgb, out FormatInfo formatInfo)) - { - if (gpuVa != 0 && (int)format > 0) - { - Logger.Error?.Print(LogClass.Gpu, $"Invalid texture format 0x{format:X} (sRGB: {srgb})."); - } - - formatInfo = FormatInfo.Default; - } - - int gobBlocksInY = descriptor.UnpackGobBlocksInY(); - int gobBlocksInZ = descriptor.UnpackGobBlocksInZ(); - - int gobBlocksInTileX = descriptor.UnpackGobBlocksInTileX(); - - layerSize = 0; - - int minLod = descriptor.UnpackBaseLevel(); - int maxLod = descriptor.UnpackMaxLevelInclusive(); - - // Linear textures don't support mipmaps, so we don't handle this case here. - if ((minLod != 0 || maxLod + 1 != levels) && target != Target.TextureBuffer && !isLinear) - { - int depth = TextureInfo.GetDepth(target, depthOrLayers); - int layers = TextureInfo.GetLayers(target, depthOrLayers); - - SizeInfo sizeInfo = SizeCalculator.GetBlockLinearTextureSize( - width, - height, - depth, - levels, - layers, - formatInfo.BlockWidth, - formatInfo.BlockHeight, - formatInfo.BytesPerPixel, - gobBlocksInY, - gobBlocksInZ, - gobBlocksInTileX); - - layerSize = sizeInfo.LayerSize; - - if (minLod != 0 && minLod < levels) - { - // If the base level is not zero, we additionally add the mip level offset - // to the address, this allows the texture manager to find the base level from the - // address if there is a overlapping texture on the cache that can contain the new texture. - gpuVa += (ulong)sizeInfo.GetMipOffset(minLod); - - width = Math.Max(1, width >> minLod); - height = Math.Max(1, height >> minLod); - - if (target == Target.Texture3D) - { - depthOrLayers = Math.Max(1, depthOrLayers >> minLod); - } - - (gobBlocksInY, gobBlocksInZ) = SizeCalculator.GetMipGobBlockSizes(height, depth, formatInfo.BlockHeight, gobBlocksInY, gobBlocksInZ); - } - - levels = (maxLod - minLod) + 1; - } - - SwizzleComponent swizzleR = descriptor.UnpackSwizzleR().Convert(); - SwizzleComponent swizzleG = descriptor.UnpackSwizzleG().Convert(); - SwizzleComponent swizzleB = descriptor.UnpackSwizzleB().Convert(); - SwizzleComponent swizzleA = descriptor.UnpackSwizzleA().Convert(); - - DepthStencilMode depthStencilMode = GetDepthStencilMode( - formatInfo.Format, - swizzleR, - swizzleG, - swizzleB, - swizzleA); - - if (formatInfo.Format.IsDepthOrStencil()) - { - swizzleR = SwizzleComponent.Red; - swizzleG = SwizzleComponent.Red; - swizzleB = SwizzleComponent.Red; - - if (depthStencilMode == DepthStencilMode.Depth) - { - swizzleA = SwizzleComponent.One; - } - else - { - swizzleA = SwizzleComponent.Red; - } - } - - return new TextureInfo( - gpuVa, - width, - height, - depthOrLayers, - levels, - samplesInX, - samplesInY, - stride, - isLinear, - gobBlocksInY, - gobBlocksInZ, - gobBlocksInTileX, - target, - formatInfo, - depthStencilMode, - swizzleR, - swizzleG, - swizzleB, - 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. - // On 24-bits depth formats, this is inverted (Stencil is R etc). - // NVN setup: - // For depth, A is set to 1.0f, the other components are set to Depth. - // For stencil, all components are set to Stencil. - SwizzleComponent component = components[0]; - - for (int index = 1; index < 4 && !IsRG(component); index++) - { - component = components[index]; - } - - if (!IsRG(component)) - { - return DepthStencilMode.Depth; - } - - if (format == Format.D24UnormS8Uint) - { - return component == SwizzleComponent.Red - ? DepthStencilMode.Stencil - : DepthStencilMode.Depth; - } - else - { - return component == SwizzleComponent.Red - ? DepthStencilMode.Depth - : DepthStencilMode.Stencil; - } - } - - /// <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 green, 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(this); - } - - public override void Dispose() - { - ProcessDereferenceQueue(); - - base.Dispose(); - } - } -}
\ No newline at end of file |
