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:
parent
3bcc395253
commit
d786d8d2b9
9 changed files with 131 additions and 160 deletions
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Reference in a new issue