From 772d4be8d30f8e8320ca4b4957c5b94573870bcf Mon Sep 17 00:00:00 2001 From: "SND\\AstrorEnales_cp" Date: Sat, 18 Feb 2012 22:43:08 +0000 Subject: [PATCH] - OpenGL render system now keeps track of all it's resources and Disposes and Recreates them if needed - OpenGL Device is now Reset correctly when for example the window size changes (Recreating all resources) - OpenGL render system doesn't crash anymore when closing the application - Introduced TestStateAttribute for development to mark a file as tested/untested --- ANX.Framework/ANX.Framework.csproj | 1 + ANX.Framework/Graphics/GraphicsDevice.cs | 2 +- .../NonXNA/Development/TestStateAttribute.cs | 82 ++++++ .../ANX.Framework.Windows.GL3.csproj | 3 +- .../BlendStateGL3.cs | 44 ++-- .../ANX.Framework.Windows.GL3/Creator.cs | 5 +- .../DepthStencilStateGL3.cs | 16 +- .../ANX.Framework.Windows.GL3/EffectGL3.cs | 56 ++++- .../EffectParameterGL3.cs | 5 +- .../GraphicsDeviceWindowsGL3.cs | 58 +++-- .../{ => Helpers}/DatatypesMapping.cs | 73 +++++- .../Helpers/GraphicsResourceManager.cs | 238 ++++++++++++++++++ .../Helpers/LinuxInterop.cs | 12 + .../IndexBufferGL3.cs | 60 ++++- .../RasterizerStateGL3.cs | 16 +- .../RenderTarget2DGL3.cs | 2 + .../ANX.Framework.Windows.GL3/Texture2DGL3.cs | 146 ++++++++++- .../VertexBufferGL3.cs | 46 +++- 18 files changed, 795 insertions(+), 70 deletions(-) create mode 100644 ANX.Framework/NonXNA/Development/TestStateAttribute.cs rename RenderSystems/ANX.Framework.Windows.GL3/{ => Helpers}/DatatypesMapping.cs (80%) create mode 100644 RenderSystems/ANX.Framework.Windows.GL3/Helpers/GraphicsResourceManager.cs diff --git a/ANX.Framework/ANX.Framework.csproj b/ANX.Framework/ANX.Framework.csproj index 86f2f122..36d05077 100644 --- a/ANX.Framework/ANX.Framework.csproj +++ b/ANX.Framework/ANX.Framework.csproj @@ -416,6 +416,7 @@ + diff --git a/ANX.Framework/Graphics/GraphicsDevice.cs b/ANX.Framework/Graphics/GraphicsDevice.cs index be1ebab2..6b3e719d 100644 --- a/ANX.Framework/Graphics/GraphicsDevice.cs +++ b/ANX.Framework/Graphics/GraphicsDevice.cs @@ -349,7 +349,7 @@ namespace ANX.Framework.Graphics } // reset presentation parameters - nativeDevice.ResizeBuffers(presentationParameters); //TODO: check if necessary + nativeDevice.ResizeBuffers(presentationParameters); raise_DeviceReset(this, EventArgs.Empty); } diff --git a/ANX.Framework/NonXNA/Development/TestStateAttribute.cs b/ANX.Framework/NonXNA/Development/TestStateAttribute.cs new file mode 100644 index 00000000..d5b9013a --- /dev/null +++ b/ANX.Framework/NonXNA/Development/TestStateAttribute.cs @@ -0,0 +1,82 @@ +using System; + +#region License + +// +// This file is part of the ANX.Framework created by the "ANX.Framework developer group". +// +// This file is released under the Ms-PL license. +// +// +// +// Microsoft Public License (Ms-PL) +// +// This license governs use of the accompanying software. If you use the software, you accept this license. +// If you do not accept the license, do not use the software. +// +// 1.Definitions +// The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning +// here as under U.S. copyright law. +// A "contribution" is the original software, or any additions or changes to the software. +// A "contributor" is any person that distributes its contribution under this license. +// "Licensed patents" are a contributor's patent claims that read directly on its contribution. +// +// 2.Grant of Rights +// (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations +// in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to +// reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution +// or any derivative works that you create. +// (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in +// section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed +// patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution +// in the software or derivative works of the contribution in the software. +// +// 3.Conditions and Limitations +// (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. +// (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your +// patent license from such contributor to the software ends automatically. +// (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution +// notices that are present in the software. +// (D) If you distribute any portion of the software in source code form, you may do so only under this license by including +// a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or +// object code form, you may only do so under a license that complies with this license. +// (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees, +// or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the +// extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a +// particular purpose and non-infringement. + +#endregion // License + +namespace ANX.Framework.NonXNA.Development +{ + public class TestStateAttribute : Attribute + { + #region TestState (enum) + public enum TestState + { + Untested, + InProgress, + Tested, + } + #endregion + + #region Public + public TestState State + { + get; + private set; + } + #endregion + + #region Constructor + /// + /// Create a new test state attribute. + /// + /// The state of testing. + public TestStateAttribute(TestState setState) + { + State = setState; + } + #endregion + } +} diff --git a/RenderSystems/ANX.Framework.Windows.GL3/ANX.Framework.Windows.GL3.csproj b/RenderSystems/ANX.Framework.Windows.GL3/ANX.Framework.Windows.GL3.csproj index 40e13506..309942cb 100644 --- a/RenderSystems/ANX.Framework.Windows.GL3/ANX.Framework.Windows.GL3.csproj +++ b/RenderSystems/ANX.Framework.Windows.GL3/ANX.Framework.Windows.GL3.csproj @@ -50,7 +50,7 @@ - + @@ -58,6 +58,7 @@ + diff --git a/RenderSystems/ANX.Framework.Windows.GL3/BlendStateGL3.cs b/RenderSystems/ANX.Framework.Windows.GL3/BlendStateGL3.cs index 504d7881..77353271 100644 --- a/RenderSystems/ANX.Framework.Windows.GL3/BlendStateGL3.cs +++ b/RenderSystems/ANX.Framework.Windows.GL3/BlendStateGL3.cs @@ -1,6 +1,8 @@ using System; using ANX.Framework.Graphics; using ANX.Framework.NonXNA; +using ANX.Framework.NonXNA.Development; +using ANX.Framework.Windows.GL3.Helpers; using OpenTK.Graphics.OpenGL; #region License @@ -60,8 +62,18 @@ namespace ANX.Framework.Windows.GL3 /// /// For Information on OpenGL blending: http://www.opengl.org/wiki/Blending /// + [PercentageComplete(90)] + [TestStateAttribute(TestStateAttribute.TestState.Untested)] public class BlendStateGL3 : INativeBlendState { + #region Private + internal static BlendStateGL3 Current + { + get; + private set; + } + #endregion + #region Public #region IsBound /// @@ -181,7 +193,7 @@ namespace ANX.Framework.Windows.GL3 } #endregion - #region Apply + #region Apply (TODO) /// /// Apply the blend state on the graphics device. /// @@ -189,6 +201,7 @@ namespace ANX.Framework.Windows.GL3 public void Apply(GraphicsDevice graphicsDevice) { IsBound = true; + Current = this; GL.Enable(EnableCap.Blend); @@ -226,6 +239,7 @@ namespace ANX.Framework.Windows.GL3 public void Release() { IsBound = false; + Current = null; } #endregion @@ -236,7 +250,6 @@ namespace ANX.Framework.Windows.GL3 public void Dispose() { } - #endregion #region SetColorWriteChannel @@ -247,10 +260,10 @@ namespace ANX.Framework.Windows.GL3 /// Mask channels to enable. private void SetColorWriteChannel(int index, ColorWriteChannels channels) { - bool r = (channels & Graphics.ColorWriteChannels.Red) == Graphics.ColorWriteChannels.Red; - bool g = (channels & Graphics.ColorWriteChannels.Green) == Graphics.ColorWriteChannels.Green; - bool b = (channels & Graphics.ColorWriteChannels.Blue) == Graphics.ColorWriteChannels.Blue; - bool a = (channels & Graphics.ColorWriteChannels.Alpha) == Graphics.ColorWriteChannels.Alpha; + bool r = (channels | Graphics.ColorWriteChannels.Red) == channels; + bool g = (channels | Graphics.ColorWriteChannels.Green) == channels; + bool b = (channels | Graphics.ColorWriteChannels.Blue) == channels; + bool a = (channels | Graphics.ColorWriteChannels.Alpha) == channels; GL.ColorMask(index, r, g, b, a); ErrorHelper.Check("ColorMask"); @@ -267,10 +280,6 @@ namespace ANX.Framework.Windows.GL3 { switch (blending) { - default: - throw new NotSupportedException("The blend mode '" + blending + - "' is not supported for OpenGL BlendingFactorSrc!"); - case Blend.SourceAlpha: return BlendingFactorSrc.SrcAlpha; @@ -297,6 +306,10 @@ namespace ANX.Framework.Windows.GL3 case Blend.Zero: return BlendingFactorSrc.Zero; + + default: + throw new ArgumentException("Unable to translate SourceBlend '" + + blending + "' to OpenGL BlendingFactorSrc."); } } #endregion @@ -314,10 +327,6 @@ namespace ANX.Framework.Windows.GL3 case Blend.SourceAlpha: return BlendingFactorDest.SrcAlpha; - default: - throw new NotSupportedException("The blend mode '" + blending + - "' is not supported for OpenGL BlendingFactorDest!"); - case Blend.DestinationAlpha: return BlendingFactorDest.DstAlpha; @@ -344,6 +353,10 @@ namespace ANX.Framework.Windows.GL3 case Blend.Zero: return BlendingFactorDest.Zero; + + default: + throw new ArgumentException("Unable to translate DestinationBlend '" + + blending + "' to OpenGL BlendingFactorDest."); } } #endregion @@ -374,7 +387,8 @@ namespace ANX.Framework.Windows.GL3 return BlendEquationMode.Max; } - throw new ArgumentException("don't know how to translate BlendFunction '" + func.ToString() + "' to BlendEquationMode"); + throw new ArgumentException("Unable to translate BlendFunction '" + + func + "' to OpenGL BlendEquationMode."); } #endregion } diff --git a/RenderSystems/ANX.Framework.Windows.GL3/Creator.cs b/RenderSystems/ANX.Framework.Windows.GL3/Creator.cs index d4c07637..5aac67e4 100644 --- a/RenderSystems/ANX.Framework.Windows.GL3/Creator.cs +++ b/RenderSystems/ANX.Framework.Windows.GL3/Creator.cs @@ -4,6 +4,7 @@ using System.Collections.ObjectModel; using System.IO; using ANX.Framework.Graphics; using ANX.Framework.NonXNA; +using ANX.Framework.NonXNA.Development; using ANX.Framework.NonXNA.RenderSystem; using NLog; using OpenTK; @@ -60,6 +61,8 @@ namespace ANX.Framework.Windows.GL3 /// /// OpenGL graphics creator. /// + [PercentageComplete(90)] + [TestState(TestStateAttribute.TestState.Untested)] public class Creator : IRenderSystemCreator { private static Logger logger = LogManager.GetCurrentClassLogger(); @@ -283,7 +286,7 @@ namespace ANX.Framework.Windows.GL3 } #endregion - #region GetAdapterList + #region GetAdapterList (TODO) /// /// Get a list of available graphics adapter information. /// diff --git a/RenderSystems/ANX.Framework.Windows.GL3/DepthStencilStateGL3.cs b/RenderSystems/ANX.Framework.Windows.GL3/DepthStencilStateGL3.cs index eb747069..b32568b8 100644 --- a/RenderSystems/ANX.Framework.Windows.GL3/DepthStencilStateGL3.cs +++ b/RenderSystems/ANX.Framework.Windows.GL3/DepthStencilStateGL3.cs @@ -1,6 +1,6 @@ -using System; +using ANX.Framework.Graphics; using ANX.Framework.NonXNA; -using ANX.Framework.Graphics; +using ANX.Framework.NonXNA.Development; using OpenTK.Graphics.OpenGL; #region License @@ -58,8 +58,18 @@ namespace ANX.Framework.Windows.GL3 /// Basically this is a wrapper class for setting the different values all /// at once, because OpenGL has no State objects like DirectX. /// + [PercentageComplete(100)] + [TestStateAttribute(TestStateAttribute.TestState.Untested)] public class DepthStencilStateGL3 : INativeDepthStencilState { + #region Private + internal static DepthStencilStateGL3 Current + { + get; + private set; + } + #endregion + #region Public #region IsBound /// @@ -219,6 +229,7 @@ namespace ANX.Framework.Windows.GL3 public void Apply(GraphicsDevice graphicsDevice) { IsBound = true; + Current = this; #region Depth if (DepthBufferEnable) @@ -416,6 +427,7 @@ namespace ANX.Framework.Windows.GL3 public void Release() { IsBound = false; + Current = null; } #endregion diff --git a/RenderSystems/ANX.Framework.Windows.GL3/EffectGL3.cs b/RenderSystems/ANX.Framework.Windows.GL3/EffectGL3.cs index fc817a26..7ea300b2 100644 --- a/RenderSystems/ANX.Framework.Windows.GL3/EffectGL3.cs +++ b/RenderSystems/ANX.Framework.Windows.GL3/EffectGL3.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using ANX.Framework.Graphics; using ANX.Framework.NonXNA; +using ANX.Framework.Windows.GL3.Helpers; using OpenTK.Graphics.OpenGL; #region License @@ -84,6 +85,11 @@ namespace ANX.Framework.Windows.GL3 { get { + if (managedEffect.CurrentTechnique == null) + { + return null; + } + return managedEffect.CurrentTechnique.NativeTechnique as EffectTechniqueGL3; } } @@ -92,6 +98,8 @@ namespace ANX.Framework.Windows.GL3 /// The active uniforms of this technique. /// internal List parameters; + + internal bool IsDisposed; #endregion #region Public @@ -102,7 +110,7 @@ namespace ANX.Framework.Windows.GL3 { if (techniques.Count == 0) { - CompileTechniques(); + Compile(); } return techniques; @@ -115,6 +123,11 @@ namespace ANX.Framework.Windows.GL3 { get { + if (techniques.Count == 0) + { + Compile(); + } + return parameters; } } @@ -128,11 +141,18 @@ namespace ANX.Framework.Windows.GL3 /// private EffectGL3(Effect setManagedEffect) { + GraphicsResourceManager.UpdateResource(this, true); + parameters = new List(); techniques = new List(); managedEffect = setManagedEffect; } + ~EffectGL3() + { + GraphicsResourceManager.UpdateResource(this, false); + } + /// /// Create a new effect instance of separate streams. /// @@ -160,8 +180,15 @@ namespace ANX.Framework.Windows.GL3 } #endregion - #region CompileTechniques - private void CompileTechniques() + #region RecreateData + internal void RecreateData() + { + Compile(); + } + #endregion + + #region Compile + private void Compile() { parameters.Clear(); techniques.Clear(); @@ -302,9 +329,24 @@ namespace ANX.Framework.Windows.GL3 /// public void Dispose() { + if (IsDisposed == false) + { + IsDisposed = true; + DisposeResource(); + } + } + + internal void DisposeResource() + { + if (GraphicsDeviceWindowsGL3.IsContextCurrent == false) + { + return; + } + foreach (EffectTechnique technique in techniques) { - int programHandle = (technique.NativeTechnique as EffectTechniqueGL3).programHandle; + int programHandle = + (technique.NativeTechnique as EffectTechniqueGL3).programHandle; GL.DeleteProgram(programHandle); ErrorHelper.Check("DeleteProgram"); @@ -315,12 +357,12 @@ namespace ANX.Framework.Windows.GL3 { string deleteError; GL.GetProgramInfoLog(programHandle, out deleteError); - throw new Exception("Failed to delete the shader program '" + technique.Name + - "' because of: " + deleteError); + throw new Exception("Failed to delete the shader program '" + + technique.Name + "' because of: " + deleteError); } } - techniques.Clear(); + parameters.Clear(); } #endregion } diff --git a/RenderSystems/ANX.Framework.Windows.GL3/EffectParameterGL3.cs b/RenderSystems/ANX.Framework.Windows.GL3/EffectParameterGL3.cs index fa3a166a..3ab54e16 100644 --- a/RenderSystems/ANX.Framework.Windows.GL3/EffectParameterGL3.cs +++ b/RenderSystems/ANX.Framework.Windows.GL3/EffectParameterGL3.cs @@ -1,6 +1,6 @@ using System; -using ANX.Framework.NonXNA; using ANX.Framework.Graphics; +using ANX.Framework.NonXNA; using OpenTK.Graphics.OpenGL; #region License @@ -161,8 +161,9 @@ namespace ANX.Framework.Windows.GL3 GL.UseProgram(parentTechnique.programHandle); ErrorHelper.Check("UseProgram"); if (textureCache == null || - textureCache != value) + textureCache != value) { + textureCache = value; // TODO: multiple texture units TextureUnit textureUnit = TextureUnit.Texture0; GL.ActiveTexture(textureUnit); diff --git a/RenderSystems/ANX.Framework.Windows.GL3/GraphicsDeviceWindowsGL3.cs b/RenderSystems/ANX.Framework.Windows.GL3/GraphicsDeviceWindowsGL3.cs index 36da1d49..d1fede58 100644 --- a/RenderSystems/ANX.Framework.Windows.GL3/GraphicsDeviceWindowsGL3.cs +++ b/RenderSystems/ANX.Framework.Windows.GL3/GraphicsDeviceWindowsGL3.cs @@ -76,12 +76,24 @@ namespace ANX.Framework.Windows.GL3 /// private IWindowInfo nativeWindowInfo; - internal static VertexBufferGL3[] boundVertexBuffers = - new VertexBufferGL3[0]; - private static RenderTarget2DGL3[] boundRenderTargets = - new RenderTarget2DGL3[0]; + internal static VertexBufferGL3[] boundVertexBuffers; + private static RenderTarget2DGL3[] boundRenderTargets; internal static IndexBufferGL3 boundIndexBuffer; internal static EffectGL3 activeEffect; + + internal static GraphicsDeviceWindowsGL3 Current + { + get; + private set; + } + + internal static bool IsContextCurrent + { + get + { + return Current.nativeContext.IsCurrent; + } + } #endregion #region Public @@ -109,6 +121,7 @@ namespace ANX.Framework.Windows.GL3 internal GraphicsDeviceWindowsGL3( PresentationParameters presentationParameters) { + Current = this; ResetDevice(presentationParameters); } #endregion @@ -125,17 +138,16 @@ namespace ANX.Framework.Windows.GL3 #region Validation if (nativeContext != null) { - nativeContext.Dispose(); - nativeContext = null; - } - - if (nativeWindowInfo != null) - { - nativeWindowInfo.Dispose(); - nativeWindowInfo = null; + Dispose(); } #endregion + // Reset the previous set buffers, effects and targets. + boundVertexBuffers = new VertexBufferGL3[0]; + boundRenderTargets = new RenderTarget2DGL3[0]; + boundIndexBuffer = null; + activeEffect = null; + // OpenGL Depth Buffer Size: 0/16/24/32 int depth = 0; int stencil = 0; @@ -183,6 +195,8 @@ namespace ANX.Framework.Windows.GL3 // int.Parse(parts[0]), int.Parse(parts[1]), GraphicsContextFlags.Default); //nativeContext.MakeCurrent(nativeWindowInfo); //nativeContext.LoadAll(); + + GraphicsResourceManager.RecreateAllResources(); } #endregion @@ -223,7 +237,7 @@ namespace ANX.Framework.Windows.GL3 #endregion #region Clear - private uint lastClearColor; + private uint? lastClearColor; /// /// Clear the current screen by the specified clear color. /// @@ -231,7 +245,8 @@ namespace ANX.Framework.Windows.GL3 public void Clear(ref Color color) { uint newClearColor = color.PackedValue; - if (lastClearColor != newClearColor) + if (lastClearColor.HasValue == false || + lastClearColor != newClearColor) { lastClearColor = newClearColor; GL.ClearColor(color.R * ColorMultiplier, color.G * ColorMultiplier, @@ -422,7 +437,9 @@ namespace ANX.Framework.Windows.GL3 } else { - throw new NotImplementedException(); + LinuxInterop.ResizeWindow(presentationParameters.DeviceWindowHandle, + presentationParameters.BackBufferWidth, + presentationParameters.BackBufferHeight); } } #endregion @@ -467,6 +484,7 @@ namespace ANX.Framework.Windows.GL3 public void GetBackBufferData(T[] data) where T : struct { + //glReadPixels(0, 0, nWidth, nHeight, GL_RGB, GL_UNSIGNED_BYTE, m_pPixelData) throw new NotImplementedException(); } @@ -477,18 +495,24 @@ namespace ANX.Framework.Windows.GL3 } #endregion - #region ResizeBuffers (TODO) + #region ResizeBuffers public void ResizeBuffers(PresentationParameters presentationParameters) { ResizeRenderWindow(presentationParameters); - throw new NotImplementedException(); + GL.Viewport(0, 0, presentationParameters.BackBufferWidth, + presentationParameters.BackBufferHeight); + + ResetDevice(presentationParameters); } #endregion #region Dispose public void Dispose() { + GraphicsResourceManager.DisposeAllResources(); + + lastClearColor = new uint?(); boundVertexBuffers = null; boundIndexBuffer = null; activeEffect = null; diff --git a/RenderSystems/ANX.Framework.Windows.GL3/DatatypesMapping.cs b/RenderSystems/ANX.Framework.Windows.GL3/Helpers/DatatypesMapping.cs similarity index 80% rename from RenderSystems/ANX.Framework.Windows.GL3/DatatypesMapping.cs rename to RenderSystems/ANX.Framework.Windows.GL3/Helpers/DatatypesMapping.cs index fcfe2ee8..ece0b4ef 100644 --- a/RenderSystems/ANX.Framework.Windows.GL3/DatatypesMapping.cs +++ b/RenderSystems/ANX.Framework.Windows.GL3/Helpers/DatatypesMapping.cs @@ -50,7 +50,7 @@ using OpenTK.Graphics.OpenGL; #endregion // License -namespace ANX.Framework.Windows.GL3 +namespace ANX.Framework.Windows.GL3.Helpers { internal static class DatatypesMapping { @@ -198,6 +198,7 @@ namespace ANX.Framework.Windows.GL3 case SurfaceFormat.HalfVector2: return PixelInternalFormat.Rg16; + case SurfaceFormat.Rgba64: case SurfaceFormat.HalfVector4: return PixelInternalFormat.Rgba16f; @@ -210,24 +211,19 @@ namespace ANX.Framework.Windows.GL3 case SurfaceFormat.Alpha8: return PixelInternalFormat.Alpha8; + case SurfaceFormat.Vector2: case SurfaceFormat.Rg32: return PixelInternalFormat.Rg32f; case SurfaceFormat.Rgba1010102: return PixelInternalFormat.Rgb10A2; - case SurfaceFormat.Rgba64: - return PixelInternalFormat.Rgba16f; - case SurfaceFormat.HalfSingle: return PixelInternalFormat.R16f; case SurfaceFormat.Single: return PixelInternalFormat.R32f; - case SurfaceFormat.Vector2: - return PixelInternalFormat.Rg32f; - case SurfaceFormat.Vector4: return PixelInternalFormat.Rgba32f; } @@ -268,6 +264,26 @@ namespace ANX.Framework.Windows.GL3 #region Tests private class Tests { + #region TestConvertColorToOtkColor + public static void TestConvertColorToOtkColor() + { + Color anxColor = new Color(1f, 0.5f, 0.75f, 0f); + Color4 color; + DatatypesMapping.Convert(ref anxColor, out color); + Console.WriteLine(color.ToString()); + } + #endregion + + #region TestConvertOtkColorToColor + public static void TestConvertOtkColorToColor() + { + Color4 color = new Color4(1f, 0.5f, 0.75f, 0f); + Color anxColor; + DatatypesMapping.Convert(ref color, out anxColor); + Console.WriteLine(anxColor.ToString()); + } + #endregion + #region TestConvertVector4ToColor public static void TestConvertVector4ToColor() { @@ -277,6 +293,49 @@ namespace ANX.Framework.Windows.GL3 Console.WriteLine(color.ToString()); } #endregion + + #region TestPrimitiveTypeToBeginMode + public static void TestPrimitiveTypeToBeginMode() + { + PrimitiveType type = PrimitiveType.LineList; + int primitiveCount = 10; + int count = 0; + + BeginMode result = DatatypesMapping.PrimitiveTypeToBeginMode(type, + primitiveCount, out count); + AssetValues(result, BeginMode.Lines); + AssetValues(count, primitiveCount * 2); + + type = PrimitiveType.LineStrip; + result = DatatypesMapping.PrimitiveTypeToBeginMode(type, primitiveCount, + out count); + AssetValues(result, BeginMode.LineStrip); + AssetValues(count, primitiveCount + 1); + + type = PrimitiveType.TriangleList; + result = DatatypesMapping.PrimitiveTypeToBeginMode(type, primitiveCount, + out count); + AssetValues(result, BeginMode.Triangles); + AssetValues(count, primitiveCount * 3); + + type = PrimitiveType.TriangleStrip; + result = DatatypesMapping.PrimitiveTypeToBeginMode(type, primitiveCount, + out count); + AssetValues(result, BeginMode.TriangleStrip); + AssetValues(count, primitiveCount + 2); + } + #endregion + + #region AssetValues + private static void AssetValues(T first, T second) + { + if (first.Equals(second) == false) + { + throw new Exception("The two values are not equal:\n\t1: " + first + + "\n\t2: " + second); + } + } + #endregion } #endregion } diff --git a/RenderSystems/ANX.Framework.Windows.GL3/Helpers/GraphicsResourceManager.cs b/RenderSystems/ANX.Framework.Windows.GL3/Helpers/GraphicsResourceManager.cs new file mode 100644 index 00000000..e79c62dd --- /dev/null +++ b/RenderSystems/ANX.Framework.Windows.GL3/Helpers/GraphicsResourceManager.cs @@ -0,0 +1,238 @@ +using System; +using System.Collections.Generic; + +#region License + +// +// This file is part of the ANX.Framework created by the "ANX.Framework developer group". +// +// This file is released under the Ms-PL license. +// +// +// +// Microsoft Public License (Ms-PL) +// +// This license governs use of the accompanying software. If you use the software, you accept this license. +// If you do not accept the license, do not use the software. +// +// 1.Definitions +// The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning +// here as under U.S. copyright law. +// A "contribution" is the original software, or any additions or changes to the software. +// A "contributor" is any person that distributes its contribution under this license. +// "Licensed patents" are a contributor's patent claims that read directly on its contribution. +// +// 2.Grant of Rights +// (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations +// in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to +// reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution +// or any derivative works that you create. +// (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in +// section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed +// patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution +// in the software or derivative works of the contribution in the software. +// +// 3.Conditions and Limitations +// (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. +// (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your +// patent license from such contributor to the software ends automatically. +// (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution +// notices that are present in the software. +// (D) If you distribute any portion of the software in source code form, you may do so only under this license by including +// a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or +// object code form, you may only do so under a license that complies with this license. +// (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees, +// or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the +// extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a +// particular purpose and non-infringement. + +#endregion // License + +namespace ANX.Framework.Windows.GL3.Helpers +{ + internal static class GraphicsResourceManager + { + #region Private + private static List allTextures; + + private static List allEffects; + + private static List allVertexBuffers; + + private static List allIndexBuffers; + #endregion + + #region Constructor + static GraphicsResourceManager() + { + allTextures = new List(); + allEffects = new List(); + allVertexBuffers = new List(); + allIndexBuffers = new List(); + } + #endregion + + #region UpdateResource + public static void UpdateResource(T resource, bool register) + { + IList list = null; + + if (typeof(T) == typeof(Texture2DGL3)) + { + list = (IList)allTextures; + } + else if (typeof(T) == typeof(EffectGL3)) + { + list = (IList)allEffects; + } + else if (typeof(T) == typeof(VertexBufferGL3)) + { + list = (IList)allVertexBuffers; + } + else if (typeof(T) == typeof(IndexBufferGL3)) + { + list = (IList)allIndexBuffers; + } + + lock (list) + { + if (register) + { + list.Add(resource); + } + else + { + list.Remove(resource); + } + } + } + #endregion + + #region DisposeAllResources + public static void DisposeAllResources() + { + #region Textures + lock (allTextures) + { + foreach (Texture2DGL3 texture in allTextures) + { + if (texture.IsDisposed == false) + { + texture.DisposeResource(); + } + } + } + #endregion + + #region Effects + lock (allEffects) + { + foreach (EffectGL3 effect in allEffects) + { + if (effect.IsDisposed == false) + { + effect.DisposeResource(); + } + } + } + #endregion + + #region VertexBuffers + lock (allVertexBuffers) + { + foreach (VertexBufferGL3 buffer in allVertexBuffers) + { + if (buffer.IsDisposed == false) + { + buffer.DisposeResource(); + } + } + } + #endregion + + #region IndexBuffers + lock (allIndexBuffers) + { + foreach (IndexBufferGL3 buffer in allIndexBuffers) + { + if (buffer.IsDisposed == false) + { + buffer.DisposeResource(); + } + } + } + #endregion + } + #endregion + + #region RecreateAllResources + public static void RecreateAllResources() + { + #region Textures + lock (allTextures) + { + foreach (Texture2DGL3 texture in allTextures) + { + if (texture.IsDisposed == false) + { + texture.RecreateData(); + } + } + } + #endregion + + #region Effects + lock (allEffects) + { + foreach (EffectGL3 effect in allEffects) + { + if (effect.IsDisposed == false) + { + effect.RecreateData(); + } + } + } + #endregion + + #region VertexBuffers + lock (allVertexBuffers) + { + foreach (VertexBufferGL3 buffer in allVertexBuffers) + { + if (buffer.IsDisposed == false) + { + buffer.RecreateData(); + } + } + } + #endregion + + #region IndexBuffers + lock (allIndexBuffers) + { + foreach (IndexBufferGL3 buffer in allIndexBuffers) + { + if (buffer.IsDisposed == false) + { + buffer.RecreateData(); + } + } + } + #endregion + + if (BlendStateGL3.Current != null) + { + BlendStateGL3.Current.Apply(null); + } + if (RasterizerStateGL3.Current != null) + { + RasterizerStateGL3.Current.Apply(null); + } + if (DepthStencilStateGL3.Current != null) + { + DepthStencilStateGL3.Current.Apply(null); + } + } + #endregion + } +} diff --git a/RenderSystems/ANX.Framework.Windows.GL3/Helpers/LinuxInterop.cs b/RenderSystems/ANX.Framework.Windows.GL3/Helpers/LinuxInterop.cs index 19eb2033..263206f3 100644 --- a/RenderSystems/ANX.Framework.Windows.GL3/Helpers/LinuxInterop.cs +++ b/RenderSystems/ANX.Framework.Windows.GL3/Helpers/LinuxInterop.cs @@ -88,6 +88,10 @@ namespace ANX.Framework.Windows.GL3.Helpers [DllImport("libX11")] private static extern int XPending(IntPtr diplay); + + [DllImport("libX11")] + private static extern void XResizeWindow(IntPtr display, IntPtr window, + int width, int height); #endregion #region GetStaticFieldValue @@ -145,5 +149,13 @@ namespace ANX.Framework.Windows.GL3.Helpers rootWindow, infoPtr); } #endregion + + #region ResizeWindow + public static void ResizeWindow(IntPtr windowHandle, int backBufferWidth, + int backBufferHeight) + { + XResizeWindow(IntPtr.Zero, windowHandle, backBufferWidth, backBufferHeight); + } + #endregion } } diff --git a/RenderSystems/ANX.Framework.Windows.GL3/IndexBufferGL3.cs b/RenderSystems/ANX.Framework.Windows.GL3/IndexBufferGL3.cs index 5c7fceb3..4a7d208c 100644 --- a/RenderSystems/ANX.Framework.Windows.GL3/IndexBufferGL3.cs +++ b/RenderSystems/ANX.Framework.Windows.GL3/IndexBufferGL3.cs @@ -1,6 +1,7 @@ using System; -using ANX.Framework.NonXNA; using ANX.Framework.Graphics; +using ANX.Framework.NonXNA; +using ANX.Framework.Windows.GL3.Helpers; using OpenTK.Graphics.OpenGL; #region License @@ -77,6 +78,8 @@ namespace ANX.Framework.Windows.GL3 private BufferUsage usage; private BufferUsageHint usageHint; + + internal bool IsDisposed; #endregion #region Constructor @@ -86,6 +89,8 @@ namespace ANX.Framework.Windows.GL3 internal IndexBufferGL3(IndexElementSize setElementSize, int setIndexCount, BufferUsage setUsage) { + GraphicsResourceManager.UpdateResource(this, true); + indexCount = setIndexCount; elementSize = setElementSize; usage = setUsage; @@ -97,8 +102,43 @@ namespace ANX.Framework.Windows.GL3 BufferUsageHint.DynamicDraw : BufferUsageHint.StaticDraw; + CreateBuffer(); + } + + ~IndexBufferGL3() + { + GraphicsResourceManager.UpdateResource(this, false); + } + #endregion + + #region CreateBuffer + private void CreateBuffer() + { GL.GenBuffers(1, out bufferHandle); ErrorHelper.Check("GenBuffers"); + GL.BindBuffer(BufferTarget.ElementArrayBuffer, bufferHandle); + ErrorHelper.Check("BindBuffer"); + int size = indexCount * + (elementSize == IndexElementSize.SixteenBits ? 16 : 32); + GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)size, IntPtr.Zero, + usageHint); + ErrorHelper.Check("BufferData"); + + int setSize; + GL.GetBufferParameter(BufferTarget.ElementArrayBuffer, + BufferParameterName.BufferSize, out setSize); + if (setSize != size) + { + throw new Exception("Failed to set the vertexBuffer data. DataSize=" + + size + " SetSize=" + setSize); + } + } + #endregion + + #region RecreateData + internal void RecreateData() + { + CreateBuffer(); } #endregion @@ -185,8 +225,22 @@ namespace ANX.Framework.Windows.GL3 /// public void Dispose() { - GL.DeleteBuffers(1, ref bufferHandle); - ErrorHelper.Check("DeleteBuffers"); + if (IsDisposed == false) + { + IsDisposed = true; + DisposeResource(); + } + } + + internal void DisposeResource() + { + if (bufferHandle != -1 && + GraphicsDeviceWindowsGL3.IsContextCurrent) + { + GL.DeleteBuffers(1, ref bufferHandle); + ErrorHelper.Check("DeleteBuffers"); + bufferHandle = -1; + } } #endregion } diff --git a/RenderSystems/ANX.Framework.Windows.GL3/RasterizerStateGL3.cs b/RenderSystems/ANX.Framework.Windows.GL3/RasterizerStateGL3.cs index 9d45cd1c..1fb5ec81 100644 --- a/RenderSystems/ANX.Framework.Windows.GL3/RasterizerStateGL3.cs +++ b/RenderSystems/ANX.Framework.Windows.GL3/RasterizerStateGL3.cs @@ -1,6 +1,6 @@ -using System; +using ANX.Framework.Graphics; using ANX.Framework.NonXNA; -using ANX.Framework.Graphics; +using ANX.Framework.NonXNA.Development; using OpenTK.Graphics.OpenGL; #region License @@ -58,8 +58,18 @@ namespace ANX.Framework.Windows.GL3 /// Basically this is a wrapper class for setting the different values all /// at once, because OpenGL has no State objects like DirectX. /// + [PercentageComplete(100)] + [TestStateAttribute(TestStateAttribute.TestState.Untested)] public class RasterizerStateGL3 : INativeRasterizerState { + #region Private + internal static RasterizerStateGL3 Current + { + get; + private set; + } + #endregion + #region Public #region IsBound /// @@ -157,6 +167,7 @@ namespace ANX.Framework.Windows.GL3 public void Apply(GraphicsDevice graphicsDevice) { IsBound = true; + Current = this; #region Cull Mode GL.FrontFace(FrontFaceDirection.Cw); @@ -234,6 +245,7 @@ namespace ANX.Framework.Windows.GL3 public void Release() { IsBound = false; + Current = null; } #endregion diff --git a/RenderSystems/ANX.Framework.Windows.GL3/RenderTarget2DGL3.cs b/RenderSystems/ANX.Framework.Windows.GL3/RenderTarget2DGL3.cs index 25975dc9..74cf6775 100644 --- a/RenderSystems/ANX.Framework.Windows.GL3/RenderTarget2DGL3.cs +++ b/RenderSystems/ANX.Framework.Windows.GL3/RenderTarget2DGL3.cs @@ -1,6 +1,7 @@ using System; using ANX.Framework.Graphics; using ANX.Framework.NonXNA.RenderSystem; +using ANX.Framework.Windows.GL3.Helpers; using OpenTK.Graphics.OpenGL; namespace ANX.Framework.Windows.GL3 @@ -19,6 +20,7 @@ namespace ANX.Framework.Windows.GL3 public RenderTarget2DGL3(int width, int height, bool mipMap, SurfaceFormat preferredFormat, DepthFormat preferredDepthFormat, int preferredMultiSampleCount, RenderTargetUsage usage) + : base() { generateMipmaps = mipMap; PixelInternalFormat nativeFormat = diff --git a/RenderSystems/ANX.Framework.Windows.GL3/Texture2DGL3.cs b/RenderSystems/ANX.Framework.Windows.GL3/Texture2DGL3.cs index 322a3844..c1bf83c9 100644 --- a/RenderSystems/ANX.Framework.Windows.GL3/Texture2DGL3.cs +++ b/RenderSystems/ANX.Framework.Windows.GL3/Texture2DGL3.cs @@ -2,6 +2,7 @@ using System.Runtime.InteropServices; using ANX.Framework.Graphics; using ANX.Framework.NonXNA.RenderSystem; +using ANX.Framework.Windows.GL3.Helpers; using OpenTK.Graphics.OpenGL; #region License @@ -83,6 +84,17 @@ namespace ANX.Framework.Windows.GL3 /// Flag if the texture is a compressed format or not. /// private bool isCompressed; + + internal bool IsDisposed; + + private int uncompressedDataSize; + + private byte[] texData; + + /// + /// TODO: find better solution + /// + private int maxSetDataSize; #endregion #region Public @@ -99,6 +111,7 @@ namespace ANX.Framework.Windows.GL3 #region Constructor internal Texture2DGL3() { + GraphicsResourceManager.UpdateResource(this, true); } /// @@ -111,13 +124,28 @@ namespace ANX.Framework.Windows.GL3 internal Texture2DGL3(SurfaceFormat surfaceFormat, int setWidth, int setHeight, int mipCount) { + GraphicsResourceManager.UpdateResource(this, true); + width = setWidth; height = setHeight; numberOfMipMaps = mipCount; - nativeFormat = - DatatypesMapping.SurfaceToPixelInternalFormat(surfaceFormat); + nativeFormat = DatatypesMapping.SurfaceToPixelInternalFormat(surfaceFormat); isCompressed = nativeFormat.ToString().StartsWith("Compressed"); + uncompressedDataSize = GetUncompressedDataSize(); + + CreateTexture(); + } + + ~Texture2DGL3() + { + GraphicsResourceManager.UpdateResource(this, false); + } + #endregion + + #region CreateTexture + private void CreateTexture() + { NativeHandle = GL.GenTexture(); #if DEBUG ErrorHelper.Check("GenTexture"); @@ -128,7 +156,9 @@ namespace ANX.Framework.Windows.GL3 #endif int wrapMode = (int)All.ClampToEdge; - int filter = (int)(mipCount > 1 ? All.LinearMipmapLinear : All.Linear); + int filter = (int)(numberOfMipMaps > 1 ? + All.LinearMipmapLinear : + All.Linear); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, wrapMode); @@ -174,6 +204,11 @@ namespace ANX.Framework.Windows.GL3 ErrorHelper.Check("BindTexture"); #endif + if (data.Length > maxSetDataSize) + { + maxSetDataSize = data.Length; + } + GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned); // TODO: get size of first mipmap! @@ -195,9 +230,9 @@ namespace ANX.Framework.Windows.GL3 } else { - GL.TexImage2D(TextureTarget.Texture2D, 0, nativeFormat, - width, height, 0, (PixelFormat)nativeFormat, - PixelType.UnsignedByte, dataPointer); + GL.TexImage2D(TextureTarget.Texture2D, 0, nativeFormat, + width, height, 0, (PixelFormat)nativeFormat, + PixelType.UnsignedByte, dataPointer); #if DEBUG ErrorHelper.Check("TexImage2D Format=" + nativeFormat); #endif @@ -240,16 +275,111 @@ namespace ANX.Framework.Windows.GL3 } #endregion + #region GetTextureData + private void GetTextureData() + { + GL.BindTexture(TextureTarget.Texture2D, NativeHandle); + + if (isCompressed) + { + texData = new byte[maxSetDataSize]; + GCHandle handle = GCHandle.Alloc(texData, GCHandleType.Pinned); + + GL.GetCompressedTexImage(TextureTarget.Texture2D, 0, + handle.AddrOfPinnedObject()); + + handle.Free(); + } + else + { + texData = new byte[uncompressedDataSize]; + GCHandle handle = GCHandle.Alloc(texData, GCHandleType.Pinned); + + GL.GetTexImage(TextureTarget.Texture2D, 0, (PixelFormat)nativeFormat, + PixelType.UnsignedByte, handle.AddrOfPinnedObject()); + + handle.Free(); + } + } + #endregion + + #region RecreateData + internal void RecreateData() + { + CreateTexture(); + SetData(null, texData); + texData = null; + } + #endregion + + #region GetUncompressedDataSize + private int GetUncompressedDataSize() + { + int size = width * height; + + switch (nativeFormat) + { + default: + case PixelInternalFormat.R32f: + case PixelInternalFormat.Rgb10A2: + case PixelInternalFormat.Rg16: + case PixelInternalFormat.Rgba: + size *= 4; + break; + + case PixelInternalFormat.Rg32f: + case PixelInternalFormat.Rgba16f: + size *= 8; + break; + + case PixelInternalFormat.R16f: + case PixelInternalFormat.Rgb5A1: + case PixelInternalFormat.Rgba4: + size *= 2; + break; + + case PixelInternalFormat.Alpha8: + //size *= 1; + break; + + case PixelInternalFormat.Rgba32f: + size *= 16; + break; + } + + return size; + } + #endregion + #region Dispose /// /// Dispose the native OpenGL texture handle. /// public virtual void Dispose() { - GL.DeleteTexture(NativeHandle); + if (IsDisposed == false) + { + IsDisposed = true; + DisposeResource(); + } + } + + internal void DisposeResource() + { + if (IsDisposed == false) + { + GetTextureData(); + } + + if (NativeHandle != -1 && + GraphicsDeviceWindowsGL3.IsContextCurrent) + { + GL.DeleteTexture(NativeHandle); + NativeHandle = -1; #if DEBUG - ErrorHelper.Check("DeleteTexture"); + ErrorHelper.Check("DeleteTexture"); #endif + } } #endregion } diff --git a/RenderSystems/ANX.Framework.Windows.GL3/VertexBufferGL3.cs b/RenderSystems/ANX.Framework.Windows.GL3/VertexBufferGL3.cs index 4cbebdfb..e8f5c557 100644 --- a/RenderSystems/ANX.Framework.Windows.GL3/VertexBufferGL3.cs +++ b/RenderSystems/ANX.Framework.Windows.GL3/VertexBufferGL3.cs @@ -1,6 +1,7 @@ using System; -using ANX.Framework.NonXNA; using ANX.Framework.Graphics; +using ANX.Framework.NonXNA; +using ANX.Framework.Windows.GL3.Helpers; using OpenTK.Graphics.OpenGL; #region License @@ -80,6 +81,8 @@ namespace ANX.Framework.Windows.GL3 private int vertexCount; private BufferUsageHint usageHint; + + internal bool IsDisposed; #endregion #region Constructor @@ -89,6 +92,8 @@ namespace ANX.Framework.Windows.GL3 internal VertexBufferGL3(VertexDeclaration setVertexDeclaration, int setVertexCount, BufferUsage setUsage) { + GraphicsResourceManager.UpdateResource(this, true); + vertexDeclaration = setVertexDeclaration; usage = setUsage; vertexCount = setVertexCount; @@ -100,11 +105,23 @@ namespace ANX.Framework.Windows.GL3 BufferUsageHint.DynamicDraw : BufferUsageHint.StaticDraw; + CreateBuffer(); + } + + ~VertexBufferGL3() + { + GraphicsResourceManager.UpdateResource(this, false); + } + #endregion + + #region CreateBuffer + private void CreateBuffer() + { GL.GenBuffers(1, out bufferHandle); ErrorHelper.Check("GenBuffers"); GL.BindBuffer(BufferTarget.ArrayBuffer, bufferHandle); ErrorHelper.Check("BindBuffer"); - int size = vertexDeclaration.VertexStride * setVertexCount; + int size = vertexDeclaration.VertexStride * vertexCount; GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)size, IntPtr.Zero, usageHint); ErrorHelper.Check("BufferData"); @@ -120,6 +137,13 @@ namespace ANX.Framework.Windows.GL3 } #endregion + #region RecreateData + internal void RecreateData() + { + CreateBuffer(); + } + #endregion + #region SetData public void SetData(GraphicsDevice graphicsDevice, T[] data) where T : struct @@ -243,8 +267,22 @@ namespace ANX.Framework.Windows.GL3 /// public void Dispose() { - GL.DeleteBuffers(1, ref bufferHandle); - ErrorHelper.Check("DeleteBuffers"); + if (IsDisposed == false) + { + IsDisposed = true; + DisposeResource(); + } + } + + internal void DisposeResource() + { + if (bufferHandle != -1 && + GraphicsDeviceWindowsGL3.IsContextCurrent) + { + GL.DeleteBuffers(1, ref bufferHandle); + ErrorHelper.Check("DeleteBuffers"); + bufferHandle = -1; + } } #endregion }