Make OpenGL context management separate.

This commit is contained in:
Brandon Wright 2018-10-26 18:22:51 -05:00
parent b35d8d9ae5
commit f9b553638f
8 changed files with 268 additions and 209 deletions

View File

@ -239,9 +239,11 @@ if OPENGL
snes9x_gtk_SOURCES += \ snes9x_gtk_SOURCES += \
src/gtk_display_driver_opengl.cpp \ src/gtk_display_driver_opengl.cpp \
src/gtk_display_driver_opengl.h \ src/gtk_display_driver_opengl.h \
src/gtk_glx_context.cpp \
../shaders/glsl.cpp \ ../shaders/glsl.cpp \
../shaders/shader_helpers.cpp \ ../shaders/shader_helpers.cpp \
src/gtk_shader_parameters.cpp src/gtk_shader_parameters.cpp
endif endif
if XV if XV

View File

@ -1,8 +1,4 @@
#include <gtk/gtk.h> #include <gtk/gtk.h>
#ifdef GDK_WINDOWING_X11
#include <gdk/gdkx.h>
#include <X11/Xlib.h>
#endif
#include <libxml/parser.h> #include <libxml/parser.h>
#include <libxml/tree.h> #include <libxml/tree.h>
#include <dlfcn.h> #include <dlfcn.h>
@ -13,18 +9,8 @@
#include "gtk_display.h" #include "gtk_display.h"
#include "gtk_display_driver_opengl.h" #include "gtk_display_driver_opengl.h"
#include "gtk_shader_parameters.h" #include "gtk_shader_parameters.h"
#include "shaders/shader_helpers.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, static void S9xViewportCallback (int src_width, int src_height,
int viewport_x, int viewport_y, int viewport_x, int viewport_y,
int viewport_width, int viewport_height, int viewport_width, int viewport_height,
@ -65,7 +51,7 @@ S9xOpenGLDisplayDriver::update (int width, int height, int yoffset)
if (output_window_width != allocation.width || if (output_window_width != allocation.width ||
output_window_height != allocation.height) output_window_height != allocation.height)
{ {
resize_window (allocation.width, allocation.height); resize ();
} }
#if GTK_CHECK_VERSION(3,10,0) #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) if (using_shaders && using_glsl_shaders)
{ {
glsl_shader->render (texmap, width, height, x, allocation.height - y - h, w, h, S9xViewportCallback); glsl_shader->render (texmap, width, height, x, allocation.height - y - h, w, h, S9xViewportCallback);
gl_swap (); swap_buffers ();
return; return;
} }
else if (using_shaders) else if (using_shaders)
@ -281,7 +267,7 @@ S9xOpenGLDisplayDriver::update (int width, int height, int yoffset)
glDrawArrays (GL_QUADS, 0, 4); glDrawArrays (GL_QUADS, 0, 4);
gl_swap (); swap_buffers ();
return; return;
} }
@ -668,117 +654,44 @@ S9xOpenGLDisplayDriver::refresh (int width, int height)
} }
void void
S9xOpenGLDisplayDriver::resize_window (int width, int height) S9xOpenGLDisplayDriver::resize ()
{ {
ON_WAYLAND context->resize ();
( context->swap_interval (config->sync_to_vblank);
wl.resize (width, height); output_window_width = context->width;
wl.swap_interval (config->sync_to_vblank); output_window_height = context->height;
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);
return; 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 int
S9xOpenGLDisplayDriver::init_gl (void) S9xOpenGLDisplayDriver::init_gl (void)
{ {
ON_WAYLAND gdk_window = gtk_widget_get_window (drawing_area);
(
gdk_window = gtk_widget_get_window (drawing_area);
if (!wl.attach (gdk_window))
return 0;
if (!wl.create_egl_context (256, 224)) #ifdef GDK_WINDOWING_WAYLAND
return 0; if (GDK_IS_WAYLAND_WINDOW (gdk_window))
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)
{ {
fprintf (stderr, _("Couldn't find an adequate OpenGL visual.\n")); context = &wl;
return 0;
} }
#endif
xcolormap = XCreateColormap (display, #ifdef GDK_WINDOWING_X11
GDK_COMPAT_WINDOW_XID (gtk_widget_get_window (drawing_area)), if (GDK_IS_X11_WINDOW (gdk_window))
vi->visual,
AllocNone);
create_window (1, 1);
gdk_window_hide (gdk_window);
glx_context = glXCreateContext (display, vi, 0, 1);
if (!glx_context)
{ {
XFreeColormap (display, xcolormap); context = &glx;
gdk_window_destroy (gdk_window);
fprintf (stderr, _("Couldn't create an OpenGL context.\n"));
return 0;
} }
#endif
if (!glXMakeCurrent (display, xwindow, glx_context)) if (!context->attach (drawing_area))
{
XFreeColormap (display, xcolormap);
g_object_unref (gdk_window);
gdk_window_destroy (gdk_window);
fprintf (stderr, "glXMakeCurrent failed.\n");
return 0; return 0;
}
if (!context->create_context ())
return 0;
output_window_width = context->width;
output_window_height = context->height;
context->make_current ();
return 1; return 1;
} }
@ -809,39 +722,13 @@ S9xOpenGLDisplayDriver::init (void)
GFX.Screen = (uint16 *) padded_buffer[0]; GFX.Screen = (uint16 *) padded_buffer[0];
GFX.Pitch = image_width * image_bpp; GFX.Pitch = image_width * image_bpp;
swap_control (config->sync_to_vblank); context->swap_interval (config->sync_to_vblank);
initialized = 1; initialized = 1;
return 0; 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 * uint16 *
S9xOpenGLDisplayDriver::get_next_buffer (void) S9xOpenGLDisplayDriver::get_next_buffer (void)
{ {
@ -863,24 +750,9 @@ S9xOpenGLDisplayDriver::get_current_buffer (void)
} }
void void
S9xOpenGLDisplayDriver::gl_swap (void) S9xOpenGLDisplayDriver::swap_buffers (void)
{ {
ON_WAYLAND context->swap_buffers ();
(
wl.swap_buffers ();
if (config->sync_every_frame)
{
usleep (0);
glFinish ();
}
return;
)
#ifdef GDK_WINDOWING_X11
glXSwapBuffers (display, xwindow);
#endif
if (config->sync_every_frame) if (config->sync_every_frame)
{ {
@ -931,16 +803,6 @@ S9xOpenGLDisplayDriver::deinit (void)
glDeleteTextures (1, &texmap); glDeleteTextures (1, &texmap);
ON_WAYLAND
(
return;
)
glXDestroyContext (display, glx_context);
gdk_window_destroy (gdk_window);
XFree (vi);
XFreeColormap (display, xcolormap);
return; return;
} }
@ -955,10 +817,12 @@ S9xOpenGLDisplayDriver::query_availability (void)
{ {
GdkDisplay *gdk_display = gdk_display_get_default (); GdkDisplay *gdk_display = gdk_display_get_default ();
ON_WAYLAND #ifdef GDK_WINDOWING_WAYLAND
( if (GDK_IS_WAYLAND_DISPLAY (gdk_display))
{
return 1; return 1;
) }
#endif
#ifdef GDK_WINDOWING_X11 #ifdef GDK_WINDOWING_X11
if (GDK_IS_X11_DISPLAY (gdk_display)) if (GDK_IS_X11_DISPLAY (gdk_display))

View File

@ -5,10 +5,11 @@
#include "gtk_display_driver.h" #include "gtk_display_driver.h"
#include <epoxy/gl.h> #include <epoxy/gl.h>
#ifdef GDK_WINDOWING_X11
#include <epoxy/glx.h>
#endif
#include "gtk_opengl_context.h"
#ifdef GDK_WINDOWING_X11
#include "gtk_glx_context.h"
#endif
#ifdef GDK_WINDOWING_WAYLAND #ifdef GDK_WINDOWING_WAYLAND
#include "gtk_wayland_egl_context.h" #include "gtk_wayland_egl_context.h"
#endif #endif
@ -36,29 +37,27 @@ class S9xOpenGLDisplayDriver : public S9xDisplayDriver
public: public:
S9xOpenGLDisplayDriver (Snes9xWindow *window, Snes9xConfig *config); S9xOpenGLDisplayDriver (Snes9xWindow *window, Snes9xConfig *config);
void refresh (int width, int height); void refresh (int width, int height);
int init (void); int init ();
void deinit (void); void deinit ();
void clear_buffers (void); void clear_buffers ();
void update (int width, int height, int yoffset); void update (int width, int height, int yoffset);
uint16 *get_next_buffer (void); uint16 *get_next_buffer ();
uint16 *get_current_buffer (void); uint16 *get_current_buffer ();
void push_buffer (uint16 *src); void push_buffer (uint16 *src);
void reconfigure (int width, int height); void reconfigure (int width, int height);
void *get_parameters (void); void *get_parameters ();
void save (const char *filename); void save (const char *filename);
static int query_availability (void); static int query_availability ();
private: private:
int opengl_defaults (void); int opengl_defaults ();
void swap_control (int enable); void swap_buffers ();
void gl_swap (void); int pbos_available ();
int pbos_available (void); int shaders_available ();
int shaders_available (void);
int load_shaders (const char *); int load_shaders (const char *);
void update_texture_size (int width, int height); void update_texture_size (int width, int height);
int init_gl (void); int init_gl ();
void create_window (int width, int height); void resize ();
void resize_window (int width, int height);
GLint texture_width; GLint texture_width;
GLint texture_height; GLint texture_height;
@ -82,16 +81,13 @@ class S9xOpenGLDisplayDriver : public S9xDisplayDriver
int output_window_width; int output_window_width;
int output_window_height; int output_window_height;
#ifdef GDK_WINDOWING_X11 OpenGLContext *context;
Display *display;
Window xwindow;
Colormap xcolormap;
XVisualInfo *vi;
GLXContext glx_context;
#endif
#ifdef GDK_WINDOWING_X11
GTKGLXContext glx;
#endif
#ifdef GDK_WINDOWING_WAYLAND #ifdef GDK_WINDOWING_WAYLAND
WaylandEGLContext wl; WaylandEGLContext wl;
#endif #endif
}; };

146
gtk/src/gtk_glx_context.cpp Normal file
View File

@ -0,0 +1,146 @@
#include <stdio.h>
#include <string.h>
#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);
}

31
gtk/src/gtk_glx_context.h Normal file
View File

@ -0,0 +1,31 @@
#pragma once
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <epoxy/glx.h>
#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;
};

View File

@ -0,0 +1,17 @@
#pragma once
#include <gtk/gtk.h>
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;
};

View File

@ -66,15 +66,15 @@ WaylandEGLContext::~WaylandEGLContext ()
wl_egl_window_destroy (egl_window); 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)) if (!GDK_IS_WAYLAND_WINDOW (window))
return false; return false;
gdk_window = window; 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)); display = gdk_wayland_display_get_wl_display (gdk_window_get_display (gdk_window));
parent = gdk_wayland_window_get_wl_surface (gdk_window); parent = gdk_wayland_window_get_wl_surface (gdk_window);
@ -97,9 +97,10 @@ bool WaylandEGLContext::attach (GdkWindow *window)
return true; return true;
} }
bool WaylandEGLContext::create_egl_context (int width, int height) bool WaylandEGLContext::create_context ()
{ {
int scale = gdk_window_get_scale_factor (gdk_window); int scale = gdk_window_get_scale_factor (gdk_window);
gdk_window_get_geometry (gdk_window, &x, &y, &width, &height);
EGLint surface_attribs[] = { EGLint surface_attribs[] = {
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
@ -156,14 +157,14 @@ bool WaylandEGLContext::create_egl_context (int width, int height)
return true; 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); 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); wl_subsurface_set_position (subsurface, x, y);
make_current (); make_current ();

View File

@ -3,13 +3,15 @@
#include <wayland-egl.h> #include <wayland-egl.h>
#include <epoxy/egl.h> #include <epoxy/egl.h>
struct WaylandEGLContext #include "gtk_opengl_context.h"
struct WaylandEGLContext : OpenGLContext
{ {
WaylandEGLContext (); WaylandEGLContext ();
~WaylandEGLContext (); ~WaylandEGLContext ();
bool attach (GdkWindow *window); bool attach (GtkWidget *widget);
bool create_egl_context (int width, int height); bool create_context ();
void resize (int width, int height); void resize ();
void swap_buffers (); void swap_buffers ();
void swap_interval (int frames); void swap_interval (int frames);
void make_current (); void make_current ();