diff --git a/Source/OpenTK/Platform/Egl/EglAngle.cs b/Source/OpenTK/Platform/Egl/EglAngle.cs new file mode 100644 index 00000000..9cf708e8 --- /dev/null +++ b/Source/OpenTK/Platform/Egl/EglAngle.cs @@ -0,0 +1,42 @@ +using System; +using System.Runtime.InteropServices; + +namespace OpenTK.Platform.Egl +{ + using EGLDisplay = IntPtr; + using EGLNativeDisplayType = IntPtr; + using EGLSurface = IntPtr; + using ShareHandle = IntPtr; + + static partial class Egl + { + // See + // - ANGLE_platform_angle + // - ANGLE_platform_angle_d3d + // - ANGLE_platform_angle_opengl + public const int PLATFORM_ANGLE = 0x3202; + public const int PLATFORM_ANGLE_TYPE = 0x3203; + public const int PLATFORM_ANGLE_MAX_VERSION_MAJOR = 0x3204; + public const int PLATFORM_ANGLE_MAX_VERSION_MINOR = 0x3205; + public const int PLATFORM_ANGLE_TYPE_DEFAULT = 0x3206; + public const int PLATFORM_ANGLE_TYPE_D3D9 = 0x3207; + public const int PLATFORM_ANGLE_TYPE_D3D11 = 0x3208; + public const int PLATFORM_ANGLE_DEVICE_TYPE = 0x3209; + public const int PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE = 0x320A; + public const int PLATFORM_ANGLE_DEVICE_TYPE_WARP = 0x320B; + public const int PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE = 0x320C; + public const int PLATFORM_ANGLE_TYPE_OPENGL = 0x320D; + public const int PLATFORM_ANGLE_TYPE_OPENGLES = 0x320E; + // See EGL_ANGLE_surface_d3d_texture_2d_share_handle + public const int EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE = 0x3200; + + [DllImport("libEGL.dll", EntryPoint = "eglGetPlatformDisplayEXT")] + public static extern EGLDisplay GetPlatformDisplay(int platform, EGLNativeDisplayType display_id, + int[] attrib_list); + + [DllImport("libEGL.dll", EntryPoint = "eglQuerySurfacePointerANGLE")] + public static extern bool QuerySurfacePointerANGLE(EGLDisplay display, EGLSurface surface, + int attribute, out IntPtr value); + + } +} \ No newline at end of file diff --git a/src/OpenTK/Graphics/GraphicsContext.cs b/src/OpenTK/Graphics/GraphicsContext.cs index d12e360f..35a5d354 100644 --- a/src/OpenTK/Graphics/GraphicsContext.cs +++ b/src/OpenTK/Graphics/GraphicsContext.cs @@ -112,6 +112,18 @@ namespace OpenTK.Graphics if (minor < 0) minor = 0; + // Angle needs an embedded context + var use_angle_flag = GraphicsContextFlags.Angle + | GraphicsContextFlags.AngleD3D9 + | GraphicsContextFlags.AngleD3D11 + | GraphicsContextFlags.AngleOpenGL; + var use_angle = false; + if ((flags & use_angle_flag) != 0) + { + flags |= GraphicsContextFlags.Embedded; + use_angle = true; + } + Debug.Print("Creating GraphicsContext."); try { diff --git a/src/OpenTK/Graphics/GraphicsContextFlags.cs b/src/OpenTK/Graphics/GraphicsContextFlags.cs index a7ee2f59..a7df6e16 100644 --- a/src/OpenTK/Graphics/GraphicsContextFlags.cs +++ b/src/OpenTK/Graphics/GraphicsContextFlags.cs @@ -56,6 +56,30 @@ namespace OpenTK.Graphics /// /// Indicates that this GraphicsContext is targeting OpenGL|ES. /// - Embedded = 0x0004 + Embedded = 0x0004, + /// + /// Indicates that this GraphicsContext is intended for offscreen rendering. + /// + Offscreen = 0x0008, + /// + /// Indicates that this GraphicsContext is targeting OpenGL|ES via Angle + /// and that angle-specific extensions are available. + /// + Angle = 0x0010, + /// + /// Indicates that this GraphicsContext is targeting OpenGL|ES via Angle + /// and uses Direct3D9 as rendering backend. + /// + AngleD3D9 = 0x0020, + /// + /// Indicates that this GraphicsContext is targeting OpenGL|ES via Angle + /// and uses Direct3D11 as rendering backend. + /// + AngleD3D11 = 0x0040, + /// + /// Indicates that this GraphicsContext is targeting OpenGL|ES via Angle + /// and uses OpenGL as rendering backend. + /// + AngleOpenGL = 0x0080, } } diff --git a/src/OpenTK/OpenTK.csproj b/src/OpenTK/OpenTK.csproj index aaa09898..14760545 100644 --- a/src/OpenTK/OpenTK.csproj +++ b/src/OpenTK/OpenTK.csproj @@ -134,6 +134,7 @@ + diff --git a/src/OpenTK/Platform/Egl/Egl.cs b/src/OpenTK/Platform/Egl/Egl.cs index 118054d1..df395812 100644 --- a/src/OpenTK/Platform/Egl/Egl.cs +++ b/src/OpenTK/Platform/Egl/Egl.cs @@ -78,6 +78,17 @@ namespace OpenTK.Platform.Egl CONTEXT_LOST = 12302, } + enum SurfaceType + { + PBUFFER_BIT = 0x0001, + PIXMAP_BIT = 0x0002, + WINDOW_BIT = 0x0004, + VG_COLORSPACE_LINEAR_BIT = 0x0020, + VG_ALPHA_FORMAT_PRE_BIT = 0x0040, + MULTISAMPLE_RESOLVE_BOX_BIT = 0x0200, + SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400, + } + static partial class Egl { public const int VERSION_1_0 = 1; diff --git a/src/OpenTK/Platform/Egl/EglContext.cs b/src/OpenTK/Platform/Egl/EglContext.cs index 2844686d..76992c92 100644 --- a/src/OpenTK/Platform/Egl/EglContext.cs +++ b/src/OpenTK/Platform/Egl/EglContext.cs @@ -28,6 +28,7 @@ using System; using System.Diagnostics; using OpenTK.Graphics; +using OpenTK.Graphics.ES20; namespace OpenTK.Platform.Egl { @@ -36,9 +37,11 @@ namespace OpenTK.Platform.Egl #region Fields protected readonly RenderableFlags Renderable; - protected EglWindowInfo WindowInfo; + internal EglWindowInfo WindowInfo; - IntPtr HandleAsEGLContext { get { return Handle.Handle; } set { Handle = new ContextHandle(value); } } + internal GraphicsContextFlags GraphicsContextFlags { get; set; } + + internal IntPtr HandleAsEGLContext { get { return Handle.Handle; } set { Handle = new ContextHandle(value); } } int swap_interval = 1; // Default interval is defined as 1 in EGL. #endregion @@ -85,19 +88,38 @@ namespace OpenTK.Platform.Egl Debug.Print("[EGL] Failed to bind rendering API. Error: {0}", Egl.GetError()); } - Mode = new EglGraphicsMode().SelectGraphicsMode(window, - mode.ColorFormat, mode.Depth, mode.Stencil, mode.Samples, - mode.AccumulatorFormat, mode.Buffers, mode.Stereo, - Renderable); + bool offscreen = (flags & GraphicsContextFlags.Offscreen) != 0; + + SurfaceType surface_type = offscreen + ? SurfaceType.PBUFFER_BIT + : SurfaceType.WINDOW_BIT; + + Mode = new EglGraphicsMode().SelectGraphicsMode(surface_type, + window.Display, mode.ColorFormat, mode.Depth, mode.Stencil, + mode.Samples, mode.AccumulatorFormat, mode.Buffers, mode.Stereo, + Renderable); + if (!Mode.Index.HasValue) throw new GraphicsModeException("Invalid or unsupported GraphicsMode."); IntPtr config = Mode.Index.Value; if (window.Surface == IntPtr.Zero) - window.CreateWindowSurface(config); + { + if (!offscreen) + { + window.CreateWindowSurface(config); + } + else + { + window.CreatePbufferSurface(config); + } + } int[] attrib_list = new int[] { Egl.CONTEXT_CLIENT_VERSION, major, Egl.NONE }; - HandleAsEGLContext = Egl.CreateContext(window.Display, config, sharedContext != null ? (sharedContext as IGraphicsContextInternal).Context.Handle : IntPtr.Zero, attrib_list); + var share_context = shared != null ? shared.HandleAsEGLContext : IntPtr.Zero; + HandleAsEGLContext = Egl.CreateContext(window.Display, config, share_context, attrib_list); + + GraphicsContextFlags = flags; } public EglContext(ContextHandle handle, EglWindowInfo window, IGraphicsContext sharedContext, @@ -133,6 +155,9 @@ namespace OpenTK.Platform.Egl { if (window is EglWindowInfo) WindowInfo = (EglWindowInfo) window; + else if (window is IAngleWindowInfoInternal) + WindowInfo = ((IAngleWindowInfoInternal) window).EglWindowInfo; + if (!Egl.MakeCurrent(WindowInfo.Display, WindowInfo.Surface, WindowInfo.Surface, HandleAsEGLContext)) { throw new GraphicsContextException(string.Format("Failed to make context {0} current. Error: {1}", Handle, Egl.GetError())); diff --git a/src/OpenTK/Platform/Egl/EglGraphicsMode.cs b/src/OpenTK/Platform/Egl/EglGraphicsMode.cs index 779e8ff2..682caf3e 100644 --- a/src/OpenTK/Platform/Egl/EglGraphicsMode.cs +++ b/src/OpenTK/Platform/Egl/EglGraphicsMode.cs @@ -47,11 +47,23 @@ namespace OpenTK.Platform.Egl ColorFormat color, int depth, int stencil, int samples, ColorFormat accum, int buffers, bool stereo, RenderableFlags renderable_flags) + { + return SelectGraphicsMode( + SurfaceType.WINDOW_BIT, + window.Display, + color, depth, stencil, samples, accum, buffers, stereo, renderable_flags + ); + } + + public GraphicsMode SelectGraphicsMode(SurfaceType surface_type, + IntPtr display, ColorFormat color, int depth, int stencil, + int samples, ColorFormat accum, int buffers, bool stereo, + RenderableFlags renderable_flags) { IntPtr[] configs = new IntPtr[1]; int[] attribList = new int[] { - Egl.SURFACE_TYPE, Egl.WINDOW_BIT, + Egl.SURFACE_TYPE, (int) surface_type, Egl.RENDERABLE_TYPE, (int)renderable_flags, Egl.RED_SIZE, color.Red, @@ -68,8 +80,6 @@ namespace OpenTK.Platform.Egl Egl.NONE, }; - IntPtr display = window.Display; - int num_configs; if (!Egl.ChooseConfig(display, attribList, configs, configs.Length, out num_configs) || num_configs == 0) { @@ -92,5 +102,6 @@ namespace OpenTK.Platform.Egl return new GraphicsMode(active_config, new ColorFormat(r, g, b, a), d, s, sample_buffers > 0 ? samples : 0, 0, 2, false); } + } } diff --git a/src/OpenTK/Platform/Egl/EglWindowInfo.cs b/src/OpenTK/Platform/Egl/EglWindowInfo.cs index 10f495be..db73aa3d 100644 --- a/src/OpenTK/Platform/Egl/EglWindowInfo.cs +++ b/src/OpenTK/Platform/Egl/EglWindowInfo.cs @@ -98,20 +98,66 @@ namespace OpenTK.Platform.Egl public void CreatePbufferSurface(IntPtr config) { - Surface = Egl.CreatePbufferSurface(Display, config, null); + int[] attribs = new int[]{Egl.NONE}; + Surface = Egl.CreatePbufferSurface(Display, config, attribs); + if (Surface == IntPtr.Zero) + { + throw new GraphicsContextException(String.Format( + "[EGL] Failed to create pbuffer surface, error {0}.", Egl.GetError())); + } + } + + public void CreatePbufferSurface(IntPtr config, int width, int height) + { + if (surface != IntPtr.Zero) + { + DestroySurface(); + } + CreatePbufferSurface(config, width, height, out surface); + } + + public void CreatePbufferSurface(IntPtr config, int width, int height, out IntPtr surface_) + { + int[] attribs = new int[] + { + Egl.WIDTH, width, + Egl.HEIGHT, height, + Egl.TEXTURE_TARGET, Egl.TEXTURE_2D, + Egl.TEXTURE_FORMAT, Egl.TEXTURE_RGBA, + Egl.NONE + }; + surface_ = Egl.CreatePbufferSurface(Display, config, attribs); + if (surface_ == IntPtr.Zero) + { + throw new GraphicsContextException(String.Format( + "[EGL] Failed to create pbuffer surface, error {0}.", Egl.GetError())); + } + } public void DestroySurface() { - if (Surface != IntPtr.Zero) - { - if (Egl.GetCurrentSurface(Egl.DRAW) == Surface) - Egl.MakeCurrent(Display, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); + DestroySurface(ref surface); + } - if (!Egl.DestroySurface(Display, Surface)) - Debug.Print("[Warning] Failed to destroy {0}:{1}.", Surface.GetType().Name, Surface); - Surface = IntPtr.Zero; + public void DestroySurface(ref IntPtr surface_) + { + if (surface_ == IntPtr.Zero) + { + return; } + + if (Egl.GetCurrentSurface(Egl.DRAW) == Surface) + Egl.MakeCurrent(Display, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); + + if (Egl.DestroySurface(Display, surface_)) + { + surface_ = IntPtr.Zero; + return; + } + + Debug.Print("[Warning] Failed to destroy {0}:{1}.", Surface.GetType().Name, Surface); + Surface = IntPtr.Zero; } public void TerminateDisplay()