From 54f97a49289c40503442df37424e2f544615cd69 Mon Sep 17 00:00:00 2001 From: Flamefire Date: Sat, 4 Oct 2014 10:44:48 +0200 Subject: [PATCH] Fix artifacts on NPOT textures in OGL Fix reuse check of textures Introduce Size field for textures (replacing W2, H2) --- Vocaluxe/Lib/Draw/CDirect3D.cs | 4 +-- Vocaluxe/Lib/Draw/COpenGL.cs | 31 ++++++++++++++++++++++-- Vocaluxe/Lib/Draw/CTextureBase.cs | 35 +++++++-------------------- Vocaluxe/Lib/Draw/CTextureProvider.cs | 28 ++++++++++++--------- 4 files changed, 56 insertions(+), 42 deletions(-) diff --git a/Vocaluxe/Lib/Draw/CDirect3D.cs b/Vocaluxe/Lib/Draw/CDirect3D.cs index 9e7a6193..919fdef7 100644 --- a/Vocaluxe/Lib/Draw/CDirect3D.cs +++ b/Vocaluxe/Lib/Draw/CDirect3D.cs @@ -46,11 +46,11 @@ namespace Vocaluxe.Lib.Draw { public readonly Texture D3DTexture; - public CD3DTexture(Device device, Size dataSize, int texWidth = 0, int texHeight = 0) : base(dataSize, texWidth, texHeight) + public CD3DTexture(Device device, Size dataSize, int texWidth = 0, int texHeight = 0) : base(dataSize, new Size(texWidth, texHeight)) { //Create a new texture in the managed pool, which does not need to be recreated on a lost device //because a copy of the texture is hold in the Ram - D3DTexture = device == null ? null : new Texture(device, W2, H2, 0, Usage.AutoGenerateMipMap, Format.A8R8G8B8, Pool.Managed); + D3DTexture = device == null ? null : new Texture(device, texWidth, texHeight, 0, Usage.AutoGenerateMipMap, Format.A8R8G8B8, Pool.Managed); } public override bool IsLoaded diff --git a/Vocaluxe/Lib/Draw/COpenGL.cs b/Vocaluxe/Lib/Draw/COpenGL.cs index cefca707..c00535d7 100644 --- a/Vocaluxe/Lib/Draw/COpenGL.cs +++ b/Vocaluxe/Lib/Draw/COpenGL.cs @@ -15,6 +15,7 @@ // along with Vocaluxe. If not, see . #endregion +using System.Diagnostics; using System.Drawing.Imaging; using OpenTK; using OpenTK.Graphics; @@ -61,14 +62,14 @@ namespace Vocaluxe.Lib.Draw //The texture "name" according to the specs public readonly int Name; - public COGLTexture(int name, Size dataSize, int texWidth = 0, int texHeight = 0) : base(dataSize, texWidth, texHeight) + public COGLTexture(int name, Size dataSize, int texWidth = 0, int texHeight = 0) : base(dataSize, new Size(texWidth, texHeight)) { Name = name; if (name == 0) return; GL.BindTexture(TextureTarget.Texture2D, Name); - GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, W2, H2, 0, PixelFormat.Bgra, PixelType.UnsignedByte, IntPtr.Zero); + GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, texWidth, texHeight, 0, PixelFormat.Bgra, PixelType.UnsignedByte, IntPtr.Zero); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge); @@ -94,6 +95,7 @@ namespace Vocaluxe.Lib.Draw class COpenGL : CDrawBaseWindows, IDraw { private readonly GLControl _Control; + private int _FBO; public COpenGL() { @@ -233,9 +235,17 @@ namespace Vocaluxe.Lib.Draw GL.Enable(EnableCap.DepthTest); GL.ClearColor(Color.Black); + GL.GenFramebuffers(1, out _FBO); + return true; } + public override void Unload() + { + base.Unload(); + GL.DeleteFramebuffers(1, ref _FBO); + } + protected override void _OnBeforeDraw() { //Nothing to do @@ -400,8 +410,23 @@ namespace Vocaluxe.Lib.Draw return texture; } + private void _ClearTexture(COGLTexture texture) + { + if (texture.DataSize.Equals(texture.Size)) + return; + GL.BindFramebuffer(OpenTK.Graphics.OpenGL.FramebufferTarget.Framebuffer, _FBO); + GL.FramebufferTexture2D(OpenTK.Graphics.OpenGL.FramebufferTarget.Framebuffer, OpenTK.Graphics.OpenGL.FramebufferAttachment.ColorAttachment0, TextureTarget.Texture2D, + texture.Name, 0); + GL.ClearColor(Color.FromArgb(0)); + GL.Clear(ClearBufferMask.ColorBufferBit); + GL.ClearColor(Color.Black); + GL.BindFramebuffer(OpenTK.Graphics.OpenGL.FramebufferTarget.Framebuffer, 0); + } + protected override void _WriteDataToTexture(COGLTexture texture, byte[] data) { + Debug.Assert(texture.Name > 0); + _ClearTexture(texture); GL.BindTexture(TextureTarget.Texture2D, texture.Name); GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, texture.DataSize.Width, texture.DataSize.Height, PixelFormat.Bgra, PixelType.UnsignedByte, data); @@ -412,6 +437,8 @@ namespace Vocaluxe.Lib.Draw protected override void _WriteDataToTexture(COGLTexture texture, IntPtr data) { + Debug.Assert(texture.Name > 0); + _ClearTexture(texture); GL.BindTexture(TextureTarget.Texture2D, texture.Name); GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, texture.DataSize.Width, texture.DataSize.Height, PixelFormat.Bgra, PixelType.UnsignedByte, data); diff --git a/Vocaluxe/Lib/Draw/CTextureBase.cs b/Vocaluxe/Lib/Draw/CTextureBase.cs index ab4850b3..385c1227 100644 --- a/Vocaluxe/Lib/Draw/CTextureBase.cs +++ b/Vocaluxe/Lib/Draw/CTextureBase.cs @@ -23,13 +23,9 @@ namespace Vocaluxe.Lib.Draw } /// - /// texture width (on device), a power of 2 if necessary + /// texture Size (on device), a power of 2 if necessary /// - public int W2 { get; protected set; } - /// - /// texture height (on device), a power of 2 if necessary - /// - public int H2 { get; protected set; } + public Size Size { get; private set; } /// /// Specifies which part of texture memory is actually used @@ -49,38 +45,25 @@ namespace Vocaluxe.Lib.Draw /// Creates a new texture /// /// Size of the data used - /// Width in video memory - /// Height in video memory - protected CTextureBase(Size dataSize, int texWidth = 0, int texHeight = 0) + /// Size in video memory + protected CTextureBase(Size dataSize, Size textureSize) { _DataSize = dataSize; - W2 = (texWidth > 0) ? texWidth : dataSize.Width; - H2 = (texHeight > 0) ? texHeight : dataSize.Height; + Size = textureSize; _CalcRatios(); } private void _CalcRatios() { - if (_DataSize.Width == W2) + if (_DataSize.Width == Size.Width) WidthRatio = 1f; else - { - // OpenGL has a problem with partial (NPOT) textures, so we remove 1 pixel - int mod = 0; - if (_DataSize.Width > 1) - mod = -1; - WidthRatio = (float)(_DataSize.Width + mod) / W2; - } - if (_DataSize.Height == H2) + WidthRatio = (float)_DataSize.Width / Size.Width; + if (_DataSize.Height == Size.Height) HeightRatio = 1f; else - { - int mod = 0; - if (_DataSize.Height > 1) - mod = -1; - HeightRatio = (float)(_DataSize.Height + mod) / H2; - } + HeightRatio = (float)_DataSize.Height / Size.Height; } private bool _IsDisposed; diff --git a/Vocaluxe/Lib/Draw/CTextureProvider.cs b/Vocaluxe/Lib/Draw/CTextureProvider.cs index 8a2f31a0..0c863979 100644 --- a/Vocaluxe/Lib/Draw/CTextureProvider.cs +++ b/Vocaluxe/Lib/Draw/CTextureProvider.cs @@ -388,15 +388,15 @@ namespace Vocaluxe.Lib.Draw return _GetTextureReference(new Size(origWidth, origHeight), texture); } - private static bool _IsTextureUsable(TTextureType texture, int dataWidth, int dataHeight) + private static bool _IsTextureUsable(TTextureType texture, Size dataSize) { if (texture == null) return false; - if (texture.DataSize.Width != dataWidth || texture.DataSize.Height != dataHeight) + if (!texture.DataSize.Equals(dataSize)) { - if (texture.W2 > dataWidth || texture.H2 > dataHeight) + if (texture.Size.Width < dataSize.Width || texture.Size.Height < dataSize.Height) return false; // Texture memory to small - if (texture.W2 * 0.9 < dataWidth || texture.H2 * 0.9 < dataHeight) + if (texture.Size.Width * 0.9 > dataSize.Width || texture.Size.Height * 0.9 > dataSize.Height) return false; // Texture memory to big } return true; @@ -491,7 +491,7 @@ namespace Vocaluxe.Lib.Draw bmp.Dispose(); } else if (q.Data is byte[]) - UpdateTexture(textureRef, q.DataSize.Width, q.DataSize.Height, (byte[])q.Data); + UpdateTexture(textureRef, q.DataSize, (byte[])q.Data); else throw new ArgumentException("q.Data is of invalid type"); // ReSharper restore CanBeReplacedWithTryCastAndCheckForNull @@ -776,30 +776,34 @@ namespace Vocaluxe.Lib.Draw _EnqueueTextureAddOrUpdate(textureRef, bmp, EQueueAction.Update, true); } + public void UpdateTexture(CTextureRef textureRef, int w, int h, byte[] data) + { + UpdateTexture(textureRef, new Size(w, h), data); + } + /// /// Updates the data of a texture /// /// The texture to update - /// - /// + /// /// A byte array containing the new texture's data /// True if succeeded - public void UpdateTexture(CTextureRef textureRef, int w, int h, byte[] data) + public void UpdateTexture(CTextureRef textureRef, Size dataSize, byte[] data) { _EnsureMainThread(); TTextureType texture; if (!_GetTexture(textureRef, out texture, false)) return; - bool reuseTexture = _IsTextureUsable(texture, w, h); + bool reuseTexture = _IsTextureUsable(texture, dataSize); if (reuseTexture && texture.RefCount == 1) { - texture.DataSize = new Size(w, h); + texture.DataSize = dataSize; _WriteDataToTexture(texture, data); } else { _DisposeTexture(texture); - texture = _CreateAndFillTexture(new Size(w, h), data); + texture = _CreateAndFillTexture(dataSize, data); texture.RefCount = 1; _Textures[textureRef.ID] = texture; } @@ -811,7 +815,7 @@ namespace Vocaluxe.Lib.Draw TTextureType texture; if (!_GetTexture(textureRef, out texture, false)) return; - bool reuseTexture = _IsTextureUsable(texture, bmp.Width, bmp.Height); + bool reuseTexture = _IsTextureUsable(texture, bmp.Size); if (reuseTexture && texture.RefCount == 1) _WriteBitmapToTexture(ref texture, bmp); else