1 /** 2 * Common code shared by SDL-based video drivers. 3 * 4 * License: 5 * This Source Code Form is subject to the terms of 6 * the Mozilla Public License, v. 2.0. If a copy of 7 * the MPL was not distributed with this file, You 8 * can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * Authors: 11 * Vladimir Panteleev <vladimir@thecybershadow.net> 12 */ 13 14 module ae.ui.video.sdl2common.video; 15 16 import std.process : environment; 17 import std.string; 18 19 import derelict.sdl2.sdl; 20 21 import ae.ui.video.threadedvideo; 22 import ae.ui.app.application; 23 import ae.ui.shell.shell; 24 import ae.ui.shell.sdl2.shell; 25 26 class SDL2CommonVideo : ThreadedVideo 27 { 28 override void getScreenSize(out uint width, out uint height) 29 { 30 width = screenWidth; 31 height = screenHeight; 32 } 33 34 override void shutdown() 35 { 36 super.shutdown(); 37 if (window) 38 { 39 SDL_DestroyWindow(window); 40 window = null; 41 } 42 } 43 44 SDL_Window* window; 45 SDL_Renderer* renderer; 46 47 protected: 48 override @property bool initializeVideoInRenderThread() 49 { 50 return true; 51 } 52 53 uint getSDLFlags () { return 0; } 54 SDL_RendererFlags getRendererFlags() { return cast(SDL_RendererFlags)0; } 55 void prepare() {} 56 57 uint screenWidth, screenHeight; 58 59 /// Main thread initialization. 60 override void initMain(Application application) 61 { 62 SDL_WindowFlags flags = SDL_WINDOW_SHOWN; 63 flags |= getSDLFlags(); 64 65 auto settings = application.getShellSettings(); 66 screenWidth = screenHeight = 0; 67 uint windowPosX = SDL_WINDOWPOS_UNDEFINED, windowPosY = SDL_WINDOWPOS_UNDEFINED; 68 69 final switch (settings.screenMode) 70 { 71 case ScreenMode.windowed: 72 screenWidth = settings.windowSizeX; 73 screenHeight = settings.windowSizeY; 74 windowPosX = settings.windowPosX == int.min ? SDL_WINDOWPOS_CENTERED : settings.windowPosX; 75 windowPosY = settings.windowPosY == int.min ? SDL_WINDOWPOS_CENTERED : settings.windowPosY; 76 break; 77 case ScreenMode.maximized: 78 flags |= SDL_WINDOW_MAXIMIZED; 79 break; 80 case ScreenMode.fullscreen: 81 screenWidth = settings.fullScreenX; 82 screenHeight = settings.fullScreenY; 83 flags |= SDL_WINDOW_FULLSCREEN; 84 break; 85 case ScreenMode.windowedFullscreen: 86 { 87 SDL_DisplayMode dm; 88 sdlEnforce(SDL_GetDesktopDisplayMode(0, &dm)==0, "Can't get desktop display mode"); 89 windowPosX = 0; 90 windowPosY = 0; 91 screenWidth = dm.w; 92 screenHeight = dm.h; 93 flags |= SDL_WINDOW_BORDERLESS; 94 break; 95 } 96 } 97 98 if (application.isResizable()) 99 flags |= SDL_WINDOW_RESIZABLE; 100 101 if (window) 102 { 103 // We need to recreate the window if renderer flags, 104 // such as SDL_WINDOW_OPENGL, have changed. 105 // Also recreate when switching fullscreen modes. 106 enum recreateMask = 107 SDL_WINDOW_OPENGL | 108 SDL_WINDOW_FULLSCREEN | 109 SDL_WINDOW_BORDERLESS | 110 SDL_WINDOW_RESIZABLE; 111 if ((currentFlags & recreateMask) != (flags & recreateMask) 112 || (flags & SDL_WINDOW_FULLSCREEN)) 113 { 114 SDL_DestroyWindow(window); 115 window = null; 116 } 117 } 118 119 if (window) 120 { 121 // Adjust parameters of existing window. 122 123 if (windowPosX != SDL_WINDOWPOS_UNDEFINED && windowPosY != SDL_WINDOWPOS_UNDEFINED) 124 { 125 int currentX, currentY; 126 SDL_GetWindowPosition(window, ¤tX, ¤tY); 127 if (currentX != windowPosX || currentY != windowPosY) 128 SDL_SetWindowPosition(window, windowPosX, windowPosY); 129 } 130 if (screenWidth && screenHeight) 131 { 132 int currentW, currentH; 133 SDL_GetWindowSize(window, ¤tW, ¤tH); 134 if (currentW != screenWidth || currentH != screenHeight) 135 SDL_SetWindowSize(window, screenWidth, screenHeight); 136 } 137 } 138 else 139 { 140 // Create a new window. 141 142 // Window must always be created in the main (SDL event) thread, 143 // otherwise we get Win32 deadlocks due to messages being sent 144 // to the render thread. 145 // As a result, if the event thread does something that results 146 // in a Windows message, the message gets put on the render thread 147 // message queue. However, while waiting for the message to be 148 // processed, the event thread holds the application global lock, 149 // and the render thread is waiting on it - thus resulting in a 150 // deadlock. 151 152 window = sdlEnforce( 153 SDL_CreateWindow( 154 toStringz(application.getName()), 155 windowPosX, windowPosY, 156 screenWidth, screenHeight, 157 flags), 158 "Can't create window"); 159 } 160 161 currentFlags = flags; 162 } 163 164 /// Main/render thread initialization (depends on InitializeVideoInRenderThread). 165 override void initVary() 166 { 167 prepare(); 168 renderer = sdlEnforce(SDL_CreateRenderer(window, -1, getRendererFlags()), "Can't create renderer"); 169 } 170 171 /// Main/render thread finalization (depends on InitializeVideoInRenderThread). 172 override void doneVary() 173 { 174 SDL_DestroyRenderer(renderer); renderer = null; 175 } 176 177 /// Main thread finalization. 178 override void doneMain() {} 179 180 private: 181 uint currentFlags; 182 }