public static IntPtr SelectFBConfig(IntPtr display, FramebufferFormat format) { List <int> visualAttribute = FramebufferFormatToVisualAttribute(format); IntPtr result = IntPtr.Zero; // TODO: make screen configurable? int screen = DefaultScreenLocked(display); int fbcount; unsafe { IntPtr *fbConfigs = GLX.ChooseFBConfig(display, screen, visualAttribute.ToArray(), out fbcount); if (fbcount > 0 && fbConfigs != null) { result = *fbConfigs; XFree((IntPtr)fbConfigs); } } return(result); }
public static OpenGLContextBase CreateOpenGLContext(FramebufferFormat framebufferFormat, int major, int minor, OpenGLContextFlags flags = OpenGLContextFlags.Default, bool directRendering = true, OpenGLContextBase shareContext = null) { if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { // TODO: detect X11/Wayland/DRI if (shareContext != null && !(shareContext is GLXOpenGLContext)) { throw new ContextException($"shared context must be of type {typeof(GLXOpenGLContext).Name}."); } return(new GLXOpenGLContext(framebufferFormat, major, minor, flags, directRendering, (GLXOpenGLContext)shareContext)); } if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { if (shareContext != null && !(shareContext is GLXOpenGLContext)) { throw new ContextException($"shared context must be of type {typeof(GLXOpenGLContext).Name}."); } return(new WGLOpenGLContext(framebufferFormat, major, minor, flags, directRendering, (WGLOpenGLContext)shareContext)); } throw new NotImplementedException(); }
public static IntPtr CreateContext(ref IntPtr windowHandle, FramebufferFormat framebufferFormat, int major, int minor, OpenGLContextFlags flags, bool directRendering, IntPtr shareContext) { EnsureInit(); bool hasTempWindow = windowHandle == IntPtr.Zero; if (hasTempWindow) { windowHandle = Win32Helper.CreateNativeWindow(WindowStylesEx.WS_EX_OVERLAPPEDWINDOW, WindowStyles.WS_CLIPSIBLINGS | WindowStyles.WS_CLIPCHILDREN, "SPB intermediary context", 0, 0, 1, 1); } IntPtr dcHandle = GetDC(windowHandle); int pixelFormat = FindPerfectFormat(dcHandle, framebufferFormat); // Perfect match not availaible, search for the closest if (pixelFormat == -1) { pixelFormat = FindClosestFormat(dcHandle, framebufferFormat); } if (pixelFormat == -1) { throw new PlatformException("Cannot find a valid pixel format"); } PixelFormatDescriptor pfd = PixelFormatDescriptor.Create(); int res = DescribePixelFormat(dcHandle, pixelFormat, Marshal.SizeOf <PixelFormatDescriptor>(), ref pfd); if (res == 0) { throw new PlatformException($"DescribePixelFormat failed: {Marshal.GetLastWin32Error()}"); } res = SetPixelFormat(dcHandle, pixelFormat, ref pfd); if (res == 0) { throw new PlatformException($"DescribePixelFormat failed: {Marshal.GetLastWin32Error()}"); } List <int> contextAttributes = GetContextCreationARBAttribute(major, minor, flags); IntPtr context = CreateContextAttribsArb(dcHandle, shareContext, contextAttributes.ToArray()); ReleaseDC(windowHandle, dcHandle); if (hasTempWindow) { DestroyWindow(windowHandle); } return(context); }
public GLWidget(FramebufferFormat framebufferFormat, int major, int minor, OpenGLContextFlags flags = OpenGLContextFlags.Default, bool directRendering = true, OpenGLContextBase sharedContext = null) { FramebufferFormat = framebufferFormat; GLVersionMajor = major; GLVersionMinor = minor; ContextFlags = flags; DirectRendering = directRendering; SharedContext = sharedContext; }
public OpenGLContextBase(FramebufferFormat framebufferFormat, int major, int minor, OpenGLContextFlags flags, bool directRendering, OpenGLContextBase shareContext) { FramebufferFormat = framebufferFormat; Major = major; Minor = minor; Flags = flags; DirectRendering = directRendering; ShareContext = shareContext; }
public static GLXWindow CreateGLXWindow(NativeHandle display, FramebufferFormat format, int x, int y, int width, int height) { IntPtr fbConfig = GLXHelper.SelectFBConfig(display.RawHandle, format); unsafe { X11.XVisualInfo *visualInfo; if (fbConfig != IntPtr.Zero) { visualInfo = GLX.GLX.GetVisualFromFBConfig(display.RawHandle, fbConfig); } else { // TODO: support old visual selection throw new NotImplementedException(); } if (visualInfo == null) { throw new NotImplementedException(); } // make screen configurable? int screen = X11.DefaultScreenLocked(display.RawHandle); IntPtr rootWindow = X11.RootWindow(display.RawHandle, screen); X11.XSetWindowAttributes attributes = new X11.XSetWindowAttributes { BackgroundPixel = IntPtr.Zero, BorderPixel = IntPtr.Zero, ColorMap = X11.CreateColormap(display.RawHandle, rootWindow, visualInfo->Visual, 0) }; // TODO: events X11.SetWindowValueMask windowValueMask = X11.SetWindowValueMask.ColorMap | X11.SetWindowValueMask.EventMask | X11.SetWindowValueMask.BackPixel | X11.SetWindowValueMask.BorderPixel; X11.XSetWindowAttributes *attributesPtr = &attributes; IntPtr rawWindowHandle = X11.CreateWindow(display.RawHandle, rootWindow, x, y, width, height, 0, visualInfo->Depth, (int)X11.CreateWindowArgs.InputOutput, visualInfo->Visual, (IntPtr)windowValueMask, (IntPtr)attributesPtr); if (rawWindowHandle == IntPtr.Zero) { throw new ApplicationException("Cannot create X window!"); } return(new GLXWindow(display, new NativeHandle(rawWindowHandle))); } }
public static SwappableNativeWindowBase CreateOpenGLWindow(FramebufferFormat format, int x, int y, int width, int height) { if (OperatingSystem.IsLinux()) { // TODO: detect X11/Wayland/DRI return(X11Helper.CreateGLXWindow(new NativeHandle(X11.X11.DefaultDisplay), format, x, y, width, height)); } else if (OperatingSystem.IsWindows()) { // TODO pass format return(Win32Helper.CreateWindowForWGL(x, y, width, height)); } throw new NotImplementedException(); }
public static NativeWindowBase CreateWindow(FramebufferFormat format, int x, int y, int width, int height) { if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { // TODO: detect X11/Wayland/DRI return(X11Helper.CreateGLXWindow(new NativeHandle(X11.X11.DefaultDisplay), format, x, y, width, height)); } if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { // TODO pass format return(Win32Helper.CreateWindowForWGL(x, y, width, height)); } throw new NotImplementedException(); }
private static int FindPerfectFormat(IntPtr dcHandle, FramebufferFormat format) { List <int> attributes = FramebufferFormatToPixelFormatAttributes(format); int[] formats = new int[1]; if (!ChoosePixelFormatArb(dcHandle, attributes.ToArray(), null, formats.Length, formats, out int numFormat)) { throw new PlatformException($"wglChoosePixelFormatARB failed: {Marshal.GetLastWin32Error()}"); } if (numFormat == 0) { return(-1); } return(formats[0]); }
public static List <int> FramebufferFormatToVisualAttribute(FramebufferFormat format) { List <int> result = new List <int>(); if (format.Color.BitsPerPixel > 0) { result.Add((int)GLX.Attribute.RENDER_TYPE); result.Add((int)GLX.RenderTypeMask.RGBA_BIT); result.Add((int)GLX.Attribute.RED_SIZE); result.Add(format.Color.Red); result.Add((int)GLX.Attribute.GREEN_SIZE); result.Add(format.Color.Green); result.Add((int)GLX.Attribute.BLUE_SIZE); result.Add(format.Color.Blue); result.Add((int)GLX.Attribute.ALPHA_SIZE); result.Add(format.Color.Alpha); } if (format.DepthBits > 0) { result.Add((int)GLX.Attribute.DEPTH_SIZE); result.Add(format.DepthBits); } if (format.Buffers > 1) { result.Add((int)GLX.Attribute.DOUBLEBUFFER); result.Add(1); } if (format.Stereo) { result.Add((int)GLX.Attribute.STENCIL_SIZE); result.Add(format.Stereo ? 1 : 0); } if (format.Accumulator.BitsPerPixel > 0) { result.Add((int)GLX.Attribute.ACCUM_ALPHA_SIZE); result.Add(format.Accumulator.Alpha); result.Add((int)GLX.Attribute.ACCUM_BLUE_SIZE); result.Add(format.Accumulator.Blue); result.Add((int)GLX.Attribute.ACCUM_GREEN_SIZE); result.Add(format.Accumulator.Green); result.Add((int)GLX.Attribute.ACCUM_RED_SIZE); result.Add(format.Accumulator.Red); } if (format.Samples > 0) { result.Add((int)GLX.Attribute.SAMPLE_BUFFERS); result.Add(1); result.Add((int)GLX.Attribute.SAMPLES); result.Add((int)format.Samples); } if (format.Stereo) { result.Add((int)GLX.Attribute.STEREO); result.Add(1); } // NOTE: Format is key: value, nothing in the spec specify if the end marker follow or not this format. // BODY: As such, we add an extra 0 just to be sure we don't break anything. result.Add(0); result.Add(0); return(result); }
public WGLOpenGLContext(FramebufferFormat framebufferFormat, int major, int minor, OpenGLContextFlags flags = OpenGLContextFlags.Default, bool directRendering = true, WGLOpenGLContext shareContext = null) : base(framebufferFormat, major, minor, flags, directRendering, shareContext) { _deviceContext = IntPtr.Zero; _window = null; }
private static int FindClosestFormat(IntPtr dcHandle, FramebufferFormat format) { const int WGL_NO_ACCELERATION_ARB = 0x2025; int[] formatValue = new int[1]; if (!GetPixelFormatAttribivARB(dcHandle, 1, 0, 1, new int[1] { (int)WGL.ARB.Attribute.WGL_NUMBER_PIXEL_FORMATS_ARB }, formatValue)) { throw new PlatformException($"wglGetPixelFormatAttribivARB failed: {Marshal.GetLastWin32Error()}"); } int formatCount = formatValue[0]; List <int> tempAttributeList = new List <int>(); tempAttributeList.Add((int)WGL.ARB.Attribute.WGL_SUPPORT_OPENGL_ARB); tempAttributeList.Add((int)WGL.ARB.Attribute.WGL_DRAW_TO_WINDOW_ARB); tempAttributeList.Add((int)WGL.ARB.Attribute.WGL_PIXEL_TYPE_ARB); tempAttributeList.Add((int)WGL.ARB.Attribute.WGL_ACCELERATION_ARB); tempAttributeList.Add((int)WGL.ARB.Attribute.WGL_RED_BITS_ARB); tempAttributeList.Add((int)WGL.ARB.Attribute.WGL_GREEN_BITS_ARB); tempAttributeList.Add((int)WGL.ARB.Attribute.WGL_BLUE_BITS_ARB); tempAttributeList.Add((int)WGL.ARB.Attribute.WGL_ALPHA_BITS_ARB); tempAttributeList.Add((int)WGL.ARB.Attribute.WGL_DEPTH_BITS_ARB); tempAttributeList.Add((int)WGL.ARB.Attribute.WGL_STENCIL_BITS_ARB); tempAttributeList.Add((int)WGL.ARB.Attribute.WGL_ACCUM_RED_BITS_ARB); tempAttributeList.Add((int)WGL.ARB.Attribute.WGL_ACCUM_GREEN_BITS_ARB); tempAttributeList.Add((int)WGL.ARB.Attribute.WGL_ACCUM_BLUE_BITS_ARB); tempAttributeList.Add((int)WGL.ARB.Attribute.WGL_ACCUM_ALPHA_BITS_ARB); tempAttributeList.Add((int)WGL.ARB.Attribute.WGL_STEREO_ARB); tempAttributeList.Add((int)WGL.ARB.Attribute.WGL_DOUBLE_BUFFER_ARB); if (Extensions.Contains("WGL_ARB_multisample")) { tempAttributeList.Add((int)WGL.ARB.Attribute.WGL_SAMPLES_ARB); } int[] attributes = tempAttributeList.ToArray(); int[] values = new int[Unsafe.SizeOf <AttributeInformation>() / sizeof(int)]; int closestIndex = int.MaxValue; uint leastMissing = uint.MaxValue; uint leastRawColorDifference = uint.MaxValue; uint leastExtraDifference = uint.MaxValue; for (int index = 0; index < formatCount; index++) { if (!GetPixelFormatAttribivARB(dcHandle, index + 1, 0, (uint)attributes.Length, attributes, values)) { throw new PlatformException($"wglGetPixelFormatAttribivARB failed: {Marshal.GetLastWin32Error()}"); } AttributeInformation information = MemoryMarshal.Cast <int, AttributeInformation>(values)[0]; if (information.SupportOpenGL != 0 && information.Acceleration != WGL_NO_ACCELERATION_ARB) { if (format.Stereo && information.Stereo == 0) { continue; } if (format.Buffers > 1 && information.DoubleBuffer == 0) { continue; } // Based on glfw3 algorithm. information.CompareWithDesiredFormat(format, out uint missing, out uint rawColorDifference, out uint extraDifference); if (missing < leastMissing) { closestIndex = index; } else if (missing == leastMissing) { if ((rawColorDifference < leastRawColorDifference) || ((rawColorDifference == leastRawColorDifference) && (extraDifference < leastExtraDifference))) { closestIndex = index; } } if (closestIndex == index) { leastMissing = missing; leastRawColorDifference = rawColorDifference; leastExtraDifference = extraDifference; } } } if (closestIndex == int.MaxValue) { closestIndex = -1; } return(closestIndex); }
public void CompareWithDesiredFormat(FramebufferFormat desiredFormat, out uint miss, out uint rawColorDifference, out uint extraDifference) { miss = 0; if (desiredFormat.StencilBits > 0 && StencilBits == 0) { miss++; } if (desiredFormat.DepthBits > 0 && DepthBits == 0) { miss++; } if (desiredFormat.Color.Alpha > 0 && AlphaBits == 0) { miss++; } if (desiredFormat.Samples > 0 && Samples == 0) { miss++; } rawColorDifference = 0; if (desiredFormat.Color.BitsPerPixel > 0) { rawColorDifference = (uint)((desiredFormat.Color.Red - RedBits) * (desiredFormat.Color.Red - RedBits) + (desiredFormat.Color.Blue - BlueBits) * (desiredFormat.Color.Blue - BlueBits) + (desiredFormat.Color.Green - GreenBits) * (desiredFormat.Color.Green - GreenBits)); } extraDifference = 0; if (desiredFormat.StencilBits > 0) { extraDifference += (uint)((desiredFormat.StencilBits - StencilBits) * (desiredFormat.StencilBits - StencilBits)); } if (desiredFormat.DepthBits > 0) { extraDifference += (uint)((desiredFormat.DepthBits - DepthBits) * (desiredFormat.DepthBits - DepthBits)); } if (desiredFormat.Accumulator.BitsPerPixel > 0) { extraDifference += (uint)((desiredFormat.Accumulator.Red - AccumRedBits) * (desiredFormat.Accumulator.Red - AccumRedBits) + (desiredFormat.Accumulator.Blue - AccumBlueBits) * (desiredFormat.Accumulator.Blue - AccumBlueBits) + (desiredFormat.Accumulator.Green - AccumGreenBits) * (desiredFormat.Accumulator.Green - AccumGreenBits)); } if (desiredFormat.Accumulator.Alpha > 0) { extraDifference += (uint)((desiredFormat.Accumulator.Alpha - AccumAlphaBits) * (desiredFormat.Accumulator.Alpha - AccumAlphaBits)); } if (desiredFormat.Samples > 0) { extraDifference += (uint)(((int)desiredFormat.Samples - Samples) * ((int)desiredFormat.Samples - Samples)); } }
private static List <int> FramebufferFormatToPixelFormatAttributes(FramebufferFormat format) { const int WGL_FULL_ACCELERATION_ARB = 0x2027; List <int> result = new List <int>(); // Full acceleration required result.Add((int)WGL.ARB.Attribute.WGL_ACCELERATION_ARB); result.Add(WGL_FULL_ACCELERATION_ARB); // We use OpenGL so we need it... result.Add((int)WGL.ARB.Attribute.WGL_SUPPORT_OPENGL_ARB); result.Add(1); result.Add((int)WGL.ARB.Attribute.WGL_DRAW_TO_WINDOW_ARB); result.Add(1); if (format.Color.BitsPerPixel > 0) { result.Add((int)WGL.ARB.Attribute.WGL_RED_BITS_ARB); result.Add(format.Color.Red); result.Add((int)WGL.ARB.Attribute.WGL_GREEN_BITS_ARB); result.Add(format.Color.Green); result.Add((int)WGL.ARB.Attribute.WGL_BLUE_BITS_ARB); result.Add(format.Color.Blue); result.Add((int)WGL.ARB.Attribute.WGL_ALPHA_BITS_ARB); result.Add(format.Color.Alpha); } if (format.DepthBits > 0) { result.Add((int)WGL.ARB.Attribute.WGL_DEPTH_BITS_ARB); result.Add(format.DepthBits); } if (format.Buffers > 1) { result.Add((int)WGL.ARB.Attribute.WGL_DOUBLE_BUFFER_ARB); result.Add(1); } if (format.StencilBits > 0) { result.Add((int)WGL.ARB.Attribute.WGL_STENCIL_BITS_ARB); result.Add(format.StencilBits); } if (format.Accumulator.BitsPerPixel > 0) { result.Add((int)WGL.ARB.Attribute.WGL_ACCUM_ALPHA_BITS_ARB); result.Add(format.Accumulator.Alpha); result.Add((int)WGL.ARB.Attribute.WGL_ACCUM_BLUE_BITS_ARB); result.Add(format.Accumulator.Blue); result.Add((int)WGL.ARB.Attribute.WGL_ACCUM_GREEN_BITS_ARB); result.Add(format.Accumulator.Green); result.Add((int)WGL.ARB.Attribute.WGL_ACCUM_RED_BITS_ARB); result.Add(format.Accumulator.Red); } if (format.Samples > 0) { result.Add((int)WGL.ARB.Attribute.WGL_DOUBLE_BUFFER_ARB); result.Add(1); } if (format.Stereo) { result.Add((int)WGL.ARB.Attribute.WGL_STEREO_ARB); result.Add(format.Stereo ? 1 : 0); } // NOTE: Format is key: value, nothing in the spec specify if the end marker follow or not this format. // BODY: As such, we add an extra 0 just to be sure we don't break anything. result.Add(0); result.Add(0); return(result); }