mirror of
				https://gitlab.freedesktop.org/wlroots/wlroots.git
				synced 2025-11-03 09:01:40 -05:00 
			
		
		
		
	backend/drm: add support for output layers
This commit is contained in:
		
							parent
							
								
									2398621b8b
								
							
						
					
					
						commit
						4d6fbb2289
					
				
					 3 changed files with 211 additions and 7 deletions
				
			
		| 
						 | 
					@ -42,7 +42,8 @@ static const uint32_t COMMIT_OUTPUT_STATE =
 | 
				
			||||||
	WLR_OUTPUT_STATE_MODE |
 | 
						WLR_OUTPUT_STATE_MODE |
 | 
				
			||||||
	WLR_OUTPUT_STATE_ENABLED |
 | 
						WLR_OUTPUT_STATE_ENABLED |
 | 
				
			||||||
	WLR_OUTPUT_STATE_GAMMA_LUT |
 | 
						WLR_OUTPUT_STATE_GAMMA_LUT |
 | 
				
			||||||
	WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED;
 | 
						WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED |
 | 
				
			||||||
 | 
						WLR_OUTPUT_STATE_LAYERS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const uint32_t SUPPORTED_OUTPUT_STATE =
 | 
					static const uint32_t SUPPORTED_OUTPUT_STATE =
 | 
				
			||||||
	WLR_OUTPUT_STATE_BACKEND_OPTIONAL | COMMIT_OUTPUT_STATE;
 | 
						WLR_OUTPUT_STATE_BACKEND_OPTIONAL | COMMIT_OUTPUT_STATE;
 | 
				
			||||||
| 
						 | 
					@ -276,6 +277,8 @@ bool init_drm_resources(struct wlr_drm_backend *drm) {
 | 
				
			||||||
		if (!get_drm_crtc_props(drm->fd, crtc->id, &crtc->props)) {
 | 
							if (!get_drm_crtc_props(drm->fd, crtc->id, &crtc->props)) {
 | 
				
			||||||
			goto error_crtcs;
 | 
								goto error_crtcs;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							wl_list_init(&crtc->layers);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!init_planes(drm)) {
 | 
						if (!init_planes(drm)) {
 | 
				
			||||||
| 
						 | 
					@ -336,6 +339,64 @@ static struct wlr_drm_connector *get_drm_connector_from_output(
 | 
				
			||||||
	return (struct wlr_drm_connector *)wlr_output;
 | 
						return (struct wlr_drm_connector *)wlr_output;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void layer_handle_addon_destroy(struct wlr_addon *addon) {
 | 
				
			||||||
 | 
						struct wlr_drm_layer *layer = wl_container_of(addon, layer, addon);
 | 
				
			||||||
 | 
						wlr_addon_finish(&layer->addon);
 | 
				
			||||||
 | 
						wl_list_remove(&layer->link);
 | 
				
			||||||
 | 
					#if HAVE_LIBLIFTOFF
 | 
				
			||||||
 | 
						liftoff_layer_destroy(layer->liftoff);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						drm_fb_clear(&layer->pending_fb);
 | 
				
			||||||
 | 
						drm_fb_clear(&layer->queued_fb);
 | 
				
			||||||
 | 
						drm_fb_clear(&layer->current_fb);
 | 
				
			||||||
 | 
						free(layer);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const struct wlr_addon_interface layer_impl = {
 | 
				
			||||||
 | 
						.name = "wlr_drm_layer",
 | 
				
			||||||
 | 
						.destroy = layer_handle_addon_destroy,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_drm_layer *get_drm_layer(struct wlr_drm_backend *drm,
 | 
				
			||||||
 | 
							struct wlr_output_layer *wlr_layer) {
 | 
				
			||||||
 | 
						struct wlr_addon *addon =
 | 
				
			||||||
 | 
							wlr_addon_find(&wlr_layer->addons, drm, &layer_impl);
 | 
				
			||||||
 | 
						assert(addon != NULL);
 | 
				
			||||||
 | 
						struct wlr_drm_layer *layer = wl_container_of(addon, layer, addon);
 | 
				
			||||||
 | 
						return layer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct wlr_drm_layer *get_or_create_layer(struct wlr_drm_backend *drm,
 | 
				
			||||||
 | 
							struct wlr_drm_crtc *crtc, struct wlr_output_layer *wlr_layer) {
 | 
				
			||||||
 | 
						struct wlr_drm_layer *layer;
 | 
				
			||||||
 | 
						struct wlr_addon *addon =
 | 
				
			||||||
 | 
							wlr_addon_find(&wlr_layer->addons, drm, &layer_impl);
 | 
				
			||||||
 | 
						if (addon != NULL) {
 | 
				
			||||||
 | 
							layer = wl_container_of(addon, layer, addon);
 | 
				
			||||||
 | 
							return layer;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						layer = calloc(1, sizeof(*layer));
 | 
				
			||||||
 | 
						if (layer == NULL) {
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if HAVE_LIBLIFTOFF
 | 
				
			||||||
 | 
						layer->liftoff = liftoff_layer_create(crtc->liftoff);
 | 
				
			||||||
 | 
						if (layer->liftoff == NULL) {
 | 
				
			||||||
 | 
							free(layer);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						abort(); // unreachable
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wlr_addon_init(&layer->addon, &wlr_layer->addons, drm, &layer_impl);
 | 
				
			||||||
 | 
						wl_list_insert(&crtc->layers, &layer->link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return layer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool drm_crtc_commit(struct wlr_drm_connector *conn,
 | 
					static bool drm_crtc_commit(struct wlr_drm_connector *conn,
 | 
				
			||||||
		const struct wlr_drm_connector_state *state,
 | 
							const struct wlr_drm_connector_state *state,
 | 
				
			||||||
		uint32_t flags, bool test_only) {
 | 
							uint32_t flags, bool test_only) {
 | 
				
			||||||
| 
						 | 
					@ -353,6 +414,11 @@ static bool drm_crtc_commit(struct wlr_drm_connector *conn,
 | 
				
			||||||
		if (crtc->cursor != NULL) {
 | 
							if (crtc->cursor != NULL) {
 | 
				
			||||||
			drm_fb_move(&crtc->cursor->queued_fb, &conn->cursor_pending_fb);
 | 
								drm_fb_move(&crtc->cursor->queued_fb, &conn->cursor_pending_fb);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							struct wlr_drm_layer *layer;
 | 
				
			||||||
 | 
							wl_list_for_each(layer, &crtc->layers, link) {
 | 
				
			||||||
 | 
								drm_fb_move(&layer->queued_fb, &layer->pending_fb);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		// The set_cursor() hook is a bit special: it's not really synchronized
 | 
							// The set_cursor() hook is a bit special: it's not really synchronized
 | 
				
			||||||
		// to commit() or test(). Once set_cursor() returns true, the new
 | 
							// to commit() or test(). Once set_cursor() returns true, the new
 | 
				
			||||||
| 
						 | 
					@ -360,6 +426,11 @@ static bool drm_crtc_commit(struct wlr_drm_connector *conn,
 | 
				
			||||||
		// risk ending up in a state where we don't have a cursor FB but
 | 
							// risk ending up in a state where we don't have a cursor FB but
 | 
				
			||||||
		// wlr_drm_connector.cursor_enabled is true.
 | 
							// wlr_drm_connector.cursor_enabled is true.
 | 
				
			||||||
		// TODO: fix our output interface to avoid this issue.
 | 
							// TODO: fix our output interface to avoid this issue.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							struct wlr_drm_layer *layer;
 | 
				
			||||||
 | 
							wl_list_for_each(layer, &crtc->layers, link) {
 | 
				
			||||||
 | 
								drm_fb_clear(&layer->pending_fb);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return ok;
 | 
						return ok;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -457,6 +528,42 @@ static bool drm_connector_state_update_primary_fb(struct wlr_drm_connector *conn
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool drm_connector_set_pending_layer_fbs(struct wlr_drm_connector *conn,
 | 
				
			||||||
 | 
							const struct wlr_output_state *state) {
 | 
				
			||||||
 | 
						struct wlr_drm_backend *drm = conn->backend;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_drm_crtc *crtc = conn->crtc;
 | 
				
			||||||
 | 
						if (!crtc || drm->parent) {
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!crtc->liftoff) {
 | 
				
			||||||
 | 
							return true; // libliftoff is disabled
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert(state->committed & WLR_OUTPUT_STATE_LAYERS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (size_t i = 0; i < state->layers_len; i++) {
 | 
				
			||||||
 | 
							struct wlr_output_layer_state *layer_state = &state->layers[i];
 | 
				
			||||||
 | 
							struct wlr_drm_layer *layer =
 | 
				
			||||||
 | 
								get_or_create_layer(drm, crtc, layer_state->layer);
 | 
				
			||||||
 | 
							if (!layer) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (layer_state->buffer != NULL) {
 | 
				
			||||||
 | 
								layer->pending_width = layer_state->buffer->width;
 | 
				
			||||||
 | 
								layer->pending_height = layer_state->buffer->height;
 | 
				
			||||||
 | 
								drm_fb_import(&layer->pending_fb, drm, layer_state->buffer, NULL);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								layer->pending_width = layer->pending_height = 0;
 | 
				
			||||||
 | 
								drm_fb_clear(&layer->pending_fb);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool drm_connector_alloc_crtc(struct wlr_drm_connector *conn);
 | 
					static bool drm_connector_alloc_crtc(struct wlr_drm_connector *conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool drm_connector_test(struct wlr_output *output,
 | 
					static bool drm_connector_test(struct wlr_output *output,
 | 
				
			||||||
| 
						 | 
					@ -533,6 +640,11 @@ static bool drm_connector_test(struct wlr_output *output,
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (state->committed & WLR_OUTPUT_STATE_LAYERS) {
 | 
				
			||||||
 | 
							if (!drm_connector_set_pending_layer_fbs(conn, pending.base)) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ok = drm_crtc_commit(conn, &pending, 0, true);
 | 
						ok = drm_crtc_commit(conn, &pending, 0, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -618,6 +730,11 @@ bool drm_connector_commit_state(struct wlr_drm_connector *conn,
 | 
				
			||||||
	if (pending.modeset && pending.active) {
 | 
						if (pending.modeset && pending.active) {
 | 
				
			||||||
		flags |= DRM_MODE_PAGE_FLIP_EVENT;
 | 
							flags |= DRM_MODE_PAGE_FLIP_EVENT;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (pending.base->committed & WLR_OUTPUT_STATE_LAYERS) {
 | 
				
			||||||
 | 
							if (!drm_connector_set_pending_layer_fbs(conn, pending.base)) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (pending.modeset) {
 | 
						if (pending.modeset) {
 | 
				
			||||||
		if (pending.active) {
 | 
							if (pending.active) {
 | 
				
			||||||
| 
						 | 
					@ -1564,6 +1681,11 @@ static void handle_page_flip(int fd, unsigned seq,
 | 
				
			||||||
			&conn->crtc->cursor->queued_fb);
 | 
								&conn->crtc->cursor->queued_fb);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_drm_layer *layer;
 | 
				
			||||||
 | 
						wl_list_for_each(layer, &conn->crtc->layers, link) {
 | 
				
			||||||
 | 
							drm_fb_move(&layer->current_fb, &layer->queued_fb);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint32_t present_flags = WLR_OUTPUT_PRESENT_VSYNC |
 | 
						uint32_t present_flags = WLR_OUTPUT_PRESENT_VSYNC |
 | 
				
			||||||
		WLR_OUTPUT_PRESENT_HW_CLOCK | WLR_OUTPUT_PRESENT_HW_COMPLETION;
 | 
							WLR_OUTPUT_PRESENT_HW_CLOCK | WLR_OUTPUT_PRESENT_HW_COMPLETION;
 | 
				
			||||||
	/* Don't report ZERO_COPY in multi-gpu situations, because we had to copy
 | 
						/* Don't report ZERO_COPY in multi-gpu situations, because we had to copy
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -142,10 +142,9 @@ static void rollback_blob(struct wlr_drm_backend *drm,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool set_plane_props(struct wlr_drm_plane *plane,
 | 
					static bool set_plane_props(struct wlr_drm_plane *plane,
 | 
				
			||||||
		struct liftoff_layer *layer, int32_t x, int32_t y, uint64_t zpos) {
 | 
							struct liftoff_layer *layer, struct wlr_drm_fb *fb, int32_t x, int32_t y, uint64_t zpos) {
 | 
				
			||||||
	struct wlr_drm_fb *fb = plane_get_next_fb(plane);
 | 
					 | 
				
			||||||
	if (fb == NULL) {
 | 
						if (fb == NULL) {
 | 
				
			||||||
		wlr_log(WLR_ERROR, "Failed to acquire FB");
 | 
							wlr_log(WLR_ERROR, "Failed to acquire FB for plane %"PRIu32, plane->id);
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -169,6 +168,52 @@ static bool disable_plane(struct wlr_drm_plane *plane) {
 | 
				
			||||||
	return liftoff_layer_set_property(plane->liftoff_layer, "FB_ID", 0) == 0;
 | 
						return liftoff_layer_set_property(plane->liftoff_layer, "FB_ID", 0) == 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint64_t to_fp16(double v) {
 | 
				
			||||||
 | 
						return (uint64_t)round(v * (1 << 16));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool set_layer_props(struct wlr_drm_backend *drm,
 | 
				
			||||||
 | 
							const struct wlr_output_layer_state *state, uint64_t zpos) {
 | 
				
			||||||
 | 
						struct wlr_drm_layer *layer = get_drm_layer(drm, state->layer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_drm_fb *fb = layer->pending_fb;
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
						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);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							ret = liftoff_layer_set_property(layer->liftoff, "FB_ID", fb->id);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (ret != 0) {
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint32_t width = layer->pending_width;
 | 
				
			||||||
 | 
						uint32_t height = layer->pending_height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint64_t crtc_x = (uint64_t)state->x;
 | 
				
			||||||
 | 
						uint64_t crtc_y = (uint64_t)state->y;
 | 
				
			||||||
 | 
						uint64_t crtc_w = (uint64_t)width;
 | 
				
			||||||
 | 
						uint64_t crtc_h = (uint64_t)height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint64_t src_x = to_fp16(0);
 | 
				
			||||||
 | 
						uint64_t src_y = to_fp16(0);
 | 
				
			||||||
 | 
						uint64_t src_w = to_fp16(width);
 | 
				
			||||||
 | 
						uint64_t src_h = to_fp16(height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
							liftoff_layer_set_property(layer->liftoff, "zpos", zpos) == 0 &&
 | 
				
			||||||
 | 
							liftoff_layer_set_property(layer->liftoff, "CRTC_X", crtc_x) == 0 &&
 | 
				
			||||||
 | 
							liftoff_layer_set_property(layer->liftoff, "CRTC_Y", crtc_y) == 0 &&
 | 
				
			||||||
 | 
							liftoff_layer_set_property(layer->liftoff, "CRTC_W", crtc_w) == 0 &&
 | 
				
			||||||
 | 
							liftoff_layer_set_property(layer->liftoff, "CRTC_H", crtc_h) == 0 &&
 | 
				
			||||||
 | 
							liftoff_layer_set_property(layer->liftoff, "SRC_X", src_x) == 0 &&
 | 
				
			||||||
 | 
							liftoff_layer_set_property(layer->liftoff, "SRC_Y", src_y) == 0 &&
 | 
				
			||||||
 | 
							liftoff_layer_set_property(layer->liftoff, "SRC_W", src_w) == 0 &&
 | 
				
			||||||
 | 
							liftoff_layer_set_property(layer->liftoff, "SRC_H", src_h) == 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool crtc_commit(struct wlr_drm_connector *conn,
 | 
					static bool crtc_commit(struct wlr_drm_connector *conn,
 | 
				
			||||||
		const struct wlr_drm_connector_state *state, uint32_t flags,
 | 
							const struct wlr_drm_connector_state *state, uint32_t flags,
 | 
				
			||||||
		bool test_only) {
 | 
							bool test_only) {
 | 
				
			||||||
| 
						 | 
					@ -272,16 +317,25 @@ static bool crtc_commit(struct wlr_drm_connector *conn,
 | 
				
			||||||
			ok = ok && add_prop(req, crtc->id, crtc->props.vrr_enabled, vrr_enabled);
 | 
								ok = ok && add_prop(req, crtc->id, crtc->props.vrr_enabled, vrr_enabled);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ok = ok &&
 | 
							ok = ok &&
 | 
				
			||||||
			set_plane_props(crtc->primary, crtc->primary->liftoff_layer, 0, 0, 0) &&
 | 
								set_plane_props(crtc->primary, crtc->primary->liftoff_layer, state->primary_fb, 0, 0, 0) &&
 | 
				
			||||||
			set_plane_props(crtc->primary, crtc->liftoff_composition_layer, 0, 0, 0);
 | 
								set_plane_props(crtc->primary, crtc->liftoff_composition_layer, state->primary_fb, 0, 0, 0);
 | 
				
			||||||
		liftoff_layer_set_property(crtc->primary->liftoff_layer,
 | 
							liftoff_layer_set_property(crtc->primary->liftoff_layer,
 | 
				
			||||||
			"FB_DAMAGE_CLIPS", fb_damage_clips);
 | 
								"FB_DAMAGE_CLIPS", fb_damage_clips);
 | 
				
			||||||
		liftoff_layer_set_property(crtc->liftoff_composition_layer,
 | 
							liftoff_layer_set_property(crtc->liftoff_composition_layer,
 | 
				
			||||||
			"FB_DAMAGE_CLIPS", fb_damage_clips);
 | 
								"FB_DAMAGE_CLIPS", fb_damage_clips);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (state->base->committed & WLR_OUTPUT_STATE_LAYERS) {
 | 
				
			||||||
 | 
								for (size_t i = 0; i < state->base->layers_len; i++) {
 | 
				
			||||||
 | 
									const struct wlr_output_layer_state *layer_state = &state->base->layers[i];
 | 
				
			||||||
 | 
									ok = ok && set_layer_props(drm, layer_state, i + 1);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (crtc->cursor) {
 | 
							if (crtc->cursor) {
 | 
				
			||||||
			if (drm_connector_is_cursor_visible(conn)) {
 | 
								if (drm_connector_is_cursor_visible(conn)) {
 | 
				
			||||||
				ok = ok && set_plane_props(crtc->cursor, crtc->cursor->liftoff_layer,
 | 
									ok = ok && set_plane_props(crtc->cursor, crtc->cursor->liftoff_layer,
 | 
				
			||||||
					conn->cursor_x, conn->cursor_y, 1);
 | 
										get_next_cursor_fb(conn), conn->cursor_x, conn->cursor_y,
 | 
				
			||||||
 | 
										wl_list_length(&crtc->layers) + 1);
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				ok = ok && disable_plane(crtc->cursor);
 | 
									ok = ok && disable_plane(crtc->cursor);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					@ -320,6 +374,15 @@ static bool crtc_commit(struct wlr_drm_connector *conn,
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (state->base->committed & WLR_OUTPUT_STATE_LAYERS) {
 | 
				
			||||||
 | 
							for (size_t i = 0; i < state->base->layers_len; i++) {
 | 
				
			||||||
 | 
								struct wlr_output_layer_state *layer_state = &state->base->layers[i];
 | 
				
			||||||
 | 
								struct wlr_drm_layer *layer = get_drm_layer(drm, layer_state->layer);
 | 
				
			||||||
 | 
								layer_state->accepted =
 | 
				
			||||||
 | 
									!liftoff_layer_needs_composition(layer->liftoff);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	drmModeAtomicFree(req);
 | 
						drmModeAtomicFree(req);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,6 +10,7 @@
 | 
				
			||||||
#include <wlr/backend/drm.h>
 | 
					#include <wlr/backend/drm.h>
 | 
				
			||||||
#include <wlr/backend/session.h>
 | 
					#include <wlr/backend/session.h>
 | 
				
			||||||
#include <wlr/render/drm_format_set.h>
 | 
					#include <wlr/render/drm_format_set.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_output_layer.h>
 | 
				
			||||||
#include <xf86drmMode.h>
 | 
					#include <xf86drmMode.h>
 | 
				
			||||||
#include "backend/drm/iface.h"
 | 
					#include "backend/drm/iface.h"
 | 
				
			||||||
#include "backend/drm/properties.h"
 | 
					#include "backend/drm/properties.h"
 | 
				
			||||||
| 
						 | 
					@ -36,11 +37,27 @@ struct wlr_drm_plane {
 | 
				
			||||||
	struct liftoff_layer *liftoff_layer;
 | 
						struct liftoff_layer *liftoff_layer;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_drm_layer {
 | 
				
			||||||
 | 
						struct liftoff_layer *liftoff;
 | 
				
			||||||
 | 
						struct wlr_addon addon; // wlr_output_layer.addons
 | 
				
			||||||
 | 
						struct wl_list link; // wlr_drm_crtc.layers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Buffer to be submitted to the kernel on the next page-flip */
 | 
				
			||||||
 | 
						struct wlr_drm_fb *pending_fb;
 | 
				
			||||||
 | 
						/* Buffer submitted to the kernel, will be presented on next vblank */
 | 
				
			||||||
 | 
						struct wlr_drm_fb *queued_fb;
 | 
				
			||||||
 | 
						/* Buffer currently displayed on screen */
 | 
				
			||||||
 | 
						struct wlr_drm_fb *current_fb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int pending_width, pending_height;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_drm_crtc {
 | 
					struct wlr_drm_crtc {
 | 
				
			||||||
	uint32_t id;
 | 
						uint32_t id;
 | 
				
			||||||
	struct wlr_drm_lease *lease;
 | 
						struct wlr_drm_lease *lease;
 | 
				
			||||||
	struct liftoff_output *liftoff;
 | 
						struct liftoff_output *liftoff;
 | 
				
			||||||
	struct liftoff_layer *liftoff_composition_layer;
 | 
						struct liftoff_layer *liftoff_composition_layer;
 | 
				
			||||||
 | 
						struct wl_list layers; // wlr_drm_layer.link
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Atomic modesetting only
 | 
						// Atomic modesetting only
 | 
				
			||||||
	uint32_t mode_id;
 | 
						uint32_t mode_id;
 | 
				
			||||||
| 
						 | 
					@ -163,6 +180,8 @@ size_t drm_crtc_get_gamma_lut_size(struct wlr_drm_backend *drm,
 | 
				
			||||||
void drm_lease_destroy(struct wlr_drm_lease *lease);
 | 
					void drm_lease_destroy(struct wlr_drm_lease *lease);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_drm_fb *get_next_cursor_fb(struct wlr_drm_connector *conn);
 | 
					struct wlr_drm_fb *get_next_cursor_fb(struct wlr_drm_connector *conn);
 | 
				
			||||||
 | 
					struct wlr_drm_layer *get_drm_layer(struct wlr_drm_backend *drm,
 | 
				
			||||||
 | 
						struct wlr_output_layer *layer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define wlr_drm_conn_log(conn, verb, fmt, ...) \
 | 
					#define wlr_drm_conn_log(conn, verb, fmt, ...) \
 | 
				
			||||||
	wlr_log(verb, "connector %s: " fmt, conn->name, ##__VA_ARGS__)
 | 
						wlr_log(verb, "connector %s: " fmt, conn->name, ##__VA_ARGS__)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue