diff options
| author | 2020-11-22 16:05:18 -0500 | |
|---|---|---|
| committer | 2020-11-23 17:58:49 -0500 | |
| commit | 994f4977810749c0b597e7a7531a02d907967a68 (patch) | |
| tree | 82eaf8b6dea5baf60e17601771dc8191b8e69a8f /src | |
| parent | Merge pull request #4451 from slashiee/extended-logging (diff) | |
| download | yuzu-994f4977810749c0b597e7a7531a02d907967a68.tar.gz yuzu-994f4977810749c0b597e7a7531a02d907967a68.tar.xz yuzu-994f4977810749c0b597e7a7531a02d907967a68.zip | |
Overhaul EmuWindow::PollEvents to fix yuzu-cmd calling SDL_PollEvents off main thread
EmuWindow::PollEvents was called from the GPU thread (or the CPU thread
in sync-GPU mode) when swapping buffers. It had three implementations:
- In GRenderWindow, it didn't actually poll events, just set a flag and
emit a signal to indicate that a frame was displayed.
- In EmuWindow_SDL2_Hide, it did nothing.
- In EmuWindow_SDL2, it did call SDL_PollEvents, but this is wrong
because SDL_PollEvents is supposed to be called on the thread that set
up video - in this case, the main thread, which was sleeping in a
busyloop (regardless of whether sync-GPU was enabled). On macOS this
causes a crash.
To fix this:
- Rename EmuWindow::PollEvents to OnFrameDisplayed, and give it a
default implementation that does nothing.
- In EmuWindow_SDL2, do not override OnFrameDisplayed, but instead have
the main thread call SDL_WaitEvent in a loop.
Diffstat (limited to '')
| -rw-r--r-- | src/core/frontend/emu_window.h | 4 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.cpp | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/renderer_vulkan.cpp | 4 | ||||
| -rw-r--r-- | src/yuzu/bootmanager.cpp | 2 | ||||
| -rw-r--r-- | src/yuzu/bootmanager.h | 2 | ||||
| -rw-r--r-- | src/yuzu_cmd/emu_window/emu_window_sdl2.cpp | 100 | ||||
| -rw-r--r-- | src/yuzu_cmd/emu_window/emu_window_sdl2.h | 20 | ||||
| -rw-r--r-- | src/yuzu_cmd/yuzu.cpp | 2 | ||||
| -rw-r--r-- | src/yuzu_tester/emu_window/emu_window_sdl2_hide.cpp | 2 | ||||
| -rw-r--r-- | src/yuzu_tester/emu_window/emu_window_sdl2_hide.h | 3 |
10 files changed, 68 insertions, 73 deletions
diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index 3e8780243..276d2b906 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h | |||
| @@ -102,8 +102,8 @@ public: | |||
| 102 | float render_surface_scale = 1.0f; | 102 | float render_surface_scale = 1.0f; |
| 103 | }; | 103 | }; |
| 104 | 104 | ||
| 105 | /// Polls window events | 105 | /// Called from GPU thread when a frame is displayed. |
| 106 | virtual void PollEvents() = 0; | 106 | virtual void OnFrameDisplayed() {} |
| 107 | 107 | ||
| 108 | /** | 108 | /** |
| 109 | * Returns a GraphicsContext that the frontend provides to be used for rendering. | 109 | * Returns a GraphicsContext that the frontend provides to be used for rendering. |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 2ccca1993..c869bb0e2 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -151,8 +151,8 @@ void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | |||
| 151 | 151 | ||
| 152 | rasterizer->TickFrame(); | 152 | rasterizer->TickFrame(); |
| 153 | 153 | ||
| 154 | render_window.PollEvents(); | ||
| 155 | context->SwapBuffers(); | 154 | context->SwapBuffers(); |
| 155 | render_window.OnFrameDisplayed(); | ||
| 156 | } | 156 | } |
| 157 | 157 | ||
| 158 | void RendererOpenGL::PrepareRendertarget(const Tegra::FramebufferConfig* framebuffer) { | 158 | void RendererOpenGL::PrepareRendertarget(const Tegra::FramebufferConfig* framebuffer) { |
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index f2610868e..a2173edd2 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp | |||
| @@ -252,8 +252,6 @@ RendererVulkan::~RendererVulkan() { | |||
| 252 | } | 252 | } |
| 253 | 253 | ||
| 254 | void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | 254 | void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { |
| 255 | render_window.PollEvents(); | ||
| 256 | |||
| 257 | if (!framebuffer) { | 255 | if (!framebuffer) { |
| 258 | return; | 256 | return; |
| 259 | } | 257 | } |
| @@ -283,7 +281,7 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | |||
| 283 | rasterizer->TickFrame(); | 281 | rasterizer->TickFrame(); |
| 284 | } | 282 | } |
| 285 | 283 | ||
| 286 | render_window.PollEvents(); | 284 | render_window.OnFrameDisplayed(); |
| 287 | } | 285 | } |
| 288 | 286 | ||
| 289 | bool RendererVulkan::Init() { | 287 | bool RendererVulkan::Init() { |
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index d62b0efc2..8b490c109 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp | |||
| @@ -308,7 +308,7 @@ GRenderWindow::~GRenderWindow() { | |||
| 308 | input_subsystem->Shutdown(); | 308 | input_subsystem->Shutdown(); |
| 309 | } | 309 | } |
| 310 | 310 | ||
| 311 | void GRenderWindow::PollEvents() { | 311 | void GRenderWindow::OnFrameDisplayed() { |
| 312 | if (!first_frame) { | 312 | if (!first_frame) { |
| 313 | first_frame = true; | 313 | first_frame = true; |
| 314 | emit FirstFrameDisplayed(); | 314 | emit FirstFrameDisplayed(); |
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index ca35cf831..96563a55c 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h | |||
| @@ -131,7 +131,7 @@ public: | |||
| 131 | ~GRenderWindow() override; | 131 | ~GRenderWindow() override; |
| 132 | 132 | ||
| 133 | // EmuWindow implementation. | 133 | // EmuWindow implementation. |
| 134 | void PollEvents() override; | 134 | void OnFrameDisplayed() override; |
| 135 | bool IsShown() const override; | 135 | bool IsShown() const override; |
| 136 | std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override; | 136 | std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override; |
| 137 | 137 | ||
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp index 521209622..c4a4a36be 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp | |||
| @@ -121,62 +121,64 @@ void EmuWindow_SDL2::Fullscreen() { | |||
| 121 | SDL_MaximizeWindow(render_window); | 121 | SDL_MaximizeWindow(render_window); |
| 122 | } | 122 | } |
| 123 | 123 | ||
| 124 | void EmuWindow_SDL2::PollEvents() { | 124 | void EmuWindow_SDL2::WaitEvent() { |
| 125 | // Called on main thread | ||
| 125 | SDL_Event event; | 126 | SDL_Event event; |
| 126 | 127 | ||
| 127 | // SDL_PollEvent returns 0 when there are no more events in the event queue | 128 | if (!SDL_WaitEvent(&event)) { |
| 128 | while (SDL_PollEvent(&event)) { | 129 | LOG_CRITICAL(Frontend, "SDL_WaitEvent failed: {}", SDL_GetError()); |
| 129 | switch (event.type) { | 130 | exit(1); |
| 130 | case SDL_WINDOWEVENT: | 131 | } |
| 131 | switch (event.window.event) { | 132 | |
| 132 | case SDL_WINDOWEVENT_SIZE_CHANGED: | 133 | switch (event.type) { |
| 133 | case SDL_WINDOWEVENT_RESIZED: | 134 | case SDL_WINDOWEVENT: |
| 134 | case SDL_WINDOWEVENT_MAXIMIZED: | 135 | switch (event.window.event) { |
| 135 | case SDL_WINDOWEVENT_RESTORED: | 136 | case SDL_WINDOWEVENT_SIZE_CHANGED: |
| 136 | OnResize(); | 137 | case SDL_WINDOWEVENT_RESIZED: |
| 137 | break; | 138 | case SDL_WINDOWEVENT_MAXIMIZED: |
| 138 | case SDL_WINDOWEVENT_MINIMIZED: | 139 | case SDL_WINDOWEVENT_RESTORED: |
| 139 | case SDL_WINDOWEVENT_EXPOSED: | 140 | OnResize(); |
| 140 | is_shown = event.window.event == SDL_WINDOWEVENT_EXPOSED; | ||
| 141 | OnResize(); | ||
| 142 | break; | ||
| 143 | case SDL_WINDOWEVENT_CLOSE: | ||
| 144 | is_open = false; | ||
| 145 | break; | ||
| 146 | } | ||
| 147 | break; | ||
| 148 | case SDL_KEYDOWN: | ||
| 149 | case SDL_KEYUP: | ||
| 150 | OnKeyEvent(static_cast<int>(event.key.keysym.scancode), event.key.state); | ||
| 151 | break; | ||
| 152 | case SDL_MOUSEMOTION: | ||
| 153 | // ignore if it came from touch | ||
| 154 | if (event.button.which != SDL_TOUCH_MOUSEID) | ||
| 155 | OnMouseMotion(event.motion.x, event.motion.y); | ||
| 156 | break; | ||
| 157 | case SDL_MOUSEBUTTONDOWN: | ||
| 158 | case SDL_MOUSEBUTTONUP: | ||
| 159 | // ignore if it came from touch | ||
| 160 | if (event.button.which != SDL_TOUCH_MOUSEID) { | ||
| 161 | OnMouseButton(event.button.button, event.button.state, event.button.x, | ||
| 162 | event.button.y); | ||
| 163 | } | ||
| 164 | break; | ||
| 165 | case SDL_FINGERDOWN: | ||
| 166 | OnFingerDown(event.tfinger.x, event.tfinger.y); | ||
| 167 | break; | ||
| 168 | case SDL_FINGERMOTION: | ||
| 169 | OnFingerMotion(event.tfinger.x, event.tfinger.y); | ||
| 170 | break; | 141 | break; |
| 171 | case SDL_FINGERUP: | 142 | case SDL_WINDOWEVENT_MINIMIZED: |
| 172 | OnFingerUp(); | 143 | case SDL_WINDOWEVENT_EXPOSED: |
| 144 | is_shown = event.window.event == SDL_WINDOWEVENT_EXPOSED; | ||
| 145 | OnResize(); | ||
| 173 | break; | 146 | break; |
| 174 | case SDL_QUIT: | 147 | case SDL_WINDOWEVENT_CLOSE: |
| 175 | is_open = false; | 148 | is_open = false; |
| 176 | break; | 149 | break; |
| 177 | default: | ||
| 178 | break; | ||
| 179 | } | 150 | } |
| 151 | break; | ||
| 152 | case SDL_KEYDOWN: | ||
| 153 | case SDL_KEYUP: | ||
| 154 | OnKeyEvent(static_cast<int>(event.key.keysym.scancode), event.key.state); | ||
| 155 | break; | ||
| 156 | case SDL_MOUSEMOTION: | ||
| 157 | // ignore if it came from touch | ||
| 158 | if (event.button.which != SDL_TOUCH_MOUSEID) | ||
| 159 | OnMouseMotion(event.motion.x, event.motion.y); | ||
| 160 | break; | ||
| 161 | case SDL_MOUSEBUTTONDOWN: | ||
| 162 | case SDL_MOUSEBUTTONUP: | ||
| 163 | // ignore if it came from touch | ||
| 164 | if (event.button.which != SDL_TOUCH_MOUSEID) { | ||
| 165 | OnMouseButton(event.button.button, event.button.state, event.button.x, event.button.y); | ||
| 166 | } | ||
| 167 | break; | ||
| 168 | case SDL_FINGERDOWN: | ||
| 169 | OnFingerDown(event.tfinger.x, event.tfinger.y); | ||
| 170 | break; | ||
| 171 | case SDL_FINGERMOTION: | ||
| 172 | OnFingerMotion(event.tfinger.x, event.tfinger.y); | ||
| 173 | break; | ||
| 174 | case SDL_FINGERUP: | ||
| 175 | OnFingerUp(); | ||
| 176 | break; | ||
| 177 | case SDL_QUIT: | ||
| 178 | is_open = false; | ||
| 179 | break; | ||
| 180 | default: | ||
| 181 | break; | ||
| 180 | } | 182 | } |
| 181 | 183 | ||
| 182 | const u32 current_time = SDL_GetTicks(); | 184 | const u32 current_time = SDL_GetTicks(); |
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.h b/src/yuzu_cmd/emu_window/emu_window_sdl2.h index 53d756c3c..a93141240 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.h +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.h | |||
| @@ -23,38 +23,38 @@ public: | |||
| 23 | explicit EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem); | 23 | explicit EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem); |
| 24 | ~EmuWindow_SDL2(); | 24 | ~EmuWindow_SDL2(); |
| 25 | 25 | ||
| 26 | /// Polls window events | ||
| 27 | void PollEvents() override; | ||
| 28 | |||
| 29 | /// Whether the window is still open, and a close request hasn't yet been sent | 26 | /// Whether the window is still open, and a close request hasn't yet been sent |
| 30 | bool IsOpen() const; | 27 | bool IsOpen() const; |
| 31 | 28 | ||
| 32 | /// Returns if window is shown (not minimized) | 29 | /// Returns if window is shown (not minimized) |
| 33 | bool IsShown() const override; | 30 | bool IsShown() const override; |
| 34 | 31 | ||
| 32 | /// Wait for the next event on the main thread. | ||
| 33 | void WaitEvent(); | ||
| 34 | |||
| 35 | protected: | 35 | protected: |
| 36 | /// Called by PollEvents when a key is pressed or released. | 36 | /// Called by WaitEvent when a key is pressed or released. |
| 37 | void OnKeyEvent(int key, u8 state); | 37 | void OnKeyEvent(int key, u8 state); |
| 38 | 38 | ||
| 39 | /// Called by PollEvents when the mouse moves. | 39 | /// Called by WaitEvent when the mouse moves. |
| 40 | void OnMouseMotion(s32 x, s32 y); | 40 | void OnMouseMotion(s32 x, s32 y); |
| 41 | 41 | ||
| 42 | /// Called by PollEvents when a mouse button is pressed or released | 42 | /// Called by WaitEvent when a mouse button is pressed or released |
| 43 | void OnMouseButton(u32 button, u8 state, s32 x, s32 y); | 43 | void OnMouseButton(u32 button, u8 state, s32 x, s32 y); |
| 44 | 44 | ||
| 45 | /// Translates pixel position (0..1) to pixel positions | 45 | /// Translates pixel position (0..1) to pixel positions |
| 46 | std::pair<unsigned, unsigned> TouchToPixelPos(float touch_x, float touch_y) const; | 46 | std::pair<unsigned, unsigned> TouchToPixelPos(float touch_x, float touch_y) const; |
| 47 | 47 | ||
| 48 | /// Called by PollEvents when a finger starts touching the touchscreen | 48 | /// Called by WaitEvent when a finger starts touching the touchscreen |
| 49 | void OnFingerDown(float x, float y); | 49 | void OnFingerDown(float x, float y); |
| 50 | 50 | ||
| 51 | /// Called by PollEvents when a finger moves while touching the touchscreen | 51 | /// Called by WaitEvent when a finger moves while touching the touchscreen |
| 52 | void OnFingerMotion(float x, float y); | 52 | void OnFingerMotion(float x, float y); |
| 53 | 53 | ||
| 54 | /// Called by PollEvents when a finger stops touching the touchscreen | 54 | /// Called by WaitEvent when a finger stops touching the touchscreen |
| 55 | void OnFingerUp(); | 55 | void OnFingerUp(); |
| 56 | 56 | ||
| 57 | /// Called by PollEvents when any event that may cause the window to be resized occurs | 57 | /// Called by WaitEvent when any event that may cause the window to be resized occurs |
| 58 | void OnResize(); | 58 | void OnResize(); |
| 59 | 59 | ||
| 60 | /// Called when user passes the fullscreen parameter flag | 60 | /// Called when user passes the fullscreen parameter flag |
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index 3a76c785f..3c675ecb8 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp | |||
| @@ -242,7 +242,7 @@ int main(int argc, char** argv) { | |||
| 242 | 242 | ||
| 243 | system.Run(); | 243 | system.Run(); |
| 244 | while (emu_window->IsOpen()) { | 244 | while (emu_window->IsOpen()) { |
| 245 | std::this_thread::sleep_for(std::chrono::milliseconds(1)); | 245 | emu_window->WaitEvent(); |
| 246 | } | 246 | } |
| 247 | system.Pause(); | 247 | system.Pause(); |
| 248 | system.Shutdown(); | 248 | system.Shutdown(); |
diff --git a/src/yuzu_tester/emu_window/emu_window_sdl2_hide.cpp b/src/yuzu_tester/emu_window/emu_window_sdl2_hide.cpp index 78f75fb38..358e03870 100644 --- a/src/yuzu_tester/emu_window/emu_window_sdl2_hide.cpp +++ b/src/yuzu_tester/emu_window/emu_window_sdl2_hide.cpp | |||
| @@ -109,8 +109,6 @@ EmuWindow_SDL2_Hide::~EmuWindow_SDL2_Hide() { | |||
| 109 | SDL_Quit(); | 109 | SDL_Quit(); |
| 110 | } | 110 | } |
| 111 | 111 | ||
| 112 | void EmuWindow_SDL2_Hide::PollEvents() {} | ||
| 113 | |||
| 114 | bool EmuWindow_SDL2_Hide::IsShown() const { | 112 | bool EmuWindow_SDL2_Hide::IsShown() const { |
| 115 | return false; | 113 | return false; |
| 116 | } | 114 | } |
diff --git a/src/yuzu_tester/emu_window/emu_window_sdl2_hide.h b/src/yuzu_tester/emu_window/emu_window_sdl2_hide.h index a553b4b95..adccdf35e 100644 --- a/src/yuzu_tester/emu_window/emu_window_sdl2_hide.h +++ b/src/yuzu_tester/emu_window/emu_window_sdl2_hide.h | |||
| @@ -17,9 +17,6 @@ public: | |||
| 17 | explicit EmuWindow_SDL2_Hide(); | 17 | explicit EmuWindow_SDL2_Hide(); |
| 18 | ~EmuWindow_SDL2_Hide(); | 18 | ~EmuWindow_SDL2_Hide(); |
| 19 | 19 | ||
| 20 | /// Polls window events | ||
| 21 | void PollEvents() override; | ||
| 22 | |||
| 23 | /// Whether the screen is being shown or not. | 20 | /// Whether the screen is being shown or not. |
| 24 | bool IsShown() const override; | 21 | bool IsShown() const override; |
| 25 | 22 | ||