diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 6ea652da..439caf67 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -239,9 +239,11 @@ if OPENGL snes9x_gtk_SOURCES += \ src/gtk_display_driver_opengl.cpp \ src/gtk_display_driver_opengl.h \ + src/gtk_glx_context.cpp \ ../shaders/glsl.cpp \ ../shaders/shader_helpers.cpp \ - src/gtk_shader_parameters.cpp + src/gtk_shader_parameters.cpp + endif if XV diff --git a/gtk/src/gtk_display_driver_opengl.cpp b/gtk/src/gtk_display_driver_opengl.cpp index 7a21f18b..24d1395d 100644 --- a/gtk/src/gtk_display_driver_opengl.cpp +++ b/gtk/src/gtk_display_driver_opengl.cpp @@ -1,8 +1,4 @@ #include -#ifdef GDK_WINDOWING_X11 -#include -#include -#endif #include #include #include @@ -13,18 +9,8 @@ #include "gtk_display.h" #include "gtk_display_driver_opengl.h" #include "gtk_shader_parameters.h" - #include "shaders/shader_helpers.h" -#ifdef GDK_WINDOWING_WAYLAND -#define ON_WAYLAND(BLOCK) if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default())) \ - { \ - BLOCK \ - } -#else -#define ON_WAYLAND(BLOCK) do {} while (0); -#endif - static void S9xViewportCallback (int src_width, int src_height, int viewport_x, int viewport_y, int viewport_width, int viewport_height, @@ -65,7 +51,7 @@ S9xOpenGLDisplayDriver::update (int width, int height, int yoffset) if (output_window_width != allocation.width || output_window_height != allocation.height) { - resize_window (allocation.width, allocation.height); + resize (); } #if GTK_CHECK_VERSION(3,10,0) @@ -253,7 +239,7 @@ S9xOpenGLDisplayDriver::update (int width, int height, int yoffset) if (using_shaders && using_glsl_shaders) { glsl_shader->render (texmap, width, height, x, allocation.height - y - h, w, h, S9xViewportCallback); - gl_swap (); + swap_buffers (); return; } else if (using_shaders) @@ -281,7 +267,7 @@ S9xOpenGLDisplayDriver::update (int width, int height, int yoffset) glDrawArrays (GL_QUADS, 0, 4); - gl_swap (); + swap_buffers (); return; } @@ -668,117 +654,44 @@ S9xOpenGLDisplayDriver::refresh (int width, int height) } void -S9xOpenGLDisplayDriver::resize_window (int width, int height) +S9xOpenGLDisplayDriver::resize () { - ON_WAYLAND - ( - wl.resize (width, height); - wl.swap_interval (config->sync_to_vblank); - output_window_width = width; - output_window_height = height; - return; - ) - - gdk_window_destroy (gdk_window); - create_window (width, height); - -#ifdef GDK_WINDOWING_X11 - glXMakeCurrent (display, xwindow, glx_context); -#endif - - swap_control (config->sync_to_vblank); + context->resize (); + context->swap_interval (config->sync_to_vblank); + output_window_width = context->width; + output_window_height = context->height; return; } -void -S9xOpenGLDisplayDriver::create_window (int width, int height) -{ -#ifdef GDK_WINDOWING_X11 - GdkWindowAttr window_attr; - memset (&window_attr, 0, sizeof (GdkWindowAttr)); - window_attr.event_mask = GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK; - window_attr.width = width; - window_attr.height = height; - window_attr.x = 0; - window_attr.y = 0; - window_attr.wclass = GDK_INPUT_OUTPUT; - window_attr.window_type = GDK_WINDOW_CHILD; - window_attr.visual = gdk_x11_screen_lookup_visual (gtk_widget_get_screen (drawing_area), vi->visualid); - - gdk_window = gdk_window_new (gtk_widget_get_window (drawing_area), - &window_attr, - GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL); - gdk_window_set_user_data (gdk_window, (gpointer) drawing_area); - - gdk_window_show (gdk_window); - xwindow = GDK_COMPAT_WINDOW_XID (gdk_window); -#endif - - output_window_width = width; - output_window_height = height; -} - int S9xOpenGLDisplayDriver::init_gl (void) { - ON_WAYLAND - ( - gdk_window = gtk_widget_get_window (drawing_area); - if (!wl.attach (gdk_window)) - return 0; + gdk_window = gtk_widget_get_window (drawing_area); - if (!wl.create_egl_context (256, 224)) - return 0; - - output_window_width = 256; - output_window_height = 224; - - wl.make_current (); - - return 1; - ) - - int glx_attribs[] = { GLX_RGBA, GLX_DOUBLEBUFFER, None }; - - display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); - - vi = glXChooseVisual (display, DefaultScreen (display), glx_attribs); - - if (!vi) +#ifdef GDK_WINDOWING_WAYLAND + if (GDK_IS_WAYLAND_WINDOW (gdk_window)) { - fprintf (stderr, _("Couldn't find an adequate OpenGL visual.\n")); - return 0; + context = &wl; } - - xcolormap = XCreateColormap (display, - GDK_COMPAT_WINDOW_XID (gtk_widget_get_window (drawing_area)), - vi->visual, - AllocNone); - - create_window (1, 1); - gdk_window_hide (gdk_window); - - glx_context = glXCreateContext (display, vi, 0, 1); - - if (!glx_context) +#endif +#ifdef GDK_WINDOWING_X11 + if (GDK_IS_X11_WINDOW (gdk_window)) { - XFreeColormap (display, xcolormap); - gdk_window_destroy (gdk_window); - - fprintf (stderr, _("Couldn't create an OpenGL context.\n")); - return 0; + context = &glx; } +#endif - if (!glXMakeCurrent (display, xwindow, glx_context)) - { - XFreeColormap (display, xcolormap); - g_object_unref (gdk_window); - gdk_window_destroy (gdk_window); - - fprintf (stderr, "glXMakeCurrent failed.\n"); + if (!context->attach (drawing_area)) return 0; - } + + if (!context->create_context ()) + return 0; + + output_window_width = context->width; + output_window_height = context->height; + + context->make_current (); return 1; } @@ -809,39 +722,13 @@ S9xOpenGLDisplayDriver::init (void) GFX.Screen = (uint16 *) padded_buffer[0]; GFX.Pitch = image_width * image_bpp; - swap_control (config->sync_to_vblank); + context->swap_interval (config->sync_to_vblank); initialized = 1; return 0; } -void -S9xOpenGLDisplayDriver::swap_control (int enable) -{ - enable = enable ? 1 : 0; - - ON_WAYLAND - ( - wl.swap_interval (enable); - ) - -#ifdef GDK_WINDOWING_X11 - const char *extensions = (const char *) glGetString (GL_EXTENSIONS); - - if (strstr (extensions, "EXT_swap_control")) - { - glXSwapIntervalEXT (display, xwindow, enable); - } - else if (strstr (extensions, "SGI_swap_control")) - { - glXSwapIntervalSGI (enable); - } -#endif - - return; -} - uint16 * S9xOpenGLDisplayDriver::get_next_buffer (void) { @@ -863,24 +750,9 @@ S9xOpenGLDisplayDriver::get_current_buffer (void) } void -S9xOpenGLDisplayDriver::gl_swap (void) +S9xOpenGLDisplayDriver::swap_buffers (void) { - ON_WAYLAND - ( - wl.swap_buffers (); - - if (config->sync_every_frame) - { - usleep (0); - glFinish (); - } - - return; - ) - -#ifdef GDK_WINDOWING_X11 - glXSwapBuffers (display, xwindow); -#endif + context->swap_buffers (); if (config->sync_every_frame) { @@ -931,16 +803,6 @@ S9xOpenGLDisplayDriver::deinit (void) glDeleteTextures (1, &texmap); - ON_WAYLAND - ( - return; - ) - - glXDestroyContext (display, glx_context); - gdk_window_destroy (gdk_window); - XFree (vi); - XFreeColormap (display, xcolormap); - return; } @@ -955,10 +817,12 @@ S9xOpenGLDisplayDriver::query_availability (void) { GdkDisplay *gdk_display = gdk_display_get_default (); - ON_WAYLAND - ( +#ifdef GDK_WINDOWING_WAYLAND + if (GDK_IS_WAYLAND_DISPLAY (gdk_display)) + { return 1; - ) + } +#endif #ifdef GDK_WINDOWING_X11 if (GDK_IS_X11_DISPLAY (gdk_display)) diff --git a/gtk/src/gtk_display_driver_opengl.h b/gtk/src/gtk_display_driver_opengl.h index c6e408df..18a6d4e3 100644 --- a/gtk/src/gtk_display_driver_opengl.h +++ b/gtk/src/gtk_display_driver_opengl.h @@ -5,10 +5,11 @@ #include "gtk_display_driver.h" #include -#ifdef GDK_WINDOWING_X11 -#include -#endif +#include "gtk_opengl_context.h" +#ifdef GDK_WINDOWING_X11 +#include "gtk_glx_context.h" +#endif #ifdef GDK_WINDOWING_WAYLAND #include "gtk_wayland_egl_context.h" #endif @@ -36,29 +37,27 @@ class S9xOpenGLDisplayDriver : public S9xDisplayDriver public: S9xOpenGLDisplayDriver (Snes9xWindow *window, Snes9xConfig *config); void refresh (int width, int height); - int init (void); - void deinit (void); - void clear_buffers (void); + int init (); + void deinit (); + void clear_buffers (); void update (int width, int height, int yoffset); - uint16 *get_next_buffer (void); - uint16 *get_current_buffer (void); + uint16 *get_next_buffer (); + uint16 *get_current_buffer (); void push_buffer (uint16 *src); void reconfigure (int width, int height); - void *get_parameters (void); + void *get_parameters (); void save (const char *filename); - static int query_availability (void); + static int query_availability (); private: - int opengl_defaults (void); - void swap_control (int enable); - void gl_swap (void); - int pbos_available (void); - int shaders_available (void); + int opengl_defaults (); + void swap_buffers (); + int pbos_available (); + int shaders_available (); int load_shaders (const char *); void update_texture_size (int width, int height); - int init_gl (void); - void create_window (int width, int height); - void resize_window (int width, int height); + int init_gl (); + void resize (); GLint texture_width; GLint texture_height; @@ -82,16 +81,13 @@ class S9xOpenGLDisplayDriver : public S9xDisplayDriver int output_window_width; int output_window_height; -#ifdef GDK_WINDOWING_X11 - Display *display; - Window xwindow; - Colormap xcolormap; - XVisualInfo *vi; - GLXContext glx_context; -#endif + OpenGLContext *context; +#ifdef GDK_WINDOWING_X11 + GTKGLXContext glx; +#endif #ifdef GDK_WINDOWING_WAYLAND - WaylandEGLContext wl; + WaylandEGLContext wl; #endif }; diff --git a/gtk/src/gtk_glx_context.cpp b/gtk/src/gtk_glx_context.cpp new file mode 100644 index 00000000..83039976 --- /dev/null +++ b/gtk/src/gtk_glx_context.cpp @@ -0,0 +1,146 @@ +#include +#include + +#include "gtk_s9x.h" +#include "gtk_glx_context.h" + +GTKGLXContext::GTKGLXContext () +{ + gdk_display = NULL; + parent_gdk_window = NULL; + gdk_window = NULL; + display = NULL; + vi = NULL; + context = NULL; +} + +GTKGLXContext::~GTKGLXContext () +{ + if (context) + glXDestroyContext (display, context); + + if (gdk_window) + gdk_window_destroy (gdk_window); + + if (vi) + XFree (vi); +} + +bool GTKGLXContext::attach (GtkWidget *widget) +{ + GdkScreen *gdk_screen; + GdkWindow *window; + GLXFBConfig *fbconfigs; + int num_fbconfigs; + int screen; + + int attribs[] = { + GLX_DOUBLEBUFFER, True, + GLX_X_RENDERABLE, True, + GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + None + }; + + window = gtk_widget_get_window (widget); + this->widget = widget; + + if (!GDK_IS_X11_WINDOW (window)) + return false; + + parent_gdk_window = window; + gdk_display = gdk_window_get_display (window); + gdk_screen = gdk_window_get_screen (window); + screen = gdk_x11_screen_get_screen_number (gdk_screen); + display = GDK_DISPLAY_XDISPLAY (gdk_display); + + fbconfigs = glXChooseFBConfig (display, screen, attribs, &num_fbconfigs); + if (!fbconfigs || num_fbconfigs < 1) + { + printf ("Couldn't match a GLX framebuffer config.\n"); + return false; + } + fbconfig = fbconfigs[0]; + XFree (fbconfigs); + + vi = glXGetVisualFromFBConfig (display, fbconfig); + + gdk_window_get_geometry (window, &x, &y, &width, &height); + memset (&window_attr, 0, sizeof (GdkWindowAttr)); + window_attr.width = width; + window_attr.height = height; + window_attr.wclass = GDK_INPUT_OUTPUT; + window_attr.window_type = GDK_WINDOW_CHILD; + window_attr.visual = gdk_x11_screen_lookup_visual (gdk_screen, vi->visualid); + + gdk_window = gdk_window_new (window, &window_attr, GDK_WA_VISUAL); + gdk_window_set_user_data (gdk_window, (gpointer) widget); + gdk_window_show (gdk_window); + xid = GDK_COMPAT_WINDOW_XID (gdk_window); + + return true; +} + +bool GTKGLXContext::create_context () +{ + int context_attribs[] = { + GLX_CONTEXT_MAJOR_VERSION_ARB, 4, + GLX_CONTEXT_MINOR_VERSION_ARB, 5, + GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, + None + }; + + context = glXCreateContextAttribsARB (display, fbconfig, NULL, True, context_attribs); + + if (!context) + { + printf ("Couldn't create GLX context.\n"); + return false; + } + + return true; +} + +void GTKGLXContext::resize () +{ + gdk_window_get_geometry (parent_gdk_window, &x, &y, &width, &height); + + if (window_attr.width == width && window_attr.height == height) + return; + + window_attr.width = width; + window_attr.height = height; + + gdk_window_destroy (gdk_window); + gdk_window = gdk_window_new (parent_gdk_window, &window_attr, GDK_WA_VISUAL); + gdk_window_set_user_data (gdk_window, (gpointer) widget); + gdk_window_show (gdk_window); + xid = GDK_COMPAT_WINDOW_XID (gdk_window); + + make_current (); +} + +void GTKGLXContext::swap_buffers () +{ + glXSwapBuffers (display, xid); +} + +void GTKGLXContext::make_current () +{ + glXMakeCurrent (display, xid, context); +} + +void GTKGLXContext::swap_interval (int frames) +{ + const char *extensions = (const char *) glGetString (GL_EXTENSIONS); + if (!extensions) + return; + + if (strstr (extensions, "EXT_swap_control")) + glXSwapIntervalEXT (display, xid, frames); + else if (strstr (extensions, "SGI_swap_control")) + glXSwapIntervalSGI (frames); +} + + diff --git a/gtk/src/gtk_glx_context.h b/gtk/src/gtk_glx_context.h new file mode 100644 index 00000000..64d8da72 --- /dev/null +++ b/gtk/src/gtk_glx_context.h @@ -0,0 +1,31 @@ +#pragma once +#include +#include +#include + +#include "gtk_opengl_context.h" + +struct GTKGLXContext : OpenGLContext +{ + GTKGLXContext (); + ~GTKGLXContext (); + bool attach (GtkWidget *widget); + bool create_context (); + void resize (); + void swap_buffers (); + void swap_interval (int frames); + void make_current (); + + GtkWidget *widget; + + GdkDisplay *gdk_display; + GdkWindow *parent_gdk_window; + GdkWindow *gdk_window; + GdkWindowAttr window_attr; + + GLXContext context; + GLXFBConfig fbconfig; + Display *display; + XVisualInfo *vi; + Window xid; +}; diff --git a/gtk/src/gtk_opengl_context.h b/gtk/src/gtk_opengl_context.h new file mode 100644 index 00000000..8d2bc11e --- /dev/null +++ b/gtk/src/gtk_opengl_context.h @@ -0,0 +1,17 @@ +#pragma once +#include + +struct OpenGLContext +{ + virtual bool attach (GtkWidget *widget) = 0; + virtual bool create_context () = 0; + virtual void resize () = 0; + virtual void swap_buffers () = 0; + virtual void swap_interval (int frames) = 0; + virtual void make_current () = 0; + + int x; + int y; + int width; + int height; +}; diff --git a/gtk/src/gtk_wayland_egl_context.cpp b/gtk/src/gtk_wayland_egl_context.cpp index 249a59ff..c25b0df1 100644 --- a/gtk/src/gtk_wayland_egl_context.cpp +++ b/gtk/src/gtk_wayland_egl_context.cpp @@ -66,15 +66,15 @@ WaylandEGLContext::~WaylandEGLContext () wl_egl_window_destroy (egl_window); } -bool WaylandEGLContext::attach (GdkWindow *window) +bool WaylandEGLContext::attach (GtkWidget *widget) { - int x, y, w, h; + GdkWindow *window = gtk_widget_get_window (widget); if (!GDK_IS_WAYLAND_WINDOW (window)) return false; gdk_window = window; - gdk_window_get_geometry (gdk_window, &x, &y, &w, &h); + 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); @@ -97,9 +97,10 @@ bool WaylandEGLContext::attach (GdkWindow *window) return true; } -bool WaylandEGLContext::create_egl_context (int width, int height) +bool WaylandEGLContext::create_context () { 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, @@ -156,14 +157,14 @@ bool WaylandEGLContext::create_egl_context (int width, int height) return true; } -void WaylandEGLContext::resize (int width, int height) +void WaylandEGLContext::resize () { - int x, y, w, h, scale; + int scale; - gdk_window_get_geometry (gdk_window, &x, &y, &w, &h); + gdk_window_get_geometry (gdk_window, &x, &y, &width, &height); scale = gdk_window_get_scale_factor (gdk_window); - wl_egl_window_resize (egl_window, w * scale, h * scale, 0, 0); + wl_egl_window_resize (egl_window, width * scale, height * scale, 0, 0); wl_subsurface_set_position (subsurface, x, y); make_current (); diff --git a/gtk/src/gtk_wayland_egl_context.h b/gtk/src/gtk_wayland_egl_context.h index f3497352..d2112914 100644 --- a/gtk/src/gtk_wayland_egl_context.h +++ b/gtk/src/gtk_wayland_egl_context.h @@ -3,13 +3,15 @@ #include #include -struct WaylandEGLContext +#include "gtk_opengl_context.h" + +struct WaylandEGLContext : OpenGLContext { WaylandEGLContext (); ~WaylandEGLContext (); - bool attach (GdkWindow *window); - bool create_egl_context (int width, int height); - void resize (int width, int height); + bool attach (GtkWidget *widget); + bool create_context (); + void resize (); void swap_buffers (); void swap_interval (int frames); void make_current ();