Organized GL test contexts
This commit is contained in:
Matthew Leibowitz 2017-02-16 16:07:34 +02:00
Родитель 8444644b8e
Коммит 1dbb79b2af
25 изменённых файлов: 1246 добавлений и 503 удалений

Просмотреть файл

@ -101,14 +101,65 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\Tests\CglContext.cs">
<Link>CglContext.cs</Link>
<Compile Include="..\Tests\GlContexts\Cgl\Cgl.cs">
<Link>GlContexts\Cgl\Cgl.cs</Link>
</Compile>
<Compile Include="..\Tests\GlxContext.cs">
<Link>GlxContext.cs</Link>
<Compile Include="..\Tests\GlContexts\Cgl\CglContext.cs">
<Link>GlContexts\Cgl\CglContext.cs</Link>
</Compile>
<Compile Include="..\Tests\SKCodecTest.cs">
<Link>SKCodecTest.cs</Link>
<Compile Include="..\Tests\GlContexts\Cgl\CGLError.cs">
<Link>GlContexts\Cgl\CGLError.cs</Link>
</Compile>
<Compile Include="..\Tests\GlContexts\Cgl\CGLOpenGLProfile.cs">
<Link>GlContexts\Cgl\CGLOpenGLProfile.cs</Link>
</Compile>
<Compile Include="..\Tests\GlContexts\Cgl\CGLPixelFormatAttribute.cs">
<Link>GlContexts\Cgl\CGLPixelFormatAttribute.cs</Link>
</Compile>
<Compile Include="..\Tests\GlContexts\GlContext.cs">
<Link>GlContexts\GlContext.cs</Link>
</Compile>
<Compile Include="..\Tests\GlContexts\Glx\Glx.cs">
<Link>GlContexts\Glx\Glx.cs</Link>
</Compile>
<Compile Include="..\Tests\GlContexts\Glx\GlxContext.cs">
<Link>GlContexts\Glx\GlxContext.cs</Link>
</Compile>
<Compile Include="..\Tests\GlContexts\Glx\Xlib.cs">
<Link>GlContexts\Glx\Xlib.cs</Link>
</Compile>
<Compile Include="..\Tests\GlContexts\Glx\XVisualClass.cs">
<Link>GlContexts\Glx\XVisualClass.cs</Link>
</Compile>
<Compile Include="..\Tests\GlContexts\Glx\XVisualInfo.cs">
<Link>GlContexts\Glx\XVisualInfo.cs</Link>
</Compile>
<Compile Include="..\Tests\GlContexts\Wgl\Gdi32.cs">
<Link>GlContexts\Wgl\Gdi32.cs</Link>
</Compile>
<Compile Include="..\Tests\GlContexts\Wgl\Kernel32.cs">
<Link>GlContexts\Wgl\Kernel32.cs</Link>
</Compile>
<Compile Include="..\Tests\GlContexts\Wgl\PIXELFORMATDESCRIPTOR.cs">
<Link>GlContexts\Wgl\PIXELFORMATDESCRIPTOR.cs</Link>
</Compile>
<Compile Include="..\Tests\GlContexts\Wgl\RECT.cs">
<Link>GlContexts\Wgl\RECT.cs</Link>
</Compile>
<Compile Include="..\Tests\GlContexts\Wgl\User32.cs">
<Link>GlContexts\Wgl\User32.cs</Link>
</Compile>
<Compile Include="..\Tests\GlContexts\Wgl\Wgl.cs">
<Link>GlContexts\Wgl\Wgl.cs</Link>
</Compile>
<Compile Include="..\Tests\GlContexts\Wgl\WglContext.cs">
<Link>GlContexts\Wgl\WglContext.cs</Link>
</Compile>
<Compile Include="..\Tests\GlContexts\Wgl\WindowStyles.cs">
<Link>GlContexts\Wgl\WindowStyles.cs</Link>
</Compile>
<Compile Include="..\Tests\GlContexts\Wgl\WNDCLASS.cs">
<Link>GlContexts\Wgl\WNDCLASS.cs</Link>
</Compile>
<Compile Include="..\Tests\GRContextTest.cs">
<Link>GRContextTest.cs</Link>
@ -116,46 +167,49 @@
<Compile Include="..\Tests\GRGlInterfaceTest.cs">
<Link>GRGlInterfaceTest.cs</Link>
</Compile>
<Compile Include="..\Tests\SKStringTest.cs">
<Link>SKStringTest.cs</Link>
<Compile Include="..\Tests\SKBasicTypesTest.cs">
<Link>SKBasicTypesTest.cs</Link>
</Compile>
<Compile Include="..\Tests\SKBitmapTest.cs">
<Link>SKBitmapTest.cs</Link>
</Compile>
<Compile Include="..\Tests\SKCodecTest.cs">
<Link>SKCodecTest.cs</Link>
</Compile>
<Compile Include="..\Tests\SKColorTableTest.cs">
<Link>SKColorTableTest.cs</Link>
</Compile>
<Compile Include="..\Tests\SKColorTest.cs">
<Link>SKColorTest.cs</Link>
</Compile>
<Compile Include="..\Tests\SKDataTest.cs">
<Link>SKDataTest.cs</Link>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="..\Tests\SKManagedStreamTest.cs">
<Link>SKManagedStreamTest.cs</Link>
</Compile>
<Compile Include="..\Tests\SKSurfaceTest.cs">
<Link>SKSurfaceTest.cs</Link>
</Compile>
<Compile Include="..\Tests\SKTest.cs">
<Link>SKTest.cs</Link>
</Compile>
<Compile Include="..\Tests\SKTypefaceTest.cs">
<Link>SKTypefaceTest.cs</Link>
</Compile>
<Compile Include="..\Tests\SKPaintTest.cs">
<Link>SKPaintTest.cs</Link>
</Compile>
<Compile Include="..\Tests\SKPathTest.cs">
<Link>SKPathTest.cs</Link>
</Compile>
<Compile Include="..\Tests\SKColorTest.cs">
<Link>SKColorTest.cs</Link>
<Compile Include="..\Tests\SKStringTest.cs">
<Link>SKStringTest.cs</Link>
</Compile>
<Compile Include="..\Tests\SKBasicTypesTest.cs">
<Link>SKBasicTypesTest.cs</Link>
</Compile>
<Compile Include="..\Tests\SKBitmapTest.cs">
<Link>SKBitmapTest.cs</Link>
</Compile>
<Compile Include="..\Tests\SKDataTest.cs">
<Link>SKDataTest.cs</Link>
</Compile>
<Compile Include="..\Tests\SKColorTableTest.cs">
<Link>SKColorTableTest.cs</Link>
<Compile Include="..\Tests\SKSurfaceTest.cs">
<Link>SKSurfaceTest.cs</Link>
</Compile>
<Compile Include="..\Tests\SKSvgTest.cs">
<Link>SKSvgTest.cs</Link>
</Compile>
<Compile Include="..\Tests\SKTest.cs">
<Link>SKTest.cs</Link>
</Compile>
<Compile Include="..\Tests\SKTypefaceTest.cs">
<Link>SKTypefaceTest.cs</Link>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="..\Content\fonts\content-font.ttf">

Просмотреть файл

@ -7,7 +7,7 @@
],
"allowUnsafe": true,
"compile": {
"include": "../Tests/*.cs",
"include": "../Tests/**/*.cs",
"excludeFiles":[
"../Tests/SKSurfaceTest.cs"
]

Просмотреть файл

@ -1,134 +0,0 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace SkiaSharp.Tests
{
internal class CglContext : GlContext
{
private IntPtr fContext;
public CglContext()
{
var attributes = new [] {
CGLPixelFormatAttribute.kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute)CGLOpenGLProfile.kCGLOGLPVersion_3_2_Core,
CGLPixelFormatAttribute.kCGLPFADoubleBuffer,
CGLPixelFormatAttribute.kCGLPFANone
};
IntPtr pixFormat;
int npix;
Cgl.CGLChoosePixelFormat(attributes, out pixFormat, out npix);
if (pixFormat == IntPtr.Zero) {
throw new Exception("CGLChoosePixelFormat failed.");
}
Cgl.CGLCreateContext(pixFormat, IntPtr.Zero, out fContext);
Cgl.CGLReleasePixelFormat(pixFormat);
if (fContext == IntPtr.Zero) {
throw new Exception("CGLCreateContext failed.");
}
}
public override void MakeCurrent()
{
Cgl.CGLSetCurrentContext(fContext);
}
public override void SwapBuffers()
{
Cgl.CGLFlushDrawable(fContext);
}
public override void Destroy()
{
if (fContext != IntPtr.Zero) {
Cgl.CGLReleaseContext(fContext);
fContext = IntPtr.Zero;
}
}
}
internal enum CGLOpenGLProfile {
kCGLOGLPVersion_Legacy = 0x1000,
kCGLOGLPVersion_3_2_Core = 0x3200,
kCGLOGLPVersion_GL3_Core = 0x3200,
kCGLOGLPVersion_GL4_Core = 0x4100,
}
internal enum CGLPixelFormatAttribute {
kCGLPFANone = 0,
kCGLPFAAllRenderers = 1,
kCGLPFATripleBuffer = 3,
kCGLPFADoubleBuffer = 5,
kCGLPFAColorSize = 8,
kCGLPFAAlphaSize = 11,
kCGLPFADepthSize = 12,
kCGLPFAStencilSize = 13,
kCGLPFAMinimumPolicy = 51,
kCGLPFAMaximumPolicy = 52,
kCGLPFASampleBuffers = 55,
kCGLPFASamples = 56,
kCGLPFAColorFloat = 58,
kCGLPFAMultisample = 59,
kCGLPFASupersample = 60,
kCGLPFASampleAlpha = 61,
kCGLPFARendererID = 70,
kCGLPFANoRecovery = 72,
kCGLPFAAccelerated = 73,
kCGLPFAClosestPolicy = 74,
kCGLPFABackingStore = 76,
kCGLPFABackingVolatile = 77,
kCGLPFADisplayMask = 84,
kCGLPFAAllowOfflineRenderers = 96,
kCGLPFAAcceleratedCompute = 97,
kCGLPFAOpenGLProfile = 99,
kCGLPFASupportsAutomaticGraphicsSwitching = 101,
kCGLPFAVirtualScreenCount = 128,
}
internal enum CGLError {
kCGLNoError = 0,
kCGLBadAttribute = 10000,
kCGLBadProperty = 10001,
kCGLBadPixelFormat = 10002,
kCGLBadRendererInfo = 10003,
kCGLBadContext = 10004,
kCGLBadDrawable = 10005,
kCGLBadDisplay = 10006,
kCGLBadState = 10007,
kCGLBadValue = 10008,
kCGLBadMatch = 10009,
kCGLBadEnumeration = 10010,
kCGLBadOffScreen = 10011,
kCGLBadFullScreen = 10012,
kCGLBadWindow = 10013,
kCGLBadAddress = 10014,
kCGLBadCodeModule = 10015,
kCGLBadAlloc = 10016,
kCGLBadConnection = 10017,
}
internal class Cgl
{
private const string libGL = "/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL";
[DllImport(libGL)]
public extern static void CGLGetVersion(out int majorvers, out int minorvers);
[DllImport(libGL)]
public extern static CGLError CGLChoosePixelFormat([In] CGLPixelFormatAttribute[] attribs, out IntPtr pix, out int npix);
[DllImport(libGL)]
public extern static CGLError CGLCreateContext(IntPtr pix, IntPtr share, out IntPtr ctx);
[DllImport(libGL)]
public extern static CGLError CGLReleasePixelFormat(IntPtr pix);
[DllImport(libGL)]
public extern static CGLError CGLSetCurrentContext(IntPtr ctx);
[DllImport(libGL)]
public extern static void CGLReleaseContext(IntPtr ctx);
[DllImport(libGL)]
public extern static CGLError CGLFlushDrawable(IntPtr ctx);
}
}

Просмотреть файл

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace SkiaSharp.Tests
{
internal enum CGLError {
kCGLNoError = 0,
kCGLBadAttribute = 10000,
kCGLBadProperty = 10001,
kCGLBadPixelFormat = 10002,
kCGLBadRendererInfo = 10003,
kCGLBadContext = 10004,
kCGLBadDrawable = 10005,
kCGLBadDisplay = 10006,
kCGLBadState = 10007,
kCGLBadValue = 10008,
kCGLBadMatch = 10009,
kCGLBadEnumeration = 10010,
kCGLBadOffScreen = 10011,
kCGLBadFullScreen = 10012,
kCGLBadWindow = 10013,
kCGLBadAddress = 10014,
kCGLBadCodeModule = 10015,
kCGLBadAlloc = 10016,
kCGLBadConnection = 10017,
}
}

Просмотреть файл

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace SkiaSharp.Tests
{
internal enum CGLOpenGLProfile {
kCGLOGLPVersion_Legacy = 0x1000,
kCGLOGLPVersion_3_2_Core = 0x3200,
kCGLOGLPVersion_GL3_Core = 0x3200,
kCGLOGLPVersion_GL4_Core = 0x4100,
}
}

Просмотреть файл

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace SkiaSharp.Tests
{
internal enum CGLPixelFormatAttribute {
kCGLPFANone = 0,
kCGLPFAAllRenderers = 1,
kCGLPFATripleBuffer = 3,
kCGLPFADoubleBuffer = 5,
kCGLPFAColorSize = 8,
kCGLPFAAlphaSize = 11,
kCGLPFADepthSize = 12,
kCGLPFAStencilSize = 13,
kCGLPFAMinimumPolicy = 51,
kCGLPFAMaximumPolicy = 52,
kCGLPFASampleBuffers = 55,
kCGLPFASamples = 56,
kCGLPFAColorFloat = 58,
kCGLPFAMultisample = 59,
kCGLPFASupersample = 60,
kCGLPFASampleAlpha = 61,
kCGLPFARendererID = 70,
kCGLPFANoRecovery = 72,
kCGLPFAAccelerated = 73,
kCGLPFAClosestPolicy = 74,
kCGLPFABackingStore = 76,
kCGLPFABackingVolatile = 77,
kCGLPFADisplayMask = 84,
kCGLPFAAllowOfflineRenderers = 96,
kCGLPFAAcceleratedCompute = 97,
kCGLPFAOpenGLProfile = 99,
kCGLPFASupportsAutomaticGraphicsSwitching = 101,
kCGLPFAVirtualScreenCount = 128,
}
}

Просмотреть файл

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace SkiaSharp.Tests
{
internal class Cgl
{
private const string libGL = "/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL";
[DllImport(libGL)]
public extern static void CGLGetVersion(out int majorvers, out int minorvers);
[DllImport(libGL)]
public extern static CGLError CGLChoosePixelFormat([In] CGLPixelFormatAttribute[] attribs, out IntPtr pix, out int npix);
[DllImport(libGL)]
public extern static CGLError CGLCreateContext(IntPtr pix, IntPtr share, out IntPtr ctx);
[DllImport(libGL)]
public extern static CGLError CGLReleasePixelFormat(IntPtr pix);
[DllImport(libGL)]
public extern static CGLError CGLSetCurrentContext(IntPtr ctx);
[DllImport(libGL)]
public extern static void CGLReleaseContext(IntPtr ctx);
[DllImport(libGL)]
public extern static CGLError CGLFlushDrawable(IntPtr ctx);
}
}

Просмотреть файл

@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace SkiaSharp.Tests
{
internal class CglContext : GlContext
{
private IntPtr fContext;
public CglContext()
{
var attributes = new [] {
CGLPixelFormatAttribute.kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute)CGLOpenGLProfile.kCGLOGLPVersion_3_2_Core,
CGLPixelFormatAttribute.kCGLPFADoubleBuffer,
CGLPixelFormatAttribute.kCGLPFANone
};
IntPtr pixFormat;
int npix;
Cgl.CGLChoosePixelFormat(attributes, out pixFormat, out npix);
if (pixFormat == IntPtr.Zero) {
throw new Exception("CGLChoosePixelFormat failed.");
}
Cgl.CGLCreateContext(pixFormat, IntPtr.Zero, out fContext);
Cgl.CGLReleasePixelFormat(pixFormat);
if (fContext == IntPtr.Zero) {
throw new Exception("CGLCreateContext failed.");
}
}
public override void MakeCurrent()
{
Cgl.CGLSetCurrentContext(fContext);
}
public override void SwapBuffers()
{
Cgl.CGLFlushDrawable(fContext);
}
public override void Destroy()
{
if (fContext != IntPtr.Zero) {
Cgl.CGLReleaseContext(fContext);
fContext = IntPtr.Zero;
}
}
}
}

Просмотреть файл

@ -0,0 +1,16 @@
using System;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
namespace SkiaSharp.Tests
{
public abstract class GlContext : IDisposable
{
public abstract void MakeCurrent();
public abstract void SwapBuffers();
public abstract void Destroy();
void IDisposable.Dispose() => Destroy();
}
}

Просмотреть файл

@ -0,0 +1,126 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace SkiaSharp.Tests
{
internal class Glx
{
private const string libGL = "libGL";
public const int GLX_USE_GL = 1;
public const int GLX_BUFFER_SIZE = 2;
public const int GLX_LEVEL = 3;
public const int GLX_RGBA = 4;
public const int GLX_DOUBLEBUFFER = 5;
public const int GLX_STEREO = 6;
public const int GLX_AUX_BUFFERS = 7;
public const int GLX_RED_SIZE = 8;
public const int GLX_GREEN_SIZE = 9;
public const int GLX_BLUE_SIZE = 10;
public const int GLX_ALPHA_SIZE = 11;
public const int GLX_DEPTH_SIZE = 12;
public const int GLX_STENCIL_SIZE = 13;
public const int GLX_ACCUM_RED_SIZE = 14;
public const int GLX_ACCUM_GREEN_SIZE = 15;
public const int GLX_ACCUM_BLUE_SIZE = 16;
public const int GLX_ACCUM_ALPHA_SIZE = 17;
public const int GLX_DRAWABLE_TYPE = 0x8010;
public const int GLX_RENDER_TYPE = 0x8011;
public const int GLX_X_RENDERABLE = 0x8012;
public const int GLX_RGBA_TYPE = 0x8014;
public const int GLX_COLOR_INDEX_TYPE = 0x8015;
public const int GLX_PIXMAP_BIT = 0x00000002;
public const int GLX_RGBA_BIT = 0x00000001;
public const int GLX_SAMPLE_BUFFERS = 0x186a0;
public const int GLX_SAMPLES = 0x186a1;
public const int GLX_CONTEXT_DEBUG_BIT_ARB = 0x00000001;
public const int GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB = 0x00000002;
public const int GLX_CONTEXT_MAJOR_VERSION_ARB = 0x2091;
public const int GLX_CONTEXT_MINOR_VERSION_ARB = 0x2092;
public const int GLX_CONTEXT_FLAGS_ARB = 0x2094;
public const int GLX_CONTEXT_CORE_PROFILE_BIT_ARB = 0x00000001;
public const int GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB = 0x00000002;
public const int GLX_CONTEXT_PROFILE_MASK_ARB = 0x9126;
static Glx()
{
var ptr = glXGetProcAddressARB("glXCreateContextAttribsARB");
if (ptr != IntPtr.Zero) {
glXCreateContextAttribsARB = (glXCreateContextAttribsARBDelegate)Marshal.GetDelegateForFunctionPointer(ptr, typeof(glXCreateContextAttribsARBDelegate));
}
}
[DllImport(libGL)]
public extern static bool glXQueryVersion(IntPtr dpy, out int maj, out int min);
[DllImport(libGL)]
public extern static IntPtr glXChooseFBConfig(IntPtr dpy, int screen, [In] int[] attribList, out int nitems);
public static IntPtr[] ChooseFBConfig(IntPtr dpy, int screen, int[] attribList)
{
int nitems;
var fbcArrayPtr = glXChooseFBConfig(dpy, screen, attribList, out nitems);
var fbcArray = new IntPtr[nitems];
Marshal.Copy(fbcArrayPtr, fbcArray, 0, nitems);
Xlib.XFree(fbcArrayPtr);
return fbcArray;
}
[DllImport(libGL)]
public extern static IntPtr glXGetVisualFromFBConfig(IntPtr dpy, IntPtr config);
public static XVisualInfo GetVisualFromFBConfig(IntPtr dpy, IntPtr config)
{
var visualPtr = glXGetVisualFromFBConfig(dpy, config);
if (visualPtr == IntPtr.Zero) {
throw new Exception("Failed to retrieve visual from framebuffer config.");
}
var visual = (XVisualInfo) Marshal.PtrToStructure(visualPtr, typeof(XVisualInfo));
Xlib.XFree(visualPtr);
return visual;
}
[DllImport(libGL)]
public extern static bool glXMakeCurrent(IntPtr dpy, IntPtr drawable, IntPtr ctx);
[DllImport(libGL)]
public extern static bool glXSwapBuffers(IntPtr dpy, IntPtr drawable);
[DllImport(libGL)]
public extern static bool glXIsDirect(IntPtr dpy, IntPtr ctx);
[DllImport(libGL)]
public extern static int glXGetFBConfigAttrib(IntPtr dpy, IntPtr config, int attribute, out int value);
[DllImport(libGL)]
public extern static IntPtr glXCreateGLXPixmap(IntPtr dpy, ref XVisualInfo visual, IntPtr pixmap);
[DllImport(libGL)]
public extern static void glXDestroyGLXPixmap(IntPtr dpy, IntPtr pixmap);
[DllImport(libGL)]
public extern static void glXDestroyContext(IntPtr dpy, IntPtr ctx);
[DllImport(libGL)]
public extern static IntPtr glXQueryExtensionsString(IntPtr dpy, int screen);
public static string QueryExtensionsString(IntPtr dpy, int screen)
{
return Marshal.PtrToStringAnsi(glXQueryExtensionsString(dpy, screen));
}
public static string[] QueryExtensions(IntPtr dpy, int screen)
{
var str = QueryExtensionsString(dpy, screen);
if (string.IsNullOrEmpty(str)) {
return new string[0];
}
return str.Split(' ');
}
[DllImport(libGL)]
public extern static IntPtr glXGetProcAddressARB(string procname);
[DllImport(libGL)]
public extern static IntPtr glXCreateNewContext(IntPtr dpy, IntPtr config, int renderType, IntPtr shareList, int direct);
public static readonly glXCreateContextAttribsARBDelegate glXCreateContextAttribsARB;
public delegate IntPtr glXCreateContextAttribsARBDelegate(IntPtr dpy, IntPtr config, IntPtr share_context, int direct, int[] attrib_list);
}
}

Просмотреть файл

@ -0,0 +1,144 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace SkiaSharp.Tests
{
internal class GlxContext : GlContext
{
private IntPtr fDisplay;
private IntPtr fPixmap;
private IntPtr fGlxPixmap;
private IntPtr fContext;
public GlxContext()
{
fDisplay = Xlib.XOpenDisplay(null);
if (fDisplay == IntPtr.Zero) {
Destroy();
throw new Exception("Failed to open X display.");
}
var visualAttribs = new [] {
Glx.GLX_X_RENDERABLE, Xlib.True,
Glx.GLX_DRAWABLE_TYPE, Glx.GLX_PIXMAP_BIT,
Glx.GLX_RENDER_TYPE, Glx.GLX_RGBA_BIT,
// Glx.GLX_DOUBLEBUFFER, Xlib.True,
Glx.GLX_RED_SIZE, 8,
Glx.GLX_GREEN_SIZE, 8,
Glx.GLX_BLUE_SIZE, 8,
Glx.GLX_ALPHA_SIZE, 8,
Glx.GLX_DEPTH_SIZE, 24,
Glx.GLX_STENCIL_SIZE, 8,
// Glx.GLX_SAMPLE_BUFFERS, 1,
// Glx.GLX_SAMPLES, 4,
Xlib.None
};
int glxMajor, glxMinor;
if (!Glx.glXQueryVersion(fDisplay, out glxMajor, out glxMinor) ||
(glxMajor < 1) ||
(glxMajor == 1 && glxMinor < 3)) {
Destroy();
throw new Exception("GLX version 1.3 or higher required.");
}
var fbc = Glx.ChooseFBConfig(fDisplay, Xlib.XDefaultScreen(fDisplay), visualAttribs);
if (fbc.Length == 0) {
Destroy();
throw new Exception("Failed to retrieve a framebuffer config.");
}
var bestFBC = IntPtr.Zero;
var bestNumSamp = -1;
for (int i = 0; i < fbc.Length; i++) {
int sampleBuf, samples;
Glx.glXGetFBConfigAttrib(fDisplay, fbc[i], Glx.GLX_SAMPLE_BUFFERS, out sampleBuf);
Glx.glXGetFBConfigAttrib(fDisplay, fbc[i], Glx.GLX_SAMPLES, out samples);
if (bestFBC == IntPtr.Zero || (sampleBuf > 0 && samples > bestNumSamp)) {
bestFBC = fbc[i];
bestNumSamp = samples;
}
}
var vi = Glx.GetVisualFromFBConfig(fDisplay, bestFBC);
fPixmap = Xlib.XCreatePixmap(fDisplay, Xlib.XRootWindow(fDisplay, vi.screen), 10, 10, (uint)vi.depth);
if (fPixmap == IntPtr.Zero) {
Destroy();
throw new Exception("Failed to create pixmap.");
}
fGlxPixmap = Glx.glXCreateGLXPixmap(fDisplay, ref vi, fPixmap);
var glxExts = Glx.QueryExtensions(fDisplay, Xlib.XDefaultScreen(fDisplay));
if (Array.IndexOf(glxExts, "GLX_ARB_create_context") == -1 ||
Glx.glXCreateContextAttribsARB == null) {
Console.WriteLine("OpenGL 3.0 doesn't seem to be available.");
fContext = Glx.glXCreateNewContext(fDisplay, bestFBC, Glx.GLX_RGBA_TYPE, IntPtr.Zero, Xlib.True);
} else {
// Let's just use OpenGL 3.0, but we could try find the highest
int major = 3, minor = 0;
var flags = new List<int> {
Glx.GLX_CONTEXT_MAJOR_VERSION_ARB, major,
Glx.GLX_CONTEXT_MINOR_VERSION_ARB, minor,
};
if (major > 2) {
flags.AddRange(new[] {
Glx.GLX_CONTEXT_PROFILE_MASK_ARB, Glx.GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
});
}
flags.Add(Xlib.None);
fContext = Glx.glXCreateContextAttribsARB(fDisplay, bestFBC, IntPtr.Zero, Xlib.True, flags.ToArray());
}
if (fContext == IntPtr.Zero) {
Destroy();
throw new Exception("Failed to create an OpenGL context.");
}
if (!Glx.glXIsDirect(fDisplay, fContext)) {
Console.WriteLine("Obtained indirect GLX rendering context.");
}
}
public override void MakeCurrent()
{
if (!Glx.glXMakeCurrent(fDisplay, fGlxPixmap, fContext)) {
Destroy();
throw new Exception("Failed to set the context.");
}
}
public override void SwapBuffers()
{
Glx.glXSwapBuffers(fDisplay, fGlxPixmap);
}
public override void Destroy()
{
if (fDisplay != IntPtr.Zero) {
Glx.glXMakeCurrent(fDisplay, IntPtr.Zero, IntPtr.Zero);
if (fContext != IntPtr.Zero) {
Glx.glXDestroyContext(fDisplay, fContext);
fContext = IntPtr.Zero;
}
if (fGlxPixmap != IntPtr.Zero) {
Glx.glXDestroyGLXPixmap(fDisplay, fGlxPixmap);
fGlxPixmap = IntPtr.Zero;
}
if (fPixmap != IntPtr.Zero) {
Xlib.XFreePixmap(fDisplay, fPixmap);
fPixmap = IntPtr.Zero;
}
fDisplay = IntPtr.Zero;
}
}
}
}

Просмотреть файл

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace SkiaSharp.Tests
{
internal enum XVisualClass : int {
StaticGray = 0,
GrayScale = 1,
StaticColor = 2,
PseudoColor = 3,
TrueColor = 4,
DirectColor = 5
}
}

Просмотреть файл

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace SkiaSharp.Tests
{
[StructLayout(LayoutKind.Sequential)]
internal struct XVisualInfo
{
public IntPtr visual;
public IntPtr visualid;
public int screen;
public int depth;
public XVisualClass c_class;
public ulong red_mask;
public ulong green_mask;
public ulong blue_mask;
public int colormap_size;
public int bits_per_rgb;
}
}

Просмотреть файл

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace SkiaSharp.Tests
{
internal class Xlib
{
private const string libX11 = "libX11";
public const int None = 0;
public const int True = 1;
public const int False = 0;
[DllImport(libX11)]
public extern static IntPtr XOpenDisplay(string display_name);
[DllImport(libX11)]
public extern static int XFree(IntPtr data);
[DllImport(libX11)]
public extern static int XDefaultScreen(IntPtr display);
[DllImport(libX11)]
public extern static IntPtr XRootWindow(IntPtr display, int screen);
[DllImport(libX11)]
public extern static IntPtr XCreatePixmap(IntPtr display, IntPtr d, uint width, uint height, uint depth);
[DllImport(libX11)]
public extern static IntPtr XFreePixmap(IntPtr display, IntPtr pixmap);
}
}

Просмотреть файл

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace SkiaSharp.Tests
{
internal class Gdi32
{
private const string gdi32 = "gdi32.dll";
public const byte PFD_TYPE_RGBA = 0;
public const byte PFD_MAIN_PLANE = 0;
public const uint PFD_DRAW_TO_WINDOW = 0x00000004;
public const uint PFD_SUPPORT_OPENGL = 0x00000020;
[DllImport(gdi32, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetPixelFormat(IntPtr hdc, int iPixelFormat, [In] ref PIXELFORMATDESCRIPTOR ppfd);
[DllImport(gdi32, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
public static extern int ChoosePixelFormat(IntPtr hdc, [In] ref PIXELFORMATDESCRIPTOR ppfd);
[DllImport(gdi32, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SwapBuffers(IntPtr hdc);
}
}

Просмотреть файл

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace SkiaSharp.Tests
{
internal class Kernel32
{
private const string kernel32 = "kernel32.dll";
static Kernel32()
{
CurrentModuleHandle = Kernel32.GetModuleHandle(null);
if (CurrentModuleHandle == IntPtr.Zero)
{
throw new Exception("Could not get module handle.");
}
}
public static IntPtr CurrentModuleHandle { get; }
[DllImport(kernel32, CallingConvention = CallingConvention.Winapi, BestFitMapping = false, ThrowOnUnmappableChar = true)]
public static extern IntPtr GetModuleHandle([MarshalAs(UnmanagedType.LPTStr)] string lpModuleName);
}
}

Просмотреть файл

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace SkiaSharp.Tests
{
[StructLayout(LayoutKind.Sequential)]
internal struct PIXELFORMATDESCRIPTOR
{
public ushort nSize;
public ushort nVersion;
public uint dwFlags;
public byte iPixelType;
public byte cColorBits;
public byte cRedBits;
public byte cRedShift;
public byte cGreenBits;
public byte cGreenShift;
public byte cBlueBits;
public byte cBlueShift;
public byte cAlphaBits;
public byte cAlphaShift;
public byte cAccumBits;
public byte cAccumRedBits;
public byte cAccumGreenBits;
public byte cAccumBlueBits;
public byte cAccumAlphaBits;
public byte cDepthBits;
public byte cStencilBits;
public byte cAuxBuffers;
public byte iLayerType;
public byte bReserved;
public int dwLayerMask;
public int dwVisibleMask;
public int dwDamageMask;
}
}

Просмотреть файл

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace SkiaSharp.Tests
{
[StructLayout(LayoutKind.Sequential)]
internal struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
}

Просмотреть файл

@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace SkiaSharp.Tests
{
internal class User32
{
private const string user32 = "user32.dll";
public const uint IDC_ARROW = 32512;
public const uint IDI_APPLICATION = 32512;
public const uint IDI_WINLOGO = 32517;
public const int SW_HIDE = 0;
public const uint CS_VREDRAW = 0x1;
public const uint CS_HREDRAW = 0x2;
public const uint CS_OWNDC = 0x20;
public const uint WS_EX_CLIENTEDGE = 0x00000200;
[DllImport(user32, CallingConvention = CallingConvention.Winapi, SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)]
public static extern ushort RegisterClass(ref WNDCLASS lpWndClass);
[DllImport(user32, CallingConvention = CallingConvention.Winapi, SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)]
public static extern ushort UnregisterClass([MarshalAs(UnmanagedType.LPTStr)] string lpClassName, IntPtr hInstance);
[DllImport(user32, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
public static extern IntPtr LoadCursor(IntPtr hInstance, int lpCursorName);
[DllImport(user32, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
public static extern IntPtr LoadIcon(IntPtr hInstance, IntPtr lpIconName);
[DllImport(user32, CallingConvention = CallingConvention.Winapi)]
public static extern IntPtr DefWindowProc(IntPtr hWnd, uint uMsg, IntPtr wParam, IntPtr lParam);
[DllImport(user32, CallingConvention = CallingConvention.Winapi, SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)]
public static extern IntPtr CreateWindowEx(uint dwExStyle, [MarshalAs(UnmanagedType.LPTStr)] string lpClassName, [MarshalAs(UnmanagedType.LPTStr)] string lpWindowName, WindowStyles dwStyle, int x, int y, int nWidth, int nHeight, IntPtr hWndParent, IntPtr hMenu, IntPtr hInstance, IntPtr lpParam);
public static IntPtr CreateWindow(string lpClassName, string lpWindowName, WindowStyles dwStyle, int x, int y, int nWidth, int nHeight, IntPtr hWndParent, IntPtr hMenu, IntPtr hInstance, IntPtr lpParam)
{
return CreateWindowEx(0, lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam);
}
[DllImport(user32, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
public static extern IntPtr GetDC(IntPtr hWnd);
[DllImport(user32, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);
[DllImport(user32, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DestroyWindow(IntPtr hWnd);
[DllImport(user32, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsWindow(IntPtr hWnd);
[DllImport(user32, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport(user32, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool AdjustWindowRectEx(ref RECT lpRect, WindowStyles dwStyle, bool bMenu, uint dwExStyle);
[DllImport(user32, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ShowWindow(IntPtr hWnd, uint nCmdShow);
}
}

Просмотреть файл

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace SkiaSharp.Tests
{
internal delegate IntPtr WNDPROC(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
[StructLayout(LayoutKind.Sequential)]
internal struct WNDCLASS
{
public uint style;
[MarshalAs(UnmanagedType.FunctionPtr)]
public WNDPROC lpfnWndProc;
public int cbClsExtra;
public int cbWndExtra;
public IntPtr hInstance;
public IntPtr hIcon;
public IntPtr hCursor;
public IntPtr hbrBackground;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpszMenuName;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpszClassName;
}
}

Просмотреть файл

@ -0,0 +1,249 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace SkiaSharp.Tests
{
internal class Wgl
{
private const string opengl32 = "opengl32.dll";
public const int NONE = 0;
public const int FALSE = 0;
public const int TRUE = 1;
public const int WGL_NUMBER_PIXEL_FORMATS_ARB = 0x2000;
public const int WGL_DRAW_TO_WINDOW_ARB = 0x2001;
public const int WGL_DRAW_TO_BITMAP_ARB = 0x2002;
public const int WGL_ACCELERATION_ARB = 0x2003;
public const int WGL_NEED_PALETTE_ARB = 0x2004;
public const int WGL_NEED_SYSTEM_PALETTE_ARB = 0x2005;
public const int WGL_SWAP_LAYER_BUFFERS_ARB = 0x2006;
public const int WGL_SWAP_METHOD_ARB = 0x2007;
public const int WGL_NUMBER_OVERLAYS_ARB = 0x2008;
public const int WGL_NUMBER_UNDERLAYS_ARB = 0x2009;
public const int WGL_TRANSPARENT_ARB = 0x200A;
public const int WGL_TRANSPARENT_RED_VALUE_ARB = 0x2037;
public const int WGL_TRANSPARENT_GREEN_VALUE_ARB = 0x2038;
public const int WGL_TRANSPARENT_BLUE_VALUE_ARB = 0x2039;
public const int WGL_TRANSPARENT_ALPHA_VALUE_ARB = 0x203A;
public const int WGL_TRANSPARENT_INDEX_VALUE_ARB = 0x203B;
public const int WGL_SHARE_DEPTH_ARB = 0x200C;
public const int WGL_SHARE_STENCIL_ARB = 0x200D;
public const int WGL_SHARE_ACCUM_ARB = 0x200E;
public const int WGL_SUPPORT_GDI_ARB = 0x200F;
public const int WGL_SUPPORT_OPENGL_ARB = 0x2010;
public const int WGL_DOUBLE_BUFFER_ARB = 0x2011;
public const int WGL_STEREO_ARB = 0x2012;
public const int WGL_PIXEL_TYPE_ARB = 0x2013;
public const int WGL_COLOR_BITS_ARB = 0x2014;
public const int WGL_RED_BITS_ARB = 0x2015;
public const int WGL_RED_SHIFT_ARB = 0x2016;
public const int WGL_GREEN_BITS_ARB = 0x2017;
public const int WGL_GREEN_SHIFT_ARB = 0x2018;
public const int WGL_BLUE_BITS_ARB = 0x2019;
public const int WGL_BLUE_SHIFT_ARB = 0x201A;
public const int WGL_ALPHA_BITS_ARB = 0x201B;
public const int WGL_ALPHA_SHIFT_ARB = 0x201C;
public const int WGL_ACCUM_BITS_ARB = 0x201D;
public const int WGL_ACCUM_RED_BITS_ARB = 0x201E;
public const int WGL_ACCUM_GREEN_BITS_ARB = 0x201F;
public const int WGL_ACCUM_BLUE_BITS_ARB = 0x2020;
public const int WGL_ACCUM_ALPHA_BITS_ARB = 0x2021;
public const int WGL_DEPTH_BITS_ARB = 0x2022;
public const int WGL_STENCIL_BITS_ARB = 0x2023;
public const int WGL_AUX_BUFFERS_ARB = 0x2024;
public const int WGL_NO_ACCELERATION_ARB = 0x2025;
public const int WGL_GENERIC_ACCELERATION_ARB = 0x2026;
public const int WGL_FULL_ACCELERATION_ARB = 0x2027;
public const int WGL_SWAP_EXCHANGE_ARB = 0x2028;
public const int WGL_SWAP_COPY_ARB = 0x2029;
public const int WGL_SWAP_UNDEFINED_ARB = 0x202A;
public const int WGL_TYPE_RGBA_ARB = 0x202B;
public const int WGL_TYPE_COLORINDEX_ARB = 0x202C;
static Wgl()
{
// save the current GL context
var prevDC = Wgl.wglGetCurrentDC();
var prevGLRC = Wgl.wglGetCurrentContext();
// register the dummy window class
var wc = new WNDCLASS
{
style = (User32.CS_HREDRAW | User32.CS_VREDRAW | User32.CS_OWNDC),
lpfnWndProc = (WNDPROC)User32.DefWindowProc,
cbClsExtra = 0,
cbWndExtra = 0,
hInstance = Kernel32.CurrentModuleHandle,
hCursor = User32.LoadCursor(IntPtr.Zero, (int)User32.IDC_ARROW),
hIcon = User32.LoadIcon(IntPtr.Zero, (IntPtr)User32.IDI_WINLOGO),
hbrBackground = IntPtr.Zero,
lpszMenuName = null,
lpszClassName = "DummyClass"
};
if (User32.RegisterClass(ref wc) == 0)
{
throw new Exception("Could not register dummy class.");
}
// get the the dummy window bounds
var windowRect = new RECT { left = 0, right = 8, top = 0, bottom = 8 };
User32.AdjustWindowRectEx(ref windowRect, WindowStyles.WS_SYSMENU, false, User32.WS_EX_CLIENTEDGE);
// create the dummy window
var dummyWND = User32.CreateWindowEx(
User32.WS_EX_CLIENTEDGE,
"DummyClass",
"DummyWindow",
WindowStyles.WS_CLIPSIBLINGS | WindowStyles.WS_CLIPCHILDREN | WindowStyles.WS_SYSMENU,
0, 0,
windowRect.right - windowRect.left, windowRect.bottom - windowRect.top,
IntPtr.Zero, IntPtr.Zero, Kernel32.CurrentModuleHandle, IntPtr.Zero);
if (dummyWND == IntPtr.Zero)
{
User32.UnregisterClass("DummyClass", Kernel32.CurrentModuleHandle);
throw new Exception("Could not create dummy window.");
}
// get the dummy DC
var dummyDC = User32.GetDC(dummyWND);
// get the dummy pixel format
var dummyPFD = new PIXELFORMATDESCRIPTOR();
dummyPFD.nSize = (ushort)Marshal.SizeOf(dummyPFD);
dummyPFD.nVersion = 1;
dummyPFD.dwFlags = Gdi32.PFD_DRAW_TO_WINDOW | Gdi32.PFD_SUPPORT_OPENGL;
dummyPFD.iPixelType = Gdi32.PFD_TYPE_RGBA;
dummyPFD.cColorBits = 32;
dummyPFD.cDepthBits = 24;
dummyPFD.cStencilBits = 8;
dummyPFD.iLayerType = Gdi32.PFD_MAIN_PLANE;
var dummyFormat = Gdi32.ChoosePixelFormat(dummyDC, ref dummyPFD);
Gdi32.SetPixelFormat(dummyDC, dummyFormat, ref dummyPFD);
// get the dummy GL context
var dummyGLRC = Wgl.wglCreateContext(dummyDC);
if (dummyGLRC == IntPtr.Zero)
{
throw new Exception("Could not create dummy GL context.");
}
Wgl.wglMakeCurrent(dummyDC, dummyGLRC);
// get the extension methods using the dummy context
wglGetExtensionsStringARB = Wgl.wglGetProcAddress<wglGetExtensionsStringARBDelegate>("wglGetExtensionsStringARB");
wglChoosePixelFormatARB = Wgl.wglGetProcAddress<wglChoosePixelFormatARBDelegate>("wglChoosePixelFormatARB");
wglCreatePbufferARB = Wgl.wglGetProcAddress<wglCreatePbufferARBDelegate>("wglCreatePbufferARB");
wglDestroyPbufferARB = Wgl.wglGetProcAddress<wglDestroyPbufferARBDelegate>("wglDestroyPbufferARB");
wglGetPbufferDCARB = Wgl.wglGetProcAddress<wglGetPbufferDCARBDelegate>("wglGetPbufferDCARB");
wglReleasePbufferDCARB = Wgl.wglGetProcAddress<wglReleasePbufferDCARBDelegate>("wglReleasePbufferDCARB");
wglSwapIntervalEXT = Wgl.wglGetProcAddress<wglSwapIntervalEXTDelegate>("wglSwapIntervalEXT");
// GET_PROC(ChoosePixelFormat, ARB);
// GET_PROC(GetPixelFormatAttribiv, ARB);
// GET_PROC(GetPixelFormatAttribfv, ARB);
// GET_PROC(CreateContextAttribs, ARB);
// destroy the dummy GL context
Wgl.wglMakeCurrent(dummyDC, IntPtr.Zero);
Wgl.wglDeleteContext(dummyGLRC);
// destroy the dummy window
User32.DestroyWindow(dummyWND);
User32.UnregisterClass("DummyClass", Kernel32.CurrentModuleHandle);
// reset the initial GL context
Wgl.wglMakeCurrent(prevDC, prevGLRC);
}
public static bool HasExtension(IntPtr dc, string ext)
{
if (ext == "WGL_ARB_extensions_string")
{
return true;
}
return Array.IndexOf(GetExtensionsARB(dc), ext) != -1;
}
public static string GetExtensionsStringARB(IntPtr dc)
{
return Marshal.PtrToStringAnsi(wglGetExtensionsStringARB(dc));
}
public static string[] GetExtensionsARB(IntPtr dc)
{
var str = GetExtensionsStringARB(dc);
if (string.IsNullOrEmpty(str))
{
return new string[0];
}
return str.Split(' ');
}
public static readonly wglGetExtensionsStringARBDelegate wglGetExtensionsStringARB;
public static readonly wglChoosePixelFormatARBDelegate wglChoosePixelFormatARB;
public static readonly wglCreatePbufferARBDelegate wglCreatePbufferARB;
public static readonly wglDestroyPbufferARBDelegate wglDestroyPbufferARB;
public static readonly wglGetPbufferDCARBDelegate wglGetPbufferDCARB;
public static readonly wglReleasePbufferDCARBDelegate wglReleasePbufferDCARB;
public static readonly wglSwapIntervalEXTDelegate wglSwapIntervalEXT;
[DllImport(opengl32, CallingConvention = CallingConvention.Winapi)]
public static extern IntPtr wglGetCurrentDC();
[DllImport(opengl32, CallingConvention = CallingConvention.Winapi)]
public static extern IntPtr wglGetCurrentContext();
[DllImport(opengl32, CallingConvention = CallingConvention.Winapi)]
public static extern IntPtr wglCreateContext(IntPtr hDC);
[DllImport(opengl32, CallingConvention = CallingConvention.Winapi)]
public static extern bool wglMakeCurrent(IntPtr hDC, IntPtr hRC);
[DllImport(opengl32, CallingConvention = CallingConvention.Winapi)]
public static extern bool wglDeleteContext(IntPtr hRC);
[DllImport(opengl32, CallingConvention = CallingConvention.Winapi)]
public static extern IntPtr wglGetProcAddress([MarshalAs(UnmanagedType.LPStr)] string lpszProc);
public static T wglGetProcAddress<T>(string lpszProc)
{
var ptr = wglGetProcAddress(lpszProc);
if (ptr == IntPtr.Zero)
{
throw new Exception("Unable to load proc: " + lpszProc);
}
return (T)(object)Marshal.GetDelegateForFunctionPointer(ptr, typeof(T));
}
}
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
public delegate IntPtr wglGetExtensionsStringARBDelegate(IntPtr dc);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
public delegate bool wglChoosePixelFormatARBDelegate(
IntPtr dc,
[In] int[] attribIList,
[In] float[] attribFList,
uint maxFormats,
[Out] int[] pixelFormats,
out uint numFormats);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
public delegate IntPtr wglCreatePbufferARBDelegate(IntPtr dc, int pixelFormat, int width, int height, [In] int[] attribList);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
public delegate bool wglDestroyPbufferARBDelegate(IntPtr pbuffer);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
public delegate IntPtr wglGetPbufferDCARBDelegate(IntPtr pbuffer);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
public delegate int wglReleasePbufferDCARBDelegate(IntPtr pbuffer, IntPtr dc);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
public delegate bool wglSwapIntervalEXTDelegate(int interval);
}

Просмотреть файл

@ -0,0 +1,163 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace SkiaSharp.Tests
{
internal class WglContext : GlContext
{
private ushort gWC;
private IntPtr fWindow;
private IntPtr fDeviceContext;
private IntPtr fPbuffer;
private IntPtr fPbufferDC;
private IntPtr fPbufferGlContext;
public WglContext()
{
var wc = new WNDCLASS
{
cbClsExtra = 0,
cbWndExtra = 0,
hbrBackground = IntPtr.Zero,
hCursor = User32.LoadCursor(IntPtr.Zero, (int)User32.IDC_ARROW),
hIcon = User32.LoadIcon(IntPtr.Zero, (IntPtr)User32.IDI_APPLICATION),
hInstance = Kernel32.CurrentModuleHandle,
lpfnWndProc = (WNDPROC)User32.DefWindowProc,
lpszClassName = "Griffin",
lpszMenuName = null,
style = User32.CS_HREDRAW | User32.CS_VREDRAW | User32.CS_OWNDC
};
gWC = User32.RegisterClass(ref wc);
if (gWC == 0)
{
throw new Exception("Could not register window class.");
}
fWindow = User32.CreateWindow(
"Griffin",
"The Invisible Man",
WindowStyles.WS_OVERLAPPEDWINDOW,
0, 0,
1, 1,
IntPtr.Zero, IntPtr.Zero, Kernel32.CurrentModuleHandle, IntPtr.Zero);
if (fWindow == IntPtr.Zero)
{
throw new Exception($"Could not create window.");
}
fDeviceContext = User32.GetDC(fWindow);
if (fDeviceContext == IntPtr.Zero)
{
Destroy();
throw new Exception("Could not get device context.");
}
if (!Wgl.HasExtension(fDeviceContext, "WGL_ARB_pixel_format") ||
!Wgl.HasExtension(fDeviceContext, "WGL_ARB_pbuffer"))
{
Destroy();
throw new Exception("DC does not have extensions.");
}
var iAttrs = new int[]
{
Wgl.WGL_ACCELERATION_ARB, Wgl.WGL_FULL_ACCELERATION_ARB,
Wgl.WGL_DRAW_TO_WINDOW_ARB, Wgl.TRUE,
//Wgl.WGL_DOUBLE_BUFFER_ARB, (doubleBuffered ? TRUE : FALSE),
Wgl.WGL_SUPPORT_OPENGL_ARB, Wgl.TRUE,
Wgl.WGL_RED_BITS_ARB, 8,
Wgl.WGL_GREEN_BITS_ARB, 8,
Wgl.WGL_BLUE_BITS_ARB, 8,
Wgl.WGL_ALPHA_BITS_ARB, 8,
Wgl.WGL_STENCIL_BITS_ARB, 8,
Wgl.NONE, Wgl.NONE
};
var piFormats = new int[1];
uint nFormats;
Wgl.wglChoosePixelFormatARB(fDeviceContext, iAttrs, null, (uint)piFormats.Length, piFormats, out nFormats);
if (nFormats == 0)
{
Destroy();
throw new Exception("Could not get pixel formats.");
}
fPbuffer = Wgl.wglCreatePbufferARB(fDeviceContext, piFormats[0], 1, 1, null);
if (fPbuffer == IntPtr.Zero)
{
Destroy();
throw new Exception("Could not create Pbuffer.");
}
fPbufferDC = Wgl.wglGetPbufferDCARB(fPbuffer);
if (fPbufferDC == IntPtr.Zero)
{
Destroy();
throw new Exception("Could not get Pbuffer DC.");
}
var prevDC = Wgl.wglGetCurrentDC();
var prevGLRC = Wgl.wglGetCurrentContext();
fPbufferGlContext = Wgl.wglCreateContext(fPbufferDC);
Wgl.wglMakeCurrent(prevDC, prevGLRC);
if (fPbufferGlContext == IntPtr.Zero)
{
Destroy();
throw new Exception("Could not creeate Pbuffer GL context.");
}
}
public override void MakeCurrent()
{
if (!Wgl.wglMakeCurrent(fPbufferDC, fPbufferGlContext))
{
Destroy();
throw new Exception("Could not set the context.");
}
}
public override void SwapBuffers()
{
if (!Gdi32.SwapBuffers(fPbufferDC))
{
Destroy();
throw new Exception("Could not complete SwapBuffers.");
}
}
public override void Destroy()
{
if (!Wgl.HasExtension(fPbufferDC, "WGL_ARB_pbuffer"))
{
// ASSERT
}
Wgl.wglDeleteContext(fPbufferGlContext);
Wgl.wglReleasePbufferDCARB(fPbuffer, fPbufferDC);
Wgl.wglDestroyPbufferARB(fPbuffer);
if (fWindow != IntPtr.Zero)
{
if (fDeviceContext != IntPtr.Zero)
{
User32.ReleaseDC(fWindow, fDeviceContext);
fDeviceContext = IntPtr.Zero;
}
User32.DestroyWindow(fWindow);
fWindow = IntPtr.Zero;
}
User32.UnregisterClass("Griffin", Kernel32.CurrentModuleHandle);
}
}
}

Просмотреть файл

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace SkiaSharp.Tests
{
[Flags]
internal enum WindowStyles : uint
{
WS_BORDER = 0x800000,
WS_CAPTION = 0xc00000,
WS_CHILD = 0x40000000,
WS_CLIPCHILDREN = 0x2000000,
WS_CLIPSIBLINGS = 0x4000000,
WS_DISABLED = 0x8000000,
WS_DLGFRAME = 0x400000,
WS_GROUP = 0x20000,
WS_HSCROLL = 0x100000,
WS_MAXIMIZE = 0x1000000,
WS_MAXIMIZEBOX = 0x10000,
WS_MINIMIZE = 0x20000000,
WS_MINIMIZEBOX = 0x20000,
WS_OVERLAPPED = 0x0,
WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_SIZEFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
WS_POPUP = 0x80000000u,
WS_POPUPWINDOW = WS_POPUP | WS_BORDER | WS_SYSMENU,
WS_SIZEFRAME = 0x40000,
WS_SYSMENU = 0x80000,
WS_TABSTOP = 0x10000,
WS_VISIBLE = 0x10000000,
WS_VSCROLL = 0x200000
}
}

Просмотреть файл

@ -1,327 +0,0 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace SkiaSharp.Tests
{
internal class GlxContext : GlContext
{
private IntPtr fDisplay;
private IntPtr fPixmap;
private IntPtr fGlxPixmap;
private IntPtr fContext;
public GlxContext()
{
fDisplay = Xlib.XOpenDisplay(null);
if (fDisplay == IntPtr.Zero) {
Destroy();
throw new Exception("Failed to open X display.");
}
var visualAttribs = new [] {
Glx.GLX_X_RENDERABLE, Xlib.True,
Glx.GLX_DRAWABLE_TYPE, Glx.GLX_PIXMAP_BIT,
Glx.GLX_RENDER_TYPE, Glx.GLX_RGBA_BIT,
// Glx.GLX_DOUBLEBUFFER, Xlib.True,
Glx.GLX_RED_SIZE, 8,
Glx.GLX_GREEN_SIZE, 8,
Glx.GLX_BLUE_SIZE, 8,
Glx.GLX_ALPHA_SIZE, 8,
Glx.GLX_DEPTH_SIZE, 24,
Glx.GLX_STENCIL_SIZE, 8,
// Glx.GLX_SAMPLE_BUFFERS, 1,
// Glx.GLX_SAMPLES, 4,
Xlib.None
};
int glxMajor, glxMinor;
if (!Glx.glXQueryVersion(fDisplay, out glxMajor, out glxMinor) ||
(glxMajor < 1) ||
(glxMajor == 1 && glxMinor < 3)) {
Destroy();
throw new Exception("GLX version 1.3 or higher required.");
}
var fbc = Glx.ChooseFBConfig(fDisplay, Xlib.XDefaultScreen(fDisplay), visualAttribs);
if (fbc.Length == 0) {
Destroy();
throw new Exception("Failed to retrieve a framebuffer config.");
}
var bestFBC = IntPtr.Zero;
var bestNumSamp = -1;
for (int i = 0; i < fbc.Length; i++) {
int sampleBuf, samples;
Glx.glXGetFBConfigAttrib(fDisplay, fbc[i], Glx.GLX_SAMPLE_BUFFERS, out sampleBuf);
Glx.glXGetFBConfigAttrib(fDisplay, fbc[i], Glx.GLX_SAMPLES, out samples);
if (bestFBC == IntPtr.Zero || (sampleBuf > 0 && samples > bestNumSamp)) {
bestFBC = fbc[i];
bestNumSamp = samples;
}
}
var vi = Glx.GetVisualFromFBConfig(fDisplay, bestFBC);
fPixmap = Xlib.XCreatePixmap(fDisplay, Xlib.XRootWindow(fDisplay, vi.screen), 10, 10, (uint)vi.depth);
if (fPixmap == IntPtr.Zero) {
Destroy();
throw new Exception("Failed to create pixmap.");
}
fGlxPixmap = Glx.glXCreateGLXPixmap(fDisplay, ref vi, fPixmap);
var glxExts = Glx.QueryExtensions(fDisplay, Xlib.XDefaultScreen(fDisplay));
if (Array.IndexOf(glxExts, "GLX_ARB_create_context") == -1 ||
Glx.glXCreateContextAttribsARB == null) {
Console.WriteLine("OpenGL 3.0 doesn't seem to be available.");
fContext = Glx.glXCreateNewContext(fDisplay, bestFBC, Glx.GLX_RGBA_TYPE, IntPtr.Zero, Xlib.True);
} else {
// Let's just use OpenGL 3.0, but we could try find the highest
int major = 3, minor = 0;
var flags = new List<int> {
Glx.GLX_CONTEXT_MAJOR_VERSION_ARB, major,
Glx.GLX_CONTEXT_MINOR_VERSION_ARB, minor,
};
if (major > 2) {
flags.AddRange(new[] {
Glx.GLX_CONTEXT_PROFILE_MASK_ARB, Glx.GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
});
}
flags.Add(Xlib.None);
fContext = Glx.glXCreateContextAttribsARB(fDisplay, bestFBC, IntPtr.Zero, Xlib.True, flags.ToArray());
}
if (fContext == IntPtr.Zero) {
Destroy();
throw new Exception("Failed to create an OpenGL context.");
}
if (!Glx.glXIsDirect(fDisplay, fContext)) {
Console.WriteLine("Obtained indirect GLX rendering context.");
}
}
public override void MakeCurrent()
{
if (!Glx.glXMakeCurrent(fDisplay, fGlxPixmap, fContext)) {
Destroy();
throw new Exception("Failed to set the context.");
}
}
public override void SwapBuffers()
{
Glx.glXSwapBuffers(fDisplay, fGlxPixmap);
}
public override void Destroy()
{
if (fDisplay != IntPtr.Zero) {
Glx.glXMakeCurrent(fDisplay, IntPtr.Zero, IntPtr.Zero);
if (fContext != IntPtr.Zero) {
Glx.glXDestroyContext(fDisplay, fContext);
fContext = IntPtr.Zero;
}
if (fGlxPixmap != IntPtr.Zero) {
Glx.glXDestroyGLXPixmap(fDisplay, fGlxPixmap);
fGlxPixmap = IntPtr.Zero;
}
if (fPixmap != IntPtr.Zero) {
Xlib.XFreePixmap(fDisplay, fPixmap);
fPixmap = IntPtr.Zero;
}
fDisplay = IntPtr.Zero;
}
}
}
internal class Xlib
{
private const string libX11 = "libX11";
public const int None = 0;
public const int True = 1;
public const int False = 0;
[DllImport(libX11)]
public extern static IntPtr XOpenDisplay(string display_name);
[DllImport(libX11)]
public extern static int XFree(IntPtr data);
[DllImport(libX11)]
public extern static int XDefaultScreen(IntPtr display);
[DllImport(libX11)]
public extern static IntPtr XRootWindow(IntPtr display, int screen);
[DllImport(libX11)]
public extern static IntPtr XCreatePixmap(IntPtr display, IntPtr d, uint width, uint height, uint depth);
[DllImport(libX11)]
public extern static IntPtr XFreePixmap(IntPtr display, IntPtr pixmap);
[StructLayout(LayoutKind.Sequential)]
public struct XVisualInfo
{
public IntPtr visual;
public IntPtr visualid;
public int screen;
public int depth;
public XVisualClass c_class;
public ulong red_mask;
public ulong green_mask;
public ulong blue_mask;
public int colormap_size;
public int bits_per_rgb;
public override string ToString()
{
return
"{XVisualInfo " +
$", visual={visual}" +
$", visualid={visualid}" +
$", screen={screen}" +
$", depth={depth}" +
$", c_class={c_class}" +
$", red_mask={red_mask}" +
$", green_mask={green_mask}" +
$", blue_mask={blue_mask}" +
$", colormap_size={colormap_size}" +
$", bits_per_rgb={bits_per_rgb}" +
"}";
}
}
}
internal enum XVisualClass : int {
StaticGray = 0,
GrayScale = 1,
StaticColor = 2,
PseudoColor = 3,
TrueColor = 4,
DirectColor = 5
}
internal class Glx
{
private const string libGL = "libGL";
public const int GLX_USE_GL = 1;
public const int GLX_BUFFER_SIZE = 2;
public const int GLX_LEVEL = 3;
public const int GLX_RGBA = 4;
public const int GLX_DOUBLEBUFFER = 5;
public const int GLX_STEREO = 6;
public const int GLX_AUX_BUFFERS = 7;
public const int GLX_RED_SIZE = 8;
public const int GLX_GREEN_SIZE = 9;
public const int GLX_BLUE_SIZE = 10;
public const int GLX_ALPHA_SIZE = 11;
public const int GLX_DEPTH_SIZE = 12;
public const int GLX_STENCIL_SIZE = 13;
public const int GLX_ACCUM_RED_SIZE = 14;
public const int GLX_ACCUM_GREEN_SIZE = 15;
public const int GLX_ACCUM_BLUE_SIZE = 16;
public const int GLX_ACCUM_ALPHA_SIZE = 17;
public const int GLX_DRAWABLE_TYPE = 0x8010;
public const int GLX_RENDER_TYPE = 0x8011;
public const int GLX_X_RENDERABLE = 0x8012;
public const int GLX_RGBA_TYPE = 0x8014;
public const int GLX_COLOR_INDEX_TYPE = 0x8015;
public const int GLX_PIXMAP_BIT = 0x00000002;
public const int GLX_RGBA_BIT = 0x00000001;
public const int GLX_SAMPLE_BUFFERS = 0x186a0;
public const int GLX_SAMPLES = 0x186a1;
public const int GLX_CONTEXT_DEBUG_BIT_ARB = 0x00000001;
public const int GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB = 0x00000002;
public const int GLX_CONTEXT_MAJOR_VERSION_ARB = 0x2091;
public const int GLX_CONTEXT_MINOR_VERSION_ARB = 0x2092;
public const int GLX_CONTEXT_FLAGS_ARB = 0x2094;
public const int GLX_CONTEXT_CORE_PROFILE_BIT_ARB = 0x00000001;
public const int GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB = 0x00000002;
public const int GLX_CONTEXT_PROFILE_MASK_ARB = 0x9126;
static Glx()
{
var ptr = glXGetProcAddressARB("glXCreateContextAttribsARB");
if (ptr != IntPtr.Zero) {
glXCreateContextAttribsARB = (glXCreateContextAttribsARBDelegate)Marshal.GetDelegateForFunctionPointer(ptr, typeof(glXCreateContextAttribsARBDelegate));
}
}
[DllImport(libGL)]
public extern static bool glXQueryVersion(IntPtr dpy, out int maj, out int min);
[DllImport(libGL)]
public extern static IntPtr glXChooseFBConfig(IntPtr dpy, int screen, [In] int[] attribList, out int nitems);
public static IntPtr[] ChooseFBConfig(IntPtr dpy, int screen, int[] attribList)
{
int nitems;
var fbcArrayPtr = glXChooseFBConfig(dpy, screen, attribList, out nitems);
var fbcArray = new IntPtr[nitems];
Marshal.Copy(fbcArrayPtr, fbcArray, 0, nitems);
Xlib.XFree(fbcArrayPtr);
return fbcArray;
}
[DllImport(libGL)]
public extern static IntPtr glXGetVisualFromFBConfig(IntPtr dpy, IntPtr config);
public static Xlib.XVisualInfo GetVisualFromFBConfig(IntPtr dpy, IntPtr config)
{
var visualPtr = glXGetVisualFromFBConfig(dpy, config);
if (visualPtr == IntPtr.Zero) {
throw new Exception("Failed to retrieve visual from framebuffer config.");
}
var visual = (Xlib.XVisualInfo) Marshal.PtrToStructure(visualPtr, typeof(Xlib.XVisualInfo));
Xlib.XFree(visualPtr);
return visual;
}
[DllImport(libGL)]
public extern static bool glXMakeCurrent(IntPtr dpy, IntPtr drawable, IntPtr ctx);
[DllImport(libGL)]
public extern static bool glXSwapBuffers(IntPtr dpy, IntPtr drawable);
[DllImport(libGL)]
public extern static bool glXIsDirect(IntPtr dpy, IntPtr ctx);
[DllImport(libGL)]
public extern static int glXGetFBConfigAttrib(IntPtr dpy, IntPtr config, int attribute, out int value);
[DllImport(libGL)]
public extern static IntPtr glXCreateGLXPixmap(IntPtr dpy, ref Xlib.XVisualInfo visual, IntPtr pixmap);
[DllImport(libGL)]
public extern static void glXDestroyGLXPixmap(IntPtr dpy, IntPtr pixmap);
[DllImport(libGL)]
public extern static void glXDestroyContext(IntPtr dpy, IntPtr ctx);
[DllImport(libGL)]
public extern static IntPtr glXQueryExtensionsString(IntPtr dpy, int screen);
public static string QueryExtensionsString(IntPtr dpy, int screen)
{
return Marshal.PtrToStringAnsi(glXQueryExtensionsString(dpy, screen));
}
public static string[] QueryExtensions(IntPtr dpy, int screen)
{
var str = QueryExtensionsString(dpy, screen);
if (string.IsNullOrEmpty(str)) {
return new string[0];
}
return str.Split(' ');
}
[DllImport(libGL)]
public extern static IntPtr glXGetProcAddressARB(string procname);
[DllImport(libGL)]
public extern static IntPtr glXCreateNewContext(IntPtr dpy, IntPtr config, int renderType, IntPtr shareList, int direct);
public static readonly glXCreateContextAttribsARBDelegate glXCreateContextAttribsARB;
public delegate IntPtr glXCreateContextAttribsARBDelegate(IntPtr dpy, IntPtr config, IntPtr share_context, int direct, int[] attrib_list);
}
}

Просмотреть файл

@ -61,19 +61,10 @@ namespace SkiaSharp.Tests
} else if (IsMac) {
return new CglContext();
} else if (IsWindows) {
return null;
return new WglContext();
} else {
return null;
}
}
}
public abstract class GlContext : IDisposable
{
public abstract void MakeCurrent();
public abstract void SwapBuffers();
public abstract void Destroy();
void IDisposable.Dispose() => Destroy();
}
}