Exemple #1
0
        static void SetSDLAttributes(GLProfile profile)
        {
            SDL.SDL_GL_ResetAttributes();
            SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_DOUBLEBUFFER, 1);
            SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_RED_SIZE, 8);
            SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_GREEN_SIZE, 8);
            SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_BLUE_SIZE, 8);
            SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_ALPHA_SIZE, 0);

            var useAngle = profile == GLProfile.ANGLE ? "1" : "0";

            SDL.SDL_SetHint("SDL_OPENGL_ES_DRIVER", useAngle);

            switch (profile)
            {
            case GLProfile.Modern:
                SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_MAJOR_VERSION, 3);
                SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_MINOR_VERSION, 2);
                SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_PROFILE_MASK, (int)SDL.SDL_GLprofile.SDL_GL_CONTEXT_PROFILE_CORE);
                break;

            case GLProfile.ANGLE:
            case GLProfile.Embedded:
                SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_MAJOR_VERSION, 3);
                SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_MINOR_VERSION, 0);
                SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_PROFILE_MASK, (int)SDL.SDL_GLprofile.SDL_GL_CONTEXT_PROFILE_ES);
                break;

            case GLProfile.Legacy:
                SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_MAJOR_VERSION, 2);
                SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_MINOR_VERSION, 1);
                break;
            }
        }
Exemple #2
0
        static DisplaySettingsLogic()
        {
            var original = Game.Settings;

            OriginalGraphicsMode           = original.Graphics.Mode;
            OriginalVideoDisplay           = original.Graphics.VideoDisplay;
            OriginalGraphicsWindowedSize   = original.Graphics.WindowedSize;
            OriginalGraphicsFullscreenSize = original.Graphics.FullscreenSize;
            OriginalGLProfile = original.Graphics.GLProfile;
        }
Exemple #3
0
        public GLFeature(string api, Version number, string name)
        {
            Api    = api;
            Number = number;
            Name   = name;

            BaseProfile = new GLProfile(string.Empty);

            Profiles = new Dictionary <string, GLProfile>();
            Profiles.Add(BaseProfile.Name, BaseProfile);
        }
Exemple #4
0
        static bool CanCreateGLWindow(GLProfile profile, List <string> errorLog)
        {
            // Implementation inspired by TestIndividualGLVersion from Veldrid

            // Need to create and destroy its own SDL contexts as a workaround for specific buggy drivers
            if (SDL.SDL_Init(SDL.SDL_INIT_VIDEO) != 0)
            {
                // Continue to harvest additional SDL errors below
                errorLog.Add($"{profile}: SDL init failed: {SDL.SDL_GetError()}");
                SDL.SDL_ClearError();
            }

            SetSDLAttributes(profile);

            var flags  = SDL.SDL_WindowFlags.SDL_WINDOW_HIDDEN | SDL.SDL_WindowFlags.SDL_WINDOW_OPENGL;
            var window = SDL.SDL_CreateWindow("", 0, 0, 1, 1, flags);

            if (window == IntPtr.Zero || !string.IsNullOrEmpty(SDL.SDL_GetError()))
            {
                errorLog.Add($"{profile}: SDL window creation failed: {SDL.SDL_GetError()}");
                SDL.SDL_ClearError();
                SDL.SDL_Quit();
                return(false);
            }

            var context = SDL.SDL_GL_CreateContext(window);

            if (context == IntPtr.Zero || SDL.SDL_GL_MakeCurrent(window, context) < 0)
            {
                errorLog.Add($"{profile}: GL context creation failed: {SDL.SDL_GetError()}");
                SDL.SDL_ClearError();
                SDL.SDL_DestroyWindow(window);
                SDL.SDL_Quit();
                return(false);
            }

            // Distinguish between ANGLE and native GLES
            var success = true;

            if (profile == GLProfile.ANGLE || profile == GLProfile.Embedded)
            {
                var isAngle = SDL.SDL_GL_ExtensionSupported("GL_ANGLE_texture_usage") == SDL.SDL_bool.SDL_TRUE;
                success = isAngle ^ (profile != GLProfile.ANGLE);
                if (!success)
                {
                    errorLog.Add(isAngle ? "GL profile is ANGLE" : "GL profile is Embedded");
                }
            }

            SDL.SDL_GL_DeleteContext(context);
            SDL.SDL_DestroyWindow(window);
            SDL.SDL_Quit();
            return(success);
        }
Exemple #5
0
        public GLProfile GetOrCreateProfile(string profileName)
        {
            if (profileName == null)
            {
                return(BaseProfile);
            }
            if (!Profiles.TryGetValue(profileName, out var profile))
            {
                profile = new GLProfile(profileName);
                Profiles.Add(profileName, profile);
            }

            return(profile);
        }
Exemple #6
0
        public Sdl2PlatformWindow(Size requestEffectiveWindowSize, WindowMode windowMode,
                                  float scaleModifier, int batchSize, int videoDisplay, GLProfile requestProfile, bool enableLegacyGL)
        {
            // Lock the Window/Surface properties until initialization is complete
            lock (syncObject)
            {
                this.scaleModifier = scaleModifier;

                // Disable legacy scaling on Windows
                if (Platform.CurrentPlatform == PlatformType.Windows)
                {
                    SetProcessDPIAware();
                }

                // Decide which OpenGL profile to use.
                // Prefer standard GL over GLES provided by the native driver
                var testProfiles = new List <GLProfile> {
                    GLProfile.ANGLE, GLProfile.Modern, GLProfile.Embedded
                };
                if (enableLegacyGL)
                {
                    testProfiles.Add(GLProfile.Legacy);
                }

                supportedProfiles = testProfiles
                                    .Where(CanCreateGLWindow)
                                    .ToArray();

                if (!supportedProfiles.Any())
                {
                    throw new InvalidOperationException("No supported OpenGL profiles were found.");
                }

                profile = supportedProfiles.Contains(requestProfile) ? requestProfile : supportedProfiles.First();

                // Note: This must be called after the CanCreateGLWindow checks above,
                // which needs to create and destroy its own SDL contexts as a workaround for specific buggy drivers
                SDL.SDL_Init(SDL.SDL_INIT_VIDEO);
                SetSDLAttributes(profile);

                Console.WriteLine("Using SDL 2 with OpenGL ({0}) renderer", profile);
                if (videoDisplay < 0 || videoDisplay >= DisplayCount)
                {
                    videoDisplay = 0;
                }

                SDL.SDL_GetCurrentDisplayMode(videoDisplay, out var display);

                // Windows and Linux define window sizes in native pixel units.
                // Query the display/dpi scale so we can convert our requested effective size to pixels.
                // This is not necessary on macOS, which defines window sizes in effective units ("points").
                if (Platform.CurrentPlatform == PlatformType.Windows)
                {
                    // Launch the game with OPENRA_DISPLAY_SCALE to force a specific scaling factor
                    // Otherwise fall back to Windows's DPI configuration
                    var scaleVariable = Environment.GetEnvironmentVariable("OPENRA_DISPLAY_SCALE");
                    if (scaleVariable == null || !float.TryParse(scaleVariable, NumberStyles.Float, NumberFormatInfo.InvariantInfo, out windowScale) || windowScale <= 0)
                    {
                        if (SDL.SDL_GetDisplayDPI(videoDisplay, out var ddpi, out _, out _) == 0)
                        {
                            windowScale = ddpi / 96;
                        }
                    }
                }
                else if (Platform.CurrentPlatform == PlatformType.Linux)
                {
                    // Launch the game with OPENRA_DISPLAY_SCALE to force a specific scaling factor
                    // Otherwise fall back to GDK_SCALE or parsing the x11 DPI configuration
                    var scaleVariable = Environment.GetEnvironmentVariable("OPENRA_DISPLAY_SCALE") ?? Environment.GetEnvironmentVariable("GDK_SCALE");
                    if (scaleVariable == null || !float.TryParse(scaleVariable, NumberStyles.Float, NumberFormatInfo.InvariantInfo, out windowScale) || windowScale <= 0)
                    {
                        // Attempt to automatically detect DPI
                        try
                        {
                            var psi = new ProcessStartInfo("/usr/bin/xrdb", "-query");
                            psi.UseShellExecute        = false;
                            psi.RedirectStandardOutput = true;
                            var p     = Process.Start(psi);
                            var lines = p.StandardOutput.ReadToEnd().Split('\n');

                            foreach (var line in lines)
                            {
                                if (line.StartsWith("Xft.dpi") && int.TryParse(line.Substring(8), out var dpi))
                                {
                                    windowScale = dpi / 96f;
                                }
                            }
                        }
                        catch { }
                    }
                }

                Console.WriteLine("Desktop resolution: {0}x{1}", display.w, display.h);
                if (requestEffectiveWindowSize.Width == 0 && requestEffectiveWindowSize.Height == 0)
                {
                    Console.WriteLine("No custom resolution provided, using desktop resolution");
                    surfaceSize = windowSize = new Size(display.w, display.h);
                }
                else
                {
                    surfaceSize = windowSize = new Size((int)(requestEffectiveWindowSize.Width * windowScale), (int)(requestEffectiveWindowSize.Height * windowScale));
                }

                Console.WriteLine("Using resolution: {0}x{1}", windowSize.Width, windowSize.Height);

                var windowFlags = SDL.SDL_WindowFlags.SDL_WINDOW_OPENGL | SDL.SDL_WindowFlags.SDL_WINDOW_ALLOW_HIGHDPI;

                // HiDPI doesn't work properly on OSX with (legacy) fullscreen mode
                if (Platform.CurrentPlatform == PlatformType.OSX && windowMode == WindowMode.Fullscreen)
                {
                    SDL.SDL_SetHint(SDL.SDL_HINT_VIDEO_HIGHDPI_DISABLED, "1");
                }

                window = SDL.SDL_CreateWindow("OpenRA", SDL.SDL_WINDOWPOS_CENTERED_DISPLAY(videoDisplay), SDL.SDL_WINDOWPOS_CENTERED_DISPLAY(videoDisplay),
                                              windowSize.Width, windowSize.Height, windowFlags);

                if (Platform.CurrentPlatform == PlatformType.Linux)
                {
                    // The KDE task switcher limits itself to the 128px icon unless we
                    // set an X11 _KDE_NET_WM_DESKTOP_FILE property on the window
                    var currentDesktop  = Environment.GetEnvironmentVariable("XDG_CURRENT_DESKTOP");
                    var desktopFilename = Environment.GetEnvironmentVariable("OPENRA_DESKTOP_FILENAME");
                    if (desktopFilename != null && currentDesktop == "KDE")
                    {
                        try
                        {
                            var info = default(SDL.SDL_SysWMinfo);
                            SDL.SDL_VERSION(out info.version);
                            SDL.SDL_GetWindowWMInfo(Window, ref info);

                            var d        = info.info.x11.display;
                            var w        = info.info.x11.window;
                            var property = XInternAtom(d, "_KDE_NET_WM_DESKTOP_FILE", false);
                            var type     = XInternAtom(d, "UTF8_STRING", false);

                            XChangeProperty(d, w, property, type, 8, IntPtr.Zero, desktopFilename, desktopFilename.Length + 1);
                            XFlush(d);
                        }
                        catch
                        {
                            Log.Write("debug", "Failed to set _KDE_NET_WM_DESKTOP_FILE");
                            Console.WriteLine("Failed to set _KDE_NET_WM_DESKTOP_FILE");
                        }
                    }
                }

                // Enable high resolution rendering for Retina displays
                if (Platform.CurrentPlatform == PlatformType.OSX)
                {
                    // OSX defines the window size in "points", with a device-dependent number of pixels per point.
                    // The window scale is simply the ratio of GL pixels / window points.
                    SDL.SDL_GL_GetDrawableSize(Window, out var width, out var height);
                    surfaceSize = new Size(width, height);
                    windowScale = width * 1f / windowSize.Width;
                }
                else
                {
                    windowSize = new Size((int)(surfaceSize.Width / windowScale), (int)(surfaceSize.Height / windowScale));
                }

                Console.WriteLine("Using window scale {0:F2}", windowScale);

                if (Game.Settings.Game.LockMouseWindow)
                {
                    GrabWindowMouseFocus();
                }
                else
                {
                    ReleaseWindowMouseFocus();
                }

                if (windowMode == WindowMode.Fullscreen)
                {
                    SDL.SDL_SetWindowFullscreen(Window, (uint)SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN);

                    // Fullscreen mode on OSX will ignore the configured display resolution
                    // and instead always picks an arbitrary scaled resolution choice that may
                    // not match the window size, leading to graphical and input issues.
                    // We work around this by force disabling HiDPI and resetting the window and
                    // surface sizes to match the size that is forced by SDL.
                    // This is usually not what the player wants, but is the best we can consistently do.
                    if (Platform.CurrentPlatform == PlatformType.OSX)
                    {
                        SDL.SDL_GetWindowSize(Window, out var width, out var height);
                        windowSize  = surfaceSize = new Size(width, height);
                        windowScale = 1;
                    }
                }
                else if (windowMode == WindowMode.PseudoFullscreen)
                {
                    SDL.SDL_SetWindowFullscreen(Window, (uint)SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP);
                    SDL.SDL_SetHint(SDL.SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
                }
            }

            // Run graphics rendering on a dedicated thread.
            // The calling thread will then have more time to process other tasks, since rendering happens in parallel.
            // If the calling thread is the main game thread, this means it can run more logic and render ticks.
            // This is disabled when running in windowed mode on Windows because it breaks the ability to minimize/restore the window.
            if (Platform.CurrentPlatform == PlatformType.Windows && windowMode == WindowMode.Windowed)
            {
                var ctx = new Sdl2GraphicsContext(this);
                ctx.InitializeOpenGL();
                context = ctx;
            }
            else
            {
                context = new ThreadedGraphicsContext(new Sdl2GraphicsContext(this), batchSize);
            }

            context.SetVSyncEnabled(Game.Settings.Graphics.VSync);

            SDL.SDL_SetModState(SDL.SDL_Keymod.KMOD_NONE);
            input = new Sdl2Input();
        }
Exemple #7
0
        public Sdl2PlatformWindow(Size requestEffectiveWindowSize, WindowMode windowMode,
                                  float scaleModifier, int batchSize, int videoDisplay, GLProfile requestProfile)
        {
            // Lock the Window/Surface properties until initialization is complete
            lock (syncObject)
            {
                this.scaleModifier = scaleModifier;

                // Disable legacy scaling on Windows
                if (Platform.CurrentPlatform == PlatformType.Windows)
                {
                    SetProcessDPIAware();
                }

                // Decide which OpenGL profile to use.
                // We first need to query the available profiles on Windows/Linux.
                // On macOS, known/consistent OpenGL support is provided by the OS.
                if (Platform.CurrentPlatform == PlatformType.OSX)
                {
                    supportedProfiles = new[] { GLProfile.Modern, GLProfile.Legacy }
                }
                ;
                else
                {
                    supportedProfiles = new[] { GLProfile.Modern, GLProfile.Embedded, GLProfile.Legacy }
                }
Exemple #8
0
 public IPlatformWindow CreateWindow(Size size, WindowMode windowMode, float scaleModifier, int batchSize, int videoDisplay, GLProfile profile, bool enableLegacyGL)
 {
     return(new Sdl2PlatformWindow(size, windowMode, scaleModifier, batchSize, videoDisplay, profile, enableLegacyGL));
 }
 /**
  * Returns the highest OpenGL profile available on the current graphics device that is compatible with World Wind.
  * The returned profile favors hardware acceleration over software acceleration. With JOGL version 2.0, this returns
  * the highest available profile from the following list:
  * <p/>
  * <ul> <li>OpenGL compatibility profile 4.x</li> <li>OpenGL compatibility profile 3.x</li> <li>OpenGL profile 1.x
  * up to 3.0</li> </ul>
  *
  * @return the highest compatible OpenGL profile.
  */
 public static GLProfile getMaxCompatibleGLProfile()
 {
     return(GLProfile.getMaxFixedFunc(true)); // Favor a hardware rasterizer.
 }
Exemple #10
0
 /**
  * Creates TextureData from the given URL. Does no OpenGL work.
  *
  * @param glp        the OpenGL Profile this texture data should be created for.
  * @param url        the URL from which to read the texture data
  * @param useMipMaps whether mipmaps should be produced for this texture either by auto-generating them or reading
  *                   them from the file. Some file formats support multiple mipmaps in a single file in which case
  *                   those mipmaps will be used rather than generating them.
  *
  * @return the texture data from the URL, or null if none of the registered texture providers could read the URL
  *
  * @throws IOException if an error occurred while reading the URL
  */
 public static TextureData newTextureData(GLProfile glp, URL url, bool useMipMaps) throws IOException