1
0
Fork 0
forked from Mirror/Ryujinx

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

This commit is contained in:
gdk 2019-10-30 20:45:01 -03:00 committed by Thog
parent 3bcc395253
commit d786d8d2b9
9 changed files with 131 additions and 160 deletions
Ryujinx.Graphics.GAL
Ryujinx.Graphics.Gpu
Ryujinx.Graphics.OpenGL
Ryujinx.Graphics.Texture

View file

@ -61,7 +61,6 @@ namespace Ryujinx.Graphics.GAL
void SetRenderTargetColorMasks(uint[] componentMask); void SetRenderTargetColorMasks(uint[] componentMask);
void SetRenderTargets(ITexture color3D, ITexture depthStencil);
void SetRenderTargets(ITexture[] colors, ITexture depthStencil); void SetRenderTargets(ITexture[] colors, ITexture depthStencil);
void SetStencilTest(StencilTestDescriptor stencilTest); void SetStencilTest(StencilTestDescriptor stencilTest);

View file

@ -7,7 +7,7 @@ namespace Ryujinx.Graphics.GAL
{ {
int Handle { get; } 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); void CopyTo(ITexture destination, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter);
ITexture CreateView(TextureCreateInfo info, int firstLayer, int firstLevel); ITexture CreateView(TextureCreateInfo info, int firstLayer, int firstLevel);

View file

@ -227,39 +227,28 @@ namespace Ryujinx.Graphics.Gpu.Engine
int samplesInX = msaaMode.SamplesInX(); int samplesInX = msaaMode.SamplesInX();
int samplesInY = msaaMode.SamplesInY(); int samplesInY = msaaMode.SamplesInY();
Image.Texture color3D = Get3DRenderTarget(samplesInX, samplesInY); for (int index = 0; index < Constants.TotalRenderTargets; index++)
if (color3D == null)
{ {
for (int index = 0; index < Constants.TotalRenderTargets; index++) var colorState = _context.State.Get<RtColorState>(MethodOffset.RtColorState, index);
if (!IsRtEnabled(colorState))
{ {
var colorState = _context.State.Get<RtColorState>(MethodOffset.RtColorState, index); _textureManager.SetRenderTargetColor(index, null);
if (!IsRtEnabled(colorState)) continue;
{
_textureManager.SetRenderTargetColor(index, null);
continue;
}
Image.Texture color = _textureManager.FindOrCreateTexture(
colorState,
samplesInX,
samplesInY);
_textureManager.SetRenderTargetColor(index, color);
if (color != null)
{
color.Modified = true;
}
} }
}
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<Boolean32>(MethodOffset.RtDepthStencilEnable); 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) private static bool IsRtEnabled(RtColorState colorState)
{ {
// Colors are disabled by writing 0 to the format. // Colors are disabled by writing 0 to the format.

View file

@ -6,6 +6,7 @@ using Ryujinx.Graphics.Texture;
using Ryujinx.Graphics.Texture.Astc; using Ryujinx.Graphics.Texture.Astc;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
namespace Ryujinx.Graphics.Gpu.Image namespace Ryujinx.Graphics.Gpu.Image
{ {
@ -116,6 +117,8 @@ namespace Ryujinx.Graphics.Gpu.Image
_views.Remove(texture); _views.Remove(texture);
texture._viewStorage = null; texture._viewStorage = null;
DeleteIfNotUsed();
} }
public void ChangeSize(int width, int height, int depthOrLayers) public void ChangeSize(int width, int height, int depthOrLayers)
@ -187,7 +190,7 @@ namespace Ryujinx.Graphics.Gpu.Image
{ {
ITexture newStorage = _context.Renderer.CreateTexture(createInfo); ITexture newStorage = _context.Renderer.CreateTexture(createInfo);
HostTexture.CopyTo(newStorage); HostTexture.CopyTo(newStorage, 0, 0);
ReplaceStorage(newStorage); ReplaceStorage(newStorage);
} }
@ -413,7 +416,21 @@ namespace Ryujinx.Graphics.Gpu.Image
_info.SamplesInY == info.SamplesInY; _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. // Out of range.
if (info.Address < Address || info.Address + size > EndAddress) if (info.Address < Address || info.Address + size > EndAddress)
@ -441,12 +458,12 @@ namespace Ryujinx.Graphics.Gpu.Image
return false; return false;
} }
if (!ViewSizeMatches(info, firstLevel)) if (!ViewSizeMatches(info, firstLevel, isCopy))
{ {
return false; return false;
} }
if (!ViewTargetCompatible(info)) if (!ViewTargetCompatible(info, isCopy))
{ {
return false; return false;
} }
@ -496,18 +513,24 @@ namespace Ryujinx.Graphics.Gpu.Image
return TextureCompatibility.FormatCompatible(_info.FormatInfo, info.FormatInfo); 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 size = GetAlignedSize(_info, level);
Size otherSize = GetAlignedSize(info); Size otherSize = GetAlignedSize(info);
return size.Width == otherSize.Width && // For copies, we can copy a subset of the 3D texture slices,
size.Height == otherSize.Height && // so the depth may be different in this case.
size.Depth == otherSize.Depth; 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) switch (_info.Target)
{ {
@ -534,7 +557,8 @@ namespace Ryujinx.Graphics.Gpu.Image
info.Target == Target.Texture2DMultisampleArray; info.Target == Target.Texture2DMultisampleArray;
case Target.Texture3D: case Target.Texture3D:
return info.Target == Target.Texture3D; return info.Target == Target.Texture3D ||
(info.Target == Target.Texture2D && isCopy);
} }
return false; return false;
@ -686,7 +710,9 @@ namespace Ryujinx.Graphics.Gpu.Image
public void DecrementReferenceCount() public void DecrementReferenceCount()
{ {
if (--_referenceCount == 0) int newRefCount = --_referenceCount;
if (newRefCount == 0)
{ {
if (_viewStorage != this) if (_viewStorage != this)
{ {
@ -694,7 +720,21 @@ namespace Ryujinx.Graphics.Gpu.Image
} }
_context.Methods.TextureManager.RemoveTextureFromCache(this); _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(); DisposeTextures();
} }
} }

View file

@ -17,13 +17,10 @@ namespace Ryujinx.Graphics.Gpu.Image
private TextureBindingsManager _gpBindingsManager; private TextureBindingsManager _gpBindingsManager;
private Texture[] _rtColors; private Texture[] _rtColors;
private Texture _rtColor3D; private Texture _rtDepthStencil;
private Texture _rtDepthStencil;
private ITexture[] _rtHostColors; private ITexture[] _rtHostColors;
private ITexture _rtHostDs;
private ITexture _rtHostDs;
private RangeList<Texture> _textures; private RangeList<Texture> _textures;
@ -98,13 +95,6 @@ namespace Ryujinx.Graphics.Gpu.Image
public void SetRenderTargetColor(int index, Texture color) public void SetRenderTargetColor(int index, Texture color)
{ {
_rtColors[index] = color; _rtColors[index] = color;
_rtColor3D = null;
}
public void SetRenderTargetColor3D(Texture color)
{
_rtColor3D = color;
} }
public void SetRenderTargetDepthStencil(Texture depthStencil) public void SetRenderTargetDepthStencil(Texture depthStencil)
@ -141,38 +131,21 @@ namespace Ryujinx.Graphics.Gpu.Image
anyChanged = true; 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) if (_rtHostColors[index] != hostTexture)
{
_rtHostColors[index] = hostTexture;
anyChanged = true;
}
}
if (anyChanged)
{ {
_context.Renderer.Pipeline.SetRenderTargets(_rtHostColors, _rtHostDs); _rtHostColors[index] = hostTexture;
}
}
else
{
if (_rtHostColors[0] != _rtColor3D.HostTexture)
{
_rtHostColors[0] = _rtColor3D.HostTexture;
anyChanged = true; anyChanged = true;
} }
}
if (anyChanged) if (anyChanged)
{ {
_context.Renderer.Pipeline.SetRenderTargets(_rtColor3D.HostTexture, _rtHostDs); _context.Renderer.Pipeline.SetRenderTargets(_rtHostColors, _rtHostDs);
}
} }
} }
@ -447,11 +420,29 @@ namespace Ryujinx.Graphics.Gpu.Image
ITexture newView = texture.HostTexture.CreateView(createInfo, firstLayer, firstLevel); ITexture newView = texture.HostTexture.CreateView(createInfo, firstLayer, firstLevel);
overlap.HostTexture.CopyTo(newView); overlap.HostTexture.CopyTo(newView, 0, 0);
overlap.ReplaceView(texture, overlapInfo, newView); 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 // Sampler textures are managed by the texture pool, all other textures

View file

@ -29,16 +29,6 @@ namespace Ryujinx.Graphics.OpenGL
0); 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) public void AttachDepthStencil(TextureView depthStencil)
{ {
// Detach the last depth/stencil buffer if there is any. // Detach the last depth/stencil buffer if there is any.

View file

@ -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) public void SetRenderTargets(ITexture[] colors, ITexture depthStencil)
{ {
EnsureFramebuffer(); EnsureFramebuffer();

View file

@ -137,11 +137,11 @@ namespace Ryujinx.Graphics.OpenGL
return _parent.GetHashCode(); return _parent.GetHashCode();
} }
public void CopyTo(ITexture destination) public void CopyTo(ITexture destination, int firstLayer, int firstLevel)
{ {
TextureView destinationView = (TextureView)destination; TextureView destinationView = (TextureView)destination;
TextureCopyUnscaled.Copy(this, destinationView, 0, 0); TextureCopyUnscaled.Copy(this, destinationView, firstLayer, firstLevel);
int width = Math.Min(Width, destinationView.Width); int width = Math.Min(Width, destinationView.Width);
int height = Math.Min(Height, destinationView.Height); int height = Math.Min(Height, destinationView.Height);

View file

@ -22,8 +22,11 @@ namespace Ryujinx.Graphics.Texture
int gobBlocksInZ, int gobBlocksInZ,
int gobBlocksInTileX) int gobBlocksInTileX)
{ {
bool is3D = depth > 1;
int layerSize = 0; int layerSize = 0;
int[] allOffsets = new int[levels * layers * depth];
int[] mipOffsets = new int[levels]; int[] mipOffsets = new int[levels];
int mipGobBlocksInY = gobBlocksInY; int mipGobBlocksInY = gobBlocksInY;
@ -55,6 +58,25 @@ namespace Ryujinx.Graphics.Texture
int robSize = widthInGobs * mipGobBlocksInY * mipGobBlocksInZ * GobSize; 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; mipOffsets[level] = layerSize;
layerSize += totalBlocksOfGobsInZ * totalBlocksOfGobsInY * robSize; layerSize += totalBlocksOfGobsInZ * totalBlocksOfGobsInY * robSize;
@ -68,16 +90,17 @@ namespace Ryujinx.Graphics.Texture
gobBlocksInY, gobBlocksInY,
gobBlocksInZ); gobBlocksInZ);
int[] allOffsets = new int[levels * layers]; if (!is3D)
for (int layer = 0; layer < layers; layer++)
{ {
int baseIndex = layer * levels; for (int layer = 0; layer < layers; layer++)
int baseOffset = layer * layerSize;
for (int level = 0; level < levels; level++)
{ {
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];
}
} }
} }