mirror of
https://github.com/Ryujinx/Ryujinx.git
synced 2024-12-28 22:23:23 +01:00
Workaround for AMD and Intel view format bug (#1050)
* Workaround for Intel view format bug * Dispose of the intermmediate texture aswell * Apply workaround on AMD aswell
This commit is contained in:
parent
5c1757f7c2
commit
b18ef8e3a0
7 changed files with 222 additions and 119 deletions
|
@ -34,7 +34,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case DebugType.DebugTypeError:
|
case DebugType.DebugTypeError:
|
||||||
Logger.PrintDebug(LogClass.Gpu, fullMessage);
|
Logger.PrintError(LogClass.Gpu, fullMessage);
|
||||||
break;
|
break;
|
||||||
case DebugType.DebugTypePerformance:
|
case DebugType.DebugTypePerformance:
|
||||||
Logger.PrintWarning(LogClass.Gpu, fullMessage);
|
Logger.PrintWarning(LogClass.Gpu, fullMessage);
|
||||||
|
|
|
@ -10,9 +10,13 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
|
|
||||||
private FramebufferAttachment _lastDsAttachment;
|
private FramebufferAttachment _lastDsAttachment;
|
||||||
|
|
||||||
|
private readonly TextureView[] _colors;
|
||||||
|
|
||||||
public Framebuffer()
|
public Framebuffer()
|
||||||
{
|
{
|
||||||
Handle = GL.GenFramebuffer();
|
Handle = GL.GenFramebuffer();
|
||||||
|
|
||||||
|
_colors = new TextureView[8];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Bind()
|
public void Bind()
|
||||||
|
@ -22,11 +26,19 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
|
|
||||||
public void AttachColor(int index, TextureView color)
|
public void AttachColor(int index, TextureView color)
|
||||||
{
|
{
|
||||||
GL.FramebufferTexture(
|
FramebufferAttachment attachment = FramebufferAttachment.ColorAttachment0 + index;
|
||||||
FramebufferTarget.Framebuffer,
|
|
||||||
FramebufferAttachment.ColorAttachment0 + index,
|
if (HwCapabilities.Vendor == HwCapabilities.GpuVendor.Amd ||
|
||||||
color?.Handle ?? 0,
|
HwCapabilities.Vendor == HwCapabilities.GpuVendor.Intel)
|
||||||
0);
|
{
|
||||||
|
GL.FramebufferTexture(FramebufferTarget.Framebuffer, attachment, color?.GetIncompatibleFormatViewHandle() ?? 0, 0);
|
||||||
|
|
||||||
|
_colors[index] = color;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GL.FramebufferTexture(FramebufferTarget.Framebuffer, attachment, color?.Handle ?? 0, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AttachDepthStencil(TextureView depthStencil)
|
public void AttachDepthStencil(TextureView depthStencil)
|
||||||
|
@ -68,6 +80,21 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SignalModified()
|
||||||
|
{
|
||||||
|
if (HwCapabilities.Vendor == HwCapabilities.GpuVendor.Amd ||
|
||||||
|
HwCapabilities.Vendor == HwCapabilities.GpuVendor.Intel)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
if (_colors[i] != null)
|
||||||
|
{
|
||||||
|
_colors[i].SignalModified();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void SetDrawBuffers(int colorsCount)
|
public void SetDrawBuffers(int colorsCount)
|
||||||
{
|
{
|
||||||
DrawBuffersEnum[] drawBuffers = new DrawBuffersEnum[colorsCount];
|
DrawBuffersEnum[] drawBuffers = new DrawBuffersEnum[colorsCount];
|
||||||
|
|
|
@ -5,15 +5,25 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
{
|
{
|
||||||
static class HwCapabilities
|
static class HwCapabilities
|
||||||
{
|
{
|
||||||
private static Lazy<bool> _supportsAstcCompression = new Lazy<bool>(() => HasExtension("GL_KHR_texture_compression_astc_ldr"));
|
private static readonly Lazy<bool> _supportsAstcCompression = new Lazy<bool>(() => HasExtension("GL_KHR_texture_compression_astc_ldr"));
|
||||||
|
|
||||||
private static Lazy<int> _maximumComputeSharedMemorySize = new Lazy<int>(() => GetLimit(All.MaxComputeSharedMemorySize));
|
private static readonly Lazy<int> _maximumComputeSharedMemorySize = new Lazy<int>(() => GetLimit(All.MaxComputeSharedMemorySize));
|
||||||
private static Lazy<int> _storageBufferOffsetAlignment = new Lazy<int>(() => GetLimit(All.ShaderStorageBufferOffsetAlignment));
|
private static readonly Lazy<int> _storageBufferOffsetAlignment = new Lazy<int>(() => GetLimit(All.ShaderStorageBufferOffsetAlignment));
|
||||||
|
|
||||||
private static Lazy<bool> _isNvidiaDriver = new Lazy<bool>(() => IsNvidiaDriver());
|
public enum GpuVendor
|
||||||
|
{
|
||||||
|
Unknown,
|
||||||
|
Amd,
|
||||||
|
Intel,
|
||||||
|
Nvidia
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly Lazy<GpuVendor> _gpuVendor = new Lazy<GpuVendor>(GetGpuVendor);
|
||||||
|
|
||||||
|
public static GpuVendor Vendor => _gpuVendor.Value;
|
||||||
|
|
||||||
public static bool SupportsAstcCompression => _supportsAstcCompression.Value;
|
public static bool SupportsAstcCompression => _supportsAstcCompression.Value;
|
||||||
public static bool SupportsNonConstantTextureOffset => _isNvidiaDriver.Value;
|
public static bool SupportsNonConstantTextureOffset => _gpuVendor.Value == GpuVendor.Nvidia;
|
||||||
|
|
||||||
public static int MaximumComputeSharedMemorySize => _maximumComputeSharedMemorySize.Value;
|
public static int MaximumComputeSharedMemorySize => _maximumComputeSharedMemorySize.Value;
|
||||||
public static int StorageBufferOffsetAlignment => _storageBufferOffsetAlignment.Value;
|
public static int StorageBufferOffsetAlignment => _storageBufferOffsetAlignment.Value;
|
||||||
|
@ -38,9 +48,26 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
return GL.GetInteger((GetPName)name);
|
return GL.GetInteger((GetPName)name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsNvidiaDriver()
|
private static GpuVendor GetGpuVendor()
|
||||||
{
|
{
|
||||||
return GL.GetString(StringName.Vendor).Equals("NVIDIA Corporation");
|
string vendor = GL.GetString(StringName.Vendor).ToLower();
|
||||||
|
|
||||||
|
if (vendor == "nvidia corporation")
|
||||||
|
{
|
||||||
|
return GpuVendor.Nvidia;
|
||||||
|
}
|
||||||
|
else if (vendor == "intel")
|
||||||
|
{
|
||||||
|
return GpuVendor.Intel;
|
||||||
|
}
|
||||||
|
else if (vendor == "ati technologies inc." || vendor == "advanced micro devices, inc.")
|
||||||
|
{
|
||||||
|
return GpuVendor.Amd;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return GpuVendor.Unknown;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -19,14 +19,14 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
|
|
||||||
private PrimitiveType _primitiveType;
|
private PrimitiveType _primitiveType;
|
||||||
|
|
||||||
private int _stencilFrontMask;
|
private int _stencilFrontMask;
|
||||||
private bool _depthMask;
|
private bool _depthMask;
|
||||||
private bool _depthTest;
|
private bool _depthTest;
|
||||||
private bool _hasDepthBuffer;
|
private bool _hasDepthBuffer;
|
||||||
|
|
||||||
private TextureView _unit0Texture;
|
private TextureView _unit0Texture;
|
||||||
|
|
||||||
private ClipOrigin _clipOrigin;
|
private ClipOrigin _clipOrigin;
|
||||||
private ClipDepthMode _clipDepthMode;
|
private ClipDepthMode _clipDepthMode;
|
||||||
|
|
||||||
private uint[] _componentMasks;
|
private uint[] _componentMasks;
|
||||||
|
@ -35,7 +35,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
|
|
||||||
internal Pipeline()
|
internal Pipeline()
|
||||||
{
|
{
|
||||||
_clipOrigin = ClipOrigin.LowerLeft;
|
_clipOrigin = ClipOrigin.LowerLeft;
|
||||||
_clipDepthMode = ClipDepthMode.NegativeOneToOne;
|
_clipDepthMode = ClipDepthMode.NegativeOneToOne;
|
||||||
|
|
||||||
_scissorEnable = new bool[8];
|
_scissorEnable = new bool[8];
|
||||||
|
@ -60,6 +60,8 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
GL.ClearBuffer(ClearBuffer.Color, index, colors);
|
GL.ClearBuffer(ClearBuffer.Color, index, colors);
|
||||||
|
|
||||||
RestoreComponentMask(index);
|
RestoreComponentMask(index);
|
||||||
|
|
||||||
|
_framebuffer.SignalModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClearRenderTargetDepthStencil(float depthValue, bool depthMask, int stencilValue, int stencilMask)
|
public void ClearRenderTargetDepthStencil(float depthValue, bool depthMask, int stencilValue, int stencilMask)
|
||||||
|
@ -102,6 +104,8 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
{
|
{
|
||||||
GL.DepthMask(_depthMask);
|
GL.DepthMask(_depthMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_framebuffer.SignalModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DispatchCompute(int groupsX, int groupsY, int groupsZ)
|
public void DispatchCompute(int groupsX, int groupsY, int groupsZ)
|
||||||
|
@ -141,6 +145,8 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
{
|
{
|
||||||
DrawImpl(vertexCount, instanceCount, firstVertex, firstInstance);
|
DrawImpl(vertexCount, instanceCount, firstVertex, firstInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_framebuffer.SignalModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawQuadsImpl(
|
private void DrawQuadsImpl(
|
||||||
|
@ -251,7 +257,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
switch (_elementsType)
|
switch (_elementsType)
|
||||||
{
|
{
|
||||||
case DrawElementsType.UnsignedShort: indexElemSize = 2; break;
|
case DrawElementsType.UnsignedShort: indexElemSize = 2; break;
|
||||||
case DrawElementsType.UnsignedInt: indexElemSize = 4; break;
|
case DrawElementsType.UnsignedInt: indexElemSize = 4; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
IntPtr indexBaseOffset = _indexBaseOffset + firstIndex * indexElemSize;
|
IntPtr indexBaseOffset = _indexBaseOffset + firstIndex * indexElemSize;
|
||||||
|
@ -285,15 +291,17 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
firstVertex,
|
firstVertex,
|
||||||
firstInstance);
|
firstInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_framebuffer.SignalModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawQuadsIndexedImpl(
|
private void DrawQuadsIndexedImpl(
|
||||||
int indexCount,
|
int indexCount,
|
||||||
int instanceCount,
|
int instanceCount,
|
||||||
IntPtr indexBaseOffset,
|
IntPtr indexBaseOffset,
|
||||||
int indexElemSize,
|
int indexElemSize,
|
||||||
int firstVertex,
|
int firstVertex,
|
||||||
int firstInstance)
|
int firstInstance)
|
||||||
{
|
{
|
||||||
int quadsCount = indexCount / 4;
|
int quadsCount = indexCount / 4;
|
||||||
|
|
||||||
|
@ -367,12 +375,12 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawQuadStripIndexedImpl(
|
private void DrawQuadStripIndexedImpl(
|
||||||
int indexCount,
|
int indexCount,
|
||||||
int instanceCount,
|
int instanceCount,
|
||||||
IntPtr indexBaseOffset,
|
IntPtr indexBaseOffset,
|
||||||
int indexElemSize,
|
int indexElemSize,
|
||||||
int firstVertex,
|
int firstVertex,
|
||||||
int firstInstance)
|
int firstInstance)
|
||||||
{
|
{
|
||||||
// TODO: Instanced rendering.
|
// TODO: Instanced rendering.
|
||||||
int quadsCount = (indexCount - 2) / 2;
|
int quadsCount = (indexCount - 2) / 2;
|
||||||
|
@ -408,11 +416,11 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawIndexedImpl(
|
private void DrawIndexedImpl(
|
||||||
int indexCount,
|
int indexCount,
|
||||||
int instanceCount,
|
int instanceCount,
|
||||||
IntPtr indexBaseOffset,
|
IntPtr indexBaseOffset,
|
||||||
int firstVertex,
|
int firstVertex,
|
||||||
int firstInstance)
|
int firstInstance)
|
||||||
{
|
{
|
||||||
if (firstInstance == 0 && firstVertex == 0 && instanceCount == 1)
|
if (firstInstance == 0 && firstVertex == 0 && instanceCount == 1)
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,22 +7,30 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
{
|
{
|
||||||
static class TextureCopyUnscaled
|
static class TextureCopyUnscaled
|
||||||
{
|
{
|
||||||
public static void Copy(TextureView src, TextureView dst, int dstLayer, int dstLevel)
|
public static void Copy(
|
||||||
|
TextureCreateInfo srcInfo,
|
||||||
|
TextureCreateInfo dstInfo,
|
||||||
|
int srcHandle,
|
||||||
|
int dstHandle,
|
||||||
|
int srcLayer,
|
||||||
|
int dstLayer,
|
||||||
|
int srcLevel,
|
||||||
|
int dstLevel)
|
||||||
{
|
{
|
||||||
int srcWidth = src.Width;
|
int srcWidth = srcInfo.Width;
|
||||||
int srcHeight = src.Height;
|
int srcHeight = srcInfo.Height;
|
||||||
int srcDepth = src.DepthOrLayers;
|
int srcDepth = srcInfo.GetDepthOrLayers();
|
||||||
int srcLevels = src.Levels;
|
int srcLevels = srcInfo.Levels;
|
||||||
|
|
||||||
int dstWidth = dst.Width;
|
int dstWidth = dstInfo.Width;
|
||||||
int dstHeight = dst.Height;
|
int dstHeight = dstInfo.Height;
|
||||||
int dstDepth = dst.DepthOrLayers;
|
int dstDepth = dstInfo.GetDepthOrLayers();
|
||||||
int dstLevels = dst.Levels;
|
int dstLevels = dstInfo.Levels;
|
||||||
|
|
||||||
dstWidth = Math.Max(1, dstWidth >> dstLevel);
|
dstWidth = Math.Max(1, dstWidth >> dstLevel);
|
||||||
dstHeight = Math.Max(1, dstHeight >> dstLevel);
|
dstHeight = Math.Max(1, dstHeight >> dstLevel);
|
||||||
|
|
||||||
if (dst.Target == Target.Texture3D)
|
if (dstInfo.Target == Target.Texture3D)
|
||||||
{
|
{
|
||||||
dstDepth = Math.Max(1, dstDepth >> dstLevel);
|
dstDepth = Math.Max(1, dstDepth >> dstLevel);
|
||||||
}
|
}
|
||||||
|
@ -31,15 +39,15 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
// the non-compressed texture will have the size of the texture
|
// the non-compressed texture will have the size of the texture
|
||||||
// in blocks (not in texels), so we must adjust that size to
|
// in blocks (not in texels), so we must adjust that size to
|
||||||
// match the size in texels of the compressed texture.
|
// match the size in texels of the compressed texture.
|
||||||
if (!src.IsCompressed && dst.IsCompressed)
|
if (!srcInfo.IsCompressed && dstInfo.IsCompressed)
|
||||||
{
|
{
|
||||||
dstWidth = BitUtils.DivRoundUp(dstWidth, dst.BlockWidth);
|
dstWidth = BitUtils.DivRoundUp(dstWidth, dstInfo.BlockWidth);
|
||||||
dstHeight = BitUtils.DivRoundUp(dstHeight, dst.BlockHeight);
|
dstHeight = BitUtils.DivRoundUp(dstHeight, dstInfo.BlockHeight);
|
||||||
}
|
}
|
||||||
else if (src.IsCompressed && !dst.IsCompressed)
|
else if (srcInfo.IsCompressed && !dstInfo.IsCompressed)
|
||||||
{
|
{
|
||||||
dstWidth *= dst.BlockWidth;
|
dstWidth *= dstInfo.BlockWidth;
|
||||||
dstHeight *= dst.BlockHeight;
|
dstHeight *= dstInfo.BlockHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
int width = Math.Min(srcWidth, dstWidth);
|
int width = Math.Min(srcWidth, dstWidth);
|
||||||
|
@ -50,20 +58,20 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
for (int level = 0; level < levels; level++)
|
for (int level = 0; level < levels; level++)
|
||||||
{
|
{
|
||||||
// Stop copy if we are already out of the levels range.
|
// Stop copy if we are already out of the levels range.
|
||||||
if (level >= src.Levels || dstLevel + level >= dst.Levels)
|
if (level >= srcInfo.Levels || dstLevel + level >= dstInfo.Levels)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
GL.CopyImageSubData(
|
GL.CopyImageSubData(
|
||||||
src.Handle,
|
srcHandle,
|
||||||
src.Target.ConvertToImageTarget(),
|
srcInfo.Target.ConvertToImageTarget(),
|
||||||
level,
|
srcLevel + level,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
srcLayer,
|
||||||
dst.Handle,
|
dstHandle,
|
||||||
dst.Target.ConvertToImageTarget(),
|
dstInfo.Target.ConvertToImageTarget(),
|
||||||
dstLevel + level,
|
dstLevel + level,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
|
@ -72,10 +80,10 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
height,
|
height,
|
||||||
depth);
|
depth);
|
||||||
|
|
||||||
width = Math.Max(1, width >> 1);
|
width = Math.Max(1, width >> 1);
|
||||||
height = Math.Max(1, height >> 1);
|
height = Math.Max(1, height >> 1);
|
||||||
|
|
||||||
if (src.Target == Target.Texture3D)
|
if (srcInfo.Target == Target.Texture3D)
|
||||||
{
|
{
|
||||||
depth = Math.Max(1, depth >> 1);
|
depth = Math.Max(1, depth >> 1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,18 +8,16 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
{
|
{
|
||||||
public int Handle { get; private set; }
|
public int Handle { get; private set; }
|
||||||
|
|
||||||
|
public TextureCreateInfo Info { get; }
|
||||||
|
|
||||||
private readonly Renderer _renderer;
|
private readonly Renderer _renderer;
|
||||||
|
|
||||||
private readonly TextureCreateInfo _info;
|
|
||||||
|
|
||||||
public Target Target => _info.Target;
|
|
||||||
|
|
||||||
private int _viewsCount;
|
private int _viewsCount;
|
||||||
|
|
||||||
public TextureStorage(Renderer renderer, TextureCreateInfo info)
|
public TextureStorage(Renderer renderer, TextureCreateInfo info)
|
||||||
{
|
{
|
||||||
_renderer = renderer;
|
_renderer = renderer;
|
||||||
_info = info;
|
Info = info;
|
||||||
|
|
||||||
Handle = GL.GenTexture();
|
Handle = GL.GenTexture();
|
||||||
|
|
||||||
|
@ -28,13 +26,13 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
|
|
||||||
private void CreateImmutableStorage()
|
private void CreateImmutableStorage()
|
||||||
{
|
{
|
||||||
TextureTarget target = _info.Target.Convert();
|
TextureTarget target = Info.Target.Convert();
|
||||||
|
|
||||||
GL.ActiveTexture(TextureUnit.Texture0);
|
GL.ActiveTexture(TextureUnit.Texture0);
|
||||||
|
|
||||||
GL.BindTexture(target, Handle);
|
GL.BindTexture(target, Handle);
|
||||||
|
|
||||||
FormatInfo format = FormatTable.GetFormatInfo(_info.Format);
|
FormatInfo format = FormatTable.GetFormatInfo(Info.Format);
|
||||||
|
|
||||||
SizedInternalFormat internalFormat;
|
SizedInternalFormat internalFormat;
|
||||||
|
|
||||||
|
@ -47,92 +45,92 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
internalFormat = (SizedInternalFormat)format.PixelInternalFormat;
|
internalFormat = (SizedInternalFormat)format.PixelInternalFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (_info.Target)
|
switch (Info.Target)
|
||||||
{
|
{
|
||||||
case Target.Texture1D:
|
case Target.Texture1D:
|
||||||
GL.TexStorage1D(
|
GL.TexStorage1D(
|
||||||
TextureTarget1d.Texture1D,
|
TextureTarget1d.Texture1D,
|
||||||
_info.Levels,
|
Info.Levels,
|
||||||
internalFormat,
|
internalFormat,
|
||||||
_info.Width);
|
Info.Width);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Target.Texture1DArray:
|
case Target.Texture1DArray:
|
||||||
GL.TexStorage2D(
|
GL.TexStorage2D(
|
||||||
TextureTarget2d.Texture1DArray,
|
TextureTarget2d.Texture1DArray,
|
||||||
_info.Levels,
|
Info.Levels,
|
||||||
internalFormat,
|
internalFormat,
|
||||||
_info.Width,
|
Info.Width,
|
||||||
_info.Height);
|
Info.Height);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Target.Texture2D:
|
case Target.Texture2D:
|
||||||
GL.TexStorage2D(
|
GL.TexStorage2D(
|
||||||
TextureTarget2d.Texture2D,
|
TextureTarget2d.Texture2D,
|
||||||
_info.Levels,
|
Info.Levels,
|
||||||
internalFormat,
|
internalFormat,
|
||||||
_info.Width,
|
Info.Width,
|
||||||
_info.Height);
|
Info.Height);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Target.Texture2DArray:
|
case Target.Texture2DArray:
|
||||||
GL.TexStorage3D(
|
GL.TexStorage3D(
|
||||||
TextureTarget3d.Texture2DArray,
|
TextureTarget3d.Texture2DArray,
|
||||||
_info.Levels,
|
Info.Levels,
|
||||||
internalFormat,
|
internalFormat,
|
||||||
_info.Width,
|
Info.Width,
|
||||||
_info.Height,
|
Info.Height,
|
||||||
_info.Depth);
|
Info.Depth);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Target.Texture2DMultisample:
|
case Target.Texture2DMultisample:
|
||||||
GL.TexStorage2DMultisample(
|
GL.TexStorage2DMultisample(
|
||||||
TextureTargetMultisample2d.Texture2DMultisample,
|
TextureTargetMultisample2d.Texture2DMultisample,
|
||||||
_info.Samples,
|
Info.Samples,
|
||||||
internalFormat,
|
internalFormat,
|
||||||
_info.Width,
|
Info.Width,
|
||||||
_info.Height,
|
Info.Height,
|
||||||
true);
|
true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Target.Texture2DMultisampleArray:
|
case Target.Texture2DMultisampleArray:
|
||||||
GL.TexStorage3DMultisample(
|
GL.TexStorage3DMultisample(
|
||||||
TextureTargetMultisample3d.Texture2DMultisampleArray,
|
TextureTargetMultisample3d.Texture2DMultisampleArray,
|
||||||
_info.Samples,
|
Info.Samples,
|
||||||
internalFormat,
|
internalFormat,
|
||||||
_info.Width,
|
Info.Width,
|
||||||
_info.Height,
|
Info.Height,
|
||||||
_info.Depth,
|
Info.Depth,
|
||||||
true);
|
true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Target.Texture3D:
|
case Target.Texture3D:
|
||||||
GL.TexStorage3D(
|
GL.TexStorage3D(
|
||||||
TextureTarget3d.Texture3D,
|
TextureTarget3d.Texture3D,
|
||||||
_info.Levels,
|
Info.Levels,
|
||||||
internalFormat,
|
internalFormat,
|
||||||
_info.Width,
|
Info.Width,
|
||||||
_info.Height,
|
Info.Height,
|
||||||
_info.Depth);
|
Info.Depth);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Target.Cubemap:
|
case Target.Cubemap:
|
||||||
GL.TexStorage2D(
|
GL.TexStorage2D(
|
||||||
TextureTarget2d.TextureCubeMap,
|
TextureTarget2d.TextureCubeMap,
|
||||||
_info.Levels,
|
Info.Levels,
|
||||||
internalFormat,
|
internalFormat,
|
||||||
_info.Width,
|
Info.Width,
|
||||||
_info.Height);
|
Info.Height);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Target.CubemapArray:
|
case Target.CubemapArray:
|
||||||
GL.TexStorage3D(
|
GL.TexStorage3D(
|
||||||
(TextureTarget3d)All.TextureCubeMapArray,
|
(TextureTarget3d)All.TextureCubeMapArray,
|
||||||
_info.Levels,
|
Info.Levels,
|
||||||
internalFormat,
|
internalFormat,
|
||||||
_info.Width,
|
Info.Width,
|
||||||
_info.Height,
|
Info.Height,
|
||||||
_info.Depth);
|
Info.Depth);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -143,7 +141,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
|
|
||||||
public ITexture CreateDefaultView()
|
public ITexture CreateDefaultView()
|
||||||
{
|
{
|
||||||
return CreateView(_info, 0, 0);
|
return CreateView(Info, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ITexture CreateView(TextureCreateInfo info, int firstLayer, int firstLevel)
|
public ITexture CreateView(TextureCreateInfo info, int firstLayer, int firstLevel)
|
||||||
|
|
|
@ -14,24 +14,19 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
|
|
||||||
private TextureView _emulatedViewParent;
|
private TextureView _emulatedViewParent;
|
||||||
|
|
||||||
|
private TextureView _incompatibleFormatView;
|
||||||
|
|
||||||
private readonly TextureCreateInfo _info;
|
private readonly TextureCreateInfo _info;
|
||||||
|
|
||||||
private int _firstLayer;
|
public int FirstLayer { get; private set; }
|
||||||
private int _firstLevel;
|
public int FirstLevel { get; private set; }
|
||||||
|
|
||||||
public int Width => _info.Width;
|
public int Width => _info.Width;
|
||||||
public int Height => _info.Height;
|
public int Height => _info.Height;
|
||||||
public int DepthOrLayers => _info.GetDepthOrLayers();
|
|
||||||
public int Levels => _info.Levels;
|
|
||||||
|
|
||||||
public Target Target => _info.Target;
|
public Target Target => _info.Target;
|
||||||
public Format Format => _info.Format;
|
public Format Format => _info.Format;
|
||||||
|
|
||||||
public int BlockWidth => _info.BlockWidth;
|
|
||||||
public int BlockHeight => _info.BlockHeight;
|
|
||||||
|
|
||||||
public bool IsCompressed => _info.IsCompressed;
|
|
||||||
|
|
||||||
public TextureView(
|
public TextureView(
|
||||||
Renderer renderer,
|
Renderer renderer,
|
||||||
TextureStorage parent,
|
TextureStorage parent,
|
||||||
|
@ -43,8 +38,8 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
_parent = parent;
|
_parent = parent;
|
||||||
_info = info;
|
_info = info;
|
||||||
|
|
||||||
_firstLayer = firstLayer;
|
FirstLayer = firstLayer;
|
||||||
_firstLevel = firstLevel;
|
FirstLevel = firstLevel;
|
||||||
|
|
||||||
Handle = GL.GenTexture();
|
Handle = GL.GenTexture();
|
||||||
|
|
||||||
|
@ -73,9 +68,9 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
target,
|
target,
|
||||||
_parent.Handle,
|
_parent.Handle,
|
||||||
pixelInternalFormat,
|
pixelInternalFormat,
|
||||||
_firstLevel,
|
FirstLevel,
|
||||||
_info.Levels,
|
_info.Levels,
|
||||||
_firstLayer,
|
FirstLayer,
|
||||||
_info.GetLayers());
|
_info.GetLayers());
|
||||||
|
|
||||||
GL.ActiveTexture(TextureUnit.Texture0);
|
GL.ActiveTexture(TextureUnit.Texture0);
|
||||||
|
@ -107,8 +102,8 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
{
|
{
|
||||||
if (_info.IsCompressed == info.IsCompressed)
|
if (_info.IsCompressed == info.IsCompressed)
|
||||||
{
|
{
|
||||||
firstLayer += _firstLayer;
|
firstLayer += FirstLayer;
|
||||||
firstLevel += _firstLevel;
|
firstLevel += FirstLevel;
|
||||||
|
|
||||||
return _parent.CreateView(info, firstLayer, firstLevel);
|
return _parent.CreateView(info, firstLayer, firstLevel);
|
||||||
}
|
}
|
||||||
|
@ -123,26 +118,59 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
|
|
||||||
emulatedView._emulatedViewParent = this;
|
emulatedView._emulatedViewParent = this;
|
||||||
|
|
||||||
emulatedView._firstLayer = firstLayer;
|
emulatedView.FirstLayer = firstLayer;
|
||||||
emulatedView._firstLevel = firstLevel;
|
emulatedView.FirstLevel = firstLevel;
|
||||||
|
|
||||||
return emulatedView;
|
return emulatedView;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int GetIncompatibleFormatViewHandle()
|
||||||
|
{
|
||||||
|
// AMD and Intel has a bug where the view format is always ignored,
|
||||||
|
// it uses the parent format instead.
|
||||||
|
// As workaround we create a new texture with the correct
|
||||||
|
// format, and then do a copy after the draw.
|
||||||
|
if (_parent.Info.Format != Format)
|
||||||
|
{
|
||||||
|
if (_incompatibleFormatView == null)
|
||||||
|
{
|
||||||
|
_incompatibleFormatView = (TextureView)_renderer.CreateTexture(_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureCopyUnscaled.Copy(_parent.Info, _incompatibleFormatView._info, _parent.Handle, _incompatibleFormatView.Handle, FirstLayer, 0, FirstLevel, 0);
|
||||||
|
|
||||||
|
return _incompatibleFormatView.Handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SignalModified()
|
||||||
|
{
|
||||||
|
if (_incompatibleFormatView != null)
|
||||||
|
{
|
||||||
|
TextureCopyUnscaled.Copy(_incompatibleFormatView._info, _parent.Info, _incompatibleFormatView.Handle, _parent.Handle, 0, FirstLayer, 0, FirstLevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void CopyTo(ITexture destination, int firstLayer, int firstLevel)
|
public void CopyTo(ITexture destination, int firstLayer, int firstLevel)
|
||||||
{
|
{
|
||||||
TextureView destinationView = (TextureView)destination;
|
TextureView destinationView = (TextureView)destination;
|
||||||
|
|
||||||
TextureCopyUnscaled.Copy(this, destinationView, firstLayer, firstLevel);
|
TextureCopyUnscaled.Copy(_info, destinationView._info, Handle, destinationView.Handle, 0, firstLayer, 0, firstLevel);
|
||||||
|
|
||||||
if (destinationView._emulatedViewParent != null)
|
if (destinationView._emulatedViewParent != null)
|
||||||
{
|
{
|
||||||
TextureCopyUnscaled.Copy(
|
TextureCopyUnscaled.Copy(
|
||||||
this,
|
_info,
|
||||||
destinationView._emulatedViewParent,
|
destinationView._emulatedViewParent._info,
|
||||||
destinationView._firstLayer,
|
Handle,
|
||||||
destinationView._firstLevel);
|
destinationView._emulatedViewParent.Handle,
|
||||||
|
0,
|
||||||
|
destinationView.FirstLayer,
|
||||||
|
0,
|
||||||
|
destinationView.FirstLevel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -405,6 +433,13 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
if (_incompatibleFormatView != null)
|
||||||
|
{
|
||||||
|
_incompatibleFormatView.Dispose();
|
||||||
|
|
||||||
|
_incompatibleFormatView = null;
|
||||||
|
}
|
||||||
|
|
||||||
if (Handle != 0)
|
if (Handle != 0)
|
||||||
{
|
{
|
||||||
GL.DeleteTexture(Handle);
|
GL.DeleteTexture(Handle);
|
||||||
|
|
Loading…
Reference in a new issue