mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-04-14 08:22:25 -04:00
output-layers: change semantics of wlr_output_state.layers
Previously, we were requiring all layers to be included in wlr_output_state.layers and wlr_output_layer_state.buffer to be set to NULL to disable a layer. This commit changes these semantics: disabled layers are left out of wlr_output_state.layers, and wlr_output_layer_state.buffer is required to be non-NULL. This new API should make it easier for callers to populate the layers, at the cost of some additional complexity in backends, mostly addressed by introducing a new wlr_output_state_is_layer_enabled() helper.
This commit is contained in:
parent
f42920c414
commit
b931ac9ac0
8 changed files with 120 additions and 71 deletions
|
|
@ -804,11 +804,7 @@ static bool drm_connector_set_pending_layer_fbs(struct wlr_drm_connector *conn,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (layer_state->buffer != NULL) {
|
|
||||||
drm_fb_import(&layer->pending_fb, drm, layer_state->buffer, NULL);
|
drm_fb_import(&layer->pending_fb, drm, layer_state->buffer, NULL);
|
||||||
} else {
|
|
||||||
drm_fb_clear(&layer->pending_fb);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <wlr/interfaces/wlr_output.h>
|
||||||
#include <wlr/util/box.h>
|
#include <wlr/util/box.h>
|
||||||
#include <wlr/util/log.h>
|
#include <wlr/util/log.h>
|
||||||
|
|
||||||
|
|
@ -184,24 +185,18 @@ static bool set_layer_props(struct wlr_drm_backend *drm,
|
||||||
struct wl_array *fb_damage_clips_arr) {
|
struct wl_array *fb_damage_clips_arr) {
|
||||||
struct wlr_drm_layer *layer = get_drm_layer(drm, state->layer);
|
struct wlr_drm_layer *layer = get_drm_layer(drm, state->layer);
|
||||||
|
|
||||||
uint32_t width = 0, height = 0;
|
uint32_t width = state->buffer->width;
|
||||||
if (state->buffer != NULL) {
|
uint32_t height = state->buffer->height;
|
||||||
width = state->buffer->width;
|
|
||||||
height = state->buffer->height;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct wlr_drm_fb *fb = layer->pending_fb;
|
struct wlr_drm_fb *fb = layer->pending_fb;
|
||||||
int ret = 0;
|
if (fb == NULL) {
|
||||||
if (state->buffer == NULL) {
|
|
||||||
ret = liftoff_layer_set_property(layer->liftoff, "FB_ID", 0);
|
|
||||||
} else if (fb == NULL) {
|
|
||||||
liftoff_layer_set_fb_composited(layer->liftoff);
|
liftoff_layer_set_fb_composited(layer->liftoff);
|
||||||
} else {
|
} else {
|
||||||
ret = liftoff_layer_set_property(layer->liftoff, "FB_ID", fb->id);
|
int ret = liftoff_layer_set_property(layer->liftoff, "FB_ID", fb->id);
|
||||||
}
|
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t crtc_x = (uint64_t)state->dst_box.x;
|
uint64_t crtc_x = (uint64_t)state->dst_box.x;
|
||||||
uint64_t crtc_y = (uint64_t)state->dst_box.y;
|
uint64_t crtc_y = (uint64_t)state->dst_box.y;
|
||||||
|
|
@ -364,6 +359,18 @@ static bool add_connector(drmModeAtomicReq *req,
|
||||||
ok = ok && set_layer_props(drm, layer_state, i + 1,
|
ok = ok && set_layer_props(drm, layer_state, i + 1,
|
||||||
fb_damage_clips_arr);
|
fb_damage_clips_arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct wlr_output_layer *wlr_layer;
|
||||||
|
wl_list_for_each(wlr_layer, &conn->output.layers, link) {
|
||||||
|
if (wlr_output_state_is_layer_enabled(state->base, wlr_layer)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
struct wlr_drm_layer *layer = get_drm_layer(drm, wlr_layer);
|
||||||
|
if (layer == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
liftoff_layer_set_property(layer->liftoff, "FB_ID", 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (crtc->cursor) {
|
if (crtc->cursor) {
|
||||||
|
|
|
||||||
|
|
@ -498,7 +498,7 @@ static bool output_test(struct wlr_output *wlr_output,
|
||||||
bool supported = output->backend->subcompositor != NULL;
|
bool supported = output->backend->subcompositor != NULL;
|
||||||
for (ssize_t i = state->layers_len - 1; i >= 0; i--) {
|
for (ssize_t i = state->layers_len - 1; i >= 0; i--) {
|
||||||
struct wlr_output_layer_state *layer_state = &state->layers[i];
|
struct wlr_output_layer_state *layer_state = &state->layers[i];
|
||||||
if (layer_state->buffer != NULL) {
|
|
||||||
int x = layer_state->dst_box.x;
|
int x = layer_state->dst_box.x;
|
||||||
int y = layer_state->dst_box.y;
|
int y = layer_state->dst_box.y;
|
||||||
int width = layer_state->dst_box.width;
|
int width = layer_state->dst_box.width;
|
||||||
|
|
@ -520,7 +520,7 @@ static bool output_test(struct wlr_output *wlr_output,
|
||||||
}
|
}
|
||||||
supported = supported &&
|
supported = supported &&
|
||||||
test_buffer(output->backend, layer_state->buffer);
|
test_buffer(output->backend, layer_state->buffer);
|
||||||
}
|
|
||||||
layer_state->accepted = supported;
|
layer_state->accepted = supported;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -584,19 +584,23 @@ static struct wlr_wl_output_layer *get_or_create_output_layer(
|
||||||
|
|
||||||
static bool has_layers_order_changed(struct wlr_wl_output *output,
|
static bool has_layers_order_changed(struct wlr_wl_output *output,
|
||||||
struct wlr_output_layer_state *layers, size_t layers_len) {
|
struct wlr_output_layer_state *layers, size_t layers_len) {
|
||||||
// output_basic_check() ensures that layers_len equals the number of
|
// Iterate over all enabled layers, check whether the list of all existing
|
||||||
// registered output layers
|
// layers has the same ordering
|
||||||
size_t i = 0;
|
struct wl_list *cur = output->wlr_output.layers.next;
|
||||||
struct wlr_output_layer *layer;
|
for (size_t i = 0; i < layers_len; i++) {
|
||||||
wl_list_for_each(layer, &output->wlr_output.layers, link) {
|
bool found = false;
|
||||||
assert(i < layers_len);
|
while (cur != &output->wlr_output.layers) {
|
||||||
const struct wlr_output_layer_state *layer_state = &layers[i];
|
struct wlr_output_layer *layer = wl_container_of(cur, layer, link);
|
||||||
if (layer_state->layer != layer) {
|
if (layer == layers[i].layer) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cur = cur->next;
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
assert(i == layers_len);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -635,11 +639,6 @@ static bool output_layer_commit(struct wlr_wl_output *output,
|
||||||
wl_subsurface_set_position(layer->subsurface, state->dst_box.x, state->dst_box.y);
|
wl_subsurface_set_position(layer->subsurface, state->dst_box.x, state->dst_box.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->buffer == NULL) {
|
|
||||||
output_layer_unmap(layer);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct wlr_wl_buffer *buffer =
|
struct wlr_wl_buffer *buffer =
|
||||||
get_or_create_wl_buffer(output->backend, state->buffer);
|
get_or_create_wl_buffer(output->backend, state->buffer);
|
||||||
if (buffer == NULL) {
|
if (buffer == NULL) {
|
||||||
|
|
@ -677,22 +676,23 @@ static bool output_layer_commit(struct wlr_wl_output *output,
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool commit_layers(struct wlr_wl_output *output,
|
static bool commit_layers(struct wlr_wl_output *output,
|
||||||
struct wlr_output_layer_state *layers, size_t layers_len) {
|
const struct wlr_output_state *state) {
|
||||||
if (output->backend->subcompositor == NULL) {
|
if (!(state->committed & WLR_OUTPUT_STATE_LAYERS) ||
|
||||||
|
output->backend->subcompositor == NULL) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool reordered = has_layers_order_changed(output, layers, layers_len);
|
bool reordered = has_layers_order_changed(output, state->layers, state->layers_len);
|
||||||
|
|
||||||
struct wlr_wl_output_layer *prev_layer = NULL;
|
struct wlr_wl_output_layer *prev_layer = NULL;
|
||||||
for (size_t i = 0; i < layers_len; i++) {
|
for (size_t i = 0; i < state->layers_len; i++) {
|
||||||
struct wlr_wl_output_layer *layer =
|
struct wlr_wl_output_layer *layer =
|
||||||
get_or_create_output_layer(output, layers[i].layer);
|
get_or_create_output_layer(output, state->layers[i].layer);
|
||||||
if (layer == NULL) {
|
if (layer == NULL) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!layers[i].accepted) {
|
if (!state->layers[i].accepted) {
|
||||||
output_layer_unmap(layer);
|
output_layer_unmap(layer);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -702,13 +702,25 @@ static bool commit_layers(struct wlr_wl_output *output,
|
||||||
prev_layer->surface);
|
prev_layer->surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!output_layer_commit(output, layer, &layers[i])) {
|
if (!output_layer_commit(output, layer, &state->layers[i])) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
prev_layer = layer;
|
prev_layer = layer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct wlr_output_layer *wlr_layer;
|
||||||
|
wl_list_for_each(wlr_layer, &output->wlr_output.layers, link) {
|
||||||
|
if (wlr_output_state_is_layer_enabled(state, wlr_layer)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
struct wlr_wl_output_layer *layer =
|
||||||
|
get_or_create_output_layer(output, wlr_layer);
|
||||||
|
if (layer != NULL) {
|
||||||
|
output_layer_unmap(layer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -851,8 +863,7 @@ static bool output_commit(struct wlr_output *wlr_output, const struct wlr_output
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((state->committed & WLR_OUTPUT_STATE_LAYERS) &&
|
if (!commit_layers(output, state)) {
|
||||||
!commit_layers(output, state->layers, state->layers_len)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,10 @@ static void output_handle_frame(struct wl_listener *listener, void *data) {
|
||||||
struct wl_array layers_arr = {0};
|
struct wl_array layers_arr = {0};
|
||||||
struct output_surface *output_surface;
|
struct output_surface *output_surface;
|
||||||
wl_list_for_each(output_surface, &output->surfaces, link) {
|
wl_list_for_each(output_surface, &output->surfaces, link) {
|
||||||
|
if (output_surface->buffer == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
struct wlr_output_layer_state *layer_state =
|
struct wlr_output_layer_state *layer_state =
|
||||||
wl_array_add(&layers_arr, sizeof(*layer_state));
|
wl_array_add(&layers_arr, sizeof(*layer_state));
|
||||||
*layer_state = (struct wlr_output_layer_state){
|
*layer_state = (struct wlr_output_layer_state){
|
||||||
|
|
@ -103,6 +107,10 @@ static void output_handle_frame(struct wl_listener *listener, void *data) {
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
struct wlr_output_layer_state *layers = layers_arr.data;
|
struct wlr_output_layer_state *layers = layers_arr.data;
|
||||||
wl_list_for_each(output_surface, &output->surfaces, link) {
|
wl_list_for_each(output_surface, &output->surfaces, link) {
|
||||||
|
if (output_surface->buffer == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
struct wlr_surface *wlr_surface = output_surface->wlr_surface;
|
struct wlr_surface *wlr_surface = output_surface->wlr_surface;
|
||||||
|
|
||||||
output_surface->layer_accepted = layers[i].accepted;
|
output_surface->layer_accepted = layers[i].accepted;
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@
|
||||||
#include <wlr/backend.h>
|
#include <wlr/backend.h>
|
||||||
#include <wlr/types/wlr_output.h>
|
#include <wlr/types/wlr_output.h>
|
||||||
|
|
||||||
|
struct wlr_output_layer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Output state fields that don't require backend support. Backends can ignore
|
* Output state fields that don't require backend support. Backends can ignore
|
||||||
* them without breaking the API contract.
|
* them without breaking the API contract.
|
||||||
|
|
@ -136,4 +138,12 @@ void wlr_output_send_present(struct wlr_output *output,
|
||||||
void wlr_output_send_request_state(struct wlr_output *output,
|
void wlr_output_send_request_state(struct wlr_output *output,
|
||||||
const struct wlr_output_state *state);
|
const struct wlr_output_state *state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether a layer is enabled in an output state.
|
||||||
|
*
|
||||||
|
* The output state must have the layers field populated.
|
||||||
|
*/
|
||||||
|
bool wlr_output_state_is_layer_enabled(const struct wlr_output_state *state,
|
||||||
|
struct wlr_output_layer *layer);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,8 @@
|
||||||
* output contents to be composited onto a single buffer, e.g. during screen
|
* output contents to be composited onto a single buffer, e.g. during screen
|
||||||
* capture.
|
* capture.
|
||||||
*
|
*
|
||||||
* Callers must always include the state for all layers on output test/commit.
|
* To disable an output layer, callers can leave it out of the array supplied
|
||||||
|
* on output test/commit.
|
||||||
*/
|
*/
|
||||||
struct wlr_output_layer {
|
struct wlr_output_layer {
|
||||||
struct wl_list link; // wlr_output.layers
|
struct wl_list link; // wlr_output.layers
|
||||||
|
|
@ -62,7 +63,7 @@ struct wlr_output_layer {
|
||||||
struct wlr_output_layer_state {
|
struct wlr_output_layer_state {
|
||||||
struct wlr_output_layer *layer;
|
struct wlr_output_layer *layer;
|
||||||
|
|
||||||
// Buffer to display, or NULL to disable the layer
|
// Buffer to display, must not be NULL
|
||||||
struct wlr_buffer *buffer;
|
struct wlr_buffer *buffer;
|
||||||
// Source box, leave empty to use the whole buffer
|
// Source box, leave empty to use the whole buffer
|
||||||
struct wlr_fbox src_box;
|
struct wlr_fbox src_box;
|
||||||
|
|
|
||||||
|
|
@ -664,13 +664,14 @@ static bool output_basic_test(struct wlr_output *output,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->committed & WLR_OUTPUT_STATE_LAYERS) {
|
if (state->committed & WLR_OUTPUT_STATE_LAYERS) {
|
||||||
if (state->layers_len != (size_t)wl_list_length(&output->layers)) {
|
for (size_t i = 0; i < state->layers_len; i++) {
|
||||||
wlr_log(WLR_DEBUG, "All output layers must be specified in wlr_output_state.layers");
|
assert(state->layers[i].layer != NULL);
|
||||||
|
|
||||||
|
if (state->layers[i].buffer == NULL) {
|
||||||
|
wlr_log(WLR_DEBUG, "All output layer states must have a buffer");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < state->layers_len; i++) {
|
|
||||||
assert(state->layers[i].layer != NULL);
|
|
||||||
state->layers[i].accepted = false;
|
state->layers[i].accepted = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <wlr/interfaces/wlr_output.h>
|
||||||
#include <wlr/types/wlr_output_layer.h>
|
#include <wlr/types/wlr_output_layer.h>
|
||||||
|
#include <wlr/util/log.h>
|
||||||
|
|
||||||
struct wlr_output_layer *wlr_output_layer_create(struct wlr_output *output) {
|
struct wlr_output_layer *wlr_output_layer_create(struct wlr_output *output) {
|
||||||
struct wlr_output_layer *layer = calloc(1, sizeof(*layer));
|
struct wlr_output_layer *layer = calloc(1, sizeof(*layer));
|
||||||
|
|
@ -28,3 +30,16 @@ void wlr_output_layer_destroy(struct wlr_output_layer *layer) {
|
||||||
wl_list_remove(&layer->link);
|
wl_list_remove(&layer->link);
|
||||||
free(layer);
|
free(layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool wlr_output_state_is_layer_enabled(const struct wlr_output_state *state,
|
||||||
|
struct wlr_output_layer *layer) {
|
||||||
|
assert(state->committed & WLR_OUTPUT_STATE_LAYERS);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < state->layers_len; i++) {
|
||||||
|
if (state->layers[i].layer == layer) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue