public void Init(IntPtr windowHandle, Win32Platform platform)
        {
            _platform = platform;

            // This is how you request a context version from MESA - lol
            // This needs to be pInvoked as Environment.SetEnvironmentVariable doesn't affect native getenv calls.
            _putenv_s("MESA_GL_VERSION_OVERRIDE", "3.3FC");

            // Unload old OpenGL, if any.
            IntPtr loadedOpenGl = Kernel32.GetModuleHandle("opengl32.dll");
            var    counter      = 0;

            if (loadedOpenGl != IntPtr.Zero)
            {
                Engine.Log.Info("OpenGL32.dll is already loaded. Attempting to unload...", MessageSource.WGallium);
            }
            while (loadedOpenGl != IntPtr.Zero)
            {
                Kernel32.FreeLibrary(loadedOpenGl);
                loadedOpenGl = Kernel32.GetModuleHandle("opengl32.dll");
                counter++;
                if (counter < 100)
                {
                    continue;
                }
                Engine.Log.Error("Couldn't unload the loaded OpenGL32.dll. Gallium context couldn't be created.", MessageSource.WGallium);
                return;
            }

            if (counter > 0)
            {
                Engine.Log.Info($"OpenGL32.dll was unloaded after {counter} attempts.", MessageSource.WGallium);
            }

            // Load library.
            _openGlLibrary = _platform.LoadLibrary("mesa");
            if (_openGlLibrary == IntPtr.Zero)
            {
                Engine.Log.Error("Couldn't load mesa.", MessageSource.WGallium);
                return;
            }

            var createContext = _platform.GetFunctionByName <WglFunctions.WglCreateContext>(_openGlLibrary, "wglCreateContext");

            _deleteContext   = _platform.GetFunctionByName <WglFunctions.WglDeleteContext>(_openGlLibrary, "wglDeleteContext");
            _getProcAddress  = _platform.GetFunctionByName <WglFunctions.WglGetProcAddress>(_openGlLibrary, "wglGetProcAddress");
            _makeCurrent     = _platform.GetFunctionByName <WglFunctions.WglMakeCurrent>(_openGlLibrary, "wglMakeCurrent");
            _swapIntervalExt = NativeHelpers.GetFunctionByPtr <WglFunctions.SwapInternalExt>(_getProcAddress("wglSwapIntervalEXT"));

            // Setup context.
            _dc = User32.GetDC(windowHandle);
            if (_dc == IntPtr.Zero)
            {
                Win32Platform.CheckError("WGL: Could not get window dc.", true);
            }

            int pixelFormatIdx = SupportedPixelFormat(_dc);

            if (pixelFormatIdx == 0)
            {
                return;
            }

            var pfd = new PixelFormatDescriptor();

            pfd.NSize = (ushort)Marshal.SizeOf(pfd);
            if (Gdi32.DescribePixelFormat(_dc, pixelFormatIdx, (uint)sizeof(PixelFormatDescriptor), ref pfd) == 0)
            {
                Win32Platform.CheckError("WGL: Failed to retrieve PFD for the selected pixel format.", true);
                return;
            }

            if (!Gdi32.SetPixelFormat(_dc, pixelFormatIdx, ref pfd))
            {
                Win32Platform.CheckError("WGL: Could not set pixel format.", true);
            }

            const string contextName = "Gallium-OpenGL";

            _contextHandle = createContext(_dc);
            if (_contextHandle == IntPtr.Zero)
            {
                Win32Platform.CheckError(contextName, true);
            }

            Win32Platform.CheckError("Checking if context creation passed.");
            Engine.Log.Trace($"Requested {contextName} using pixel format id {pixelFormatIdx}", MessageSource.Win32);

            Valid = true;
        }
Beispiel #2
0
        /// <summary>
        /// Initialize the conflict from the Windows window handle and platform reference.
        /// </summary>
        public void Init(IntPtr nativeDeviceHandle, IntPtr windowHandle, Win32Platform platform)
        {
            _platform = platform;

            // Load WGL.
            _openGlLibrary = _platform.LoadLibrary("opengl32.dll");
            if (_openGlLibrary == IntPtr.Zero)
            {
                Engine.Log.Error("opengl32.dll not found.", MessageSource.WGallium);
                return;
            }

            var createContext = _platform.GetFunctionByName <WglFunctions.WglCreateContext>(_openGlLibrary, "wglCreateContext");

            _deleteContext     = _platform.GetFunctionByName <WglFunctions.WglDeleteContext>(_openGlLibrary, "wglDeleteContext");
            _getProcAddress    = _platform.GetFunctionByName <WglFunctions.WglGetProcAddress>(_openGlLibrary, "wglGetProcAddress");
            _getCurrentDc      = _platform.GetFunctionByName <WglFunctions.WglGetCurrentDc>(_openGlLibrary, "wglGetCurrentDC");
            _getCurrentContext = _platform.GetFunctionByName <WglFunctions.WglGetCurrentContext>(_openGlLibrary, "wglGetCurrentContext");
            _makeCurrent       = _platform.GetFunctionByName <WglFunctions.WglMakeCurrent>(_openGlLibrary, "wglMakeCurrent");

            // A dummy context has to be created for opengl32.dll to load the. OpenGL ICD, from which we can then query WGL extensions.
            // This code will accept the Microsoft GDI ICD;
            Debug.Assert(nativeDeviceHandle != IntPtr.Zero);
            var pfd = new PixelFormatDescriptor();

            pfd.NSize      = (ushort)Marshal.SizeOf(pfd);
            pfd.NVersion   = 1;
            pfd.DwFlags    = PixelFormatFlags.DrawToWindow | PixelFormatFlags.SupportOpenGl | PixelFormatFlags.DoubleBuffer;
            pfd.PixelType  = (byte)PixelFormatFlags.RGBA;
            pfd.CColorBits = 24;

            if (!Gdi32.SetPixelFormat(nativeDeviceHandle, Gdi32.ChoosePixelFormat(nativeDeviceHandle, ref pfd), ref pfd))
            {
                Win32Platform.CheckError("WGL: Could not set pixel format on dummy context.", true);
            }

            // Establish dummy context.
            IntPtr rc = createContext(nativeDeviceHandle);

            if (rc == IntPtr.Zero)
            {
                Win32Platform.CheckError("WGL: Could not create dummy context.", true);
            }
            if (!_makeCurrent(nativeDeviceHandle, rc))
            {
                _deleteContext(rc);
                Win32Platform.CheckError("Could not make dummy context current.", true);
                return;
            }

            // Check supported version.
            KhronosVersion glGetString = Gl.QueryVersionExternal(GetProcAddress);

            if (glGetString != null)
            {
                if (glGetString.Major < 3)
                {
                    _deleteContext(rc);
                    Engine.Log.Error("Wgl support is lower than 3.0", MessageSource.Wgl);
                    return;
                }
            }
            else
            {
                Engine.Log.Warning("Couldn't verify context version.", MessageSource.Wgl);
            }

            Engine.Log.Trace("Loaded functions.", MessageSource.Wgl);

            // Functions must be loaded first as they're needed to retrieve the extension string that tells us whether the functions are supported
            _getExtensionsStringExt    = NativeHelpers.GetFunctionByPtr <WglFunctions.GetExtensionsStringExt>(_getProcAddress("wglGetExtensionsStringEXT"));
            _getExtensionsStringArb    = NativeHelpers.GetFunctionByPtr <WglFunctions.GetExtensionsStringArb>(_getProcAddress("wglGetExtensionsStringARB"));
            _createContextAttribs      = NativeHelpers.GetFunctionByPtr <WglFunctions.CreateContextAttribs>(_getProcAddress("wglCreateContextAttribsARB"));
            _swapIntervalExt           = NativeHelpers.GetFunctionByPtr <WglFunctions.SwapInternalExt>(_getProcAddress("wglSwapIntervalEXT"));
            _getPixelFormatAttribivArb = NativeHelpers.GetFunctionByPtr <WglFunctions.GetPixelFormatAttributes>(_getProcAddress("wglGetPixelFormatAttribivARB"));

            WglGetSupportedExtensions();
            _arbMultisample          = WglSupportedExtension("WGL_ARB_multisample");
            _arbFramebufferSRgb      = WglSupportedExtension("WGL_ARB_framebuffer_sRGB");
            _extFramebufferSRgb      = WglSupportedExtension("WGL_EXT_framebuffer_sRGB");
            _arbCreateContextProfile = WglSupportedExtension("WGL_ARB_create_context_profile");
            _arbPixelFormat          = WglSupportedExtension("WGL_ARB_pixel_format");
            _autoVSyncExtension      = WglSupportedExtension("WGL_EXT_swap_control_tear");
            bool arbCreateContext = WglSupportedExtension("WGL_ARB_create_context");

            // Dispose of dummy context.
            _deleteContext(rc);
            Engine.Log.Trace("Extensions loaded.", MessageSource.Wgl);

            // Start creating actual context.
            _dc = User32.GetDC(windowHandle);
            if (_dc == IntPtr.Zero)
            {
                Win32Platform.CheckError("WGL: Could not get window dc.", true);
            }
            int pixelFormatIdx = SupportedPixelFormat(_dc);

            if (pixelFormatIdx == 0)
            {
                return;
            }

            if (Gdi32.DescribePixelFormat(_dc, pixelFormatIdx, (uint)sizeof(PixelFormatDescriptor), ref pfd) == 0)
            {
                Win32Platform.CheckError("WGL: Failed to retrieve PFD for the selected pixel format.", true);
                return;
            }

            if (!Gdi32.SetPixelFormat(_dc, pixelFormatIdx, ref pfd))
            {
                Win32Platform.CheckError("WGL: Could not set pixel format.", true);
                return;
            }

            Engine.Log.Trace($"Context ARB: {arbCreateContext}, Profile ARB: {_arbCreateContextProfile}", MessageSource.Wgl);
            if (arbCreateContext)
            {
                // Context configurations to try.
                var contextFactory = new List <GLContextDescription>(2)
                {
                    new GLContextDescription {
                        Profile = GLProfile.Core, Debug = Engine.Configuration.GlDebugMode
                    },
                    new GLContextDescription {
                        Profile = GLProfile.Any
                    }
                };

                for (var i = 0; i < contextFactory.Count; i++)
                {
                    GLContextDescription current = contextFactory[i];

                    IntPtr handle = CreateContextArb(current);
                    if (handle == IntPtr.Zero)
                    {
                        continue;
                    }

                    _contextHandle = handle;
                    Engine.Log.Info($"Created WGL context - {current}", MessageSource.Wgl);
                    break;
                }

                // If that failed too, look for errors.
                // Fallback to legacy creation.
                if (_contextHandle == IntPtr.Zero)
                {
                    Win32Platform.CheckError("Creating WGL context");
                }
            }

            if (_contextHandle == IntPtr.Zero)
            {
                _contextHandle = createContext(_dc);
                if (_contextHandle == IntPtr.Zero)
                {
                    Win32Platform.CheckError("Creating WGL legacy context", true);
                }
                Engine.Log.Info("WGL legacy context created.", MessageSource.Wgl);
            }

            Win32Platform.CheckError("Checking if context creation passed.");
            Valid = true;
        }