backend: embed backend_operations table in backend_base

The idea is to allow backend plugins to override backend functions by
modifying this table. Right now, when they do this they are actually
changing a global variable and their change will persist after backend
resets (!). Store the table inside backend_base solves this problem.

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
Yuxuan Shui 2024-05-24 05:26:28 +01:00
parent 9c4f62cd24
commit bd26302f07
No known key found for this signature in database
GPG Key ID: D3A4405BE6CC17F4
13 changed files with 124 additions and 130 deletions

View File

@ -36,15 +36,7 @@ struct managed_win;
struct ev_loop;
struct backend_operations;
typedef struct backend_base {
struct backend_operations *ops;
struct x_connection *c;
struct ev_loop *loop;
/// Whether the backend can accept new render request at the moment
bool busy;
// ...
} backend_t;
typedef struct backend_base backend_t;
// This mimics OpenGL's ARB_robustness extension, which enables detection of GPU context
// resets.
@ -475,6 +467,16 @@ struct backend_operations {
enum device_status (*device_status)(backend_t *backend_data);
};
struct backend_base {
struct backend_operations ops;
struct x_connection *c;
struct ev_loop *loop;
/// Whether the backend can accept new render request at the moment
bool busy;
// ...
};
/// Register a new backend, `major` and `minor` should be the version of the picom backend
/// interface. You should just pass `PICOM_BACKEND_MAJOR` and `PICOM_BACKEND_MINOR` here.
/// `name` is the name of the backend, `init` is the function to initialize the backend,

View File

@ -118,22 +118,22 @@ bool backend_execute(struct backend_base *backend, image_handle target, unsigned
continue;
}
succeeded =
backend->ops->blit(backend, cmd->origin, target, &cmd->blit);
backend->ops.blit(backend, cmd->origin, target, &cmd->blit);
break;
case BACKEND_COMMAND_COPY_AREA:
if (!pixman_region32_not_empty(cmd->copy_area.region)) {
continue;
}
succeeded = backend->ops->copy_area(backend, cmd->origin, target,
cmd->copy_area.source_image,
cmd->copy_area.region);
succeeded = backend->ops.copy_area(backend, cmd->origin, target,
cmd->copy_area.source_image,
cmd->copy_area.region);
break;
case BACKEND_COMMAND_BLUR:
if (!pixman_region32_not_empty(cmd->blur.target_mask)) {
continue;
}
succeeded =
backend->ops->blur(backend, cmd->origin, target, &cmd->blur);
backend->ops.blur(backend, cmd->origin, target, &cmd->blur);
break;
case BACKEND_COMMAND_INVALID:
default: assert(false);

View File

@ -6,7 +6,6 @@
#include <xcb/xcb_image.h>
#include <xcb/xcb_renderutil.h>
#include "backend/backend.h"
#include "backend/backend_common.h"
#include "common.h"
#include "config.h"
@ -413,7 +412,7 @@ void init_backend_base(struct backend_base *base, session_t *ps) {
base->c = &ps->c;
base->loop = ps->loop;
base->busy = false;
base->ops = NULL;
base->ops = (struct backend_operations){};
}
uint32_t backend_no_quirks(struct backend_base *base attr_unused) {

View File

@ -7,15 +7,14 @@
#include <stdbool.h>
#include "backend.h"
#include "config.h"
#include "region.h"
struct session;
struct win;
struct conv;
struct backend_base;
struct backend_operations;
struct x_connection;
struct dual_kawase_params {
/// Number of downsample passes

View File

@ -83,8 +83,8 @@ enum driver detect_driver(xcb_connection_t *c, backend_t *backend_data, xcb_wind
free(randr_version);
// If the backend supports driver detection, use that as well
if (backend_data && backend_data->ops->detect_driver) {
ret |= backend_data->ops->detect_driver(backend_data);
if (backend_data && backend_data->ops.detect_driver) {
ret |= backend_data->ops.detect_driver(backend_data);
}
return ret;
}

View File

@ -29,12 +29,12 @@ struct dummy_data {
struct dummy_image back_buffer;
};
struct backend_operations dummy_ops;
const struct backend_operations dummy_ops;
struct backend_base *dummy_init(session_t *ps attr_unused, xcb_window_t target attr_unused) {
auto ret = ccalloc(1, struct dummy_data);
init_backend_base(&ret->base, ps);
ret->base.ops = &dummy_ops;
ret->base.ops = dummy_ops;
list_init_head(&ret->non_pixmap_images);
return &ret->base;
}
@ -216,7 +216,7 @@ static void dummy_version(struct backend_base * /*base*/, uint64_t *major, uint6
*minor = PICOM_BACKEND_DUMMY_MINOR;
}
struct backend_operations dummy_ops = {
const struct backend_operations dummy_ops = {
.apply_alpha = dummy_apply_alpha,
.back_buffer = dummy_back_buffer,
.blit = dummy_blit,

View File

@ -4,8 +4,6 @@
*/
#include <X11/Xlib-xcb.h>
#include <assert.h>
#include <limits.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
@ -105,7 +103,7 @@ static bool egl_set_swap_interval(int interval, EGLDisplay dpy) {
return eglSwapInterval(dpy, interval);
}
struct backend_operations egl_ops;
const struct backend_operations egl_ops;
/**
* Initialize OpenGL.
*/
@ -154,7 +152,7 @@ static backend_t *egl_init(session_t *ps, xcb_window_t target) {
eglext_init(gd->display);
init_backend_base(&gd->gl.base, ps);
gd->gl.base.ops = &egl_ops;
gd->gl.base.ops = egl_ops;
if (!eglext.has_EGL_KHR_image_pixmap) {
log_error("EGL_KHR_image_pixmap not available.");
goto end;
@ -355,7 +353,7 @@ static void egl_version(struct backend_base * /*base*/, uint64_t *major, uint64_
*minor = PICOM_BACKEND_EGL_MINOR;
}
struct backend_operations egl_ops = {
const struct backend_operations egl_ops = {
.apply_alpha = gl_apply_alpha,
.back_buffer = gl_back_buffer,
.blit = gl_blit,

View File

@ -11,7 +11,6 @@
*/
#include <X11/Xlib-xcb.h>
#include <assert.h>
#include <limits.h>
#include <pixman.h>
#include <stdbool.h>
@ -31,7 +30,6 @@
#include "config.h"
#include "log.h"
#include "picom.h"
#include "region.h"
#include "utils.h"
#include "win.h"
#include "x.h"
@ -225,7 +223,7 @@ static bool glx_set_swap_interval(int interval, Display *dpy, GLXDrawable drawab
return vsync_enabled;
}
struct backend_operations glx_ops;
const struct backend_operations glx_ops;
/**
* Initialize OpenGL.
*/
@ -234,7 +232,7 @@ static backend_t *glx_init(session_t *ps, xcb_window_t target) {
glxext_init(ps->c.dpy, ps->c.screen);
auto gd = ccalloc(1, struct _glx_data);
init_backend_base(&gd->gl.base, ps);
gd->gl.base.ops = &glx_ops;
gd->gl.base.ops = glx_ops;
gd->target_win = target;
@ -529,7 +527,7 @@ static void glx_version(struct backend_base * /*base*/, uint64_t *major, uint64_
*minor = PICOM_BACKEND_GLX_MINOR;
}
struct backend_operations glx_ops = {
const struct backend_operations glx_ops = {
.apply_alpha = gl_apply_alpha,
.back_buffer = gl_back_buffer,
.bind_pixmap = glx_bind_pixmap,

View File

@ -865,7 +865,7 @@ static void xrender_get_blur_size(void *blur_context, int *width, int *height) {
*width = ctx->resize_width;
*height = ctx->resize_height;
}
struct backend_operations xrender_ops;
const struct backend_operations xrender_ops;
static backend_t *xrender_init(session_t *ps, xcb_window_t target) {
if (ps->o.dithered_present) {
log_warn("\"dithered-present\" is not supported by the xrender backend, "
@ -878,7 +878,7 @@ static backend_t *xrender_init(session_t *ps, xcb_window_t target) {
auto xd = ccalloc(1, struct xrender_data);
init_backend_base(&xd->base, ps);
xd->base.ops = &xrender_ops;
xd->base.ops = xrender_ops;
for (int i = 0; i <= MAX_ALPHA; ++i) {
double o = (double)i / (double)MAX_ALPHA;
@ -1032,7 +1032,7 @@ static void xrender_version(struct backend_base * /*base*/, uint64_t *major, uin
*minor = PICOM_BACKEND_XRENDER_MINOR;
}
struct backend_operations xrender_ops = {
const struct backend_operations xrender_ops = {
.apply_alpha = xrender_apply_alpha,
.back_buffer = xrender_back_buffer,
.bind_pixmap = xrender_bind_pixmap,

View File

@ -51,11 +51,11 @@ void print_diagnostics(session_t *ps, const char *config_file, bool compositor_r
printf(" Cannot initialize backend %s\n", backend_name(i));
continue;
}
if (backend_data->ops->diagnostics) {
if (backend_data->ops.diagnostics) {
printf("\n### Backend: %s\n\n", backend_name(i));
backend_data->ops->diagnostics(backend_data);
backend_data->ops.diagnostics(backend_data);
}
backend_data->ops->deinit(backend_data);
backend_data->ops.deinit(backend_data);
}
}

View File

@ -152,7 +152,7 @@ enum vblank_callback_action check_render_finish(struct vblank_event *e attr_unus
struct timespec render_time;
bool completed =
ps->backend_data->ops->last_render_time(ps->backend_data, &render_time);
ps->backend_data->ops.last_render_time(ps->backend_data, &render_time);
if (!completed) {
// Render hasn't completed yet, we can't start another render.
// Check again at the next vblank.
@ -575,14 +575,14 @@ static void destroy_backend(session_t *ps) {
HASH_ITER2(ps->shaders, shader) {
if (shader->backend_shader != NULL) {
ps->backend_data->ops->destroy_shader(ps->backend_data,
shader->backend_shader);
ps->backend_data->ops.destroy_shader(ps->backend_data,
shader->backend_shader);
shader->backend_shader = NULL;
}
}
if (ps->backend_data && ps->root_image) {
ps->backend_data->ops->release_image(ps->backend_data, ps->root_image);
ps->backend_data->ops.release_image(ps->backend_data, ps->root_image);
ps->root_image = NULL;
}
@ -593,11 +593,11 @@ static void destroy_backend(session_t *ps) {
}
// deinit backend
if (ps->backend_blur_context) {
ps->backend_data->ops->destroy_blur_context(
ps->backend_data->ops.destroy_blur_context(
ps->backend_data, ps->backend_blur_context);
ps->backend_blur_context = NULL;
}
ps->backend_data->ops->deinit(ps->backend_data);
ps->backend_data->ops.deinit(ps->backend_data);
ps->backend_data = NULL;
}
}
@ -635,7 +635,7 @@ static bool initialize_blur(session_t *ps) {
enum backend_image_format format = ps->o.dithered_present
? BACKEND_IMAGE_FORMAT_PIXMAP_HIGH
: BACKEND_IMAGE_FORMAT_PIXMAP;
ps->backend_blur_context = ps->backend_data->ops->create_blur_context(
ps->backend_blur_context = ps->backend_data->ops.create_blur_context(
ps->backend_data, ps->o.blur_method, format, args);
return ps->backend_blur_context != NULL;
}
@ -674,14 +674,14 @@ static bool initialize_backend(session_t *ps) {
}
// Create shaders
if (!ps->backend_data->ops->create_shader && ps->shaders) {
if (!ps->backend_data->ops.create_shader && ps->shaders) {
log_warn("Shaders are not supported by selected backend %s, "
"they will be ignored",
backend_name(ps->o.backend));
} else {
HASH_ITER2(ps->shaders, shader) {
assert(shader->backend_shader == NULL);
shader->backend_shader = ps->backend_data->ops->create_shader(
shader->backend_shader = ps->backend_data->ops.create_shader(
ps->backend_data, shader->source);
if (shader->backend_shader == NULL) {
log_warn("Failed to create shader for shader "
@ -689,9 +689,9 @@ static bool initialize_backend(session_t *ps) {
shader->key);
} else {
shader->attributes = 0;
if (ps->backend_data->ops->get_shader_attributes) {
if (ps->backend_data->ops.get_shader_attributes) {
shader->attributes =
ps->backend_data->ops->get_shader_attributes(
ps->backend_data->ops.get_shader_attributes(
ps->backend_data,
shader->backend_shader);
}
@ -719,7 +719,7 @@ static bool initialize_backend(session_t *ps) {
// The old backends binds pixmap lazily, nothing to do here
return true;
err:
ps->backend_data->ops->deinit(ps->backend_data);
ps->backend_data->ops.deinit(ps->backend_data);
ps->backend_data = NULL;
quit(ps);
return false;
@ -741,7 +741,7 @@ static void configure_root(session_t *ps) {
// On root window changes
if (!ps->o.use_legacy_backends) {
assert(ps->backend_data);
has_root_change = ps->backend_data->ops->root_change != NULL;
has_root_change = ps->backend_data->ops.root_change != NULL;
} else {
// Old backend can handle root change
has_root_change = true;
@ -788,7 +788,7 @@ static void configure_root(session_t *ps) {
#endif
if (has_root_change) {
if (ps->backend_data != NULL) {
ps->backend_data->ops->root_change(ps->backend_data, ps);
ps->backend_data->ops.root_change(ps->backend_data, ps);
}
// Old backend's root_change is not a specific function
} else {
@ -1082,7 +1082,7 @@ void root_damaged(session_t *ps) {
if (ps->backend_data) {
if (ps->root_image) {
ps->backend_data->ops->release_image(ps->backend_data, ps->root_image);
ps->backend_data->ops.release_image(ps->backend_data, ps->root_image);
ps->root_image = NULL;
}
auto pixmap = x_get_root_back_pixmap(&ps->c, ps->atoms);
@ -1116,7 +1116,7 @@ void root_damaged(session_t *ps) {
: x_get_visual_for_depth(ps->c.screen_info, r->depth);
free(r);
ps->root_image = ps->backend_data->ops->bind_pixmap(
ps->root_image = ps->backend_data->ops.bind_pixmap(
ps->backend_data, pixmap, x_get_visual_info(&ps->c, visual));
ps->root_image_generation += 1;
if (!ps->root_image) {
@ -1421,7 +1421,7 @@ static bool redirect_start(session_t *ps) {
if (!ps->o.use_legacy_backends) {
assert(ps->backend_data);
ps->damage_ring.count =
ps->backend_data->ops->max_buffer_age(ps->backend_data);
ps->backend_data->ops.max_buffer_age(ps->backend_data);
ps->layout_manager = layout_manager_new((unsigned)ps->damage_ring.count);
} else {
ps->damage_ring.count = maximum_buffer_age(ps);
@ -1435,7 +1435,7 @@ static bool redirect_start(session_t *ps) {
ps->frame_pacing = ps->o.frame_pacing && ps->o.vsync;
if ((ps->o.use_legacy_backends || ps->o.benchmark ||
!ps->backend_data->ops->last_render_time) &&
!ps->backend_data->ops.last_render_time) &&
ps->frame_pacing) {
// Disable frame pacing if we are using a legacy backend or if we are in
// benchmark mode, or if the backend doesn't report render time

View File

@ -69,19 +69,19 @@ static void renderer_reallocate_culled_masks(struct renderer *r, size_t capacity
void renderer_free(struct backend_base *backend, struct renderer *r) {
if (r->white_image) {
backend->ops->release_image(backend, r->white_image);
backend->ops.release_image(backend, r->white_image);
}
if (r->black_image) {
backend->ops->release_image(backend, r->black_image);
backend->ops.release_image(backend, r->black_image);
}
if (r->back_image) {
backend->ops->release_image(backend, r->back_image);
backend->ops.release_image(backend, r->back_image);
}
if (r->monitor_repaint_pixel) {
backend->ops->release_image(backend, r->monitor_repaint_pixel);
backend->ops.release_image(backend, r->monitor_repaint_pixel);
}
if (r->shadow_blur_context) {
backend->ops->destroy_blur_context(backend, r->shadow_blur_context);
backend->ops.destroy_blur_context(backend, r->shadow_blur_context);
}
if (r->shadow_kernel) {
free_conv(r->shadow_kernel);
@ -97,7 +97,7 @@ void renderer_free(struct backend_base *backend, struct renderer *r) {
}
if (r->monitor_repaint_copy) {
for (int i = 0; i < r->max_buffer_age; i++) {
backend->ops->release_image(backend, r->monitor_repaint_copy[i]);
backend->ops.release_image(backend, r->monitor_repaint_copy[i]);
}
free(r->monitor_repaint_copy);
}
@ -109,21 +109,21 @@ static bool
renderer_init(struct renderer *renderer, struct backend_base *backend,
double shadow_radius, struct color shadow_color, bool dithered_present) {
auto has_high_precision =
backend->ops->is_format_supported(backend, BACKEND_IMAGE_FORMAT_PIXMAP_HIGH);
backend->ops.is_format_supported(backend, BACKEND_IMAGE_FORMAT_PIXMAP_HIGH);
renderer->format = has_high_precision && dithered_present
? BACKEND_IMAGE_FORMAT_PIXMAP_HIGH
: BACKEND_IMAGE_FORMAT_PIXMAP;
renderer->back_image = NULL;
renderer->white_image =
backend->ops->new_image(backend, renderer->format, (ivec2){1, 1});
if (!renderer->white_image || !backend->ops->clear(backend, renderer->white_image,
(struct color){1, 1, 1, 1})) {
backend->ops.new_image(backend, renderer->format, (ivec2){1, 1});
if (!renderer->white_image || !backend->ops.clear(backend, renderer->white_image,
(struct color){1, 1, 1, 1})) {
return false;
}
renderer->black_image =
backend->ops->new_image(backend, renderer->format, (ivec2){1, 1});
if (!renderer->black_image || !backend->ops->clear(backend, renderer->black_image,
(struct color){0, 0, 0, 1})) {
backend->ops.new_image(backend, renderer->format, (ivec2){1, 1});
if (!renderer->black_image || !backend->ops.clear(backend, renderer->black_image,
(struct color){0, 0, 0, 1})) {
return false;
}
renderer->canvas_size = (ivec2){0, 0};
@ -132,7 +132,7 @@ renderer_init(struct renderer *renderer, struct backend_base *backend,
.size = (int)shadow_radius,
.deviation = gaussian_kernel_std_for_size(shadow_radius, 0.5 / 256.0),
};
renderer->shadow_blur_context = backend->ops->create_blur_context(
renderer->shadow_blur_context = backend->ops.create_blur_context(
backend, BLUR_METHOD_GAUSSIAN, BACKEND_IMAGE_FORMAT_MASK, &args);
if (!renderer->shadow_blur_context) {
log_error("Failed to create shadow blur context");
@ -154,7 +154,7 @@ renderer_init(struct renderer *renderer, struct backend_base *backend,
}
sum_kernel_preprocess(renderer->shadow_kernel);
}
renderer->max_buffer_age = backend->ops->max_buffer_age(backend) + 1;
renderer->max_buffer_age = backend->ops.max_buffer_age(backend) + 1;
return true;
}
@ -176,23 +176,23 @@ renderer_set_root_size(struct renderer *r, struct backend_base *backend, ivec2 r
return true;
}
if (r->back_image) {
backend->ops->release_image(backend, r->back_image);
backend->ops.release_image(backend, r->back_image);
}
if (r->back_buffer_copy) {
for (int i = 0; i < r->max_buffer_age; i++) {
backend->ops->release_image(backend, r->back_buffer_copy[i]);
backend->ops.release_image(backend, r->back_buffer_copy[i]);
}
free(r->back_buffer_copy);
r->back_buffer_copy = NULL;
}
if (r->monitor_repaint_copy) {
for (int i = 0; i < r->max_buffer_age; i++) {
backend->ops->release_image(backend, r->monitor_repaint_copy[i]);
backend->ops.release_image(backend, r->monitor_repaint_copy[i]);
}
free(r->monitor_repaint_copy);
r->monitor_repaint_copy = NULL;
}
r->back_image = backend->ops->new_image(backend, r->format, root_size);
r->back_image = backend->ops.new_image(backend, r->format, root_size);
if (r->back_image != NULL) {
r->canvas_size = root_size;
return true;
@ -205,16 +205,16 @@ static bool
renderer_bind_mask(struct renderer *r, struct backend_base *backend, struct managed_win *w) {
ivec2 size = {.width = w->widthb, .height = w->heightb};
bool succeeded = false;
auto image = backend->ops->new_image(backend, BACKEND_IMAGE_FORMAT_MASK, size);
if (!image || !backend->ops->clear(backend, image, (struct color){0, 0, 0, 0})) {
auto image = backend->ops.new_image(backend, BACKEND_IMAGE_FORMAT_MASK, size);
if (!image || !backend->ops.clear(backend, image, (struct color){0, 0, 0, 0})) {
log_error("Failed to create mask image");
goto err;
}
auto bound_region_local = win_get_bounding_shape_global_by_val(w);
pixman_region32_translate(&bound_region_local, -w->g.x, -w->g.y);
succeeded = backend->ops->copy_area(backend, (ivec2){0, 0}, (image_handle)image,
r->white_image, &bound_region_local);
succeeded = backend->ops.copy_area(backend, (ivec2){0, 0}, (image_handle)image,
r->white_image, &bound_region_local);
pixman_region32_fini(&bound_region_local);
if (!succeeded) {
log_error("Failed to fill the mask");
@ -225,7 +225,7 @@ renderer_bind_mask(struct renderer *r, struct backend_base *backend, struct mana
err:
if (image != NULL) {
backend->ops->release_image(backend, image);
backend->ops.release_image(backend, image);
}
return succeeded;
}
@ -243,11 +243,11 @@ image_handle renderer_shadow_from_mask(struct renderer *r, struct backend_base *
// Apply the properties on the mask image and blit the result into a larger
// image, each side larger by `2 * radius` so there is space for blurring.
normalized_mask_image = backend->ops->new_image(
normalized_mask_image = backend->ops.new_image(
backend, BACKEND_IMAGE_FORMAT_MASK,
(ivec2){mask_size.width + 2 * radius, mask_size.height + 2 * radius});
if (!normalized_mask_image || !backend->ops->clear(backend, normalized_mask_image,
(struct color){0, 0, 0, 0})) {
if (!normalized_mask_image || !backend->ops.clear(backend, normalized_mask_image,
(struct color){0, 0, 0, 0})) {
log_error("Failed to create mask image");
goto out;
}
@ -276,8 +276,8 @@ image_handle renderer_shadow_from_mask(struct renderer *r, struct backend_base *
pixman_region32_init_rect(&target_mask, radius, radius,
(unsigned)mask_size.width,
(unsigned)mask_size.height);
succeeded = backend->ops->blit(backend, (ivec2){radius, radius},
normalized_mask_image, &args);
succeeded = backend->ops.blit(backend, (ivec2){radius, radius},
normalized_mask_image, &args);
pixman_region32_fini(&target_mask);
if (!succeeded) {
log_error("Failed to blit for shadow generation");
@ -297,7 +297,7 @@ image_handle renderer_shadow_from_mask(struct renderer *r, struct backend_base *
(unsigned)(mask_size.width + 2 * radius),
(unsigned)(mask_size.height + 2 * radius));
succeeded =
backend->ops->blur(backend, (ivec2){0, 0}, normalized_mask_image, &args);
backend->ops.blur(backend, (ivec2){0, 0}, normalized_mask_image, &args);
pixman_region32_fini(&target_mask);
if (!succeeded) {
log_error("Failed to blur for shadow generation");
@ -306,19 +306,19 @@ image_handle renderer_shadow_from_mask(struct renderer *r, struct backend_base *
}
// Finally, we blit with this mask to colorize the shadow
succeeded = false;
shadow_image = backend->ops->new_image(
shadow_image = backend->ops.new_image(
backend, BACKEND_IMAGE_FORMAT_PIXMAP,
(ivec2){mask_size.width + 2 * radius, mask_size.height + 2 * radius});
if (!shadow_image ||
!backend->ops->clear(backend, shadow_image, (struct color){0, 0, 0, 0})) {
!backend->ops.clear(backend, shadow_image, (struct color){0, 0, 0, 0})) {
log_error("Failed to allocate shadow image");
goto out;
}
shadow_color_pixel =
backend->ops->new_image(backend, BACKEND_IMAGE_FORMAT_PIXMAP, (ivec2){1, 1});
backend->ops.new_image(backend, BACKEND_IMAGE_FORMAT_PIXMAP, (ivec2){1, 1});
if (!shadow_color_pixel ||
!backend->ops->clear(backend, shadow_color_pixel, r->shadow_color)) {
!backend->ops.clear(backend, shadow_color_pixel, r->shadow_color)) {
log_error("Failed to create shadow color image");
goto out;
}
@ -348,19 +348,19 @@ image_handle renderer_shadow_from_mask(struct renderer *r, struct backend_base *
};
pixman_region32_init_rect(&target_mask, 0, 0, (unsigned)shadow_size.width,
(unsigned)shadow_size.height);
succeeded = backend->ops->blit(backend, (ivec2){0, 0}, shadow_image, &args);
succeeded = backend->ops.blit(backend, (ivec2){0, 0}, shadow_image, &args);
pixman_region32_fini(&target_mask);
out:
if (normalized_mask_image) {
backend->ops->release_image(backend, normalized_mask_image);
backend->ops.release_image(backend, normalized_mask_image);
}
if (shadow_color_pixel) {
backend->ops->release_image(backend, shadow_color_pixel);
backend->ops.release_image(backend, shadow_color_pixel);
}
if (!succeeded && shadow_image) {
log_error("Failed to draw shadow image");
backend->ops->release_image(backend, shadow_image);
backend->ops.release_image(backend, shadow_image);
shadow_image = NULL;
}
return shadow_image;
@ -368,7 +368,7 @@ out:
static bool renderer_bind_shadow(struct renderer *r, struct backend_base *backend,
struct managed_win *w) {
if (backend->ops->quirks(backend) & BACKEND_QUIRK_SLOW_BLUR) {
if (backend->ops.quirks(backend) & BACKEND_QUIRK_SLOW_BLUR) {
xcb_pixmap_t shadow = XCB_NONE;
xcb_render_picture_t pict = XCB_NONE;
@ -379,7 +379,7 @@ static bool renderer_bind_shadow(struct renderer *r, struct backend_base *backen
auto visual =
x_get_visual_for_standard(backend->c, XCB_PICT_STANDARD_ARGB_32);
w->shadow_image = backend->ops->bind_pixmap(
w->shadow_image = backend->ops.bind_pixmap(
backend, shadow, x_get_visual_info(backend->c, visual));
} else {
if (!w->mask_image && !renderer_bind_mask(r, backend, w)) {
@ -467,16 +467,16 @@ void renderer_ensure_images_ready(struct renderer *r, struct backend_base *backe
bool monitor_repaint) {
if (monitor_repaint) {
if (!r->monitor_repaint_pixel) {
r->monitor_repaint_pixel = backend->ops->new_image(
r->monitor_repaint_pixel = backend->ops.new_image(
backend, BACKEND_IMAGE_FORMAT_PIXMAP, (ivec2){1, 1});
BUG_ON(!r->monitor_repaint_pixel);
backend->ops->clear(backend, r->monitor_repaint_pixel,
(struct color){.alpha = 0.5, .red = 0.5});
backend->ops.clear(backend, r->monitor_repaint_pixel,
(struct color){.alpha = 0.5, .red = 0.5});
}
if (!r->monitor_repaint_copy) {
r->monitor_repaint_copy = ccalloc(r->max_buffer_age, image_handle);
for (int i = 0; i < r->max_buffer_age; i++) {
r->monitor_repaint_copy[i] = backend->ops->new_image(
r->monitor_repaint_copy[i] = backend->ops.new_image(
backend, BACKEND_IMAGE_FORMAT_PIXMAP,
(ivec2){.width = r->canvas_size.width,
.height = r->canvas_size.height});
@ -493,10 +493,10 @@ void renderer_ensure_images_ready(struct renderer *r, struct backend_base *backe
if (global_debug_options.consistent_buffer_age && !r->back_buffer_copy) {
r->back_buffer_copy = ccalloc(r->max_buffer_age, image_handle);
for (int i = 0; i < r->max_buffer_age; i++) {
r->back_buffer_copy[i] = backend->ops->new_image(
backend, BACKEND_IMAGE_FORMAT_PIXMAP,
(ivec2){.width = r->canvas_size.width,
.height = r->canvas_size.height});
r->back_buffer_copy[i] =
backend->ops.new_image(backend, BACKEND_IMAGE_FORMAT_PIXMAP,
(ivec2){.width = r->canvas_size.width,
.height = r->canvas_size.height});
BUG_ON(!r->back_buffer_copy[i]);
}
}
@ -554,19 +554,19 @@ bool renderer_render(struct renderer *r, struct backend_base *backend,
pixman_region32_init(&damage_region);
pixman_region32_copy(&damage_region, &screen_region);
ivec2 blur_size = {};
if (backend->ops->get_blur_size && blur_context) {
backend->ops->get_blur_size(blur_context, &blur_size.width, &blur_size.height);
if (backend->ops.get_blur_size && blur_context) {
backend->ops.get_blur_size(blur_context, &blur_size.width, &blur_size.height);
}
auto buffer_age =
(use_damage || monitor_repaint) ? backend->ops->buffer_age(backend) : 0;
(use_damage || monitor_repaint) ? backend->ops.buffer_age(backend) : 0;
if (buffer_age > 0 && global_debug_options.consistent_buffer_age) {
int past_frame =
(r->frame_index + r->max_buffer_age - buffer_age) % r->max_buffer_age;
region_t region;
pixman_region32_init_rect(&region, 0, 0, (unsigned)r->canvas_size.width,
(unsigned)r->canvas_size.height);
backend->ops->copy_area(backend, (ivec2){}, backend->ops->back_buffer(backend),
r->back_buffer_copy[past_frame], &region);
backend->ops.copy_area(backend, (ivec2){}, backend->ops.back_buffer(backend),
r->back_buffer_copy[past_frame], &region);
pixman_region32_fini(&region);
}
if (buffer_age > 0 && (unsigned)buffer_age <= layout_manager_max_buffer_age(lm)) {
@ -595,17 +595,17 @@ bool renderer_render(struct renderer *r, struct backend_base *backend,
xcb_sync_reset_fence(backend->c->c, xsync_fence));
}
if (backend->ops->prepare) {
backend->ops->prepare(backend, &layout->commands[0].target_mask);
if (backend->ops.prepare) {
backend->ops.prepare(backend, &layout->commands[0].target_mask);
}
if (monitor_repaint && buffer_age <= r->max_buffer_age) {
// Restore the area of back buffer that was tainted by monitor repaint
int past_frame =
(r->frame_index + r->max_buffer_age - buffer_age) % r->max_buffer_age;
backend->ops->copy_area(backend, (ivec2){}, backend->ops->back_buffer(backend),
r->monitor_repaint_copy[past_frame],
&r->monitor_repaint_region[past_frame]);
backend->ops.copy_area(backend, (ivec2){}, backend->ops.back_buffer(backend),
r->monitor_repaint_copy[past_frame],
&r->monitor_repaint_region[past_frame]);
}
if (!backend_execute(backend, r->back_image, layout->number_of_commands,
@ -616,9 +616,9 @@ bool renderer_render(struct renderer *r, struct backend_base *backend,
if (monitor_repaint) {
// Keep a copy of un-tainted back image
backend->ops->copy_area(backend, (ivec2){},
r->monitor_repaint_copy[r->frame_index],
r->back_image, &damage_region);
backend->ops.copy_area(backend, (ivec2){},
r->monitor_repaint_copy[r->frame_index],
r->back_image, &damage_region);
pixman_region32_copy(&r->monitor_repaint_region[r->frame_index], &damage_region);
struct backend_blit_args blit = {
@ -631,24 +631,22 @@ bool renderer_render(struct renderer *r, struct backend_base *backend,
.scale = SCALE_IDENTITY,
};
log_trace("Blit for monitor repaint");
backend->ops->blit(backend, (ivec2){}, r->back_image, &blit);
backend->ops.blit(backend, (ivec2){}, r->back_image, &blit);
}
backend->ops->copy_area_quantize(backend, (ivec2){},
backend->ops->back_buffer(backend),
r->back_image, &damage_region);
backend->ops.copy_area_quantize(backend, (ivec2){}, backend->ops.back_buffer(backend),
r->back_image, &damage_region);
if (global_debug_options.consistent_buffer_age) {
region_t region;
pixman_region32_init_rect(&region, 0, 0, (unsigned)r->canvas_size.width,
(unsigned)r->canvas_size.height);
backend->ops->copy_area(backend, (ivec2){},
r->back_buffer_copy[r->frame_index],
backend->ops->back_buffer(backend), &region);
backend->ops.copy_area(backend, (ivec2){}, r->back_buffer_copy[r->frame_index],
backend->ops.back_buffer(backend), &region);
pixman_region32_fini(&region);
}
if (backend->ops->present && !backend->ops->present(backend)) {
if (backend->ops.present && !backend->ops.present(backend)) {
log_warn("Failed to present the frame");
}

View File

@ -331,7 +331,7 @@ static inline void win_release_pixmap(backend_t *base, struct managed_win *w) {
assert(w->win_image);
if (w->win_image) {
xcb_pixmap_t pixmap = XCB_NONE;
pixmap = base->ops->release_image(base, w->win_image);
pixmap = base->ops.release_image(base, w->win_image);
w->win_image = NULL;
// Bypassing win_set_flags, because `w` might have been destroyed
w->flags |= WIN_FLAGS_PIXMAP_NONE;
@ -345,7 +345,7 @@ static inline void win_release_shadow(backend_t *base, struct managed_win *w) {
if (w->shadow_image) {
assert(w->shadow);
xcb_pixmap_t pixmap = XCB_NONE;
pixmap = base->ops->release_image(base, w->shadow_image);
pixmap = base->ops.release_image(base, w->shadow_image);
w->shadow_image = NULL;
if (pixmap != XCB_NONE) {
xcb_free_pixmap(base->c->c, pixmap);
@ -356,7 +356,7 @@ static inline void win_release_shadow(backend_t *base, struct managed_win *w) {
static inline void win_release_mask(backend_t *base, struct managed_win *w) {
if (w->mask_image) {
xcb_pixmap_t pixmap = XCB_NONE;
pixmap = base->ops->release_image(base, w->mask_image);
pixmap = base->ops.release_image(base, w->mask_image);
w->mask_image = NULL;
if (pixmap != XCB_NONE) {
xcb_free_pixmap(base->c->c, pixmap);
@ -376,7 +376,7 @@ static inline bool win_bind_pixmap(struct backend_base *b, struct managed_win *w
return false;
}
log_debug("New named pixmap for %#010x (%s) : %#010x", w->base.id, w->name, pixmap);
w->win_image = b->ops->bind_pixmap(b, pixmap, x_get_visual_info(b->c, w->a.visual));
w->win_image = b->ops.bind_pixmap(b, pixmap, x_get_visual_info(b->c, w->a.visual));
if (!w->win_image) {
log_error("Failed to bind pixmap");
xcb_free_pixmap(b->c->c, pixmap);