snes9x/gtk/src/gtk_wayland_egl_context.cpp

232 lines
6.3 KiB
C++
Raw Normal View History

/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
This file is licensed under the Snes9x License.
For further information, consult the LICENSE file in the root directory.
\*****************************************************************************/
2018-10-21 23:03:35 +00:00
#include <stdio.h>
#include <string.h>
#include "gtk_s9x.h"
#include "gtk_wayland_egl_context.h"
2018-10-21 23:03:35 +00:00
static void wl_global(void *data,
struct wl_registry *wl_registry,
uint32_t name,
const char *interface,
uint32_t version)
2018-10-21 23:03:35 +00:00
{
WaylandEGLContext *wl = (WaylandEGLContext *)data;
2018-10-21 23:03:35 +00:00
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);
2018-10-21 23:03:35 +00:00
}
static void wl_global_remove(void *data,
struct wl_registry *wl_registry,
uint32_t name)
2018-10-21 23:03:35 +00:00
{
}
static const struct wl_registry_listener wl_registry_listener = {
wl_global,
wl_global_remove
};
WaylandEGLContext::WaylandEGLContext()
2018-10-21 23:03:35 +00:00
{
display = NULL;
registry = NULL;
compositor = NULL;
2018-10-21 23:03:35 +00:00
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;
use_sync_control = false;
ust = msc = sbc = 0;
2018-10-21 23:03:35 +00:00
}
WaylandEGLContext::~WaylandEGLContext()
2018-10-21 23:03:35 +00:00
{
if (subsurface)
wl_subsurface_destroy(subsurface);
2018-10-21 23:03:35 +00:00
if (region)
wl_region_destroy(region);
2018-10-21 23:03:35 +00:00
if (child)
wl_surface_destroy(child);
2018-10-21 23:03:35 +00:00
if (egl_context)
eglDestroyContext(egl_display, egl_context);
2018-10-21 23:03:35 +00:00
if (egl_surface)
eglDestroySurface(egl_display, egl_surface);
2018-10-21 23:03:35 +00:00
if (egl_window)
wl_egl_window_destroy(egl_window);
2018-10-21 23:03:35 +00:00
}
bool WaylandEGLContext::attach(GtkWidget *widget)
2018-10-21 23:03:35 +00:00
{
GdkWindow *window = gtk_widget_get_window(widget);
2018-10-21 23:03:35 +00:00
if (!GDK_IS_WAYLAND_WINDOW(window))
2018-10-21 23:03:35 +00:00
return false;
gdk_window = window;
gdk_window_get_geometry(gdk_window, &x, &y, &width, &height);
2018-10-21 23:03:35 +00:00
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);
2018-10-21 23:03:35 +00:00
wl_registry_add_listener(registry, &wl_registry_listener, this);
wl_display_roundtrip(display);
2018-10-21 23:03:35 +00:00
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);
2018-10-21 23:03:35 +00:00
wl_surface_set_input_region(child, region);
wl_subsurface_set_desync(subsurface);
wl_subsurface_set_position(subsurface, x, y);
2018-10-21 23:03:35 +00:00
return true;
}
bool WaylandEGLContext::create_context()
2018-10-21 23:03:35 +00:00
{
int scale = gdk_window_get_scale_factor(gdk_window);
gdk_window_get_geometry(gdk_window, &x, &y, &width, &height);
2018-10-21 23:03:35 +00:00
EGLint surface_attribs[] = {
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
EGL_RED_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_NONE
};
EGLint core_context_attribs[] = {
EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
EGL_CONTEXT_MAJOR_VERSION, 3,
EGL_CONTEXT_MINOR_VERSION, 3,
EGL_NONE
};
EGLint compatibility_context_attribs[] = {
2018-10-21 23:03:35 +00:00
EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT,
EGL_NONE
};
EGLint num_configs = 0;
if (!subsurface)
return false;
egl_display = eglGetDisplay((EGLNativeDisplayType)display);
eglInitialize(egl_display, NULL, NULL);
2018-10-21 23:03:35 +00:00
if (!eglChooseConfig(egl_display, surface_attribs, &egl_config, 1, &num_configs))
2018-10-21 23:03:35 +00:00
{
printf("Couldn't find matching config.\n");
2018-10-21 23:03:35 +00:00
return false;
}
eglBindAPI(EGL_OPENGL_API);
2018-10-21 23:03:35 +00:00
egl_window = wl_egl_window_create(child, width * scale, height * scale);
2018-10-21 23:03:35 +00:00
if (!egl_window)
{
printf("Couldn't create window.\n");
2018-10-21 23:03:35 +00:00
return false;
}
egl_surface = eglCreateWindowSurface(egl_display, egl_config, (EGLNativeWindowType)egl_window, NULL);
2018-10-21 23:03:35 +00:00
if (!egl_surface)
{
printf("Couldn't create surface.\n");
2018-10-21 23:03:35 +00:00
return false;
}
egl_context = eglCreateContext(egl_display, egl_config, EGL_NO_CONTEXT, core_context_attribs);
2018-10-21 23:03:35 +00:00
if (!egl_context)
{
egl_context = eglCreateContext(egl_display, egl_config, EGL_NO_CONTEXT, compatibility_context_attribs);
if (!egl_context)
{
printf("Couldn't create context.\n");
return false;
}
2018-10-21 23:03:35 +00:00
}
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);
2018-10-21 23:03:35 +00:00
return true;
}
void WaylandEGLContext::resize()
2018-10-21 23:03:35 +00:00
{
int scale;
2018-10-21 23:03:35 +00:00
gdk_window_get_geometry(gdk_window, &x, &y, &width, &height);
scale = gdk_window_get_scale_factor(gdk_window);
2018-10-21 23:03:35 +00:00
wl_egl_window_resize(egl_window, width * scale, height * scale, 0, 0);
wl_subsurface_set_position(subsurface, x, y);
2018-10-21 23:03:35 +00:00
make_current();
2018-10-21 23:03:35 +00:00
}
void WaylandEGLContext::swap_buffers()
2018-10-21 23:03:35 +00:00
{
if (use_sync_control)
eglGetSyncValuesCHROMIUM(egl_display, egl_surface, &ust, &msc, &sbc);
eglSwapBuffers(egl_display, egl_surface);
wl_surface_commit(child);
2018-10-21 23:03:35 +00:00
}
bool WaylandEGLContext::ready()
2018-10-21 23:03:35 +00:00
{
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;
2018-10-21 23:03:35 +00:00
}
void WaylandEGLContext::make_current()
2018-10-21 23:03:35 +00:00
{
eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context);
2018-10-21 23:03:35 +00:00
}
void WaylandEGLContext::swap_interval(int frames)
{
eglSwapInterval(egl_display, frames);
}