From ea068a36f77dd9c8328d71c3fb8ab2ed5957b7ba Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Wed, 13 Jun 2018 18:10:54 +0000 Subject: [PATCH] Allow window size/scale properties to be accessed from other threads. --- .../Sdl2PlatformWindow.cs | 261 +++++++++++------- 1 file changed, 154 insertions(+), 107 deletions(-) diff --git a/OpenRA.Platforms.Default/Sdl2PlatformWindow.cs b/OpenRA.Platforms.Default/Sdl2PlatformWindow.cs index 2e8bfa405d..b9b83218eb 100644 --- a/OpenRA.Platforms.Default/Sdl2PlatformWindow.cs +++ b/OpenRA.Platforms.Default/Sdl2PlatformWindow.cs @@ -23,122 +23,165 @@ namespace OpenRA.Platforms.Default public IGraphicsContext Context { get { return context; } } - internal readonly IntPtr Window; + readonly IntPtr window; bool disposed; - public Size WindowSize { get; private set; } - public float WindowScale { get; private set; } + readonly object syncObject = new object(); + Size windowSize; + Size surfaceSize; + float windowScale; + + internal IntPtr Window + { + get + { + lock (syncObject) + return window; + } + } + + public Size WindowSize + { + get + { + lock (syncObject) + return windowSize; + } + } + + public float WindowScale + { + get + { + lock (syncObject) + return windowScale; + } + } + + internal Size SurfaceSize + { + get + { + lock (syncObject) + return surfaceSize; + } + } - internal Size SurfaceSize { get; private set; } public event Action OnWindowScaleChanged = (before, after) => { }; [DllImport("user32.dll")] static extern bool SetProcessDPIAware(); - public Sdl2PlatformWindow(Size windowSize, WindowMode windowMode) + public Sdl2PlatformWindow(Size requestWindowSize, WindowMode windowMode) { - Console.WriteLine("Using SDL 2 with OpenGL renderer"); - WindowSize = windowSize; - - // Disable legacy scaling on Windows - if (Platform.CurrentPlatform == PlatformType.Windows && !Game.Settings.Graphics.DisableWindowsDPIScaling) - SetProcessDPIAware(); - - SDL.SDL_Init(SDL.SDL_INIT_NOPARACHUTE | SDL.SDL_INIT_VIDEO); - 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); - - SDL.SDL_DisplayMode display; - SDL.SDL_GetCurrentDisplayMode(0, out display); - - Console.WriteLine("Desktop resolution: {0}x{1}", display.w, display.h); - if (WindowSize.Width == 0 && WindowSize.Height == 0) + Console.WriteLine("Using SDL 2 with OpenGL renderer"); + + // Lock the Window/Surface properties until initialization is complete + lock (syncObject) { - Console.WriteLine("No custom resolution provided, using desktop resolution"); - WindowSize = new Size(display.w, display.h); - } - - 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, SDL.SDL_WINDOWPOS_CENTERED, - WindowSize.Width, WindowSize.Height, windowFlags); - - SurfaceSize = WindowSize; - WindowScale = 1; - - // 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. - int width, height; - SDL.SDL_GL_GetDrawableSize(Window, out width, out height); - SurfaceSize = new Size(width, height); - WindowScale = width * 1f / WindowSize.Width; - } - else if (Platform.CurrentPlatform == PlatformType.Windows) - { - float ddpi, hdpi, vdpi; - if (!Game.Settings.Graphics.DisableWindowsDPIScaling && SDL.SDL_GetDisplayDPI(0, out ddpi, out hdpi, out vdpi) == 0) + windowSize = requestWindowSize; + + // Disable legacy scaling on Windows + if (Platform.CurrentPlatform == PlatformType.Windows && !Game.Settings.Graphics.DisableWindowsDPIScaling) + SetProcessDPIAware(); + + SDL.SDL_Init(SDL.SDL_INIT_NOPARACHUTE | SDL.SDL_INIT_VIDEO); + 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); + + SDL.SDL_DisplayMode display; + SDL.SDL_GetCurrentDisplayMode(0, out display); + + Console.WriteLine("Desktop resolution: {0}x{1}", display.w, display.h); + if (windowSize.Width == 0 && windowSize.Height == 0) { - WindowScale = ddpi / 96; - WindowSize = new Size((int)(SurfaceSize.Width / WindowScale), (int)(SurfaceSize.Height / WindowScale)); - } - } - else - { - float scale = 1; - var scaleVariable = Environment.GetEnvironmentVariable("OPENRA_DISPLAY_SCALE"); - if (scaleVariable != null && float.TryParse(scaleVariable, out scale)) - { - WindowScale = scale; - 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. + Console.WriteLine("No custom resolution provided, using desktop resolution"); + windowSize = new Size(display.w, display.h); + } + + 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, SDL.SDL_WINDOWPOS_CENTERED, + windowSize.Width, windowSize.Height, windowFlags); + + surfaceSize = windowSize; + windowScale = 1; + + // Enable high resolution rendering for Retina displays if (Platform.CurrentPlatform == PlatformType.OSX) - { - int width, height; - SDL.SDL_GetWindowSize(Window, out width, out height); - WindowSize = SurfaceSize = new Size(width, height); - WindowScale = 1; + { + // 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. + int width, height; + + SDL.SDL_GL_GetDrawableSize(Window, out width, out height); + surfaceSize = new Size(width, height); + windowScale = width * 1f / windowSize.Width; + } + else if (Platform.CurrentPlatform == PlatformType.Windows) + { + float ddpi, hdpi, vdpi; + if (!Game.Settings.Graphics.DisableWindowsDPIScaling && SDL.SDL_GetDisplayDPI(0, out ddpi, out hdpi, out vdpi) == 0) + { + windowScale = ddpi / 96; + windowSize = new Size((int)(surfaceSize.Width / windowScale), (int)(surfaceSize.Height / windowScale)); + } + } + else + { + float scale = 1; + var scaleVariable = Environment.GetEnvironmentVariable("OPENRA_DISPLAY_SCALE"); + if (scaleVariable != null && float.TryParse(scaleVariable, out scale)) + { + windowScale = scale; + 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) + { + int width, height; + SDL.SDL_GetWindowSize(Window, out width, out height); + windowSize = surfaceSize = new Size(width, height); + windowScale = 1; + } + } + else if (windowMode == WindowMode.PseudoFullscreen) + { + // Work around a visual glitch in OSX: the window is offset + // partially offscreen if the dock is at the left of the screen + if (Platform.CurrentPlatform == PlatformType.OSX) + SDL.SDL_SetWindowPosition(Window, 0, 0); + + SDL.SDL_SetWindowFullscreen(Window, (uint)SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP); + SDL.SDL_SetHint(SDL.SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0"); } - } - else if (windowMode == WindowMode.PseudoFullscreen) - { - // Work around a visual glitch in OSX: the window is offset - // partially offscreen if the dock is at the left of the screen - if (Platform.CurrentPlatform == PlatformType.OSX) - SDL.SDL_SetWindowPosition(Window, 0, 0); - - SDL.SDL_SetWindowFullscreen(Window, (uint)SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP); - SDL.SDL_SetHint(SDL.SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0"); } context = new Sdl2GraphicsContext(this); @@ -207,11 +250,15 @@ namespace OpenRA.Platforms.Default if (width != SurfaceSize.Width || height != SurfaceSize.Height) { - var oldScale = WindowScale; - SurfaceSize = new Size(width, height); - WindowScale = width * 1f / WindowSize.Width; + float oldScale; + lock (syncObject) + { + oldScale = windowScale; + surfaceSize = new Size(width, height); + windowScale = width * 1f / windowSize.Width; + } - OnWindowScaleChanged(oldScale, WindowScale); + OnWindowScaleChanged(oldScale, windowScale); } } }