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 += \
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
endif
if XV

View File

@ -1,8 +1,4 @@
#include <gtk/gtk.h>
#ifdef GDK_WINDOWING_X11
#include <gdk/gdkx.h>
#include <X11/Xlib.h>
#endif
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <dlfcn.h>
@ -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))

View File

@ -5,10 +5,11 @@
#include "gtk_display_driver.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
#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
};

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);
}
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 ();

View File

@ -3,13 +3,15 @@
#include <wayland-egl.h>
#include <epoxy/egl.h>
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 ();