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()