Gtk/OpenGL/Wayland: Support fractional scale.

This commit is contained in:
BearOso 2023-03-05 18:30:46 -06:00
parent f1286eda4c
commit aa2a46f87b
4 changed files with 23 additions and 124 deletions

View File

@ -89,18 +89,12 @@ S9xOpenGLDisplayDriver::S9xOpenGLDisplayDriver(Snes9xWindow *window, Snes9xConfi
void S9xOpenGLDisplayDriver::update(uint16_t *buffer, int width, int height, int stride_in_pixels) void S9xOpenGLDisplayDriver::update(uint16_t *buffer, int width, int height, int stride_in_pixels)
{ {
Gtk::Allocation allocation = drawing_area->get_allocation(); Gtk::Allocation allocation = drawing_area->get_allocation();
if (output_window_width != allocation.get_width() || if (output_window_width != allocation.get_width() ||
output_window_height != allocation.get_height()) output_window_height != allocation.get_height())
{ {
resize(); resize();
} }
int scale_factor = drawing_area->get_scale_factor();
allocation.set_width(allocation.get_width() * scale_factor);
allocation.set_height(allocation.get_height() * scale_factor);
if (!legacy) if (!legacy)
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texmap); glBindTexture(GL_TEXTURE_2D, texmap);
@ -113,8 +107,8 @@ void S9xOpenGLDisplayDriver::update(uint16_t *buffer, int width, int height, int
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
S9xRect content = S9xApplyAspect(width, height, allocation.get_width(), allocation.get_height()); S9xRect content = S9xApplyAspect(width, height, context->width, context->height);
glViewport(content.x, allocation.get_height() - content.y - content.h, content.w, content.h); glViewport(content.x, context->height - content.y - content.h, content.w, content.h);
window->set_mouseable_area(content.x, content.y, content.w, content.h); window->set_mouseable_area(content.x, content.y, content.w, content.h);
update_texture_size(width, height); update_texture_size(width, height);
@ -124,7 +118,7 @@ void S9xOpenGLDisplayDriver::update(uint16_t *buffer, int width, int height, int
if (using_glsl_shaders) if (using_glsl_shaders)
{ {
glsl_shader->render(texmap, width, height, content.x, allocation.get_height() - content.y - content.h, content.w, content.h, S9xViewportCallback); glsl_shader->render(texmap, width, height, content.x, context->height - content.y - content.h, content.w, content.h, S9xViewportCallback);
} }
else else
{ {
@ -349,8 +343,9 @@ void S9xOpenGLDisplayDriver::resize()
{ {
context->resize(); context->resize();
context->swap_interval(config->sync_to_vblank); context->swap_interval(config->sync_to_vblank);
output_window_width = context->width; Gtk::Allocation allocation = drawing_area->get_allocation();
output_window_height = context->height; output_window_width = allocation.get_width();
output_window_height = allocation.get_height();
} }
bool S9xOpenGLDisplayDriver::create_context() bool S9xOpenGLDisplayDriver::create_context()
@ -378,9 +373,6 @@ bool S9xOpenGLDisplayDriver::create_context()
if (!context->create_context()) if (!context->create_context())
return false; return false;
output_window_width = context->width;
output_window_height = context->height;
context->make_current(); context->make_current();
legacy = false; legacy = false;

View File

@ -9,71 +9,20 @@
#include "gtk_s9x.h" #include "gtk_s9x.h"
#include "gtk_wayland_egl_context.h" #include "gtk_wayland_egl_context.h"
#include "wayland-idle-inhibit-unstable-v1.h"
static void wl_global(void *data,
struct wl_registry *wl_registry,
uint32_t name,
const char *interface,
uint32_t version)
{
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);
else if (!strcmp(interface, zwp_idle_inhibit_manager_v1_interface.name))
wl->idle_inhibit_manager = (struct zwp_idle_inhibit_manager_v1 *)wl_registry_bind(wl_registry, name, &zwp_idle_inhibit_manager_v1_interface, 1);
}
static void wl_global_remove(void *data,
struct wl_registry *wl_registry,
uint32_t name)
{
}
static const struct wl_registry_listener wl_registry_listener = {
wl_global,
wl_global_remove
};
WaylandEGLContext::WaylandEGLContext() WaylandEGLContext::WaylandEGLContext()
{ {
display = NULL;
registry = NULL;
compositor = NULL;
subcompositor = NULL;
parent = NULL;
child = NULL;
region = NULL;
subsurface = NULL;
egl_display = NULL; egl_display = NULL;
egl_surface = NULL; egl_surface = NULL;
egl_context = NULL; egl_context = NULL;
egl_config = NULL; egl_config = NULL;
egl_window = NULL; egl_window = NULL;
idle_inhibit_manager = NULL; x = 0;
idle_inhibitor = NULL; y = 0;
} }
WaylandEGLContext::~WaylandEGLContext() WaylandEGLContext::~WaylandEGLContext()
{ {
if (idle_inhibitor)
zwp_idle_inhibitor_v1_destroy(idle_inhibitor);
if (idle_inhibit_manager)
zwp_idle_inhibit_manager_v1_destroy(idle_inhibit_manager);
if (subsurface)
wl_subsurface_destroy(subsurface);
if (region)
wl_region_destroy(region);
if (child)
wl_surface_destroy(child);
if (egl_context) if (egl_context)
eglDestroyContext(egl_display, egl_context); eglDestroyContext(egl_display, egl_context);
@ -91,41 +40,14 @@ bool WaylandEGLContext::attach(GtkWidget *widget)
if (!GDK_IS_WAYLAND_WINDOW(window)) if (!GDK_IS_WAYLAND_WINDOW(window))
return false; return false;
gdk_window = window; wayland_surface = std::make_unique<WaylandSurface>();
gdk_window_get_geometry(gdk_window, &x, &y, &width, &height); wayland_surface->attach(widget);
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);
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);
wl_surface_set_input_region(child, region);
wl_subsurface_set_desync(subsurface);
wl_subsurface_set_position(subsurface, x, y);
if (idle_inhibit_manager && gui_config->prevent_screensaver)
{
printf("Inhibiting screensaver.\n");
zwp_idle_inhibit_manager_v1_create_inhibitor(idle_inhibit_manager, child);
}
return true; 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);
EGLint surface_attribs[] = { EGLint surface_attribs[] = {
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
EGL_RED_SIZE, 8, EGL_RED_SIZE, 8,
@ -148,10 +70,7 @@ bool WaylandEGLContext::create_context()
EGLint num_configs = 0; EGLint num_configs = 0;
if (!subsurface) egl_display = eglGetDisplay((EGLNativeDisplayType)wayland_surface->display);
return false;
egl_display = eglGetDisplay((EGLNativeDisplayType)display);
eglInitialize(egl_display, NULL, NULL); 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))
@ -161,7 +80,8 @@ bool WaylandEGLContext::create_context()
} }
eglBindAPI(EGL_OPENGL_API); eglBindAPI(EGL_OPENGL_API);
egl_window = wl_egl_window_create(child, width * scale, height * scale); std::tie(width, height) = wayland_surface->get_size();
egl_window = wl_egl_window_create(wayland_surface->child, width, height);
if (!egl_window) if (!egl_window)
{ {
printf("Couldn't create window.\n"); printf("Couldn't create window.\n");
@ -186,21 +106,15 @@ bool WaylandEGLContext::create_context()
} }
} }
wl_surface_set_buffer_scale(child, scale);
gdk_window_invalidate_rect(gdk_window, NULL, false);
return true; return true;
} }
void WaylandEGLContext::resize() void WaylandEGLContext::resize()
{ {
int scale; wayland_surface->resize();
gdk_window_get_geometry(gdk_window, &x, &y, &width, &height); std::tie(width, height) = wayland_surface->get_size();
scale = gdk_window_get_scale_factor(gdk_window); wl_egl_window_resize(egl_window, width, height, 0, 0);
wl_egl_window_resize(egl_window, width * scale, height * scale, 0, 0);
wl_subsurface_set_position(subsurface, x, y);
make_current(); make_current();
} }
@ -208,7 +122,7 @@ void WaylandEGLContext::resize()
void WaylandEGLContext::swap_buffers() void WaylandEGLContext::swap_buffers()
{ {
eglSwapBuffers(egl_display, egl_surface); eglSwapBuffers(egl_display, egl_surface);
wl_surface_commit(child); wl_surface_commit(wayland_surface->child);
} }
bool WaylandEGLContext::ready() bool WaylandEGLContext::ready()

View File

@ -8,9 +8,11 @@
#define __GTK_WAYLAND_EGL_CONTEXT_H #define __GTK_WAYLAND_EGL_CONTEXT_H
#include "gtk_opengl_context.h" #include "gtk_opengl_context.h"
#include "gtk_wayland_surface.h"
#include "gtk_compat.h" #include "gtk_compat.h"
#include <epoxy/egl.h> #include <epoxy/egl.h>
#include <memory>
#include <wayland-egl.h> #include <wayland-egl.h>
class WaylandEGLContext : public OpenGLContext class WaylandEGLContext : public OpenGLContext
@ -28,16 +30,6 @@ class WaylandEGLContext : public OpenGLContext
GdkWindow *gdk_window; GdkWindow *gdk_window;
struct wl_display *display;
struct wl_registry *registry;
struct wl_compositor *compositor;
struct wl_subcompositor *subcompositor;
struct wl_surface *parent;
struct wl_surface *child;
struct wl_subsurface *subsurface;
struct wl_region *region;
EGLDisplay egl_display; EGLDisplay egl_display;
EGLSurface egl_surface; EGLSurface egl_surface;
EGLContext egl_context; EGLContext egl_context;
@ -45,8 +37,7 @@ class WaylandEGLContext : public OpenGLContext
wl_egl_window *egl_window; wl_egl_window *egl_window;
struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager; std::unique_ptr<WaylandSurface> wayland_surface;
struct zwp_idle_inhibitor_v1 *idle_inhibitor;
}; };
#endif #endif

View File

@ -147,6 +147,8 @@ bool WaylandSurface::attach(GtkWidget *widget)
zwp_idle_inhibit_manager_v1_create_inhibitor(idle_inhibit_manager, child); zwp_idle_inhibit_manager_v1_create_inhibitor(idle_inhibit_manager, child);
} }
resize();
return true; return true;
} }