Archived
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

View file

@ -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);

View file

@ -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);

View file

@ -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<RtColorState>(MethodOffset.RtColorState, index);
if (!IsRtEnabled(colorState))
{
var colorState = _context.State.Get<RtColorState>(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<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.

View file

@ -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();
}
}

View file

@ -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)
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

View file

@ -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.

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)
{
EnsureFramebuffer();

View file

@ -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);

View file

@ -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];
}
}
}