From 7b310a0cf4d9abeaeffb7c4f77d9f4b20f58d535 Mon Sep 17 00:00:00 2001 From: Brandon Wright Date: Sat, 2 Mar 2019 15:25:59 -0600 Subject: [PATCH] GTK: Swap glFenceSync for sync control extension. --- gtk/src/gtk_config.cpp | 12 +- gtk/src/gtk_config.h | 4 +- gtk/src/gtk_display_driver_opengl.cpp | 25 +--- gtk/src/gtk_display_driver_opengl.h | 2 - gtk/src/gtk_glx_context.cpp | 24 ++++ gtk/src/gtk_glx_context.h | 4 + gtk/src/gtk_opengl_context.h | 1 + gtk/src/gtk_preferences.cpp | 9 +- gtk/src/gtk_wayland_egl_context.cpp | 184 +++++++++++++++----------- gtk/src/gtk_wayland_egl_context.h | 27 ++-- gtk/src/snes9x.ui | 8 +- 11 files changed, 174 insertions(+), 126 deletions(-) diff --git a/gtk/src/gtk_config.cpp b/gtk/src/gtk_config.cpp index 9752a000..7a556c59 100644 --- a/gtk/src/gtk_config.cpp +++ b/gtk/src/gtk_config.cpp @@ -151,8 +151,8 @@ int Snes9xConfig::load_defaults () npot_textures = false; use_shaders = false; shader_filename.clear (); - sync_every_frame = false; - use_fences = false; + use_glfinish = false; + use_sync_control = false; #endif /* Snes9x Variables */ @@ -267,8 +267,8 @@ int Snes9xConfig::save_config_file () #undef z #define z "OpenGL::" outbool (cf, z"VSync", sync_to_vblank); - outbool (cf, z"glFinish", sync_every_frame); - outbool (cf, z"glFenceSync", use_fences); + outbool (cf, z"glFinish", use_glfinish); + outbool (cf, z"SyncControl", use_sync_control); outbool (cf, z"UsePixelBufferObjects", use_pbos); cf.SetInt (z"PixelBufferObjectBitDepth", pbo_format); outbool (cf, z"UseNonPowerOfTwoTextures", npot_textures); @@ -497,8 +497,8 @@ int Snes9xConfig::load_config_file () #undef z #define z "OpenGL::" inbool (z"VSync", sync_to_vblank); - inbool (z"glFinish", sync_every_frame); - inbool (z"glFenceSync", use_fences); + inbool (z"glFinish", use_glfinish); + inbool (z"SyncControl", use_sync_control); inbool (z"UsePixelBufferObjects", use_pbos); inint (z"PixelBufferObjectBitDepth", pbo_format); inbool (z"UseNonPowerOfTwoTextures", npot_textures); diff --git a/gtk/src/gtk_config.h b/gtk/src/gtk_config.h index a1fb325d..a6b84d90 100644 --- a/gtk/src/gtk_config.h +++ b/gtk/src/gtk_config.h @@ -151,8 +151,8 @@ class Snes9xConfig bool npot_textures; bool use_shaders; std::string shader_filename; - bool sync_every_frame; - bool use_fences; + bool use_glfinish; + bool use_sync_control; #endif JoyDevice **joystick; diff --git a/gtk/src/gtk_display_driver_opengl.cpp b/gtk/src/gtk_display_driver_opengl.cpp index 02dfea73..a3da8686 100644 --- a/gtk/src/gtk_display_driver_opengl.cpp +++ b/gtk/src/gtk_display_driver_opengl.cpp @@ -6,6 +6,7 @@ #include "gtk_2_3_compat.h" #include +#include #include #include #include @@ -88,7 +89,6 @@ S9xOpenGLDisplayDriver::S9xOpenGLDisplayDriver (Snes9xWindow *window, this->window = window; this->config = config; this->drawing_area = GTK_WIDGET (window->drawing_area); - fence = NULL; } void S9xOpenGLDisplayDriver::update (int width, int height, int yoffset) @@ -609,9 +609,6 @@ bool S9xOpenGLDisplayDriver::create_context() else core = false; - if (version >= 31 || epoxy_has_gl_extension ("GL_ARB_sync")) - fences = true; - return true; } @@ -666,17 +663,11 @@ void S9xOpenGLDisplayDriver::swap_buffers () { context->swap_buffers (); - if (config->sync_every_frame && !config->use_fences) + if (config->use_glfinish && !config->use_sync_control) { usleep (0); glFinish (); } - else if (config->use_fences && fences) - { - if (fence) - glDeleteSync (fence); - fence = glFenceSync (GL_SYNC_GPU_COMMANDS_COMPLETE, 0); - } } void S9xOpenGLDisplayDriver::deinit () @@ -740,14 +731,10 @@ int S9xOpenGLDisplayDriver::query_availability () bool S9xOpenGLDisplayDriver::is_ready () { - if (!fence) + if (context->ready()) + { return true; + } - if (glClientWaitSync (fence, GL_SYNC_FLUSH_COMMANDS_BIT, 0) == GL_TIMEOUT_EXPIRED) - return false; - - glDeleteSync (fence); - fence = NULL; - - return true; + return false; } diff --git a/gtk/src/gtk_display_driver_opengl.h b/gtk/src/gtk_display_driver_opengl.h index 09ba550d..8dcd4dd4 100644 --- a/gtk/src/gtk_display_driver_opengl.h +++ b/gtk/src/gtk_display_driver_opengl.h @@ -75,8 +75,6 @@ class S9xOpenGLDisplayDriver : public S9xDisplayDriver OpenGLContext *context; - GLsync fence; - #ifdef GDK_WINDOWING_X11 GTKGLXContext glx; #endif diff --git a/gtk/src/gtk_glx_context.cpp b/gtk/src/gtk_glx_context.cpp index 7327ff41..4cb270fe 100644 --- a/gtk/src/gtk_glx_context.cpp +++ b/gtk/src/gtk_glx_context.cpp @@ -4,6 +4,7 @@ For further information, consult the LICENSE file in the root directory. \*****************************************************************************/ +#include #include #include @@ -22,6 +23,8 @@ GTKGLXContext::GTKGLXContext () version_major = -1; version_minor = -1; + use_oml_sync_control = false; + ust = msc = sbc = 0; } GTKGLXContext::~GTKGLXContext () @@ -120,6 +123,9 @@ bool GTKGLXContext::create_context () return false; } + if (strstr(extensions, "GLX_OML_sync_control") && gui_config->use_sync_control) + use_oml_sync_control = true; + return true; } @@ -144,9 +150,27 @@ void GTKGLXContext::resize () void GTKGLXContext::swap_buffers () { + if (use_oml_sync_control) + glXGetSyncValuesOML(display, xid, &ust, &msc, &sbc); + glXSwapBuffers (display, xid); } +bool GTKGLXContext::ready() +{ + if (use_oml_sync_control) + { + int64 ust, msc, sbc; + glXGetSyncValuesOML(display, xid, &ust, &msc, &sbc); + + if (sbc != this->sbc || msc - this->msc > 2) + return true; + return false; + } + + return true; +} + void GTKGLXContext::make_current () { glXMakeCurrent (display, xid, context); diff --git a/gtk/src/gtk_glx_context.h b/gtk/src/gtk_glx_context.h index f9cc958a..8ee7c91a 100644 --- a/gtk/src/gtk_glx_context.h +++ b/gtk/src/gtk_glx_context.h @@ -23,6 +23,7 @@ class GTKGLXContext : public OpenGLContext void swap_buffers (); void swap_interval (int frames); void make_current (); + bool ready(); GtkWidget *widget; @@ -40,6 +41,9 @@ class GTKGLXContext : public OpenGLContext int version_major; int version_minor; + + bool use_oml_sync_control; + int64_t ust, msc, sbc; }; #endif diff --git a/gtk/src/gtk_opengl_context.h b/gtk/src/gtk_opengl_context.h index 6a1da3c0..8146860b 100644 --- a/gtk/src/gtk_opengl_context.h +++ b/gtk/src/gtk_opengl_context.h @@ -19,6 +19,7 @@ class OpenGLContext virtual void swap_buffers () = 0; virtual void swap_interval (int frames) = 0; virtual void make_current () = 0; + virtual bool ready() { return true; }; int x; int y; diff --git a/gtk/src/gtk_preferences.cpp b/gtk/src/gtk_preferences.cpp index fddcd1ed..d550b4f7 100644 --- a/gtk/src/gtk_preferences.cpp +++ b/gtk/src/gtk_preferences.cpp @@ -715,8 +715,8 @@ Snes9xPreferences::move_settings_to_dialog () #ifdef USE_OPENGL set_check ("sync_to_vblank", config->sync_to_vblank); - set_check ("sync_every_frame", config->sync_every_frame); - set_check ("use_fences", config->use_fences); + set_check ("use_glfinish", config->use_glfinish); + set_check ("use_sync_control", config->use_sync_control); set_check ("use_pbos", config->use_pbos); set_combo ("pixel_format", config->pbo_format == 16 ? 0 : 1); set_check ("npot_textures", config->npot_textures); @@ -859,6 +859,7 @@ Snes9xPreferences::get_settings_from_dialog () int pbo_format = get_combo ("pixel_format") == 1 ? 32 : 16; if (config->sync_to_vblank != get_check ("sync_to_vblank") || + config->use_sync_control != get_check ("use_sync_control") || config->npot_textures != get_check ("npot_textures") || config->use_pbos != get_check ("use_pbos") || config->pbo_format != pbo_format || @@ -872,8 +873,8 @@ Snes9xPreferences::get_settings_from_dialog () config->use_pbos = get_check ("use_pbos"); config->npot_textures = get_check ("npot_textures"); config->use_shaders = get_check ("use_shaders"); - config->sync_every_frame = get_check ("sync_every_frame"); - config->use_fences = get_check ("use_fences"); + config->use_glfinish = get_check ("use_glfinish"); + config->use_sync_control = get_check ("use_sync_control"); config->shader_filename = get_entry_text ("fragment_shader"); diff --git a/gtk/src/gtk_wayland_egl_context.cpp b/gtk/src/gtk_wayland_egl_context.cpp index f389b19d..f101f41a 100644 --- a/gtk/src/gtk_wayland_egl_context.cpp +++ b/gtk/src/gtk_wayland_egl_context.cpp @@ -4,28 +4,30 @@ For further information, consult the LICENSE file in the root directory. \*****************************************************************************/ +#include #include #include +#include "gtk_s9x.h" #include "gtk_wayland_egl_context.h" -static void wl_global (void *data, - struct wl_registry *wl_registry, - uint32_t name, - const char *interface, - uint32_t version) +static void wl_global(void *data, + struct wl_registry *wl_registry, + uint32_t name, + const char *interface, + uint32_t version) { - WaylandEGLContext *wl = (WaylandEGLContext *) data; + WaylandEGLContext *wl = (WaylandEGLContext *)data; - if (!strcmp (interface, "wl_compositor")) - wl->compositor = (struct wl_compositor *) wl_registry_bind (wl_registry, name, &wl_compositor_interface, 3); - else if (!strcmp (interface, "wl_subcompositor")) - wl->subcompositor = (struct wl_subcompositor *) wl_registry_bind (wl_registry, name, &wl_subcompositor_interface, 1); + if (!strcmp(interface, "wl_compositor")) + wl->compositor = (struct wl_compositor *)wl_registry_bind(wl_registry, name, &wl_compositor_interface, 3); + else if (!strcmp(interface, "wl_subcompositor")) + wl->subcompositor = (struct wl_subcompositor *)wl_registry_bind(wl_registry, name, &wl_subcompositor_interface, 1); } -static void wl_global_remove (void *data, - struct wl_registry *wl_registry, - uint32_t name) +static void wl_global_remove(void *data, + struct wl_registry *wl_registry, + uint32_t name) { } @@ -34,79 +36,81 @@ static const struct wl_registry_listener wl_registry_listener = { wl_global_remove }; -WaylandEGLContext::WaylandEGLContext () +WaylandEGLContext::WaylandEGLContext() { - display = NULL; - registry = NULL; - compositor = NULL; + display = NULL; + registry = NULL; + compositor = NULL; subcompositor = NULL; - parent = NULL; - child = NULL; - region = NULL; - subsurface = NULL; - egl_display = NULL; - egl_surface = NULL; - egl_context = NULL; - egl_config = NULL; - egl_window = NULL; + parent = NULL; + child = NULL; + region = NULL; + subsurface = NULL; + egl_display = NULL; + egl_surface = NULL; + egl_context = NULL; + egl_config = NULL; + egl_window = NULL; + use_sync_control = false; + ust = msc = sbc = 0; } -WaylandEGLContext::~WaylandEGLContext () +WaylandEGLContext::~WaylandEGLContext() { if (subsurface) - wl_subsurface_destroy (subsurface); + wl_subsurface_destroy(subsurface); if (region) - wl_region_destroy (region); + wl_region_destroy(region); if (child) - wl_surface_destroy (child); + wl_surface_destroy(child); if (egl_context) - eglDestroyContext (egl_display, egl_context); + eglDestroyContext(egl_display, egl_context); if (egl_surface) - eglDestroySurface (egl_display, egl_surface); + eglDestroySurface(egl_display, egl_surface); if (egl_window) - wl_egl_window_destroy (egl_window); + wl_egl_window_destroy(egl_window); } -bool WaylandEGLContext::attach (GtkWidget *widget) +bool WaylandEGLContext::attach(GtkWidget *widget) { - GdkWindow *window = gtk_widget_get_window (widget); + GdkWindow *window = gtk_widget_get_window(widget); - if (!GDK_IS_WAYLAND_WINDOW (window)) + if (!GDK_IS_WAYLAND_WINDOW(window)) return false; gdk_window = window; - gdk_window_get_geometry (gdk_window, &x, &y, &width, &height); + gdk_window_get_geometry(gdk_window, &x, &y, &width, &height); - display = gdk_wayland_display_get_wl_display (gdk_window_get_display (gdk_window)); - parent = gdk_wayland_window_get_wl_surface (gdk_window); - registry = wl_display_get_registry (display); + display = gdk_wayland_display_get_wl_display(gdk_window_get_display(gdk_window)); + parent = gdk_wayland_window_get_wl_surface(gdk_window); + registry = wl_display_get_registry(display); - wl_registry_add_listener (registry, &wl_registry_listener, this); - wl_display_roundtrip (display); + wl_registry_add_listener(registry, &wl_registry_listener, this); + wl_display_roundtrip(display); if (!compositor || !subcompositor) return false; - child = wl_compositor_create_surface (compositor); - region = wl_compositor_create_region (compositor); - subsurface = wl_subcompositor_get_subsurface (subcompositor, child, parent); + child = wl_compositor_create_surface(compositor); + region = wl_compositor_create_region(compositor); + subsurface = wl_subcompositor_get_subsurface(subcompositor, child, parent); - wl_surface_set_input_region (child, region); - wl_subsurface_set_desync (subsurface); - wl_subsurface_set_position (subsurface, x, y); + wl_surface_set_input_region(child, region); + wl_subsurface_set_desync(subsurface); + wl_subsurface_set_position(subsurface, x, y); return true; } -bool WaylandEGLContext::create_context () +bool WaylandEGLContext::create_context() { - int scale = gdk_window_get_scale_factor (gdk_window); - gdk_window_get_geometry (gdk_window, &x, &y, &width, &height); + int scale = gdk_window_get_scale_factor(gdk_window); + gdk_window_get_geometry(gdk_window, &x, &y, &width, &height); EGLint surface_attribs[] = { EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, @@ -133,74 +137,96 @@ bool WaylandEGLContext::create_context () if (!subsurface) return false; - egl_display = eglGetDisplay ((EGLNativeDisplayType) display); - eglInitialize (egl_display, NULL, NULL); + egl_display = eglGetDisplay((EGLNativeDisplayType)display); + eglInitialize(egl_display, NULL, NULL); - if (!eglChooseConfig (egl_display, surface_attribs, &egl_config, 1, &num_configs)) + if (!eglChooseConfig(egl_display, surface_attribs, &egl_config, 1, &num_configs)) { - printf ("Couldn't find matching config.\n"); + printf("Couldn't find matching config.\n"); return false; } - eglBindAPI (EGL_OPENGL_API); + eglBindAPI(EGL_OPENGL_API); - egl_window = wl_egl_window_create (child, width * scale, height * scale); + egl_window = wl_egl_window_create(child, width * scale, height * scale); if (!egl_window) { - printf ("Couldn't create window.\n"); + printf("Couldn't create window.\n"); return false; } - egl_surface = eglCreateWindowSurface (egl_display, egl_config, (EGLNativeWindowType) egl_window, NULL); + egl_surface = eglCreateWindowSurface(egl_display, egl_config, (EGLNativeWindowType)egl_window, NULL); if (!egl_surface) { - printf ("Couldn't create surface.\n"); + printf("Couldn't create surface.\n"); return false; } - egl_context = eglCreateContext (egl_display, egl_config, EGL_NO_CONTEXT, core_context_attribs); + egl_context = eglCreateContext(egl_display, egl_config, EGL_NO_CONTEXT, core_context_attribs); if (!egl_context) { - egl_context = eglCreateContext (egl_display, egl_config, EGL_NO_CONTEXT, compatibility_context_attribs); + egl_context = eglCreateContext(egl_display, egl_config, EGL_NO_CONTEXT, compatibility_context_attribs); if (!egl_context) { - printf ("Couldn't create context.\n"); + printf("Couldn't create context.\n"); return false; } } - wl_surface_set_buffer_scale (child, scale); - gdk_window_invalidate_rect (gdk_window, NULL, false); + if (gui_config->use_sync_control && epoxy_has_egl_extension(egl_display, "EGL_CHROMIUM_sync_control")) + { + eglGetSyncValuesCHROMIUM = (PEGLGETSYNCVALUESCHROMIUM)eglGetProcAddress("eglGetSyncValuesCHROMIUM"); + if (eglGetSyncValuesCHROMIUM) + use_sync_control = true; + } + + wl_surface_set_buffer_scale(child, scale); + gdk_window_invalidate_rect(gdk_window, NULL, false); return true; } -void WaylandEGLContext::resize () +void WaylandEGLContext::resize() { int scale; - gdk_window_get_geometry (gdk_window, &x, &y, &width, &height); - scale = gdk_window_get_scale_factor (gdk_window); + gdk_window_get_geometry(gdk_window, &x, &y, &width, &height); + scale = gdk_window_get_scale_factor(gdk_window); - wl_egl_window_resize (egl_window, width * scale, height * scale, 0, 0); - wl_subsurface_set_position (subsurface, x, y); + wl_egl_window_resize(egl_window, width * scale, height * scale, 0, 0); + wl_subsurface_set_position(subsurface, x, y); - make_current (); + make_current(); } -void WaylandEGLContext::swap_buffers () +void WaylandEGLContext::swap_buffers() { - eglSwapBuffers (egl_display, egl_surface); - wl_surface_commit (child); + if (use_sync_control) + eglGetSyncValuesCHROMIUM(egl_display, egl_surface, &ust, &msc, &sbc); + + eglSwapBuffers(egl_display, egl_surface); + wl_surface_commit(child); } -void WaylandEGLContext::make_current () +bool WaylandEGLContext::ready() { - eglMakeCurrent (egl_display, egl_surface, egl_surface, egl_context); + if (use_sync_control) + { + EGLuint64KHR ust, msc, sbc; + eglGetSyncValuesCHROMIUM(egl_display, egl_surface, &ust, &msc, &sbc); + if (sbc != this->sbc || msc - this->msc > 2) + return true; + return false; + } + + return true; } -void WaylandEGLContext::swap_interval (int frames) +void WaylandEGLContext::make_current() { - eglSwapInterval (egl_display, frames); + eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context); } - +void WaylandEGLContext::swap_interval(int frames) +{ + eglSwapInterval(egl_display, frames); +} diff --git a/gtk/src/gtk_wayland_egl_context.h b/gtk/src/gtk_wayland_egl_context.h index 295b2b7d..29d5fb1b 100644 --- a/gtk/src/gtk_wayland_egl_context.h +++ b/gtk/src/gtk_wayland_egl_context.h @@ -7,22 +7,24 @@ #ifndef __GTK_WAYLAND_EGL_CONTEXT_H #define __GTK_WAYLAND_EGL_CONTEXT_H -#include #include +#include +#include #include "gtk_opengl_context.h" class WaylandEGLContext : public OpenGLContext { public: - WaylandEGLContext (); - ~WaylandEGLContext (); - bool attach (GtkWidget *widget); - bool create_context (); - void resize (); - void swap_buffers (); - void swap_interval (int frames); - void make_current (); + WaylandEGLContext(); + ~WaylandEGLContext(); + bool attach(GtkWidget *widget); + bool create_context(); + void resize(); + void swap_buffers(); + void swap_interval(int frames); + void make_current(); + bool ready(); GdkWindow *gdk_window; @@ -39,9 +41,14 @@ class WaylandEGLContext : public OpenGLContext EGLDisplay egl_display; EGLSurface egl_surface; EGLContext egl_context; - EGLConfig egl_config; + EGLConfig egl_config; wl_egl_window *egl_window; + + typedef EGLBoolean (*PEGLGETSYNCVALUESCHROMIUM)(EGLDisplay, EGLSurface, EGLuint64KHR *, EGLuint64KHR *, EGLuint64KHR *); + PEGLGETSYNCVALUESCHROMIUM eglGetSyncValuesCHROMIUM; + bool use_sync_control; + EGLuint64KHR ust, msc, sbc; }; #endif diff --git a/gtk/src/snes9x.ui b/gtk/src/snes9x.ui index e41564c8..cc90eda0 100644 --- a/gtk/src/snes9x.ui +++ b/gtk/src/snes9x.ui @@ -3777,7 +3777,7 @@ - + Reduce input lag with glFinish True True @@ -3792,12 +3792,12 @@ - - Reduce input lag with glFenceSync + + Reduce input lag with sync control True True False - Sync the program with the video output after every displayed frame to reduce input latency, but allow GUI events to occur in the meantime + More modern method for syncing the program with the video output to reduce input latency. Allows GUI events to occur in the meantime True