aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2020-03-29 09:48:39 -0300
committerGitHub <noreply@github.com>2020-03-29 23:48:39 +1100
commitb18ef8e3a00980595f45c7fe184dcb160dcc3cb9 (patch)
tree9d9b3fea4d7822d548878988c12c18e23a72bb52
parent5c1757f7c29fc06577b5fc551dd3d76b12b281d3 (diff)
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
-rw-r--r--Ryujinx.Graphics.OpenGL/Debugger.cs2
-rw-r--r--Ryujinx.Graphics.OpenGL/Framebuffer.cs37
-rw-r--r--Ryujinx.Graphics.OpenGL/HwCapabilities.cs41
-rw-r--r--Ryujinx.Graphics.OpenGL/Pipeline.cs44
-rw-r--r--Ryujinx.Graphics.OpenGL/TextureCopyUnscaled.cs58
-rw-r--r--Ryujinx.Graphics.OpenGL/TextureStorage.cs76
-rw-r--r--Ryujinx.Graphics.OpenGL/TextureView.cs83
7 files changed, 222 insertions, 119 deletions
diff --git a/Ryujinx.Graphics.OpenGL/Debugger.cs b/Ryujinx.Graphics.OpenGL/Debugger.cs
index f34a5048..ff9fcd85 100644
--- a/Ryujinx.Graphics.OpenGL/Debugger.cs
+++ b/Ryujinx.Graphics.OpenGL/Debugger.cs
@@ -34,7 +34,7 @@ namespace Ryujinx.Graphics.OpenGL
switch (type)
{
case DebugType.DebugTypeError:
- Logger.PrintDebug(LogClass.Gpu, fullMessage);
+ Logger.PrintError(LogClass.Gpu, fullMessage);
break;
case DebugType.DebugTypePerformance:
Logger.PrintWarning(LogClass.Gpu, fullMessage);
diff --git a/Ryujinx.Graphics.OpenGL/Framebuffer.cs b/Ryujinx.Graphics.OpenGL/Framebuffer.cs
index d416bd03..23f015b1 100644
--- a/Ryujinx.Graphics.OpenGL/Framebuffer.cs
+++ b/Ryujinx.Graphics.OpenGL/Framebuffer.cs
@@ -10,9 +10,13 @@ namespace Ryujinx.Graphics.OpenGL
private FramebufferAttachment _lastDsAttachment;
+ private readonly TextureView[] _colors;
+
public Framebuffer()
{
Handle = GL.GenFramebuffer();
+
+ _colors = new TextureView[8];
}
public void Bind()
@@ -22,11 +26,19 @@ namespace Ryujinx.Graphics.OpenGL
public void AttachColor(int index, TextureView color)
{
- GL.FramebufferTexture(
- FramebufferTarget.Framebuffer,
- FramebufferAttachment.ColorAttachment0 + index,
- color?.Handle ?? 0,
- 0);
+ FramebufferAttachment attachment = FramebufferAttachment.ColorAttachment0 + index;
+
+ if (HwCapabilities.Vendor == HwCapabilities.GpuVendor.Amd ||
+ HwCapabilities.Vendor == HwCapabilities.GpuVendor.Intel)
+ {
+ 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)
@@ -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)
{
DrawBuffersEnum[] drawBuffers = new DrawBuffersEnum[colorsCount];
diff --git a/Ryujinx.Graphics.OpenGL/HwCapabilities.cs b/Ryujinx.Graphics.OpenGL/HwCapabilities.cs
index f97bd2ea..3d72cb7d 100644
--- a/Ryujinx.Graphics.OpenGL/HwCapabilities.cs
+++ b/Ryujinx.Graphics.OpenGL/HwCapabilities.cs
@@ -5,15 +5,25 @@ namespace Ryujinx.Graphics.OpenGL
{
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 Lazy<int> _storageBufferOffsetAlignment = new Lazy<int>(() => GetLimit(All.ShaderStorageBufferOffsetAlignment));
+ private static readonly Lazy<int> _maximumComputeSharedMemorySize = new Lazy<int>(() => GetLimit(All.MaxComputeSharedMemorySize));
+ 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 SupportsNonConstantTextureOffset => _isNvidiaDriver.Value;
+ public static bool SupportsNonConstantTextureOffset => _gpuVendor.Value == GpuVendor.Nvidia;
public static int MaximumComputeSharedMemorySize => _maximumComputeSharedMemorySize.Value;
public static int StorageBufferOffsetAlignment => _storageBufferOffsetAlignment.Value;
@@ -38,9 +48,26 @@ namespace Ryujinx.Graphics.OpenGL
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;
+ }
}
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics.OpenGL/Pipeline.cs b/Ryujinx.Graphics.OpenGL/Pipeline.cs
index f01e7c7a..3480cf82 100644
--- a/Ryujinx.Graphics.OpenGL/Pipeline.cs
+++ b/Ryujinx.Graphics.OpenGL/Pipeline.cs
@@ -19,14 +19,14 @@ namespace Ryujinx.Graphics.OpenGL
private PrimitiveType _primitiveType;
- private int _stencilFrontMask;
+ private int _stencilFrontMask;
private bool _depthMask;
private bool _depthTest;
private bool _hasDepthBuffer;
private TextureView _unit0Texture;
- private ClipOrigin _clipOrigin;
+ private ClipOrigin _clipOrigin;
private ClipDepthMode _clipDepthMode;
private uint[] _componentMasks;
@@ -35,7 +35,7 @@ namespace Ryujinx.Graphics.OpenGL
internal Pipeline()
{
- _clipOrigin = ClipOrigin.LowerLeft;
+ _clipOrigin = ClipOrigin.LowerLeft;
_clipDepthMode = ClipDepthMode.NegativeOneToOne;
_scissorEnable = new bool[8];
@@ -60,6 +60,8 @@ namespace Ryujinx.Graphics.OpenGL
GL.ClearBuffer(ClearBuffer.Color, index, colors);
RestoreComponentMask(index);
+
+ _framebuffer.SignalModified();
}
public void ClearRenderTargetDepthStencil(float depthValue, bool depthMask, int stencilValue, int stencilMask)
@@ -102,6 +104,8 @@ namespace Ryujinx.Graphics.OpenGL
{
GL.DepthMask(_depthMask);
}
+
+ _framebuffer.SignalModified();
}
public void DispatchCompute(int groupsX, int groupsY, int groupsZ)
@@ -141,6 +145,8 @@ namespace Ryujinx.Graphics.OpenGL
{
DrawImpl(vertexCount, instanceCount, firstVertex, firstInstance);
}
+
+ _framebuffer.SignalModified();
}
private void DrawQuadsImpl(
@@ -251,7 +257,7 @@ namespace Ryujinx.Graphics.OpenGL
switch (_elementsType)
{
case DrawElementsType.UnsignedShort: indexElemSize = 2; break;
- case DrawElementsType.UnsignedInt: indexElemSize = 4; break;
+ case DrawElementsType.UnsignedInt: indexElemSize = 4; break;
}
IntPtr indexBaseOffset = _indexBaseOffset + firstIndex * indexElemSize;
@@ -285,15 +291,17 @@ namespace Ryujinx.Graphics.OpenGL
firstVertex,
firstInstance);
}
+
+ _framebuffer.SignalModified();
}
private void DrawQuadsIndexedImpl(
- int indexCount,
- int instanceCount,
+ int indexCount,
+ int instanceCount,
IntPtr indexBaseOffset,
- int indexElemSize,
- int firstVertex,
- int firstInstance)
+ int indexElemSize,
+ int firstVertex,
+ int firstInstance)
{
int quadsCount = indexCount / 4;
@@ -367,12 +375,12 @@ namespace Ryujinx.Graphics.OpenGL
}
private void DrawQuadStripIndexedImpl(
- int indexCount,
- int instanceCount,
+ int indexCount,
+ int instanceCount,
IntPtr indexBaseOffset,
- int indexElemSize,
- int firstVertex,
- int firstInstance)
+ int indexElemSize,
+ int firstVertex,
+ int firstInstance)
{
// TODO: Instanced rendering.
int quadsCount = (indexCount - 2) / 2;
@@ -408,11 +416,11 @@ namespace Ryujinx.Graphics.OpenGL
}
private void DrawIndexedImpl(
- int indexCount,
- int instanceCount,
+ int indexCount,
+ int instanceCount,
IntPtr indexBaseOffset,
- int firstVertex,
- int firstInstance)
+ int firstVertex,
+ int firstInstance)
{
if (firstInstance == 0 && firstVertex == 0 && instanceCount == 1)
{
diff --git a/Ryujinx.Graphics.OpenGL/TextureCopyUnscaled.cs b/Ryujinx.Graphics.OpenGL/TextureCopyUnscaled.cs
index cf13db8a..5ae75d9c 100644
--- a/Ryujinx.Graphics.OpenGL/TextureCopyUnscaled.cs
+++ b/Ryujinx.Graphics.OpenGL/TextureCopyUnscaled.cs
@@ -7,22 +7,30 @@ namespace Ryujinx.Graphics.OpenGL
{
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 srcHeight = src.Height;
- int srcDepth = src.DepthOrLayers;
- int srcLevels = src.Levels;
+ int srcWidth = srcInfo.Width;
+ int srcHeight = srcInfo.Height;
+ int srcDepth = srcInfo.GetDepthOrLayers();
+ int srcLevels = srcInfo.Levels;
- int dstWidth = dst.Width;
- int dstHeight = dst.Height;
- int dstDepth = dst.DepthOrLayers;
- int dstLevels = dst.Levels;
+ int dstWidth = dstInfo.Width;
+ int dstHeight = dstInfo.Height;
+ int dstDepth = dstInfo.GetDepthOrLayers();
+ int dstLevels = dstInfo.Levels;
dstWidth = Math.Max(1, dstWidth >> dstLevel);
dstHeight = Math.Max(1, dstHeight >> dstLevel);
- if (dst.Target == Target.Texture3D)
+ if (dstInfo.Target == Target.Texture3D)
{
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
// in blocks (not in texels), so we must adjust that size to
// 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);
- dstHeight = BitUtils.DivRoundUp(dstHeight, dst.BlockHeight);
+ dstWidth = BitUtils.DivRoundUp(dstWidth, dstInfo.BlockWidth);
+ dstHeight = BitUtils.DivRoundUp(dstHeight, dstInfo.BlockHeight);
}
- else if (src.IsCompressed && !dst.IsCompressed)
+ else if (srcInfo.IsCompressed && !dstInfo.IsCompressed)
{
- dstWidth *= dst.BlockWidth;
- dstHeight *= dst.BlockHeight;
+ dstWidth *= dstInfo.BlockWidth;
+ dstHeight *= dstInfo.BlockHeight;
}
int width = Math.Min(srcWidth, dstWidth);
@@ -50,20 +58,20 @@ namespace Ryujinx.Graphics.OpenGL
for (int level = 0; level < levels; level++)
{
// 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;
}
GL.CopyImageSubData(
- src.Handle,
- src.Target.ConvertToImageTarget(),
- level,
+ srcHandle,
+ srcInfo.Target.ConvertToImageTarget(),
+ srcLevel + level,
0,
0,
- 0,
- dst.Handle,
- dst.Target.ConvertToImageTarget(),
+ srcLayer,
+ dstHandle,
+ dstInfo.Target.ConvertToImageTarget(),
dstLevel + level,
0,
0,
@@ -72,10 +80,10 @@ namespace Ryujinx.Graphics.OpenGL
height,
depth);
- width = Math.Max(1, width >> 1);
+ width = Math.Max(1, width >> 1);
height = Math.Max(1, height >> 1);
- if (src.Target == Target.Texture3D)
+ if (srcInfo.Target == Target.Texture3D)
{
depth = Math.Max(1, depth >> 1);
}
diff --git a/Ryujinx.Graphics.OpenGL/TextureStorage.cs b/Ryujinx.Graphics.OpenGL/TextureStorage.cs
index 241b4116..b680f3a6 100644
--- a/Ryujinx.Graphics.OpenGL/TextureStorage.cs
+++ b/Ryujinx.Graphics.OpenGL/TextureStorage.cs
@@ -8,18 +8,16 @@ namespace Ryujinx.Graphics.OpenGL
{
public int Handle { get; private set; }
- private readonly Renderer _renderer;
-
- private readonly TextureCreateInfo _info;
+ public TextureCreateInfo Info { get; }
- public Target Target => _info.Target;
+ private readonly Renderer _renderer;
private int _viewsCount;
public TextureStorage(Renderer renderer, TextureCreateInfo info)
{
_renderer = renderer;
- _info = info;
+ Info = info;
Handle = GL.GenTexture();
@@ -28,13 +26,13 @@ namespace Ryujinx.Graphics.OpenGL
private void CreateImmutableStorage()
{
- TextureTarget target = _info.Target.Convert();
+ TextureTarget target = Info.Target.Convert();
GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(target, Handle);
- FormatInfo format = FormatTable.GetFormatInfo(_info.Format);
+ FormatInfo format = FormatTable.GetFormatInfo(Info.Format);
SizedInternalFormat internalFormat;
@@ -47,92 +45,92 @@ namespace Ryujinx.Graphics.OpenGL
internalFormat = (SizedInternalFormat)format.PixelInternalFormat;
}
- switch (_info.Target)
+ switch (Info.Target)
{
case Target.Texture1D:
GL.TexStorage1D(
TextureTarget1d.Texture1D,
- _info.Levels,
+ Info.Levels,
internalFormat,
- _info.Width);
+ Info.Width);
break;
case Target.Texture1DArray:
GL.TexStorage2D(
TextureTarget2d.Texture1DArray,
- _info.Levels,
+ Info.Levels,
internalFormat,
- _info.Width,
- _info.Height);
+ Info.Width,
+ Info.Height);
break;
case Target.Texture2D:
GL.TexStorage2D(
TextureTarget2d.Texture2D,
- _info.Levels,
+ Info.Levels,
internalFormat,
- _info.Width,
- _info.Height);
+ Info.Width,
+ Info.Height);
break;
case Target.Texture2DArray:
GL.TexStorage3D(
TextureTarget3d.Texture2DArray,
- _info.Levels,
+ Info.Levels,
internalFormat,
- _info.Width,
- _info.Height,
- _info.Depth);
+ Info.Width,
+ Info.Height,
+ Info.Depth);
break;
case Target.Texture2DMultisample:
GL.TexStorage2DMultisample(
TextureTargetMultisample2d.Texture2DMultisample,
- _info.Samples,
+ Info.Samples,
internalFormat,
- _info.Width,
- _info.Height,
+ Info.Width,
+ Info.Height,
true);
break;
case Target.Texture2DMultisampleArray:
GL.TexStorage3DMultisample(
TextureTargetMultisample3d.Texture2DMultisampleArray,
- _info.Samples,
+ Info.Samples,
internalFormat,
- _info.Width,
- _info.Height,
- _info.Depth,
+ Info.Width,
+ Info.Height,
+ Info.Depth,
true);
break;
case Target.Texture3D:
GL.TexStorage3D(
TextureTarget3d.Texture3D,
- _info.Levels,
+ Info.Levels,
internalFormat,
- _info.Width,
- _info.Height,
- _info.Depth);
+ Info.Width,
+ Info.Height,
+ Info.Depth);
break;
case Target.Cubemap:
GL.TexStorage2D(
TextureTarget2d.TextureCubeMap,
- _info.Levels,
+ Info.Levels,
internalFormat,
- _info.Width,
- _info.Height);
+ Info.Width,
+ Info.Height);
break;
case Target.CubemapArray:
GL.TexStorage3D(
(TextureTarget3d)All.TextureCubeMapArray,
- _info.Levels,
+ Info.Levels,
internalFormat,
- _info.Width,
- _info.Height,
- _info.Depth);
+ Info.Width,
+ Info.Height,
+ Info.Depth);
break;
default:
@@ -143,7 +141,7 @@ namespace Ryujinx.Graphics.OpenGL
public ITexture CreateDefaultView()
{
- return CreateView(_info, 0, 0);
+ return CreateView(Info, 0, 0);
}
public ITexture CreateView(TextureCreateInfo info, int firstLayer, int firstLevel)
diff --git a/Ryujinx.Graphics.OpenGL/TextureView.cs b/Ryujinx.Graphics.OpenGL/TextureView.cs
index 8fa78e5b..cb872880 100644
--- a/Ryujinx.Graphics.OpenGL/TextureView.cs
+++ b/Ryujinx.Graphics.OpenGL/TextureView.cs
@@ -14,24 +14,19 @@ namespace Ryujinx.Graphics.OpenGL
private TextureView _emulatedViewParent;
+ private TextureView _incompatibleFormatView;
+
private readonly TextureCreateInfo _info;
- private int _firstLayer;
- private int _firstLevel;
+ public int FirstLayer { get; private set; }
+ public int FirstLevel { get; private set; }
- public int Width => _info.Width;
- public int Height => _info.Height;
- public int DepthOrLayers => _info.GetDepthOrLayers();
- public int Levels => _info.Levels;
+ public int Width => _info.Width;
+ public int Height => _info.Height;
public Target Target => _info.Target;
public Format Format => _info.Format;
- public int BlockWidth => _info.BlockWidth;
- public int BlockHeight => _info.BlockHeight;
-
- public bool IsCompressed => _info.IsCompressed;
-
public TextureView(
Renderer renderer,
TextureStorage parent,
@@ -43,8 +38,8 @@ namespace Ryujinx.Graphics.OpenGL
_parent = parent;
_info = info;
- _firstLayer = firstLayer;
- _firstLevel = firstLevel;
+ FirstLayer = firstLayer;
+ FirstLevel = firstLevel;
Handle = GL.GenTexture();
@@ -73,9 +68,9 @@ namespace Ryujinx.Graphics.OpenGL
target,
_parent.Handle,
pixelInternalFormat,
- _firstLevel,
+ FirstLevel,
_info.Levels,
- _firstLayer,
+ FirstLayer,
_info.GetLayers());
GL.ActiveTexture(TextureUnit.Texture0);
@@ -107,8 +102,8 @@ namespace Ryujinx.Graphics.OpenGL
{
if (_info.IsCompressed == info.IsCompressed)
{
- firstLayer += _firstLayer;
- firstLevel += _firstLevel;
+ firstLayer += FirstLayer;
+ firstLevel += FirstLevel;
return _parent.CreateView(info, firstLayer, firstLevel);
}
@@ -123,26 +118,59 @@ namespace Ryujinx.Graphics.OpenGL
emulatedView._emulatedViewParent = this;
- emulatedView._firstLayer = firstLayer;
- emulatedView._firstLevel = firstLevel;
+ emulatedView.FirstLayer = firstLayer;
+ emulatedView.FirstLevel = firstLevel;
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)
{
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)
{
TextureCopyUnscaled.Copy(
- this,
- destinationView._emulatedViewParent,
- destinationView._firstLayer,
- destinationView._firstLevel);
+ _info,
+ destinationView._emulatedViewParent._info,
+ Handle,
+ destinationView._emulatedViewParent.Handle,
+ 0,
+ destinationView.FirstLayer,
+ 0,
+ destinationView.FirstLevel);
}
}
@@ -405,6 +433,13 @@ namespace Ryujinx.Graphics.OpenGL
public void Dispose()
{
+ if (_incompatibleFormatView != null)
+ {
+ _incompatibleFormatView.Dispose();
+
+ _incompatibleFormatView = null;
+ }
+
if (Handle != 0)
{
GL.DeleteTexture(Handle);