aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Ryujinx.Graphics.GAL/IPipeline.cs1
-rw-r--r--Ryujinx.Graphics.GAL/ITexture.cs2
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Methods.cs80
-rw-r--r--Ryujinx.Graphics.Gpu/Image/Texture.cs62
-rw-r--r--Ryujinx.Graphics.Gpu/Image/TextureManager.cs67
-rw-r--r--Ryujinx.Graphics.OpenGL/Framebuffer.cs10
-rw-r--r--Ryujinx.Graphics.OpenGL/Pipeline.cs22
-rw-r--r--Ryujinx.Graphics.OpenGL/TextureView.cs4
-rw-r--r--Ryujinx.Graphics.Texture/SizeCalculator.cs39
9 files changed, 129 insertions, 158 deletions
diff --git a/Ryujinx.Graphics.GAL/IPipeline.cs b/Ryujinx.Graphics.GAL/IPipeline.cs
index c331373b..77060689 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 6b3f5c59..f170e374 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 5d90573c..5d156312 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Methods.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Methods.cs
@@ -227,40 +227,29 @@ 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<RtColorState>(MethodOffset.RtColorState, index);
+ var colorState = _context.State.Get<RtColorState>(MethodOffset.RtColorState, index);
- if (!IsRtEnabled(colorState))
- {
- _textureManager.SetRenderTargetColor(index, null);
+ if (!IsRtEnabled(colorState))
+ {
+ _textureManager.SetRenderTargetColor(index, null);
- continue;
- }
+ continue;
+ }
- Image.Texture color = _textureManager.FindOrCreateTexture(
- colorState,
- samplesInX,
- samplesInY);
+ Image.Texture color = _textureManager.FindOrCreateTexture(
+ colorState,
+ samplesInX,
+ samplesInY);
- _textureManager.SetRenderTargetColor(index, color);
+ _textureManager.SetRenderTargetColor(index, color);
- if (color != null)
- {
- color.Modified = true;
- }
+ if (color != null)
+ {
+ color.Modified = true;
}
}
- else
- {
- _textureManager.SetRenderTargetColor3D(color3D);
-
- color3D.Modified = true;
- }
bool dsEnable = _context.State.Get<Boolean32>(MethodOffset.RtDepthStencilEnable);
@@ -286,45 +275,6 @@ namespace Ryujinx.Graphics.Gpu.Engine
}
}
- private Image.Texture Get3DRenderTarget(int samplesInX, int samplesInY)
- {
- var colorState0 = _context.State.Get<RtColorState>(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<RtColorState>(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 c34ff1d3..cc7e7bf6 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 7cf79d0f..2db1b4f2 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<Texture> _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)
- {
- _context.Renderer.Pipeline.SetRenderTargets(_rtHostColors, _rtHostDs);
- }
- }
- else
- {
- if (_rtHostColors[0] != _rtColor3D.HostTexture)
+ if (_rtHostColors[index] != 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 40913009..d416bd03 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 5df801f8..745926e7 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 8a2b50dc..8fced290 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 873f41a3..11385d28 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];
+ }
}
}