Просмотр исходного кода

device: windows: poll joypads in a background thread

Daniele Bartolini 3 лет назад
Родитель
Сommit
1930fc32e7
2 измененных файлов с 43 добавлено и 25 удалено
  1. 4 0
      docs/changelog.rst
  2. 39 25
      src/device/main_windows.cpp

+ 4 - 0
docs/changelog.rst

@@ -9,6 +9,10 @@ Changelog
 
 * Fixed file changes not detected sometimes.
 
+**Runtime**
+
+* Windows: reduced CPU usage by polling joypads' status in a background thread.
+
 **Tools**
 
 * Fixed minor issues when toggling the Console.

+ 39 - 25
src/device/main_windows.cpp

@@ -11,7 +11,7 @@
 #include "core/guid.h"
 #include "core/memory/globals.h"
 #include "core/memory/memory.inl"
-#include "core/thread/spsc_queue.inl"
+#include "core/thread/mpsc_queue.inl"
 #include "core/thread/thread.h"
 #include "core/unit_tests.h"
 #include "device/device.h"
@@ -285,14 +285,15 @@ struct WindowsDevice
 {
 	HWND _hwnd;
 	HCURSOR _hcursor;
-	SPSCQueue<OsEvent, CROWN_MAX_OS_EVENTS> _events;
+	MPSCQueue<OsEvent, CROWN_MAX_OS_EVENTS> _events;
 	DeviceEventQueue _queue;
 	Joypad _joypad;
 	s16 _mouse_last_x;
 	s16 _mouse_last_y;
 	CursorMode::Enum _cursor_mode;
+	DeviceOptions *_options;
 
-	WindowsDevice(Allocator &a)
+	WindowsDevice(Allocator &a, DeviceOptions &opts)
 		: _hwnd(NULL)
 		, _hcursor(NULL)
 		, _events(a)
@@ -300,10 +301,11 @@ struct WindowsDevice
 		, _mouse_last_x(INT16_MAX)
 		, _mouse_last_y(INT16_MAX)
 		, _cursor_mode(CursorMode::NORMAL)
+		, _options(&opts)
 	{
 	}
 
-	int run(DeviceOptions *opts)
+	int run()
 	{
 		HINSTANCE instance = (HINSTANCE)GetModuleHandle(NULL);
 		WNDCLASSEX wnd;
@@ -320,7 +322,7 @@ struct WindowsDevice
 
 		DWORD style = WS_VISIBLE;
 		DWORD exstyle = 0;
-		if (opts->_parent_window == 0) {
+		if (_options->_parent_window == 0) {
 			style |= WS_OVERLAPPEDWINDOW;
 		} else {
 			style |= WS_POPUP;
@@ -330,16 +332,16 @@ struct WindowsDevice
 		RECT rect;
 		rect.left   = 0;
 		rect.top    = 0;
-		rect.right  = opts->_window_width;
-		rect.bottom = opts->_window_height;
+		rect.right  = _options->_window_width;
+		rect.bottom = _options->_window_height;
 		AdjustWindowRect(&rect, style, FALSE);
 
 		_hwnd = CreateWindowExA(exstyle
 			, "crown"
 			, "Crown"
 			, style
-			, opts->_window_x
-			, opts->_window_y
+			, _options->_window_x
+			, _options->_window_y
 			, rect.right - rect.left
 			, rect.bottom - rect.top
 			, 0
@@ -349,8 +351,8 @@ struct WindowsDevice
 			);
 		CE_ASSERT(_hwnd != NULL, "CreateWindowA: GetLastError = %d", GetLastError());
 
-		if (opts->_parent_window != 0)
-			SetParent(_hwnd, (HWND)(UINT_PTR)opts->_parent_window);
+		if (_options->_parent_window != 0)
+			SetParent(_hwnd, (HWND)(UINT_PTR)_options->_parent_window);
 
 		_hcursor = LoadCursorA(NULL, IDC_ARROW);
 
@@ -368,25 +370,36 @@ struct WindowsDevice
 
 		Thread main_thread;
 		main_thread.start([](void *user_data) {
-				crown::run(*((DeviceOptions *)user_data));
+				WindowsDevice *win = (WindowsDevice *)user_data;
+				crown::run(*win->_options);
 				s_exit = true;
+				PostMessageA(win->_hwnd, WM_USER + 1, 0, 0);
 				return EXIT_SUCCESS;
 			}
-			, opts
+			, this
 			);
 
+		Thread joypad_thread;
+		joypad_thread.start([](void *user_data) {
+				WindowsDevice *win = (WindowsDevice *)user_data;
+				while (!s_exit) {
+					win->_joypad.update(win->_queue);
+					os::sleep(4);
+				}
+				return EXIT_SUCCESS;
+			}
+			, this
+			);
+
+		// Windows event loop.
 		MSG msg;
 		msg.message = WM_NULL;
-
-		while (!s_exit) {
-			_joypad.update(_queue);
-
-			while (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE) != 0) {
-				TranslateMessage(&msg);
-				DispatchMessage(&msg);
-			}
+		while (GetMessage(&msg, NULL, 0U, 0U) != 0) {
+			TranslateMessage(&msg);
+			DispatchMessage(&msg);
 		}
 
+		joypad_thread.stop();
 		main_thread.stop();
 
 		// Destroy standard cursors
@@ -410,9 +423,10 @@ struct WindowsDevice
 	{
 		switch (id) {
 		case WM_DESTROY:
-			break;
+		case WM_USER + 1:
+			PostQuitMessage(0);
+			return 0;
 
-		case WM_QUIT:
 		case WM_CLOSE:
 			s_exit = true;
 			_queue.push_exit_event();
@@ -856,8 +870,8 @@ int main(int argc, char **argv)
 #endif
 
 	if (ec == EXIT_SUCCESS) {
-		s_windows_device = CE_NEW(default_allocator(), WindowsDevice)(default_allocator());
-		ec = s_windows_device->run(&opts);
+		s_windows_device = CE_NEW(default_allocator(), WindowsDevice)(default_allocator(), opts);
+		ec = s_windows_device->run();
 		CE_DELETE(default_allocator(), s_windows_device);
 	}