mirror of https://github.com/snes9xgit/snes9x.git
Gtk/OpenGL/Wayland: Support fractional scale.
This commit is contained in:
parent
f1286eda4c
commit
aa2a46f87b
|
@ -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;
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue