From 58d2f6e3ffdca4b8c2e31b66a659ac36a3331b0d Mon Sep 17 00:00:00 2001 From: ts-korhonen Date: Mon, 19 Apr 2021 01:05:53 +0300 Subject: [PATCH 1/5] win_opengl: Optimize message handling by replacing SDL_PollEvents with basic win32 message pump. --- src/win/win_opengl.c | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/src/win/win_opengl.c b/src/win/win_opengl.c index 86732e0eb..59f3e005e 100644 --- a/src/win/win_opengl.c +++ b/src/win/win_opengl.c @@ -171,28 +171,21 @@ static void set_parent_binding(int enable) } /** - * @brief Windows message handler for SDL Windows. - * @param userdata winmessage_data - * @param hWnd + * @brief Windows message handler for our window. * @param message * @param wParam * @param lParam + * @param fullscreen */ -static void winmessage_hook(void* userdata, void* hWnd, unsigned int message, Uint64 wParam, Sint64 lParam) +static void handle_window_messages(UINT message, WPARAM wParam, LPARAM lParam, int fullscreen) { - winmessage_data* msg_data = (winmessage_data*)userdata; - - /* Process only our window */ - if (msg_data->window != hWnd || parent == NULL) - return; - switch (message) { case WM_LBUTTONUP: case WM_LBUTTONDOWN: case WM_MBUTTONUP: case WM_MBUTTONDOWN: - if (!*msg_data->fullscreen) + if (!fullscreen) { /* Mouse events that enter and exit capture. */ PostMessage(parent, message, wParam, lParam); @@ -202,13 +195,13 @@ static void winmessage_hook(void* userdata, void* hWnd, unsigned int message, Ui case WM_KEYUP: case WM_SYSKEYDOWN: case WM_SYSKEYUP: - if (*msg_data->fullscreen) + if (fullscreen) { PostMessage(parent, message, wParam, lParam); } break; case WM_INPUT: - if (*msg_data->fullscreen) + if (fullscreen) { /* Raw input handler from win_ui.c : input_proc */ @@ -383,8 +376,6 @@ static void opengl_main(void* param) /* Pass window handle and full screen mode to windows message hook */ winmessage_data msg_data = (winmessage_data){ window_hwnd, &fullscreen }; - - SDL_SetWindowsMessageHook(winmessage_hook, &msg_data); if (!fullscreen) set_parent_binding(1); @@ -423,10 +414,15 @@ static void opengl_main(void* param) } } - SDL_Event event; - - /* Handle SDL_Window events */ - while (SDL_PollEvent(&event)) { /* No need for actual handlers, but message queue must be processed. */ } + /* Handle window messages */ + MSG msg; + if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + if (msg.hwnd == window_hwnd) + handle_window_messages(msg.message, msg.wParam, msg.lParam, fullscreen); + TranslateMessage(&msg); + DispatchMessage(&msg); + } /* Keep cursor hidden in full screen and mouse capture */ int show_cursor = !(fullscreen || !!mouse_capture); From 3088c6c26f410f5c2b843db4136eb300669ec7b1 Mon Sep 17 00:00:00 2001 From: ts-korhonen Date: Wed, 21 Apr 2021 01:33:01 +0300 Subject: [PATCH 2/5] win_opengl: (WIP)UI for options. Add comments to help find conditionals that put opengl in dev_branch. --- src/86box.c | 3 ++ src/include/86box/86box.h | 3 ++ src/include/86box/language.h | 3 +- src/include/86box/resource.h | 11 ++++++ src/include/86box/win_opengl_glslp.h | 2 +- src/win/86Box.rc | 19 +++++++++- src/win/win.c | 17 +++++---- src/win/win_opengl.c | 57 +++++++++++++++------------- src/win/win_opengl_glslp.c | 4 +- src/win/win_ui.c | 19 +++++++++- 10 files changed, 97 insertions(+), 41 deletions(-) diff --git a/src/86box.c b/src/86box.c index 6fb7541a7..8e220a76b 100644 --- a/src/86box.c +++ b/src/86box.c @@ -129,6 +129,9 @@ int video_fullscreen_scale = 0; /* (C) video */ int video_fullscreen_first = 0; /* (C) video */ int enable_overscan = 0; /* (C) video */ int force_43 = 0; /* (C) video */ +int video_vsync = 0; /* (C) video */ +int video_frametime = -1; /* (C) video */ +char video_shader[512] = { '\0' }; /* (C) video */ int serial_enabled[SERIAL_MAX] = {0,0}; /* (C) enable serial ports */ int bugger_enabled = 0; /* (C) enable ISAbugger */ int postcard_enabled = 0; /* (C) enable POST card */ diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index 1429c698c..b16b8100b 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -90,7 +90,10 @@ extern int vid_cga_contrast, /* (C) video */ video_fullscreen_scale, /* (C) video */ enable_overscan, /* (C) video */ force_43, /* (C) video */ + video_vsync, /* (C) video */ + video_frametime, /* (C) video */ gfxcard; /* (C) graphics/video card */ +extern char video_shader[512]; /* (C) video */ extern int serial_enabled[], /* (C) enable serial ports */ bugger_enabled, /* (C) enable ISAbugger */ postcard_enabled, /* (C) enable POST card */ diff --git a/src/include/86box/language.h b/src/include/86box/language.h index 006bc2312..4f7e05f6e 100644 --- a/src/include/86box/language.h +++ b/src/include/86box/language.h @@ -116,6 +116,7 @@ #define IDS_2140 2140 // "CD-ROM images (*.ISO;*.CU.." #define IDS_2141 2141 // "%hs Device Configuration" #define IDS_2142 2142 // "Monitor in sleep mode" +#define IDS_2143 2143 // "OpenGL Shaders (*.GLSL)..." #define IDS_4096 4096 // "Hard disk (%s)" #define IDS_4097 4097 // "%01i:%01i" @@ -223,7 +224,7 @@ #define IDS_LANG_ENUS IDS_7168 -#define STR_NUM_2048 95 +#define STR_NUM_2048 96 #define STR_NUM_3072 11 #define STR_NUM_4096 39 #define STR_NUM_4352 6 diff --git a/src/include/86box/resource.h b/src/include/86box/resource.h index d2901b40f..a3b2a0f93 100644 --- a/src/include/86box/resource.h +++ b/src/include/86box/resource.h @@ -341,6 +341,17 @@ #define IDM_DISCORD 40090 #endif +#ifdef DEV_BRANCH /* feature-opengl */ +#define IDM_VID_GL_FPS_BLITTER 40100 +#define IDM_VID_GL_FPS_25 40101 +#define IDM_VID_GL_FPS_30 40102 +#define IDM_VID_GL_FPS_50 40103 +#define IDM_VID_GL_FPS_60 40104 +#define IDM_VID_GL_FPS_75 40105 +#define IDM_VID_GL_VSYNC 40106 +#define IDM_VID_GL_SHADER 40107 +#endif + #define IDM_LOG_BREAKPOINT 51201 #define IDM_DUMP_VRAM 51202 // should be an Action diff --git a/src/include/86box/win_opengl_glslp.h b/src/include/86box/win_opengl_glslp.h index 1a9e5a9ca..dcc098635 100644 --- a/src/include/86box/win_opengl_glslp.h +++ b/src/include/86box/win_opengl_glslp.h @@ -17,7 +17,7 @@ #include -GLuint load_custom_shaders(); +GLuint load_custom_shaders(const char* path); GLuint load_default_shaders(); #endif /*!WIN_OPENGL_GLSLP_H*/ \ No newline at end of file diff --git a/src/win/86Box.rc b/src/win/86Box.rc index 382c7e48a..007207b90 100644 --- a/src/win/86Box.rc +++ b/src/win/86Box.rc @@ -66,13 +66,29 @@ BEGIN MENUITEM "&SDL (Software)", IDM_VID_SDL_SW MENUITEM "SDL (&Hardware)", IDM_VID_SDL_HW MENUITEM "SDL (&OpenGL)", IDM_VID_SDL_OPENGL -#ifdef DEV_BRANCH +#ifdef DEV_BRANCH /* feature-opengl */ MENUITEM "Open&GL (3.3 Core)", IDM_VID_OPENGL_CORE #endif #ifdef USE_VNC MENUITEM "&VNC", IDM_VID_VNC #endif END +#ifdef DEV_BRANCH /* feature-opengl */ + POPUP "Renderer o&ptions" + BEGIN + POPUP "Target &framerate" + BEGIN + MENUITEM "&Sync with video", IDM_VID_GL_FPS_BLITTER + MENUITEM "&25 fps", IDM_VID_GL_FPS_25 + MENUITEM "&30 fps", IDM_VID_GL_FPS_30 + MENUITEM "&50 fps", IDM_VID_GL_FPS_50 + MENUITEM "&60 fps", IDM_VID_GL_FPS_60 + MENUITEM "&75 fps", IDM_VID_GL_FPS_75 + END + MENUITEM "&VSync", IDM_VID_GL_VSYNC + MENUITEM "&Select shader...", IDM_VID_GL_SHADER + END +#endif MENUITEM SEPARATOR MENUITEM "Specify dimensions", IDM_VID_SPECIFY_DIM MENUITEM "F&orce 4:3 display ratio", IDM_VID_FORCE43 @@ -1080,6 +1096,7 @@ BEGIN IDS_2140 "CD-ROM images (*.ISO;*.CUE)\0*.ISO;*.CUE\0All files (*.*)\0*.*\0" IDS_2141 "%hs Device Configuration" IDS_2142 "Monitor in sleep mode" + IDS_2143 "OpenGL Shaders (*.GLSL)\0*.GLSL\0All files (*.*)\0*.*\0" END STRINGTABLE DISCARDABLE diff --git a/src/win/win.c b/src/win/win.c index 52cc1fe14..22e0e9237 100644 --- a/src/win/win.c +++ b/src/win/win.c @@ -99,17 +99,18 @@ static const struct { int (*pause)(void); void (*enable)(int enable); void (*set_fs)(int fs); + void (*reload)(void); } vid_apis[RENDERERS_NUM] = { - { "SDL_Software", 1, (int(*)(void*))sdl_inits, sdl_close, NULL, sdl_pause, sdl_enable, sdl_set_fs }, - { "SDL_Hardware", 1, (int(*)(void*))sdl_inith, sdl_close, NULL, sdl_pause, sdl_enable, sdl_set_fs }, - { "SDL_OpenGL", 1, (int(*)(void*))sdl_initho, sdl_close, NULL, sdl_pause, sdl_enable, sdl_set_fs } -#ifdef DEV_BRANCH - ,{ "OpenGL_Core", 1, (int(*)(void*))opengl_init, opengl_close, opengl_resize, opengl_pause, NULL, opengl_set_fs} + { "SDL_Software", 1, (int(*)(void*))sdl_inits, sdl_close, NULL, sdl_pause, sdl_enable, sdl_set_fs, NULL }, + { "SDL_Hardware", 1, (int(*)(void*))sdl_inith, sdl_close, NULL, sdl_pause, sdl_enable, sdl_set_fs, NULL }, + { "SDL_OpenGL", 1, (int(*)(void*))sdl_initho, sdl_close, NULL, sdl_pause, sdl_enable, sdl_set_fs, NULL } +#ifdef DEV_BRANCH /* feature-opengl */ + ,{ "OpenGL_Core", 1, (int(*)(void*))opengl_init, opengl_close, opengl_resize, opengl_pause, NULL, opengl_set_fs, NULL} #else - ,{ "OpenGL_Core", 1, (int(*)(void*))sdl_initho, sdl_close, NULL, sdl_pause, sdl_enable, sdl_set_fs } /* fall back to SDL_OpenGL */ + ,{ "OpenGL_Core", 1, (int(*)(void*))sdl_initho, sdl_close, NULL, sdl_pause, sdl_enable, sdl_set_fs, NULL } /* fall back to SDL_OpenGL */ #endif #ifdef USE_VNC - ,{ "VNC", 0, vnc_init, vnc_close, vnc_resize, vnc_pause, NULL, NULL } + ,{ "VNC", 0, vnc_init, vnc_close, vnc_resize, vnc_pause, NULL, NULL } #endif }; @@ -928,7 +929,7 @@ plat_vidapi_name(int api) case 2: name = "sdl_opengl"; break; -#ifdef DEV_BRANCH +#ifdef DEV_BRANCH /* feature-opengl */ case 3: name = "opengl_core"; break; diff --git a/src/win/win_opengl.c b/src/win/win_opengl.c index 59f3e005e..c9775e462 100644 --- a/src/win/win_opengl.c +++ b/src/win/win_opengl.c @@ -41,6 +41,7 @@ #include #include +#include #include <86box/86box.h> #include <86box/plat.h> @@ -52,13 +53,6 @@ static const int INIT_WIDTH = 640; static const int INIT_HEIGHT = 400; -/* Option; Target framerate: Sync with emulation / 25 fps / 30 fps / 50 fps / 60 fps / 75 fps */ -static const int SYNC_WITH_BLITTER = 1; -static const int TARGET_FRAMETIME = 13; - -/* Option; Vsync: Off / On */ -static const int VSYNC = 0; - /** * @brief A dedicated OpenGL thread. * OpenGL context's don't handle multiple threads well. @@ -89,9 +83,10 @@ static union { HANDLE closing; HANDLE resize; + HANDLE reload; HANDLE blit_waiting; }; - HANDLE asArray[3]; + HANDLE asArray[4]; } sync_objects = { 0 }; /** @@ -115,6 +110,16 @@ static volatile struct int width, height, fullscreen, scaling_mode; } resize_info = { 0 }; +/** + * @brief Renderer options +*/ +static volatile struct +{ + int vsync; /* Vertical sync; 0 = off, 1 = on */ + int frametime; /* Frametime in ms, or -1 to sync with blitter */ + char shaderfile[512]; /* Shader file path. Match the length of openfilestring in win_dialog.c */ +} options = { 0 }; + /** * @brief Identifiers to OpenGL objects and uniforms. */ @@ -133,15 +138,6 @@ typedef struct GLint frame_count; } gl_identifiers; -/** - * @brief Userdata to pass onto windows message hook -*/ -typedef struct -{ - HWND window; - int* fullscreen; -} winmessage_data; - /** * @brief Set or unset OpenGL context window as a child window. * @@ -269,7 +265,7 @@ static gl_identifiers initialize_glcontext() glClearColor(0.f, 0.f, 0.f, 1.f); - gl.shader_progID = load_custom_shaders(); + gl.shader_progID = load_custom_shaders(options.shaderfile); if (gl.shader_progID == 0) gl.shader_progID = load_default_shaders(); @@ -362,7 +358,7 @@ static void opengl_main(void* param) window = SDL_CreateWindow("86Box OpenGL Renderer", 0, 0, resize_info.width, resize_info.height, SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS); - SDL_GL_SetSwapInterval(VSYNC); + SDL_GL_SetSwapInterval(options.vsync); /* Keep track of certain parameters, only changed in this thread to avoid race conditions */ int fullscreen = resize_info.fullscreen, video_width = INIT_WIDTH, video_height = INIT_HEIGHT; @@ -374,9 +370,6 @@ static void opengl_main(void* param) if (wmi.subsystem == SDL_SYSWM_WINDOWS) window_hwnd = wmi.info.win.window; - /* Pass window handle and full screen mode to windows message hook */ - winmessage_data msg_data = (winmessage_data){ window_hwnd, &fullscreen }; - if (!fullscreen) set_parent_binding(1); else @@ -391,23 +384,23 @@ static void opengl_main(void* param) if (gl.frame_count != -1) glUniform1i(gl.frame_count, 0); - uint32_t last_swap = -TARGET_FRAMETIME; + uint32_t last_swap = -options.frametime; /* Render loop */ int closing = 0; while (!closing) { - if (SYNC_WITH_BLITTER) + if (options.frametime < 0) render_and_swap(gl); DWORD wait_result = WAIT_TIMEOUT; do { - if (!SYNC_WITH_BLITTER) + if (options.frametime >= 0) { uint32_t ticks = plat_get_ticks(); - if (ticks - last_swap > TARGET_FRAMETIME) + if (ticks - last_swap >= options.frametime) { render_and_swap(gl); last_swap = ticks; @@ -591,6 +584,10 @@ int opengl_init(HWND hwnd) resize_info.fullscreen = video_fullscreen & 1; resize_info.scaling_mode = video_fullscreen_scale; + options.vsync = video_vsync; + options.frametime = -1; + strcpy_s(options.shaderfile, sizeof(options.shaderfile), "shaders/shader.glsl"); + thread = thread_create(opengl_main, (void*)NULL); atexit(opengl_close); @@ -652,4 +649,12 @@ void opengl_resize(int w, int h) resize_info.scaling_mode = video_fullscreen_scale; SetEvent(sync_objects.resize); +} + +void opengl_reload(void) +{ + if (thread == NULL) + return; + + SetEvent(sync_objects.reload); } \ No newline at end of file diff --git a/src/win/win_opengl_glslp.c b/src/win/win_opengl_glslp.c index 0b7e54c77..0a0d7f004 100644 --- a/src/win/win_opengl_glslp.c +++ b/src/win/win_opengl_glslp.c @@ -107,13 +107,13 @@ static char* read_file_to_string(const char* path) * @brief Compile custom shaders into a program. * @return Shader program identifier. */ -GLuint load_custom_shaders() +GLuint load_custom_shaders(const char* path) { GLint status = GL_FALSE; int info_log_length; /* TODO: get path from config */ - char* shader = read_file_to_string("shaders/shader.glsl"); + char* shader = read_file_to_string(path); if (shader != NULL) { diff --git a/src/win/win_ui.c b/src/win/win_ui.c index ce05d4a57..6a3584886 100644 --- a/src/win/win_ui.c +++ b/src/win/win_ui.c @@ -223,7 +223,7 @@ ResetAllMenus(void) CheckMenuItem(menuMain, IDM_VID_SDL_SW, MF_UNCHECKED); CheckMenuItem(menuMain, IDM_VID_SDL_HW, MF_UNCHECKED); CheckMenuItem(menuMain, IDM_VID_SDL_OPENGL, MF_UNCHECKED); -#ifdef DEV_BRANCH +#ifdef DEV_BRANCH /* feature-opengl */ CheckMenuItem(menuMain, IDM_VID_OPENGL_CORE, MF_UNCHECKED); #endif #ifdef USE_VNC @@ -672,7 +672,7 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case IDM_VID_SDL_SW: case IDM_VID_SDL_HW: case IDM_VID_SDL_OPENGL: -#ifdef DEV_BRANCH +#ifdef DEV_BRANCH /* feature-opengl */ case IDM_VID_OPENGL_CORE: #endif #ifdef USE_VNC @@ -684,6 +684,21 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) config_save(); break; +#ifdef DEV_BRANCH /* feature-opengl */ + case IDM_VID_GL_VSYNC: + video_vsync = !video_vsync; + CheckMenuItem(hmenu, IDM_VID_GL_VSYNC, video_vsync ? MF_CHECKED : MF_UNCHECKED); + //plat_reload_config + config_save(); + break; + case IDM_VID_GL_SHADER: + win_notify_dlg_open(); + if (file_dlg_st(hwnd, IDS_2143, video_shader, NULL, 0) == 0) + strcpy_s(video_shader, sizeof(video_shader), openfilestring); + win_notify_dlg_closed(); + break; +#endif + case IDM_VID_FULLSCREEN: plat_setfullscreen(1); config_save(); From 579e221a76dc695efcf5c2475885511ce4a392ab Mon Sep 17 00:00:00 2001 From: ts-korhonen Date: Thu, 22 Apr 2021 01:15:10 +0300 Subject: [PATCH 3/5] win_opengl: Protect resize_info with mutex. --- src/win/win_opengl.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/win/win_opengl.c b/src/win/win_opengl.c index c9775e462..f154cdec6 100644 --- a/src/win/win_opengl.c +++ b/src/win/win_opengl.c @@ -105,9 +105,10 @@ static volatile struct /** * @brief Resize event parameters. */ -static volatile struct +static struct { int width, height, fullscreen, scaling_mode; + mutex_t* mutex; } resize_info = { 0 }; /** @@ -461,6 +462,8 @@ static void opengl_main(void* param) } else if (sync_event == sync_objects.resize) { + thread_wait_mutex(resize_info.mutex); + if (fullscreen != resize_info.fullscreen) { fullscreen = resize_info.fullscreen; @@ -529,6 +532,8 @@ static void opengl_main(void* param) if (gl.output_size != -1) glUniform2f(gl.output_size, resize_info.width, resize_info.height); } + + thread_release_mutex(resize_info.mutex); } } @@ -568,6 +573,9 @@ static void opengl_blit(int x, int y, int y1, int y2, int w, int h) int opengl_init(HWND hwnd) { + if (thread != NULL) + return 0; + for (int i = 0; i < sizeof(sync_objects) / sizeof(HANDLE); i++) sync_objects.asArray[i] = CreateEvent(NULL, FALSE, FALSE, NULL); @@ -583,6 +591,7 @@ int opengl_init(HWND hwnd) resize_info.height = parent_size.bottom - parent_size.top; resize_info.fullscreen = video_fullscreen & 1; resize_info.scaling_mode = video_fullscreen_scale; + resize_info.mutex = thread_create_mutex(); options.vsync = video_vsync; options.frametime = -1; @@ -613,6 +622,8 @@ void opengl_close(void) memset((void*)&blit_info, 0, sizeof(blit_info)); + thread_close_mutex(resize_info.mutex); + SetEvent(blit_done); thread = NULL; @@ -633,9 +644,13 @@ void opengl_set_fs(int fs) if (thread == NULL) return; + thread_wait_mutex(resize_info.mutex); + resize_info.fullscreen = fs; resize_info.scaling_mode = video_fullscreen_scale; + thread_release_mutex(resize_info.mutex); + SetEvent(sync_objects.resize); } @@ -644,10 +659,14 @@ void opengl_resize(int w, int h) if (thread == NULL) return; + thread_wait_mutex(resize_info.mutex); + resize_info.width = w; resize_info.height = h; resize_info.scaling_mode = video_fullscreen_scale; + thread_release_mutex(resize_info.mutex); + SetEvent(sync_objects.resize); } From 2bf6c7aa11f443105ca4e7e417b29c69cf643d1e Mon Sep 17 00:00:00 2001 From: ts-korhonen Date: Fri, 23 Apr 2021 16:09:45 +0300 Subject: [PATCH 4/5] win_opengl: UI for options and add them to config. Reloading changed options at runtime. Improved framerate limitter. --- src/86box.c | 2 +- src/config.c | 21 +++ src/include/86box/86box.h | 2 +- src/include/86box/language.h | 3 +- src/include/86box/plat.h | 3 +- src/include/86box/win.h | 4 + src/include/86box/win_opengl.h | 1 + src/win/86Box.rc | 33 ++--- src/win/win.c | 29 +++- src/win/win_opengl.c | 236 +++++++++++++++++++++++---------- src/win/win_opengl_glslp.c | 8 +- src/win/win_ui.c | 87 +++++++++++- 12 files changed, 325 insertions(+), 104 deletions(-) diff --git a/src/86box.c b/src/86box.c index 8e220a76b..7ede5d857 100644 --- a/src/86box.c +++ b/src/86box.c @@ -130,7 +130,7 @@ int video_fullscreen_first = 0; /* (C) video */ int enable_overscan = 0; /* (C) video */ int force_43 = 0; /* (C) video */ int video_vsync = 0; /* (C) video */ -int video_frametime = -1; /* (C) video */ +int video_framerate = -1; /* (C) video */ char video_shader[512] = { '\0' }; /* (C) video */ int serial_enabled[SERIAL_MAX] = {0,0}; /* (C) enable serial ports */ int bugger_enabled = 0; /* (C) enable ISAbugger */ diff --git a/src/config.c b/src/config.c index 363622c9c..68f3d306d 100644 --- a/src/config.c +++ b/src/config.c @@ -528,6 +528,12 @@ load_general(void) #if USE_DISCORD enable_discord = !!config_get_int(cat, "enable_discord", 0); #endif + +#ifdef DEV_BRANCH /* feature-opengl */ + video_framerate = config_get_int(cat, "video_gl_framerate", -1); + video_vsync = config_get_int(cat, "video_gl_vsync", 0); + strcpy_s(video_shader, sizeof(video_shader), config_get_string(cat, "video_gl_shader", "")); +#endif } @@ -1968,6 +1974,21 @@ save_general(void) config_delete_var(cat, "enable_discord"); #endif +#ifdef DEV_BRANCH /* feature-opengl */ + if (video_framerate != -1) + config_set_int(cat, "video_gl_framerate", video_framerate); + else + config_delete_var(cat, "video_gl_framerate"); + if (video_vsync != 0) + config_set_int(cat, "video_gl_vsync", video_vsync); + else + config_delete_var(cat, "video_gl_vsync"); + if (strlen(video_shader) > 0) + config_set_string(cat, "video_gl_shader", video_shader); + else + config_delete_var(cat, "video_gl_shader"); +#endif + delete_section_if_empty(cat); } diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index b16b8100b..7359b5de6 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -91,7 +91,7 @@ extern int vid_cga_contrast, /* (C) video */ enable_overscan, /* (C) video */ force_43, /* (C) video */ video_vsync, /* (C) video */ - video_frametime, /* (C) video */ + video_framerate, /* (C) video */ gfxcard; /* (C) graphics/video card */ extern char video_shader[512]; /* (C) video */ extern int serial_enabled[], /* (C) enable serial ports */ diff --git a/src/include/86box/language.h b/src/include/86box/language.h index 4f7e05f6e..61a4e3933 100644 --- a/src/include/86box/language.h +++ b/src/include/86box/language.h @@ -117,6 +117,7 @@ #define IDS_2141 2141 // "%hs Device Configuration" #define IDS_2142 2142 // "Monitor in sleep mode" #define IDS_2143 2143 // "OpenGL Shaders (*.GLSL)..." +#define IDS_2144 2144 // "OpenGL options" #define IDS_4096 4096 // "Hard disk (%s)" #define IDS_4097 4097 // "%01i:%01i" @@ -224,7 +225,7 @@ #define IDS_LANG_ENUS IDS_7168 -#define STR_NUM_2048 96 +#define STR_NUM_2048 97 #define STR_NUM_3072 11 #define STR_NUM_4096 39 #define STR_NUM_4352 6 diff --git a/src/include/86box/plat.h b/src/include/86box/plat.h index 6bdf3c7a6..09be0c1de 100644 --- a/src/include/86box/plat.h +++ b/src/include/86box/plat.h @@ -101,6 +101,7 @@ extern int plat_dir_check(char *path); extern int plat_dir_create(char *path); extern uint64_t plat_timer_read(void); extern uint32_t plat_get_ticks(void); +extern uint32_t plat_get_micro_ticks(void); extern void plat_delay_ms(uint32_t count); extern void plat_pause(int p); extern void plat_mouse_capture(int on); @@ -111,7 +112,7 @@ extern void plat_vidsize(int x, int y); extern void plat_setfullscreen(int on); extern void plat_resize(int x, int y); extern void plat_vidapi_enable(int enabled); - +extern void plat_vid_reload_options(void); /* Resource management. */ extern void set_language(int id); diff --git a/src/include/86box/win.h b/src/include/86box/win.h index 449eb2c6a..09c318e2f 100644 --- a/src/include/86box/win.h +++ b/src/include/86box/win.h @@ -63,6 +63,10 @@ DECLARE_HANDLE(DPI_AWARENESS_CONTEXT); #define ZIP_SUBMENU_NAME L"ZIPSubmenu" #define MO_SUBMENU_NAME L"MOSubmenu" +#ifdef DEV_BRANCH /* feature-opengl */ +#define VID_GL_SUBMENU L"VidGLSubMenu" +#endif + /* Application-specific window messages. A dialog sends 0x8895 with WPARAM = 1 followed by 0x8896 with WPARAM = 1 on open, diff --git a/src/include/86box/win_opengl.h b/src/include/86box/win_opengl.h index 8ac402ecc..9e78c0aed 100644 --- a/src/include/86box/win_opengl.h +++ b/src/include/86box/win_opengl.h @@ -23,5 +23,6 @@ extern int opengl_pause(void); extern void opengl_close(void); extern void opengl_set_fs(int fs); extern void opengl_resize(int w, int h); +extern void opengl_reload(void); #endif /*!WIN_OPENGL_H*/ \ No newline at end of file diff --git a/src/win/86Box.rc b/src/win/86Box.rc index 007207b90..f9671af32 100644 --- a/src/win/86Box.rc +++ b/src/win/86Box.rc @@ -73,22 +73,6 @@ BEGIN MENUITEM "&VNC", IDM_VID_VNC #endif END -#ifdef DEV_BRANCH /* feature-opengl */ - POPUP "Renderer o&ptions" - BEGIN - POPUP "Target &framerate" - BEGIN - MENUITEM "&Sync with video", IDM_VID_GL_FPS_BLITTER - MENUITEM "&25 fps", IDM_VID_GL_FPS_25 - MENUITEM "&30 fps", IDM_VID_GL_FPS_30 - MENUITEM "&50 fps", IDM_VID_GL_FPS_50 - MENUITEM "&60 fps", IDM_VID_GL_FPS_60 - MENUITEM "&75 fps", IDM_VID_GL_FPS_75 - END - MENUITEM "&VSync", IDM_VID_GL_VSYNC - MENUITEM "&Select shader...", IDM_VID_GL_SHADER - END -#endif MENUITEM SEPARATOR MENUITEM "Specify dimensions", IDM_VID_SPECIFY_DIM MENUITEM "F&orce 4:3 display ratio", IDM_VID_FORCE43 @@ -253,6 +237,22 @@ BEGIN END END +#ifdef DEV_BRANCH /* feature-opengl */ +VidGLSubMenu MENU DISCARDABLE +BEGIN + POPUP "Target &framerate" + BEGIN + MENUITEM "&Sync with video", IDM_VID_GL_FPS_BLITTER + MENUITEM "&25 fps", IDM_VID_GL_FPS_25 + MENUITEM "&30 fps", IDM_VID_GL_FPS_30 + MENUITEM "&50 fps", IDM_VID_GL_FPS_50 + MENUITEM "&60 fps", IDM_VID_GL_FPS_60 + MENUITEM "&75 fps", IDM_VID_GL_FPS_75 + END + MENUITEM "&VSync", IDM_VID_GL_VSYNC + MENUITEM "&Select shader...", IDM_VID_GL_SHADER +END +#endif ///////////////////////////////////////////////////////////////////////////// // @@ -1097,6 +1097,7 @@ BEGIN IDS_2141 "%hs Device Configuration" IDS_2142 "Monitor in sleep mode" IDS_2143 "OpenGL Shaders (*.GLSL)\0*.GLSL\0All files (*.*)\0*.*\0" + IDS_2144 "OpenGL options" END STRINGTABLE DISCARDABLE diff --git a/src/win/win.c b/src/win/win.c index 22e0e9237..5d5fe22fd 100644 --- a/src/win/win.c +++ b/src/win/win.c @@ -105,7 +105,7 @@ static const struct { { "SDL_Hardware", 1, (int(*)(void*))sdl_inith, sdl_close, NULL, sdl_pause, sdl_enable, sdl_set_fs, NULL }, { "SDL_OpenGL", 1, (int(*)(void*))sdl_initho, sdl_close, NULL, sdl_pause, sdl_enable, sdl_set_fs, NULL } #ifdef DEV_BRANCH /* feature-opengl */ - ,{ "OpenGL_Core", 1, (int(*)(void*))opengl_init, opengl_close, opengl_resize, opengl_pause, NULL, opengl_set_fs, NULL} + ,{ "OpenGL_Core", 1, (int(*)(void*))opengl_init, opengl_close, opengl_resize, opengl_pause, NULL, opengl_set_fs, opengl_reload} #else ,{ "OpenGL_Core", 1, (int(*)(void*))sdl_initho, sdl_close, NULL, sdl_pause, sdl_enable, sdl_set_fs, NULL } /* fall back to SDL_OpenGL */ #endif @@ -858,9 +858,8 @@ plat_timer_read(void) return(li.QuadPart); } - -uint32_t -plat_get_ticks(void) +static LARGE_INTEGER +plat_get_ticks_common(void) { LARGE_INTEGER EndingTime, ElapsedMicroseconds; @@ -881,9 +880,20 @@ plat_get_ticks(void) ElapsedMicroseconds.QuadPart *= 1000000; ElapsedMicroseconds.QuadPart /= Frequency.QuadPart; - return (uint32_t) (ElapsedMicroseconds.QuadPart / 1000); + return ElapsedMicroseconds; } +uint32_t +plat_get_ticks(void) +{ + return (uint32_t)(plat_get_ticks_common().QuadPart / 1000); +} + +uint32_t +plat_get_micro_ticks(void) +{ + return (uint32_t)plat_get_ticks_common().QuadPart; +} void plat_delay_ms(uint32_t count) @@ -1105,6 +1115,15 @@ plat_setfullscreen(int on) plat_vidapi_enable(1); } +void +plat_vid_reload_options(void) +{ + if (!vid_api_inited || !vid_apis[vid_api].reload) + return; + + vid_apis[vid_api].reload(); +} + void take_screenshot(void) diff --git a/src/win/win_opengl.c b/src/win/win_opengl.c index f154cdec6..ad436eccc 100644 --- a/src/win/win_opengl.c +++ b/src/win/win_opengl.c @@ -114,11 +114,13 @@ static struct /** * @brief Renderer options */ -static volatile struct +static struct { int vsync; /* Vertical sync; 0 = off, 1 = on */ - int frametime; /* Frametime in ms, or -1 to sync with blitter */ + int frametime; /* Frametime in microseconds, or -1 to sync with blitter */ char shaderfile[512]; /* Shader file path. Match the length of openfilestring in win_dialog.c */ + int shaderfile_changed; /* Has shader file path changed. To prevent unnecessary shader recompilation. */ + mutex_t* mutex; } options = { 0 }; /** @@ -228,6 +230,74 @@ static void handle_window_messages(UINT message, WPARAM wParam, LPARAM lParam, i } } +/** + * @brief (Re-)apply shaders to OpenGL context. + * @param gl Identifiers from initialize +*/ +static void apply_shaders(gl_identifiers* gl) +{ + GLuint old_shader_ID = 0; + + if (gl->shader_progID != 0) + old_shader_ID = gl->shader_progID; + + if (strlen(options.shaderfile) > 0) + gl->shader_progID = load_custom_shaders(options.shaderfile); + else + gl->shader_progID = 0; + + if (gl->shader_progID == 0) + gl->shader_progID = load_default_shaders(); + + glUseProgram(gl->shader_progID); + + /* Delete old shader if one exists (changing shader) */ + if (old_shader_ID != 0) + glDeleteProgram(old_shader_ID); + + GLint vertex_coord = glGetAttribLocation(gl->shader_progID, "VertexCoord"); + if (vertex_coord != -1) + { + glEnableVertexAttribArray(vertex_coord); + glVertexAttribPointer(vertex_coord, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), 0); + } + + GLint tex_coord = glGetAttribLocation(gl->shader_progID, "TexCoord"); + if (tex_coord != -1) + { + glEnableVertexAttribArray(tex_coord); + glVertexAttribPointer(tex_coord, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(2 * sizeof(GLfloat))); + } + + GLint color = glGetAttribLocation(gl->shader_progID, "Color"); + if (color != -1) + { + glEnableVertexAttribArray(color); + glVertexAttribPointer(color, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(4 * sizeof(GLfloat))); + } + + GLint mvp_matrix = glGetUniformLocation(gl->shader_progID, "MVPMatrix"); + if (mvp_matrix != -1) + { + static const GLfloat mvp[] = { + 1.f, 0.f, 0.f, 0.f, + 0.f, 1.f, 0.f, 0.f, + 0.f, 0.f, 1.f, 0.f, + 0.f, 0.f, 0.f, 1.f + }; + glUniformMatrix4fv(mvp_matrix, 1, GL_FALSE, mvp); + } + + GLint frame_direction = glGetUniformLocation(gl->shader_progID, "FrameDirection"); + if (frame_direction != -1) + glUniform1i(frame_direction, 1); /* always forward */ + + gl->input_size = glGetUniformLocation(gl->shader_progID, "InputSize"); + gl->output_size = glGetUniformLocation(gl->shader_progID, "OutputSize"); + gl->texture_size = glGetUniformLocation(gl->shader_progID, "TextureSize"); + gl->frame_count = glGetUniformLocation(gl->shader_progID, "FrameCount"); +} + /** * @brief Initialize OpenGL context * @return Identifiers @@ -255,7 +325,7 @@ static gl_identifiers initialize_glcontext() glGenTextures(1, &gl.textureID); glBindTexture(GL_TEXTURE_2D, gl.textureID); - GLfloat border_color[] = { 0.f, 0.f, 0.f, 1.f }; + static const GLfloat border_color[] = { 0.f, 0.f, 0.f, 1.f }; glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); @@ -266,61 +336,14 @@ static gl_identifiers initialize_glcontext() glClearColor(0.f, 0.f, 0.f, 1.f); - gl.shader_progID = load_custom_shaders(options.shaderfile); - - if (gl.shader_progID == 0) - gl.shader_progID = load_default_shaders(); - - glUseProgram(gl.shader_progID); - - GLint vertex_coord = glGetAttribLocation(gl.shader_progID, "VertexCoord"); - if (vertex_coord != -1) - { - glEnableVertexAttribArray(vertex_coord); - glVertexAttribPointer(vertex_coord, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), 0); - } - - GLint tex_coord = glGetAttribLocation(gl.shader_progID, "TexCoord"); - if (tex_coord != -1) - { - glEnableVertexAttribArray(tex_coord); - glVertexAttribPointer(tex_coord, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(2 * sizeof(GLfloat))); - } - - GLint color = glGetAttribLocation(gl.shader_progID, "Color"); - if (color != -1) - { - glEnableVertexAttribArray(color); - glVertexAttribPointer(color, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(4 * sizeof(GLfloat))); - } - - GLint mvp_matrix = glGetUniformLocation(gl.shader_progID, "MVPMatrix"); - if (mvp_matrix != -1) - { - static const GLfloat mvp[] = { - 1.f, 0.f, 0.f, 0.f, - 0.f, 1.f, 0.f, 0.f, - 0.f, 0.f, 1.f, 0.f, - 0.f, 0.f, 0.f, 1.f - }; - glUniformMatrix4fv(mvp_matrix, 1, GL_FALSE, mvp); - } - - GLint frame_direction = glGetUniformLocation(gl.shader_progID, "FrameDirection"); - if (frame_direction != -1) - glUniform1i(frame_direction, 1); /* always forward */ - - gl.input_size = glGetUniformLocation(gl.shader_progID, "InputSize"); - gl.output_size = glGetUniformLocation(gl.shader_progID, "OutputSize"); - gl.texture_size = glGetUniformLocation(gl.shader_progID, "TextureSize"); - gl.frame_count = glGetUniformLocation(gl.shader_progID, "FrameCount"); + apply_shaders(&gl); return gl; } /** * @brief Clean up OpenGL context - * @param Identifiers from initialize + * @param gl Identifiers from initialize */ static void finalize_glcontext(gl_identifiers gl) { @@ -359,10 +382,9 @@ static void opengl_main(void* param) window = SDL_CreateWindow("86Box OpenGL Renderer", 0, 0, resize_info.width, resize_info.height, SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS); - SDL_GL_SetSwapInterval(options.vsync); - /* Keep track of certain parameters, only changed in this thread to avoid race conditions */ - int fullscreen = resize_info.fullscreen, video_width = INIT_WIDTH, video_height = INIT_HEIGHT; + int fullscreen = resize_info.fullscreen, video_width = INIT_WIDTH, video_height = INIT_HEIGHT, + output_width = resize_info.width, output_height = resize_info.height, frametime = options.frametime; SDL_SysWMinfo wmi = { 0 }; SDL_VERSION(&wmi.version); @@ -378,31 +400,48 @@ static void opengl_main(void* param) SDL_GLContext context = SDL_GL_CreateContext(window); + SDL_GL_SetSwapInterval(options.vsync); + gladLoadGLLoader(SDL_GL_GetProcAddress); gl_identifiers gl = initialize_glcontext(); if (gl.frame_count != -1) glUniform1i(gl.frame_count, 0); + if (gl.output_size != -1) + glUniform2f(gl.output_size, output_width, output_height); - uint32_t last_swap = -options.frametime; + uint32_t last_swap = plat_get_micro_ticks() - frametime; /* Render loop */ int closing = 0; while (!closing) { - if (options.frametime < 0) + /* Rendering is done right after handling an event. */ + if (frametime < 0) render_and_swap(gl); DWORD wait_result = WAIT_TIMEOUT; do { - if (options.frametime >= 0) + /* Rendering is timed by frame capping. */ + if (frametime >= 0) { - uint32_t ticks = plat_get_ticks(); - if (ticks - last_swap >= options.frametime) + uint32_t ticks = plat_get_micro_ticks(); + + uint32_t elapsed = ticks - last_swap; + + if (elapsed + 1000 > frametime) { + /* Spin the remaining time (< 1ms) to next frame */ + while (elapsed < frametime) + { + Sleep(0); /* Yield processor time */ + ticks = plat_get_micro_ticks(); + elapsed = ticks - last_swap; + } + render_and_swap(gl); last_swap = ticks; } @@ -418,11 +457,6 @@ static void opengl_main(void* param) DispatchMessage(&msg); } - /* Keep cursor hidden in full screen and mouse capture */ - int show_cursor = !(fullscreen || !!mouse_capture); - if (SDL_ShowCursor(-1) != show_cursor) - SDL_ShowCursor(show_cursor); - /* Wait for synchronized events for 1ms before going back to window events */ wait_result = WaitForMultipleObjects(sizeof(sync_objects) / sizeof(HANDLE), sync_objects.asArray, FALSE, 1); @@ -515,10 +549,13 @@ static void opengl_main(void* param) } } - glViewport(pad_x / 2, pad_y / 2, width - pad_x, height - pad_y); + output_width = width - pad_x; + output_height = height - pad_y; + + glViewport(pad_x / 2, pad_y / 2, output_width, output_height); if (gl.output_size != -1) - glUniform2f(gl.output_size, width - pad_x, height - pad_y); + glUniform2f(gl.output_size, output_width, output_height); } else { @@ -527,6 +564,9 @@ static void opengl_main(void* param) /* SWP_NOZORDER is needed for child window and SDL doesn't enable it. */ SetWindowPos(window_hwnd, parent, 0, 0, resize_info.width, resize_info.height, SWP_NOZORDER | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOACTIVATE); + output_width = resize_info.width; + output_height = resize_info.height; + glViewport(0, 0, resize_info.width, resize_info.height); if (gl.output_size != -1) @@ -535,6 +575,39 @@ static void opengl_main(void* param) thread_release_mutex(resize_info.mutex); } + else if (sync_event == sync_objects.reload) + { + thread_wait_mutex(options.mutex); + + frametime = options.frametime; + + SDL_GL_SetSwapInterval(options.vsync); + + if (options.shaderfile_changed) + { + /* Change shader program. */ + apply_shaders(&gl); + + /* Uniforms need to be updated after proram change. */ + if (gl.input_size != -1) + glUniform2f(gl.input_size, video_width, video_height); + if (gl.output_size != -1) + glUniform2f(gl.output_size, output_width, output_height); + if (gl.texture_size != -1) + glUniform2f(gl.texture_size, video_width, video_height); + if (gl.frame_count != -1) + glUniform1i(gl.frame_count, 0); + + options.shaderfile_changed = 0; + } + + thread_release_mutex(options.mutex); + } + + /* Keep cursor hidden in full screen and mouse capture */ + int show_cursor = !(fullscreen || !!mouse_capture); + if (SDL_ShowCursor(-1) != show_cursor) + SDL_ShowCursor(show_cursor); } finalize_glcontext(gl); @@ -543,8 +616,6 @@ static void opengl_main(void* param) set_parent_binding(0); - SDL_SetWindowsMessageHook(NULL, NULL); - SDL_DestroyWindow(window); window = NULL; @@ -571,6 +642,14 @@ static void opengl_blit(int x, int y, int y1, int y2, int w, int h) video_blit_complete(); } +static int framerate_to_frametime(int framerate) +{ + if (framerate < 0) + return -1; + + return (int)ceilf(1.e6f / (float)framerate); +} + int opengl_init(HWND hwnd) { if (thread != NULL) @@ -594,8 +673,9 @@ int opengl_init(HWND hwnd) resize_info.mutex = thread_create_mutex(); options.vsync = video_vsync; - options.frametime = -1; - strcpy_s(options.shaderfile, sizeof(options.shaderfile), "shaders/shader.glsl"); + options.frametime = framerate_to_frametime(video_framerate); + strcpy_s(options.shaderfile, sizeof(options.shaderfile), video_shader); + options.mutex = thread_create_mutex(); thread = thread_create(opengl_main, (void*)NULL); @@ -623,6 +703,7 @@ void opengl_close(void) memset((void*)&blit_info, 0, sizeof(blit_info)); thread_close_mutex(resize_info.mutex); + thread_close_mutex(options.mutex); SetEvent(blit_done); @@ -675,5 +756,18 @@ void opengl_reload(void) if (thread == NULL) return; + thread_wait_mutex(options.mutex); + + options.vsync = video_vsync; + options.frametime = framerate_to_frametime(video_framerate); + + if (strcmp(video_shader, options.shaderfile) != 0) + { + strcpy_s(options.shaderfile, sizeof(options.shaderfile), video_shader); + options.shaderfile_changed = 1; + } + + thread_release_mutex(options.mutex); + SetEvent(sync_objects.reload); } \ No newline at end of file diff --git a/src/win/win_opengl_glslp.c b/src/win/win_opengl_glslp.c index 0a0d7f004..49b48d7ec 100644 --- a/src/win/win_opengl_glslp.c +++ b/src/win/win_opengl_glslp.c @@ -69,13 +69,7 @@ void main() {\n\ */ static char* read_file_to_string(const char* path) { - char* full_path = (char*)malloc(sizeof(char) * (strlen(path) + strlen(exe_path) + 1)); - - plat_append_filename(full_path, exe_path, path); - - FILE* file_handle = plat_fopen(full_path, "rb"); - - free(full_path); + FILE* file_handle = plat_fopen(path, "rb"); if (file_handle != NULL) { diff --git a/src/win/win_ui.c b/src/win/win_ui.c index 6a3584886..0a99d7271 100644 --- a/src/win/win_ui.c +++ b/src/win/win_ui.c @@ -177,6 +177,71 @@ video_toggle_option(HMENU h, int *val, int id) device_force_redraw(); } +/* Recursively finds and deletes target submenu */ +int delete_submenu(HMENU parent, HMENU target) +{ + for (int i = 0; i < GetMenuItemCount(parent); i++) + { + MENUITEMINFO mii; + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_SUBMENU; + + if (GetMenuItemInfo(parent, i, TRUE, &mii) != 0) + { + if (mii.hSubMenu == target) + { + DeleteMenu(parent, i, MF_BYPOSITION); + return 1; + } + else if (mii.hSubMenu != NULL) + { + if (delete_submenu(mii.hSubMenu, target)) + return 1; + } + } + } + + return 0; +} + +static void +show_render_options_menu() +{ +#ifdef DEV_BRANCH /* feature-opengl */ + static int menu_vidapi = -1; + static HMENU cur_menu = NULL; + + if (vid_api == menu_vidapi) + return; + + if (cur_menu != NULL) + { + if (delete_submenu(menuMain, cur_menu)) + cur_menu = NULL; + } + + if (cur_menu == NULL) + { + switch (IDM_VID_SDL_SW + vid_api) + { + case IDM_VID_OPENGL_CORE: + cur_menu = LoadMenu(hinstance, VID_GL_SUBMENU); + InsertMenu(GetSubMenu(menuMain, 1), 4, MF_BYPOSITION | MF_STRING | MF_POPUP, (UINT_PTR)cur_menu, plat_get_string(IDS_2144)); + CheckMenuItem(menuMain, IDM_VID_GL_FPS_BLITTER, video_framerate == -1 ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_GL_FPS_25, video_framerate == 25 ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_GL_FPS_30, video_framerate == 30 ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_GL_FPS_50, video_framerate == 50 ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_GL_FPS_60, video_framerate == 60 ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_GL_FPS_75, video_framerate == 75 ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_GL_VSYNC, video_vsync ? MF_CHECKED : MF_UNCHECKED); + break; + } + } + + menu_vidapi = vid_api; +#endif +} + static void ResetAllMenus(void) @@ -225,6 +290,7 @@ ResetAllMenus(void) CheckMenuItem(menuMain, IDM_VID_SDL_OPENGL, MF_UNCHECKED); #ifdef DEV_BRANCH /* feature-opengl */ CheckMenuItem(menuMain, IDM_VID_OPENGL_CORE, MF_UNCHECKED); + show_render_options_menu(); #endif #ifdef USE_VNC CheckMenuItem(menuMain, IDM_VID_VNC, MF_UNCHECKED); @@ -682,13 +748,31 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) plat_setvid(LOWORD(wParam) - IDM_VID_SDL_SW); CheckMenuItem(hmenu, IDM_VID_SDL_SW + vid_api, MF_CHECKED); config_save(); + show_render_options_menu(); break; #ifdef DEV_BRANCH /* feature-opengl */ + case IDM_VID_GL_FPS_BLITTER: + case IDM_VID_GL_FPS_25: + case IDM_VID_GL_FPS_30: + case IDM_VID_GL_FPS_50: + case IDM_VID_GL_FPS_60: + case IDM_VID_GL_FPS_75: + { + static const int fps[] = { -1, 25, 30, 50, 60, 75 }; + int idx = 0; + for (; fps[idx] != video_framerate; idx++); + CheckMenuItem(hmenu, IDM_VID_GL_FPS_BLITTER + idx, MF_UNCHECKED); + video_framerate = fps[LOWORD(wParam) - IDM_VID_GL_FPS_BLITTER]; + CheckMenuItem(hmenu, LOWORD(wParam), MF_CHECKED); + plat_vid_reload_options(); + config_save(); + break; + } case IDM_VID_GL_VSYNC: video_vsync = !video_vsync; CheckMenuItem(hmenu, IDM_VID_GL_VSYNC, video_vsync ? MF_CHECKED : MF_UNCHECKED); - //plat_reload_config + plat_vid_reload_options(); config_save(); break; case IDM_VID_GL_SHADER: @@ -696,6 +780,7 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) if (file_dlg_st(hwnd, IDS_2143, video_shader, NULL, 0) == 0) strcpy_s(video_shader, sizeof(video_shader), openfilestring); win_notify_dlg_closed(); + plat_vid_reload_options(); break; #endif From b90601256d7cb4fc1d06df35cc3f74cd126a99a0 Mon Sep 17 00:00:00 2001 From: ts-korhonen Date: Sat, 24 Apr 2021 01:01:45 +0300 Subject: [PATCH 5/5] win_opengl: Added handling of initialization failures. --- src/win/win_opengl.c | 47 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/src/win/win_opengl.c b/src/win/win_opengl.c index ad436eccc..4a0f9e31b 100644 --- a/src/win/win_opengl.c +++ b/src/win/win_opengl.c @@ -35,6 +35,7 @@ */ #define UNICODE #include +#include #include #include #include @@ -370,6 +371,34 @@ static void render_and_swap(gl_identifiers gl) glUniform1i(gl.frame_count, frame_counter = (frame_counter + 1) & 1023); } +/** + * @brief Handle failure in OpenGL thread. + * Acts like a renderer until closing. +*/ +static void opengl_fail() +{ + if (window != NULL) + { + SDL_DestroyWindow(window); + window = NULL; + } + + /* TODO: Notify user. */ + + HANDLE handles[] = { sync_objects.closing, sync_objects.blit_waiting }; + + while (1) + { + switch (WaitForMultipleObjects(2, handles, FALSE, INFINITE)) + { + case WAIT_OBJECT_0: /* Close requested. End thread. */ + _endthread(); + case WAIT_OBJECT_0 + 1: /* Blitter is waiting, signal it to continue. */ + SetEvent(blit_done); + } + } +} + /** * @brief Main OpenGL thread proc. * @@ -382,6 +411,9 @@ static void opengl_main(void* param) window = SDL_CreateWindow("86Box OpenGL Renderer", 0, 0, resize_info.width, resize_info.height, SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS); + if (window == NULL) + opengl_fail(); + /* Keep track of certain parameters, only changed in this thread to avoid race conditions */ int fullscreen = resize_info.fullscreen, video_width = INIT_WIDTH, video_height = INIT_HEIGHT, output_width = resize_info.width, output_height = resize_info.height, frametime = options.frametime; @@ -390,8 +422,10 @@ static void opengl_main(void* param) SDL_VERSION(&wmi.version); SDL_GetWindowWMInfo(window, &wmi); - if (wmi.subsystem == SDL_SYSWM_WINDOWS) - window_hwnd = wmi.info.win.window; + if (wmi.subsystem != SDL_SYSWM_WINDOWS) + opengl_fail(); + + window_hwnd = wmi.info.win.window; if (!fullscreen) set_parent_binding(1); @@ -400,9 +434,16 @@ static void opengl_main(void* param) SDL_GLContext context = SDL_GL_CreateContext(window); + if (context == NULL) + opengl_fail(); + SDL_GL_SetSwapInterval(options.vsync); - gladLoadGLLoader(SDL_GL_GetProcAddress); + if (!gladLoadGLLoader(SDL_GL_GetProcAddress)) + { + SDL_GL_DeleteContext(context); + opengl_fail(); + } gl_identifiers gl = initialize_glcontext();