From d786d8d2b924da7cd116a2eb97d738a9f07b4e43 Mon Sep 17 00:00:00 2001 From: gdk Date: Wed, 30 Oct 2019 20:45:01 -0300 Subject: [PATCH] Support copy of slices to 3D textures, remove old 3D render target layered render support, do not delete textures with existing views created from them --- Ryujinx.Graphics.GAL/IPipeline.cs | 1 - Ryujinx.Graphics.GAL/ITexture.cs | 2 +- Ryujinx.Graphics.Gpu/Engine/Methods.cs | 84 ++++---------------- Ryujinx.Graphics.Gpu/Image/Texture.cs | 62 ++++++++++++--- Ryujinx.Graphics.Gpu/Image/TextureManager.cs | 67 +++++++--------- Ryujinx.Graphics.OpenGL/Framebuffer.cs | 10 --- Ryujinx.Graphics.OpenGL/Pipeline.cs | 22 ----- Ryujinx.Graphics.OpenGL/TextureView.cs | 4 +- Ryujinx.Graphics.Texture/SizeCalculator.cs | 39 +++++++-- 9 files changed, 131 insertions(+), 160 deletions(-) diff --git a/Ryujinx.Graphics.GAL/IPipeline.cs b/Ryujinx.Graphics.GAL/IPipeline.cs index c331373b1..770606895 100644 --- a/Ryujinx.Graphics.GAL/IPipeline.cs +++ b/Ryujinx.Graphics.GAL/IPipeline.cs @@ -61,7 +61,6 @@ namespace Ryujinx.Graphics.GAL void SetRenderTargetColorMasks(uint[] componentMask); - void SetRenderTargets(ITexture color3D, ITexture depthStencil); void SetRenderTargets(ITexture[] colors, ITexture depthStencil); void SetStencilTest(StencilTestDescriptor stencilTest); diff --git a/Ryujinx.Graphics.GAL/ITexture.cs b/Ryujinx.Graphics.GAL/ITexture.cs index 6b3f5c59e..f170e3741 100644 --- a/Ryujinx.Graphics.GAL/ITexture.cs +++ b/Ryujinx.Graphics.GAL/ITexture.cs @@ -7,7 +7,7 @@ namespace Ryujinx.Graphics.GAL { int Handle { get; } - void CopyTo(ITexture destination); + void CopyTo(ITexture destination, int firstLayer, int firstLevel); void CopyTo(ITexture destination, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter); ITexture CreateView(TextureCreateInfo info, int firstLayer, int firstLevel); diff --git a/Ryujinx.Graphics.Gpu/Engine/Methods.cs b/Ryujinx.Graphics.Gpu/Engine/Methods.cs index 5d90573c7..5d1563129 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Methods.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Methods.cs @@ -227,39 +227,28 @@ namespace Ryujinx.Graphics.Gpu.Engine int samplesInX = msaaMode.SamplesInX(); int samplesInY = msaaMode.SamplesInY(); - Image.Texture color3D = Get3DRenderTarget(samplesInX, samplesInY); - - if (color3D == null) + for (int index = 0; index < Constants.TotalRenderTargets; index++) { - for (int index = 0; index < Constants.TotalRenderTargets; index++) + var colorState = _context.State.Get(MethodOffset.RtColorState, index); + + if (!IsRtEnabled(colorState)) { - var colorState = _context.State.Get(MethodOffset.RtColorState, index); + _textureManager.SetRenderTargetColor(index, null); - if (!IsRtEnabled(colorState)) - { - _textureManager.SetRenderTargetColor(index, null); - - continue; - } - - Image.Texture color = _textureManager.FindOrCreateTexture( - colorState, - samplesInX, - samplesInY); - - _textureManager.SetRenderTargetColor(index, color); - - if (color != null) - { - color.Modified = true; - } + continue; } - } - else - { - _textureManager.SetRenderTargetColor3D(color3D); - color3D.Modified = true; + Image.Texture color = _textureManager.FindOrCreateTexture( + colorState, + samplesInX, + samplesInY); + + _textureManager.SetRenderTargetColor(index, color); + + if (color != null) + { + color.Modified = true; + } } bool dsEnable = _context.State.Get(MethodOffset.RtDepthStencilEnable); @@ -286,45 +275,6 @@ namespace Ryujinx.Graphics.Gpu.Engine } } - private Image.Texture Get3DRenderTarget(int samplesInX, int samplesInY) - { - var colorState0 = _context.State.Get(MethodOffset.RtColorState, 0); - - if (!IsRtEnabled(colorState0) || !colorState0.MemoryLayout.UnpackIsTarget3D() || colorState0.Depth != 1) - { - return null; - } - - int slices = 1; - int unused = 0; - - for (int index = 1; index < Constants.TotalRenderTargets; index++) - { - var colorState = _context.State.Get(MethodOffset.RtColorState, index); - - if (!IsRtEnabled(colorState)) - { - unused++; - - continue; - } - - if (colorState.MemoryLayout.UnpackIsTarget3D() && colorState.Depth == 1) - { - slices++; - } - } - - if (slices + unused == Constants.TotalRenderTargets) - { - colorState0.Depth = slices; - - return _textureManager.FindOrCreateTexture(colorState0, samplesInX, samplesInY); - } - - return null; - } - private static bool IsRtEnabled(RtColorState colorState) { // Colors are disabled by writing 0 to the format. diff --git a/Ryujinx.Graphics.Gpu/Image/Texture.cs b/Ryujinx.Graphics.Gpu/Image/Texture.cs index c34ff1d37..cc7e7bf60 100644 --- a/Ryujinx.Graphics.Gpu/Image/Texture.cs +++ b/Ryujinx.Graphics.Gpu/Image/Texture.cs @@ -6,6 +6,7 @@ using Ryujinx.Graphics.Texture; using Ryujinx.Graphics.Texture.Astc; using System; using System.Collections.Generic; +using System.Diagnostics; namespace Ryujinx.Graphics.Gpu.Image { @@ -116,6 +117,8 @@ namespace Ryujinx.Graphics.Gpu.Image _views.Remove(texture); texture._viewStorage = null; + + DeleteIfNotUsed(); } public void ChangeSize(int width, int height, int depthOrLayers) @@ -187,7 +190,7 @@ namespace Ryujinx.Graphics.Gpu.Image { ITexture newStorage = _context.Renderer.CreateTexture(createInfo); - HostTexture.CopyTo(newStorage); + HostTexture.CopyTo(newStorage, 0, 0); ReplaceStorage(newStorage); } @@ -413,7 +416,21 @@ namespace Ryujinx.Graphics.Gpu.Image _info.SamplesInY == info.SamplesInY; } - public bool IsViewCompatible(TextureInfo info, ulong size, out int firstLayer, out int firstLevel) + public bool IsViewCompatible( + TextureInfo info, + ulong size, + out int firstLayer, + out int firstLevel) + { + return IsViewCompatible(info, size, isCopy: false, out firstLayer, out firstLevel); + } + + public bool IsViewCompatible( + TextureInfo info, + ulong size, + bool isCopy, + out int firstLayer, + out int firstLevel) { // Out of range. if (info.Address < Address || info.Address + size > EndAddress) @@ -441,12 +458,12 @@ namespace Ryujinx.Graphics.Gpu.Image return false; } - if (!ViewSizeMatches(info, firstLevel)) + if (!ViewSizeMatches(info, firstLevel, isCopy)) { return false; } - if (!ViewTargetCompatible(info)) + if (!ViewTargetCompatible(info, isCopy)) { return false; } @@ -496,18 +513,24 @@ namespace Ryujinx.Graphics.Gpu.Image return TextureCompatibility.FormatCompatible(_info.FormatInfo, info.FormatInfo); } - private bool ViewSizeMatches(TextureInfo info, int level) + private bool ViewSizeMatches(TextureInfo info, int level, bool isCopy) { Size size = GetAlignedSize(_info, level); Size otherSize = GetAlignedSize(info); - return size.Width == otherSize.Width && - size.Height == otherSize.Height && - size.Depth == otherSize.Depth; + // For copies, we can copy a subset of the 3D texture slices, + // so the depth may be different in this case. + if (!isCopy && info.Target == Target.Texture3D && size.Depth != otherSize.Depth) + { + return false; + } + + return size.Width == otherSize.Width && + size.Height == otherSize.Height; } - private bool ViewTargetCompatible(TextureInfo info) + private bool ViewTargetCompatible(TextureInfo info, bool isCopy) { switch (_info.Target) { @@ -534,7 +557,8 @@ namespace Ryujinx.Graphics.Gpu.Image info.Target == Target.Texture2DMultisampleArray; case Target.Texture3D: - return info.Target == Target.Texture3D; + return info.Target == Target.Texture3D || + (info.Target == Target.Texture2D && isCopy); } return false; @@ -686,7 +710,9 @@ namespace Ryujinx.Graphics.Gpu.Image public void DecrementReferenceCount() { - if (--_referenceCount == 0) + int newRefCount = --_referenceCount; + + if (newRefCount == 0) { if (_viewStorage != this) { @@ -694,7 +720,21 @@ namespace Ryujinx.Graphics.Gpu.Image } _context.Methods.TextureManager.RemoveTextureFromCache(this); + } + Debug.Assert(newRefCount >= 0); + + DeleteIfNotUsed(); + } + + private void DeleteIfNotUsed() + { + // We can delete the texture as long it is not being used + // in any cache (the reference count is 0 in this case), and + // also all views that may be created from this texture were + // already deleted (views count is 0). + if (_referenceCount == 0 && _views.Count == 0) + { DisposeTextures(); } } diff --git a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs index 7cf79d0f9..2db1b4f27 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs @@ -17,13 +17,10 @@ namespace Ryujinx.Graphics.Gpu.Image private TextureBindingsManager _gpBindingsManager; private Texture[] _rtColors; - private Texture _rtColor3D; - - private Texture _rtDepthStencil; + private Texture _rtDepthStencil; private ITexture[] _rtHostColors; - - private ITexture _rtHostDs; + private ITexture _rtHostDs; private RangeList _textures; @@ -98,13 +95,6 @@ namespace Ryujinx.Graphics.Gpu.Image public void SetRenderTargetColor(int index, Texture color) { _rtColors[index] = color; - - _rtColor3D = null; - } - - public void SetRenderTargetColor3D(Texture color) - { - _rtColor3D = color; } public void SetRenderTargetDepthStencil(Texture depthStencil) @@ -141,38 +131,21 @@ namespace Ryujinx.Graphics.Gpu.Image anyChanged = true; } - if (_rtColor3D == null) + for (int index = 0; index < _rtColors.Length; index++) { - for (int index = 0; index < _rtColors.Length; index++) - { - ITexture hostTexture = _rtColors[index]?.HostTexture; + ITexture hostTexture = _rtColors[index]?.HostTexture; - if (_rtHostColors[index] != hostTexture) - { - _rtHostColors[index] = hostTexture; - - anyChanged = true; - } - } - - if (anyChanged) + if (_rtHostColors[index] != hostTexture) { - _context.Renderer.Pipeline.SetRenderTargets(_rtHostColors, _rtHostDs); - } - } - else - { - if (_rtHostColors[0] != _rtColor3D.HostTexture) - { - _rtHostColors[0] = _rtColor3D.HostTexture; + _rtHostColors[index] = hostTexture; anyChanged = true; } + } - if (anyChanged) - { - _context.Renderer.Pipeline.SetRenderTargets(_rtColor3D.HostTexture, _rtHostDs); - } + if (anyChanged) + { + _context.Renderer.Pipeline.SetRenderTargets(_rtHostColors, _rtHostDs); } } @@ -447,11 +420,29 @@ namespace Ryujinx.Graphics.Gpu.Image ITexture newView = texture.HostTexture.CreateView(createInfo, firstLayer, firstLevel); - overlap.HostTexture.CopyTo(newView); + overlap.HostTexture.CopyTo(newView, 0, 0); overlap.ReplaceView(texture, overlapInfo, newView); } } + + // If the texture is a 3D texture, we need to additionally copy any slice + // of the 3D texture to the newly created 3D texture. + if (info.Target == Target.Texture3D) + { + foreach (Texture overlap in overlaps) + { + if (texture.IsViewCompatible( + overlap.Info, + overlap.Size, + isCopy: true, + out int firstLayer, + out int firstLevel)) + { + overlap.HostTexture.CopyTo(texture.HostTexture, firstLayer, firstLevel); + } + } + } } // Sampler textures are managed by the texture pool, all other textures diff --git a/Ryujinx.Graphics.OpenGL/Framebuffer.cs b/Ryujinx.Graphics.OpenGL/Framebuffer.cs index 409130094..d416bd03f 100644 --- a/Ryujinx.Graphics.OpenGL/Framebuffer.cs +++ b/Ryujinx.Graphics.OpenGL/Framebuffer.cs @@ -29,16 +29,6 @@ namespace Ryujinx.Graphics.OpenGL 0); } - public void AttachColor(int index, TextureView color, int layer) - { - GL.FramebufferTextureLayer( - FramebufferTarget.Framebuffer, - FramebufferAttachment.ColorAttachment0 + index, - color?.Handle ?? 0, - 0, - layer); - } - public void AttachDepthStencil(TextureView depthStencil) { // Detach the last depth/stencil buffer if there is any. diff --git a/Ryujinx.Graphics.OpenGL/Pipeline.cs b/Ryujinx.Graphics.OpenGL/Pipeline.cs index 5df801f87..745926e74 100644 --- a/Ryujinx.Graphics.OpenGL/Pipeline.cs +++ b/Ryujinx.Graphics.OpenGL/Pipeline.cs @@ -697,28 +697,6 @@ namespace Ryujinx.Graphics.OpenGL } } - public void SetRenderTargets(ITexture color3D, ITexture depthStencil) - { - EnsureFramebuffer(); - - TextureView color = (TextureView)color3D; - - for (int index = 0; index < color.DepthOrLayers; index++) - { - _framebuffer.AttachColor(index, color, index); - } - - TextureView depthStencilView = (TextureView)depthStencil; - - _framebuffer.AttachDepthStencil(depthStencilView); - - _framebuffer.SetDrawBuffers(color.DepthOrLayers); - - _hasDepthBuffer = depthStencil != null && depthStencilView.Format != Format.S8Uint; - - UpdateDepthTest(); - } - public void SetRenderTargets(ITexture[] colors, ITexture depthStencil) { EnsureFramebuffer(); diff --git a/Ryujinx.Graphics.OpenGL/TextureView.cs b/Ryujinx.Graphics.OpenGL/TextureView.cs index 8a2b50dc4..8fced290d 100644 --- a/Ryujinx.Graphics.OpenGL/TextureView.cs +++ b/Ryujinx.Graphics.OpenGL/TextureView.cs @@ -137,11 +137,11 @@ namespace Ryujinx.Graphics.OpenGL return _parent.GetHashCode(); } - public void CopyTo(ITexture destination) + public void CopyTo(ITexture destination, int firstLayer, int firstLevel) { TextureView destinationView = (TextureView)destination; - TextureCopyUnscaled.Copy(this, destinationView, 0, 0); + TextureCopyUnscaled.Copy(this, destinationView, firstLayer, firstLevel); int width = Math.Min(Width, destinationView.Width); int height = Math.Min(Height, destinationView.Height); diff --git a/Ryujinx.Graphics.Texture/SizeCalculator.cs b/Ryujinx.Graphics.Texture/SizeCalculator.cs index 873f41a32..11385d28d 100644 --- a/Ryujinx.Graphics.Texture/SizeCalculator.cs +++ b/Ryujinx.Graphics.Texture/SizeCalculator.cs @@ -22,8 +22,11 @@ namespace Ryujinx.Graphics.Texture int gobBlocksInZ, int gobBlocksInTileX) { + bool is3D = depth > 1; + int layerSize = 0; + int[] allOffsets = new int[levels * layers * depth]; int[] mipOffsets = new int[levels]; int mipGobBlocksInY = gobBlocksInY; @@ -55,6 +58,25 @@ namespace Ryujinx.Graphics.Texture int robSize = widthInGobs * mipGobBlocksInY * mipGobBlocksInZ * GobSize; + if (is3D) + { + int gobSize = mipGobBlocksInY * GobSize; + + int sliceSize = totalBlocksOfGobsInY * widthInGobs * gobSize; + + int baseOffset = layerSize; + + int mask = gobBlocksInZ - 1; + + for (int z = 0; z < d; z++) + { + int zLow = z & mask; + int zHigh = z & ~mask; + + allOffsets[z * levels + level] = baseOffset + zLow * gobSize + zHigh * sliceSize; + } + } + mipOffsets[level] = layerSize; layerSize += totalBlocksOfGobsInZ * totalBlocksOfGobsInY * robSize; @@ -68,16 +90,17 @@ namespace Ryujinx.Graphics.Texture gobBlocksInY, gobBlocksInZ); - int[] allOffsets = new int[levels * layers]; - - for (int layer = 0; layer < layers; layer++) + if (!is3D) { - int baseIndex = layer * levels; - int baseOffset = layer * layerSize; - - for (int level = 0; level < levels; level++) + for (int layer = 0; layer < layers; layer++) { - allOffsets[baseIndex + level] = baseOffset + mipOffsets[level]; + int baseIndex = layer * levels; + int baseOffset = layer * layerSize; + + for (int level = 0; level < levels; level++) + { + allOffsets[baseIndex + level] = baseOffset + mipOffsets[level]; + } } }