Added AngleWindowInfo and AnglePlatformFactory
authorJonas Boesch <jonas.boesch@phonak.com>
Tue, 21 Apr 2015 14:09:29 +0000 (16:09 +0200)
committerManuel Zanin <manuel.zanin@sonova.com>
Mon, 28 Nov 2016 11:21:18 +0000 (12:21 +0100)
Both WindowInfo and PlatformFactory wrap the actual platform-specific WindowInfo and PlatformFactory.

For offscreen rendering, AngleWindowInfo can be used with a DummyWindowInfo.

The API to add additional surfaces was added to IAngleWindowInfo, since all those calls need the Display parameter that is only available on EglWindowInfo (which is not exposed to users).

Source/OpenTK/Platform/Egl/AngleWindowInfo.cs [new file with mode: 0644]
Source/OpenTK/Platform/Egl/EglAnglePlatformFactory.cs [new file with mode: 0644]
src/OpenTK/Graphics/GraphicsContext.cs
src/OpenTK/OpenTK.csproj
src/OpenTK/Platform/Factory.cs
src/OpenTK/Platform/Utilities.cs

diff --git a/Source/OpenTK/Platform/Egl/AngleWindowInfo.cs b/Source/OpenTK/Platform/Egl/AngleWindowInfo.cs
new file mode 100644 (file)
index 0000000..f062a2d
--- /dev/null
@@ -0,0 +1,183 @@
+using System;
+using OpenTK.Graphics;
+using OpenTK.Platform.Windows;
+
+namespace OpenTK.Platform.Egl
+{
+    using EGLSurface = IntPtr;
+    /// <summary>
+    /// A window info for angle. 
+    /// </summary>
+    public interface IAngleWindowInfo : IWindowInfo
+    {
+        /// <summary>
+        /// Query the underlying platform pointer / handle for this window's 
+        /// default surface or IntPtr.Zero
+        /// </summary>
+        IntPtr QuerySurfacePointer();
+        /// <summary>
+        /// Create an additional rendering surface that shares the display
+        /// of this window.
+        /// </summary>
+        /// <param name="width">width in pixels</param>
+        /// <param name="height">height in pixels</param>
+        /// <returns>A reference to the new surface</returns>
+        EGLSurface CreateSurface(int width, int height);
+        /// <summary>
+        /// Destroy a surface created with CreateSurface and clears the passed reference.
+        /// </summary>
+        /// <param name="surface">Reference to the surface.</param>
+        void DestroySurface(ref EGLSurface surface);
+        /// <summary>
+        /// MakeCurrent the custom surface created with CreateSurface.
+        /// </summary>
+        /// <param name="surface">Reference to the surface.</param>
+        void MakeCurrent(EGLSurface surface);
+        /// <summary>
+        /// Query the underlying platform pointer / handle for an EGLSurface 
+        /// created with CreateSurface.
+        /// </summary>
+        /// <param name="surface"></param>
+        IntPtr QuerySurfacePointer(EGLSurface surface);
+    }
+
+    internal interface IAngleWindowInfoInternal : IAngleWindowInfo
+    {
+        IWindowInfo PlatformWindow { get; }
+        IntPtr Display { get; }
+        IntPtr Surface { get; }
+        EglContext EglContext { get; set; }
+        EglWindowInfo EglWindowInfo { get; set; }
+        IntPtr DeviceContext { get; }
+    }
+
+    internal class AngleWindowInfo : IAngleWindowInfoInternal
+    {
+        private readonly IWindowInfo _platform_window;
+        private bool _disposed;
+
+        public AngleWindowInfo(IWindowInfo platform_window)
+        {
+            _platform_window = platform_window;
+        }
+
+        public IWindowInfo PlatformWindow
+        {
+            get { return _platform_window; }
+        }
+
+        public IWindowInfo WindowInfo
+        {
+            get { return EglWindowInfo; }
+        }
+
+        public IntPtr DeviceContext
+        {
+            get
+            {
+                var win_win = _platform_window as WinWindowInfo;
+                if (win_win != null)
+                {
+                    return win_win.DeviceContext;
+                }
+                return IntPtr.Zero;
+            }
+        }
+
+        public EglContext EglContext { get; set; }
+        public EglWindowInfo EglWindowInfo { get; set; }
+
+        public IntPtr Display
+        {
+            get { return EglWindowInfo.Display; }
+        }
+
+        public IntPtr Surface
+        {
+            get { return EglWindowInfo.Surface; }
+        }
+
+        public void Dispose()
+        {
+            Dispose(false);
+        }
+
+        public IntPtr Handle
+        {
+            get { return _platform_window.Handle; }
+        }
+
+        ~AngleWindowInfo()
+        {
+            Dispose(true);
+        }
+
+        private void Dispose(bool called_from_finalizer)
+        {
+            if (_disposed)
+            {
+                return;
+            }
+            if (!called_from_finalizer)
+            {
+                _platform_window.Dispose();
+            }
+            // dispose unmanaged
+
+            _disposed = true;
+            GC.SuppressFinalize(this);
+        }
+
+        public IntPtr QuerySurfacePointer()
+        {
+            return QuerySurfacePointer(Surface);
+        }
+
+        public EGLSurface CreateSurface(int width, int height)
+        {
+            IntPtr surface;
+            EglWindowInfo.CreatePbufferSurface(
+                EglContext.GraphicsMode.Index.Value,
+                width, height, 
+                out surface);
+            return surface;
+        }
+
+        public void DestroySurface(ref EGLSurface surface)
+        {
+            EglWindowInfo.DestroySurface(ref surface);
+        }
+
+        public void MakeCurrent(EGLSurface surface)
+        {
+            Egl.MakeCurrent(Display, surface, surface, EglContext.HandleAsEGLContext);
+        }
+
+        public IntPtr QuerySurfacePointer(IntPtr surface)
+        {
+            if (UsesDirect3DBackend())
+            {
+                return QuerySurfacePointer(surface, 
+                    Egl.EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE);
+            }
+            return IntPtr.Zero;
+        }
+
+        private IntPtr QuerySurfacePointer(IntPtr surface, int attrib)
+        {
+            IntPtr surface_pointer;
+            if (Egl.QuerySurfacePointerANGLE(
+                Display, surface, attrib, out surface_pointer))
+            {
+                return surface_pointer;
+            }
+            return IntPtr.Zero;
+        }
+
+        private bool UsesDirect3DBackend()
+        {
+            var d3d_flags = GraphicsContextFlags.AngleD3D9 | GraphicsContextFlags.AngleD3D11;
+            return ((EglContext.GraphicsContextFlags & d3d_flags) != 0);
+        }
+    }
+}
\ No newline at end of file
diff --git a/Source/OpenTK/Platform/Egl/EglAnglePlatformFactory.cs b/Source/OpenTK/Platform/Egl/EglAnglePlatformFactory.cs
new file mode 100644 (file)
index 0000000..6d5f694
--- /dev/null
@@ -0,0 +1,172 @@
+#region License
+
+//
+// The Open Toolkit Library License
+//
+// Copyright (c) 2006 - 2015 the Open Toolkit library.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights to 
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+// the Software, and to permit persons to whom the Software is furnished to do
+// so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#endregion
+
+using System;
+using OpenTK.Graphics;
+using OpenTK.Input;
+
+namespace OpenTK.Platform.Egl
+{
+    internal class EglAnglePlatformFactory : PlatformFactoryBase
+    {
+        private readonly IPlatformFactory _platform_factory;
+        #region Public Members
+
+        public EglAnglePlatformFactory(IPlatformFactory platform_factory)
+        {
+            _platform_factory = platform_factory;
+        }
+
+        public override INativeWindow CreateNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode,
+            GameWindowFlags options, DisplayDevice device)
+        {
+            return _platform_factory.CreateNativeWindow(x, y, width, height, title,
+                mode, options, device);
+        }
+
+        public override IDisplayDeviceDriver CreateDisplayDeviceDriver()
+        {
+            return _platform_factory.CreateDisplayDeviceDriver();
+        }
+
+        public override IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window,
+            IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
+        {
+            var angle_window = (IAngleWindowInfoInternal) window;
+            var egl_window = CreateWindowInfo(angle_window, major, flags);
+            var egl_context = new EglWinContext(mode, egl_window, shareContext, major, minor, flags);
+            angle_window.EglContext = egl_context;
+            return egl_context;
+        }
+
+        public override IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window,
+            IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
+        {
+            var angle_window = (IAngleWindowInfoInternal) window;
+            var egl_window = CreateWindowInfo(angle_window, major, flags);
+            var egl_context = new EglWinContext(handle, egl_window, shareContext, major, minor, flags);
+            angle_window.EglContext = egl_context;
+            return egl_context;
+        }
+
+        public override GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext()
+        {
+            return (GraphicsContext.GetCurrentContextDelegate)delegate
+            {
+                return new ContextHandle(Platform.Egl.Egl.GetCurrentContext());
+            };
+        }
+
+        public override IKeyboardDriver2 CreateKeyboardDriver()
+        {
+            return _platform_factory.CreateKeyboardDriver();
+        }
+
+        public override IMouseDriver2 CreateMouseDriver()
+        {
+            return _platform_factory.CreateMouseDriver();
+        }
+
+        public override IJoystickDriver2 CreateJoystickDriver()
+        {
+            return _platform_factory.CreateJoystickDriver();
+        }
+
+        #endregion
+
+        #region Private Members
+
+        private static bool FlagEnabled(GraphicsContextFlags flags, GraphicsContextFlags flag)
+        {
+            return (flags & flag) != 0;
+        }
+
+        private EglWindowInfo CreateWindowInfo(IAngleWindowInfoInternal window_info,
+            int major, GraphicsContextFlags flags)
+        {
+            var egl_display = GetAngleDisplay(window_info.DeviceContext, flags, major);
+            var egl_window = new EglWindowInfo(window_info.Handle, egl_display);
+            window_info.EglWindowInfo = egl_window;
+            return egl_window;
+        }
+
+        private IntPtr GetAngleDisplay(IntPtr dc, GraphicsContextFlags flags, int major)
+        {
+            // default to D3D9 for ES2, but use D3D11 for ES3 as required by Angle.
+            var platform_type = major == 2
+                ? Platform.Egl.Egl.PLATFORM_ANGLE_TYPE_D3D9
+                : Platform.Egl.Egl.PLATFORM_ANGLE_TYPE_D3D11;
+            if (FlagEnabled(flags, GraphicsContextFlags.AngleD3D11))
+            {
+                platform_type = Platform.Egl.Egl.PLATFORM_ANGLE_TYPE_D3D11;
+            }
+            else if (FlagEnabled(flags, GraphicsContextFlags.AngleD3D9))
+            {
+                platform_type = Platform.Egl.Egl.PLATFORM_ANGLE_TYPE_D3D9;
+            }
+            else if (FlagEnabled(flags, GraphicsContextFlags.AngleOpenGL))
+            {
+                platform_type = Platform.Egl.Egl.PLATFORM_ANGLE_TYPE_OPENGL;
+            }
+            else
+            {
+                // make sure the correct flag is set.
+                switch (platform_type)
+                {
+                    case Platform.Egl.Egl.PLATFORM_ANGLE_TYPE_D3D9:
+                        flags |= GraphicsContextFlags.AngleD3D9;
+                        break;
+                    case Platform.Egl.Egl.PLATFORM_ANGLE_TYPE_D3D11:
+                        flags |= GraphicsContextFlags.AngleD3D11;
+                        break;
+                    case Platform.Egl.Egl.PLATFORM_ANGLE_TYPE_OPENGL:
+                        flags |= GraphicsContextFlags.AngleOpenGL;
+                        break;
+                }
+            }
+
+            var attribs = new[]
+            {
+                Platform.Egl.Egl.PLATFORM_ANGLE_TYPE, platform_type,
+                Platform.Egl.Egl.PLATFORM_ANGLE_MAX_VERSION_MAJOR, Platform.Egl.Egl.DONT_CARE,
+                Platform.Egl.Egl.PLATFORM_ANGLE_MAX_VERSION_MINOR, Platform.Egl.Egl.DONT_CARE,
+                Platform.Egl.Egl.PLATFORM_ANGLE_DEVICE_TYPE, Platform.Egl.Egl.PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE,
+                Platform.Egl.Egl.NONE
+            };
+
+            return Platform.Egl.Egl.GetPlatformDisplay(
+                Platform.Egl.Egl.PLATFORM_ANGLE,
+                dc,
+                attribs
+                );
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
index 35a5d35..da3c9f6 100644 (file)
@@ -145,8 +145,12 @@ namespace OpenTK.Graphics
                         IPlatformFactory factory = null;
                         switch ((flags & GraphicsContextFlags.Embedded) == GraphicsContextFlags.Embedded)
                         {
-                            case false: factory = Factory.Default; break;
-                            case true: factory = Factory.Embedded; break;
+                            case false:
+                                factory = Factory.Default;
+                                break;
+                            case true:
+                                factory = use_angle ? Factory.Angle : Factory.Embedded;
+                                break;
                         }
 
                         // Note: this approach does not allow us to mix native and EGL contexts in the same process.
index 1476054..758e53a 100644 (file)
     <Compile Include="Math\Matrix4x3d.cs" />
     <Compile Include="Platform\Common\Hid.cs" />
     <Compile Include="Platform\DisplayDeviceBase.cs" />
+    <Compile Include="Platform\Egl\AngleWindowInfo.cs" />
     <Compile Include="Platform\Egl\EglException.cs" />
     <Compile Include="Platform\Egl\EglAngle.cs" />
     <Compile Include="Platform\Egl\EglUnixContext.cs" />
     <Compile Include="Platform\Egl\EglWinContext.cs" />
+    <Compile Include="Platform\Egl\EglAnglePlatformFactory.cs" />
     <Compile Include="Platform\MappedGamePadDriver.cs" />
     <Compile Include="Platform\Windows\Bindings\HidProtocol.cs" />
     <Compile Include="Platform\Windows\WinInputBase.cs" />
index 9e5eb66..35839e0 100644 (file)
@@ -29,6 +29,7 @@ using System;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.Text;
+using OpenTK.Platform.Egl;
 
 namespace OpenTK.Platform
 {
@@ -40,7 +41,7 @@ namespace OpenTK.Platform
         #region Fields
 
         bool disposed;
-        static IPlatformFactory default_implementation, embedded_implementation;
+        static IPlatformFactory default_implementation, embedded_implementation, angle_implementation;
 
         #endregion
 
@@ -102,11 +103,13 @@ namespace OpenTK.Platform
                 else if (Configuration.RunningOnAndroid) Embedded = new Android.AndroidFactory();
                 #endif
                 else Embedded = new UnsupportedPlatform();
+                Angle = new EglAnglePlatformFactory(Embedded);
             }
             #endif
             else
             {
                 Embedded = new UnsupportedPlatform();
+                Angle = Embedded;
             }
 
             if (Default is UnsupportedPlatform && !(Embedded is UnsupportedPlatform))
@@ -129,6 +132,12 @@ namespace OpenTK.Platform
             private set { embedded_implementation = value; }
         }
 
+        public static IPlatformFactory Angle
+        {
+            get { return angle_implementation; }
+            private set { angle_implementation = value; }
+        }
+
         #endregion
 
         #region IPlatformFactory Members
index 2a531f6..6746b39 100644 (file)
@@ -13,6 +13,7 @@ using System.Runtime.InteropServices;
 using System.Reflection;
 using System.Diagnostics;
 using OpenTK.Graphics;
+using OpenTK.Platform.Egl;
 
 #endregion
 
@@ -393,6 +394,22 @@ namespace OpenTK.Platform
 
         #endregion
 
+        #region
+
+        /// <summary>
+        /// Creates an IWindowInfo instance for Angle rendering, based on 
+        /// supplied platform window (e.g. a window created with 
+        /// CreateWindowsWindowInfo, or CreateDummyWindowInfo).
+        /// </summary>
+        /// <param name="platform_window"></param>
+        /// <returns></returns>
+        public static IAngleWindowInfo CreateAngleWindowInfo(IWindowInfo platform_window)
+        {
+            return new AngleWindowInfo(platform_window);
+        }
+        
+        #endregion
+
         #endregion
 
         #region RelaxGraphicsMode