/* We don't own the fd, so we shouldn't close it */
int in_fence_fd;
- pixman_region32_t damage; /* damage to kernel */
+ uint32_t damage_blob_id; /* damage to kernel */
struct wl_list link; /* drm_output_state::plane_list */
};
struct weston_compositor *c = output->base.compositor;
struct drm_plane_state *scanout_state;
struct drm_plane *scanout_plane = output->scanout_plane;
+ struct drm_property_info *damage_info =
+ &scanout_plane->props[WDRM_PLANE_FB_DAMAGE_CLIPS];
struct drm_backend *b = to_drm_backend(c);
struct drm_fb *fb;
+ pixman_region32_t scanout_damage;
+ pixman_box32_t *rects;
+ int n_rects;
/* If we already have a client buffer promoted to scanout, then we don't
* want to render. */
scanout_state->dest_w = output->base.current_mode->width;
scanout_state->dest_h = output->base.current_mode->height;
- pixman_region32_copy(&scanout_state->damage, damage);
+ pixman_region32_subtract(&c->primary_plane.damage,
+ &c->primary_plane.damage, damage);
+
+ /* Don't bother calculating plane damage if the plane doesn't support it */
+ if (damage_info->prop_id == 0)
+ return;
+
+ pixman_region32_init(&scanout_damage);
+ pixman_region32_copy(&scanout_damage, damage);
+
if (output->base.zoom.active) {
- weston_matrix_transform_region(&scanout_state->damage,
+ weston_matrix_transform_region(&scanout_damage,
&output->base.matrix,
- &scanout_state->damage);
+ &scanout_damage);
} else {
- pixman_region32_translate(&scanout_state->damage,
+ pixman_region32_translate(&scanout_damage,
-output->base.x, -output->base.y);
weston_transformed_region(output->base.width,
output->base.height,
output->base.transform,
output->base.current_scale,
- &scanout_state->damage,
- &scanout_state->damage);
+ &scanout_damage,
+ &scanout_damage);
}
- pixman_region32_subtract(&c->primary_plane.damage,
- &c->primary_plane.damage, damage);
+ assert(scanout_state->damage_blob_id == 0);
+
+ rects = pixman_region32_rectangles(&scanout_damage, &n_rects);
+
+ /*
+ * If this function fails, the blob id should still be 0.
+ * This tells the kernel there is no damage information, which means
+ * that it will consider the whole plane damaged. While this may
+ * affect efficiency, it should still produce correct results.
+ */
+ drmModeCreatePropertyBlob(b->drm.fd, rects,
+ sizeof(*rects) * n_rects,
+ &scanout_state->damage_blob_id);
+
+ pixman_region32_fini(&scanout_damage);
}
static int
return (ret <= 0) ? -1 : 0;
}
-
-static int
-plane_add_damage(drmModeAtomicReq *req, struct drm_backend *backend,
- struct drm_plane_state *plane_state)
-{
- struct drm_plane *plane = plane_state->plane;
- struct drm_property_info *info =
- &plane->props[WDRM_PLANE_FB_DAMAGE_CLIPS];
- pixman_box32_t *rects;
- uint32_t blob_id;
- int n_rects;
- int ret;
-
- if (!pixman_region32_not_empty(&plane_state->damage))
- return 0;
-
- /*
- * If a plane doesn't support fb damage blob property, kernel will
- * perform full plane update.
- */
- if (info->prop_id == 0)
- return 0;
-
- rects = pixman_region32_rectangles(&plane_state->damage, &n_rects);
-
- ret = drmModeCreatePropertyBlob(backend->drm.fd, rects,
- sizeof(*rects) * n_rects, &blob_id);
- if (ret != 0)
- return ret;
-
- ret = plane_add_prop(req, plane, WDRM_PLANE_FB_DAMAGE_CLIPS, blob_id);
- if (ret != 0)
- return ret;
-
- return 0;
-}
-
static bool
drm_head_has_prop(struct drm_head *head,
enum wdrm_connector_property prop)
plane_state->dest_w);
ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_H,
plane_state->dest_h);
- ret |= plane_add_damage(req, b, plane_state);
+ if (plane->props[WDRM_PLANE_FB_DAMAGE_CLIPS].prop_id != 0)
+ ret |= plane_add_prop(req, plane, WDRM_PLANE_FB_DAMAGE_CLIPS,
+ plane_state->damage_blob_id);
if (plane_state->fb && plane_state->fb->format)
pinfo = plane_state->fb->format;
state->plane = plane;
state->in_fence_fd = -1;
state->zpos = DRM_PLANE_ZPOS_INVALID_PLANE;
- pixman_region32_init(&state->damage);
/* Here we only add the plane state to the desired link, and not
* set the member. Having an output pointer set means that the
state->output_state = NULL;
state->in_fence_fd = -1;
state->zpos = DRM_PLANE_ZPOS_INVALID_PLANE;
- pixman_region32_fini(&state->damage);
+
+ /* Once the damage blob has been submitted, it is refcounted internally
+ * by the kernel, which means we can safely discard it.
+ */
+ if (state->damage_blob_id != 0) {
+ drmModeDestroyPropertyBlob(state->plane->backend->drm.fd,
+ state->damage_blob_id);
+ state->damage_blob_id = 0;
+ }
if (force || state != state->plane->state_cur) {
drm_fb_unref(state->fb);
drm_plane_state_duplicate(struct drm_output_state *state_output,
struct drm_plane_state *src)
{
- struct drm_plane_state *dst = malloc(sizeof(*dst));
+ struct drm_plane_state *dst = zalloc(sizeof(*dst));
struct drm_plane_state *old, *tmp;
assert(src);
assert(dst);
*dst = *src;
+ /* We don't want to copy this, because damage is transient, and only
+ * lasts for the duration of a single repaint.
+ */
+ dst->damage_blob_id = 0;
wl_list_init(&dst->link);
wl_list_for_each_safe(old, tmp, &state_output->plane_list, link) {
if (src->fb)
dst->fb = drm_fb_ref(src->fb);
dst->output_state = state_output;
- pixman_region32_init(&dst->damage);
dst->complete = false;
return dst;