Refactor CSD code to avoid un-needed rerenders and use a single shm pool for all CSD buffers
This commit is contained in:
parent
c1f8372efc
commit
0593158a86
227
glfw/wl_client_side_decorations.c
vendored
227
glfw/wl_client_side_decorations.c
vendored
@ -13,166 +13,168 @@
|
||||
#include <string.h>
|
||||
|
||||
#define decs window->wl.decorations
|
||||
#define tb decs.title_bar
|
||||
#define eb decs.edges
|
||||
|
||||
#define ARGB(a, r, g, b) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
|
||||
|
||||
static const uint32_t bg_color = 0xfffefefe;
|
||||
|
||||
static void
|
||||
free_title_bar_resources(_GLFWwindow *window) {
|
||||
if (tb.front_buffer) {
|
||||
wl_buffer_destroy(tb.front_buffer);
|
||||
tb.front_buffer = NULL;
|
||||
}
|
||||
if (tb.back_buffer) {
|
||||
wl_buffer_destroy(tb.back_buffer);
|
||||
tb.back_buffer = NULL;
|
||||
}
|
||||
if (tb.data) {
|
||||
munmap(tb.data, tb.buffer_sz * 2);
|
||||
tb.data = NULL;
|
||||
}
|
||||
static size_t
|
||||
init_buffer_pair(_GLFWWaylandBufferPair *pair, size_t width, size_t height, unsigned scale) {
|
||||
memset(pair, 0, sizeof(_GLFWWaylandBufferPair));
|
||||
pair->width = width * scale;
|
||||
pair->height = height * scale;
|
||||
pair->stride = 4 * pair->width;
|
||||
pair->size_in_bytes = pair->stride * pair->height;
|
||||
return 2 * pair->size_in_bytes;
|
||||
}
|
||||
|
||||
static void
|
||||
free_edge_resources(_GLFWwindow *window) {
|
||||
if (eb.left) { wl_buffer_destroy(eb.left); eb.left = NULL; }
|
||||
if (eb.right) { wl_buffer_destroy(eb.right); eb.right = NULL; }
|
||||
if (eb.bottom) { wl_buffer_destroy(eb.bottom); eb.bottom = NULL; }
|
||||
alloc_buffer_pair(_GLFWWaylandBufferPair *pair, struct wl_shm_pool *pool, uint8_t *data, size_t *offset) {
|
||||
pair->data.a = data + *offset;
|
||||
pair->a = wl_shm_pool_create_buffer(pool, *offset, pair->width, pair->height, pair->stride, WL_SHM_FORMAT_ARGB8888);
|
||||
*offset += pair->size_in_bytes;
|
||||
pair->data.b = data + *offset;
|
||||
pair->b = wl_shm_pool_create_buffer(pool, *offset, pair->width, pair->height, pair->stride, WL_SHM_FORMAT_ARGB8888);
|
||||
*offset += pair->size_in_bytes;
|
||||
pair->front = pair->a; pair->back = pair->b;
|
||||
pair->data.front = pair->data.a; pair->data.back = pair->data.b;
|
||||
pair->back_buffer_is_safe = true;
|
||||
}
|
||||
|
||||
static void
|
||||
render_title_bar(_GLFWwindow *window, bool to_front_buffer) {
|
||||
uint8_t *output = to_front_buffer ? decs.top.buffer.data.front : decs.top.buffer.data.back;
|
||||
for (uint32_t *px = (uint32_t*)output, *end = (uint32_t*)(output + decs.top.buffer.size_in_bytes); px < end; px++) {
|
||||
*px = bg_color;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
render_edge(_GLFWWaylandBufferPair *pair) {
|
||||
for (uint32_t *px = (uint32_t*)pair->data.front, *end = (uint32_t*)(pair->data.front + pair->size_in_bytes); px < end; px++) {
|
||||
*px = bg_color;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
create_shm_buffers_for_title_bar(_GLFWwindow* window) {
|
||||
free_title_bar_resources(window);
|
||||
int scale = window->wl.scale;
|
||||
if (scale < 1) scale = 1;
|
||||
size_t width = window->wl.width * scale, height = decs.metrics.top * scale;
|
||||
const size_t stride = 4 * width;
|
||||
tb.buffer_sz = stride * height;
|
||||
const size_t mapping_sz = tb.buffer_sz * 2;
|
||||
|
||||
int fd = createAnonymousFile(mapping_sz);
|
||||
if (fd < 0) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Creating a buffer file for %zu B failed: %s",
|
||||
mapping_sz, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
tb.data = mmap(NULL, mapping_sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (tb.data == MAP_FAILED) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: mmap failed: %s", strerror(errno));
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
for (uint32_t *px = (uint32_t*)tb.data, *end = (uint32_t*)(tb.data + tb.buffer_sz); px < end; px++) *px = bg_color;
|
||||
struct wl_shm_pool* pool = wl_shm_create_pool(_glfw.wl.shm, fd, mapping_sz);
|
||||
close(fd);
|
||||
#define c(offset) wl_shm_pool_create_buffer( \
|
||||
pool, offset, width, height, stride, WL_SHM_FORMAT_ARGB8888);
|
||||
tb.front_buffer = c(0); tb.back_buffer = c(tb.buffer_sz);
|
||||
#undef c
|
||||
wl_shm_pool_destroy(pool);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
render_left_edge(uint8_t *data, size_t width, size_t height, bool is_focused) {
|
||||
if (is_focused) for (uint32_t *px = (uint32_t*)data, *end = (uint32_t*)(data + 4 * width * height); px < end; px++) *px = bg_color;
|
||||
else memset(data, 0, 4 * width * height);
|
||||
}
|
||||
#define render_right_edge render_left_edge
|
||||
#define render_bottom_edge render_left_edge
|
||||
|
||||
static bool
|
||||
create_shm_buffers_for_edges(_GLFWwindow* window, bool is_focused) {
|
||||
free_edge_resources(window);
|
||||
create_shm_buffers(_GLFWwindow* window) {
|
||||
int scale = window->wl.scale;
|
||||
if (scale < 1) scale = 1;
|
||||
|
||||
size_t vertical_width = decs.metrics.width, vertical_height = window->wl.height + decs.metrics.top;
|
||||
size_t horizontal_height = decs.metrics.width, horizontal_width = window->wl.width + 2 * decs.metrics.width;
|
||||
vertical_width *= scale; vertical_height *= scale;
|
||||
horizontal_width *= scale; horizontal_height *= scale;
|
||||
const size_t mapping_sz = 4 * (2 * vertical_width * vertical_height + horizontal_height * horizontal_width);
|
||||
const size_t vertical_width = decs.metrics.width, vertical_height = window->wl.height + decs.metrics.top;
|
||||
const size_t horizontal_height = decs.metrics.width, horizontal_width = window->wl.width + 2 * decs.metrics.width;
|
||||
|
||||
int fd = createAnonymousFile(mapping_sz);
|
||||
decs.mapping.size = 0;
|
||||
decs.mapping.size += init_buffer_pair(&decs.top.buffer, window->wl.width, decs.metrics.top, scale);
|
||||
decs.mapping.size += init_buffer_pair(&decs.left.buffer, vertical_width, vertical_height, scale);
|
||||
decs.mapping.size += init_buffer_pair(&decs.bottom.buffer, horizontal_width, horizontal_height, scale);
|
||||
decs.mapping.size += init_buffer_pair(&decs.right.buffer, vertical_width, vertical_height, scale);
|
||||
|
||||
int fd = createAnonymousFile(decs.mapping.size);
|
||||
if (fd < 0) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Creating a buffer file for %zu B failed: %s",
|
||||
mapping_sz, strerror(errno));
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Creating a buffer file for %zu B failed: %s",
|
||||
decs.mapping.size, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
uint8_t *data = mmap(NULL, mapping_sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (data == MAP_FAILED) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: mmap failed: %s", strerror(errno));
|
||||
decs.mapping.data = mmap(NULL, decs.mapping.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (decs.mapping.data == MAP_FAILED) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: mmap failed: %s", strerror(errno));
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
render_left_edge(data, vertical_width, vertical_height, is_focused);
|
||||
render_right_edge(data + 4 * vertical_width * vertical_height, vertical_width, vertical_height, is_focused);
|
||||
render_bottom_edge(data + 8 * vertical_width * vertical_height, horizontal_width, horizontal_height, is_focused);
|
||||
struct wl_shm_pool* pool = wl_shm_create_pool(_glfw.wl.shm, fd, mapping_sz);
|
||||
struct wl_shm_pool* pool = wl_shm_create_pool(_glfw.wl.shm, fd, decs.mapping.size);
|
||||
close(fd);
|
||||
eb.left = wl_shm_pool_create_buffer(
|
||||
pool, 0, vertical_width, vertical_height, vertical_width * 4, WL_SHM_FORMAT_ARGB8888);
|
||||
eb.right = wl_shm_pool_create_buffer(
|
||||
pool, 4 * vertical_width * vertical_height, vertical_width, vertical_height, vertical_width * 4, WL_SHM_FORMAT_ARGB8888);
|
||||
eb.bottom = wl_shm_pool_create_buffer(
|
||||
pool, 8 * vertical_width * vertical_height, horizontal_width, horizontal_height, horizontal_width * 4, WL_SHM_FORMAT_ARGB8888);
|
||||
size_t offset = 0;
|
||||
#define a(which) alloc_buffer_pair(&decs.which.buffer, pool, decs.mapping.data, &offset)
|
||||
a(top); a(left); a(bottom); a(right);
|
||||
#undef a
|
||||
wl_shm_pool_destroy(pool);
|
||||
render_title_bar(window, true);
|
||||
render_edge(&decs.left.buffer); render_edge(&decs.bottom.buffer); render_edge(&decs.right.buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
free_csd_surfaces(_GLFWwindow *window) {
|
||||
#define d(which) {\
|
||||
if (decs.subsurfaces.which) wl_subsurface_destroy(decs.subsurfaces.which); decs.subsurfaces.which = NULL; \
|
||||
if (decs.surfaces.which) wl_surface_destroy(decs.surfaces.which); decs.surfaces.which = NULL; \
|
||||
if (decs.which.subsurface) wl_subsurface_destroy(decs.which.subsurface); decs.which.subsurface = NULL; \
|
||||
if (decs.which.surface) wl_surface_destroy(decs.which.surface); decs.which.surface = NULL; \
|
||||
}
|
||||
d(left); d(top); d(right); d(bottom);
|
||||
#undef d
|
||||
}
|
||||
|
||||
#define create_decoration_surfaces(which, buffer, x, y) { \
|
||||
decs.surfaces.which = wl_compositor_create_surface(_glfw.wl.compositor); \
|
||||
wl_surface_set_buffer_scale(decs.surfaces.which, window->wl.scale < 1 ? 1 : window->wl.scale); \
|
||||
decs.subsurfaces.which = wl_subcompositor_get_subsurface(_glfw.wl.subcompositor, decs.surfaces.which, window->wl.surface); \
|
||||
wl_surface_attach(decs.surfaces.which, buffer, 0, 0); \
|
||||
wl_subsurface_set_position(decs.subsurfaces.which, x, y); \
|
||||
wl_surface_commit(decs.surfaces.which); \
|
||||
static void
|
||||
free_csd_buffers(_GLFWwindow *window) {
|
||||
#define d(which) { \
|
||||
if (decs.which.buffer.a) wl_buffer_destroy(decs.which.buffer.a); \
|
||||
if (decs.which.buffer.b) wl_buffer_destroy(decs.which.buffer.b); \
|
||||
memset(&decs.which.buffer, 0, sizeof(_GLFWWaylandBufferPair)); \
|
||||
}
|
||||
d(left); d(top); d(right); d(bottom);
|
||||
#undef d
|
||||
if (decs.mapping.data) munmap(decs.mapping.data, decs.mapping.size);
|
||||
decs.mapping.data = NULL; decs.mapping.size = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
position_csd_surface(_GLFWWaylandCSDEdge *s, int x, int y, int scale) {
|
||||
wl_surface_set_buffer_scale(s->surface, scale);
|
||||
s->x = x; s->y = y;
|
||||
wl_subsurface_set_position(s->subsurface, s->x, s->y);
|
||||
}
|
||||
|
||||
static void
|
||||
create_csd_surfaces(_GLFWwindow *window, _GLFWWaylandCSDEdge *s) {
|
||||
s->surface = wl_compositor_create_surface(_glfw.wl.compositor);
|
||||
s->subsurface = wl_subcompositor_get_subsurface(_glfw.wl.subcompositor, s->surface, window->wl.surface);
|
||||
}
|
||||
|
||||
bool
|
||||
ensure_csd_resources(_GLFWwindow *window) {
|
||||
const bool is_focused = window->id == _glfw.focusedWindowId;
|
||||
const bool state_changed = (
|
||||
const bool focus_changed = is_focused != decs.for_window_state.focused;
|
||||
const bool size_changed = (
|
||||
decs.for_window_state.width != window->wl.width ||
|
||||
decs.for_window_state.height != window->wl.height ||
|
||||
decs.for_window_state.scale != window->wl.scale ||
|
||||
decs.for_window_state.focused != is_focused
|
||||
!decs.mapping.data
|
||||
);
|
||||
if (state_changed) free_all_csd_resources(window);
|
||||
else if (decs.edges.left && decs.title_bar.front_buffer) return true;
|
||||
const bool needs_update = focus_changed || size_changed || !decs.left.surface;
|
||||
if (!needs_update) return true;
|
||||
if (size_changed) {
|
||||
free_csd_buffers(window);
|
||||
if (!create_shm_buffers(window)) return false;
|
||||
}
|
||||
|
||||
if (!create_shm_buffers_for_edges(window, is_focused)) return false;
|
||||
if (!create_shm_buffers_for_title_bar(window)) return false;
|
||||
|
||||
int x, y;
|
||||
int x, y, scale = window->wl.scale < 1 ? 1 : window->wl.scale;
|
||||
x = 0; y = -decs.metrics.top;
|
||||
create_decoration_surfaces(top, decs.title_bar.front_buffer, x, y);
|
||||
if (!decs.top.surface) create_csd_surfaces(window, &decs.top);
|
||||
position_csd_surface(&decs.top, x, y, scale);
|
||||
|
||||
x = -decs.metrics.width; y = -decs.metrics.top;
|
||||
create_decoration_surfaces(left, decs.edges.left, x, y);
|
||||
|
||||
x = window->wl.width; y = -decs.metrics.top;
|
||||
create_decoration_surfaces(right, decs.edges.right, x, y);
|
||||
if (!decs.left.surface) create_csd_surfaces(window, &decs.left);
|
||||
position_csd_surface(&decs.left, x, y, scale);
|
||||
|
||||
x = -decs.metrics.width; y = window->wl.height;
|
||||
create_decoration_surfaces(bottom, decs.edges.bottom, x, y);
|
||||
if (!decs.bottom.surface) create_csd_surfaces(window, &decs.bottom);
|
||||
position_csd_surface(&decs.bottom, x, y, scale);
|
||||
|
||||
x = window->wl.width; y = -decs.metrics.top;
|
||||
if (!decs.right.surface) create_csd_surfaces(window, &decs.right);
|
||||
position_csd_surface(&decs.right, x, y, scale);
|
||||
|
||||
#define c(which, xbuffer) \
|
||||
wl_surface_attach(decs.which.surface, xbuffer, 0, 0); \
|
||||
wl_surface_damage(decs.which.surface, 0, 0, decs.which.buffer.width, decs.which.buffer.height); \
|
||||
wl_surface_commit(decs.which.surface)
|
||||
|
||||
c(top, decs.top.buffer.front);
|
||||
c(left, is_focused ? decs.left.buffer.front : decs.left.buffer.back);
|
||||
c(bottom, is_focused ? decs.bottom.buffer.front : decs.bottom.buffer.back);
|
||||
c(right, is_focused ? decs.right.buffer.front : decs.right.buffer.back);
|
||||
#undef c
|
||||
|
||||
decs.for_window_state.width = window->wl.width;
|
||||
decs.for_window_state.height = window->wl.height;
|
||||
@ -184,8 +186,7 @@ ensure_csd_resources(_GLFWwindow *window) {
|
||||
void
|
||||
free_all_csd_resources(_GLFWwindow *window) {
|
||||
free_csd_surfaces(window);
|
||||
free_title_bar_resources(window);
|
||||
free_edge_resources(window);
|
||||
free_csd_buffers(window);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
2
glfw/wl_init.c
vendored
2
glfw/wl_init.c
vendored
@ -66,7 +66,7 @@ findWindowFromDecorationSurface(struct wl_surface* surface, _GLFWdecorationSideW
|
||||
_GLFWdecorationSideWayland focus;
|
||||
if (!which) which = &focus;
|
||||
_GLFWwindow* window = _glfw.windowListHead;
|
||||
#define q(edge, result) if (surface == window->wl.decorations.surfaces.edge) { *which = result; break; }
|
||||
#define q(edge, result) if (surface == window->wl.decorations.edge.surface) { *which = result; break; }
|
||||
while (window) {
|
||||
q(top, TOP_DECORATION);
|
||||
q(left, LEFT_DECORATION);
|
||||
|
||||
32
glfw/wl_platform.h
vendored
32
glfw/wl_platform.h
vendored
@ -97,6 +97,20 @@ typedef enum _GLFWdecorationSideWayland
|
||||
BOTTOM_DECORATION,
|
||||
} _GLFWdecorationSideWayland;
|
||||
|
||||
typedef struct _GLFWWaylandBufferPair {
|
||||
struct wl_buffer *a, *b, *front, *back;
|
||||
struct { uint8_t *a, *b, *front, *back; } data;
|
||||
bool back_buffer_is_safe, has_pending_update;
|
||||
size_t size_in_bytes, width, height, stride;
|
||||
} _GLFWWaylandBufferPair;
|
||||
|
||||
typedef struct _GLFWWaylandCSDEdge {
|
||||
struct wl_surface *surface;
|
||||
struct wl_subsurface *subsurface;
|
||||
_GLFWWaylandBufferPair buffer;
|
||||
int x, y;
|
||||
} _GLFWWaylandCSDEdge;
|
||||
|
||||
|
||||
// Wayland-specific per-window data
|
||||
//
|
||||
@ -143,24 +157,12 @@ typedef struct _GLFWwindowWayland
|
||||
struct {
|
||||
bool serverSide;
|
||||
_GLFWdecorationSideWayland focus;
|
||||
_GLFWWaylandCSDEdge top, left, right, bottom;
|
||||
|
||||
struct {
|
||||
struct wl_surface *top, *left, *right, *bottom;
|
||||
} surfaces;
|
||||
|
||||
struct {
|
||||
struct wl_subsurface *top, *left, *right, *bottom;
|
||||
} subsurfaces;
|
||||
|
||||
struct {
|
||||
struct wl_buffer *front_buffer, *back_buffer;
|
||||
uint8_t *data;
|
||||
size_t buffer_sz;
|
||||
} title_bar;
|
||||
|
||||
struct {
|
||||
struct wl_buffer *left, *right, *bottom;
|
||||
} edges;
|
||||
size_t size;
|
||||
} mapping;
|
||||
|
||||
struct {
|
||||
int width, height, scale;
|
||||
|
||||
4
glfw/wl_window.c
vendored
4
glfw/wl_window.c
vendored
@ -222,7 +222,7 @@ static void resizeFramebuffer(_GLFWwindow* window)
|
||||
setOpaqueRegion(window);
|
||||
_glfwInputFramebufferSize(window, scaledWidth, scaledHeight);
|
||||
|
||||
if (window->wl.decorations.surfaces.top) resize_csd(window);
|
||||
if (window->wl.decorations.mapping.data) resize_csd(window);
|
||||
|
||||
}
|
||||
|
||||
@ -453,7 +453,7 @@ static void xdgToplevelHandleConfigure(void* data,
|
||||
}
|
||||
window->wl.fullscreened = fullscreen;
|
||||
if (!fullscreen) {
|
||||
if (window->decorated && !window->wl.decorations.serverSide && window->wl.decorations.edges.left) {
|
||||
if (window->decorated && !window->wl.decorations.serverSide && window->wl.decorations.left.surface) {
|
||||
width -= window->wl.decorations.metrics.horizontal;
|
||||
height -= window->wl.decorations.metrics.vertical;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user