From 2f615468b68d49c8ec03ceffa751f8425d4c9b6b Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 18 Jun 2021 12:15:08 +0200 Subject: [PATCH] backend: add output state allow-lists Right now, when a new output state field is added, all backends by default won't reject it. This means we need to add new checks to each and every backend when we introduce a new state field. Instead, introduce a bitmask of supported output state fields in each backend, and error out if the user has submitted an unknown field. Some fields don't need any backend involvment to work. These are listed in WLR_OUTPUT_STATE_BACKEND_OPTIONAL as a convenience. --- backend/drm/drm.c | 14 ++++++++++++++ backend/headless/output.c | 12 ++++++++++-- backend/noop/output.c | 11 +++++++++-- backend/wayland/output.c | 12 ++++++++++-- backend/x11/output.c | 12 ++++++++++-- include/wlr/interfaces/wlr_output.h | 10 ++++++++++ 6 files changed, 63 insertions(+), 8 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index caf27d71..b56cf6d5 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -31,6 +31,13 @@ #include "types/wlr_buffer.h" #include "util/signal.h" +static const uint32_t SUPPORTED_OUTPUT_STATE = + WLR_OUTPUT_STATE_BACKEND_OPTIONAL | + WLR_OUTPUT_STATE_BUFFER | + WLR_OUTPUT_STATE_MODE | + WLR_OUTPUT_STATE_ENABLED | + WLR_OUTPUT_STATE_GAMMA_LUT; + bool check_drm_features(struct wlr_drm_backend *drm) { if (drmGetCap(drm->fd, DRM_CAP_CURSOR_WIDTH, &drm->cursor_width)) { drm->cursor_width = 64; @@ -435,6 +442,13 @@ static bool drm_connector_test(struct wlr_output *output) { return false; } + uint32_t unsupported = output->pending.committed & ~SUPPORTED_OUTPUT_STATE; + if (unsupported != 0) { + wlr_log(WLR_DEBUG, "Unsupported output state fields: 0x%"PRIx32, + unsupported); + return false; + } + if ((output->pending.committed & WLR_OUTPUT_STATE_ENABLED) && output->pending.enabled) { if (output->current_mode == NULL && diff --git a/backend/headless/output.c b/backend/headless/output.c index 2e4dee2d..9ec6ce50 100644 --- a/backend/headless/output.c +++ b/backend/headless/output.c @@ -7,6 +7,11 @@ #include "backend/headless.h" #include "util/signal.h" +static const uint32_t SUPPORTED_OUTPUT_STATE = + WLR_OUTPUT_STATE_BACKEND_OPTIONAL | + WLR_OUTPUT_STATE_BUFFER | + WLR_OUTPUT_STATE_MODE; + static struct wlr_headless_output *headless_output_from_output( struct wlr_output *wlr_output) { assert(wlr_output_is_headless(wlr_output)); @@ -29,8 +34,11 @@ static bool output_set_custom_mode(struct wlr_output *wlr_output, int32_t width, } static bool output_test(struct wlr_output *wlr_output) { - if (wlr_output->pending.committed & WLR_OUTPUT_STATE_ENABLED) { - wlr_log(WLR_DEBUG, "Cannot disable a headless output"); + uint32_t unsupported = + wlr_output->pending.committed & ~SUPPORTED_OUTPUT_STATE; + if (unsupported != 0) { + wlr_log(WLR_DEBUG, "Unsupported output state fields: 0x%"PRIx32, + unsupported); return false; } diff --git a/backend/noop/output.c b/backend/noop/output.c index 1302d3d6..1e927feb 100644 --- a/backend/noop/output.c +++ b/backend/noop/output.c @@ -6,6 +6,10 @@ #include "backend/noop.h" #include "util/signal.h" +static const uint32_t SUPPORTED_OUTPUT_STATE = + WLR_OUTPUT_STATE_BACKEND_OPTIONAL | + WLR_OUTPUT_STATE_MODE; + static struct wlr_noop_output *noop_output_from_output( struct wlr_output *wlr_output) { assert(wlr_output_is_noop(wlr_output)); @@ -22,8 +26,11 @@ static void output_rollback_render(struct wlr_output *wlr_output) { } static bool output_commit(struct wlr_output *wlr_output) { - if (wlr_output->pending.committed & WLR_OUTPUT_STATE_ENABLED) { - wlr_log(WLR_DEBUG, "Cannot disable a noop output"); + uint32_t unsupported = + wlr_output->pending.committed & ~SUPPORTED_OUTPUT_STATE; + if (unsupported != 0) { + wlr_log(WLR_DEBUG, "Unsupported output state fields: 0x%"PRIx32, + unsupported); return false; } diff --git a/backend/wayland/output.c b/backend/wayland/output.c index c8730cd0..542185ce 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -27,6 +27,11 @@ #include "xdg-decoration-unstable-v1-client-protocol.h" #include "xdg-shell-client-protocol.h" +static const uint32_t SUPPORTED_OUTPUT_STATE = + WLR_OUTPUT_STATE_BACKEND_OPTIONAL | + WLR_OUTPUT_STATE_BUFFER | + WLR_OUTPUT_STATE_MODE; + static struct wlr_wl_output *get_wl_output_from_output( struct wlr_output *wlr_output) { assert(wlr_output_is_wl(wlr_output)); @@ -244,8 +249,11 @@ static bool output_test(struct wlr_output *wlr_output) { struct wlr_wl_output *output = get_wl_output_from_output(wlr_output); - if (wlr_output->pending.committed & WLR_OUTPUT_STATE_ENABLED) { - wlr_log(WLR_DEBUG, "Cannot disable a Wayland output"); + uint32_t unsupported = + wlr_output->pending.committed & ~SUPPORTED_OUTPUT_STATE; + if (unsupported != 0) { + wlr_log(WLR_DEBUG, "Unsupported output state fields: 0x%"PRIx32, + unsupported); return false; } diff --git a/backend/x11/output.c b/backend/x11/output.c index 440e26de..15d1d9a0 100644 --- a/backend/x11/output.c +++ b/backend/x11/output.c @@ -25,6 +25,11 @@ #include "util/signal.h" #include "util/time.h" +static const uint32_t SUPPORTED_OUTPUT_STATE = + WLR_OUTPUT_STATE_BACKEND_OPTIONAL | + WLR_OUTPUT_STATE_BUFFER | + WLR_OUTPUT_STATE_MODE; + static void parse_xcb_setup(struct wlr_output *output, xcb_connection_t *xcb) { const xcb_setup_t *xcb_setup = xcb_get_setup(xcb); @@ -94,8 +99,11 @@ static void output_destroy(struct wlr_output *wlr_output) { } static bool output_test(struct wlr_output *wlr_output) { - if (wlr_output->pending.committed & WLR_OUTPUT_STATE_ENABLED) { - wlr_log(WLR_DEBUG, "Cannot disable an X11 output"); + uint32_t unsupported = + wlr_output->pending.committed & ~SUPPORTED_OUTPUT_STATE; + if (unsupported != 0) { + wlr_log(WLR_DEBUG, "Unsupported output state fields: 0x%"PRIx32, + unsupported); return false; } diff --git a/include/wlr/interfaces/wlr_output.h b/include/wlr/interfaces/wlr_output.h index a727da61..83a8c321 100644 --- a/include/wlr/interfaces/wlr_output.h +++ b/include/wlr/interfaces/wlr_output.h @@ -14,6 +14,16 @@ #include #include +/** + * Output state fields that don't require backend support. Backends can ignore + * them without breaking the API contract. + */ +#define WLR_OUTPUT_STATE_BACKEND_OPTIONAL \ + (WLR_OUTPUT_STATE_DAMAGE | \ + WLR_OUTPUT_STATE_SCALE | \ + WLR_OUTPUT_STATE_TRANSFORM | \ + WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) + /** * A backend implementation of wlr_output. *