Skip to content
Commits on Source (8)
......@@ -311,8 +311,10 @@ drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage)
return NULL;
}
/* The renderer always produces an opaque image. */
ret = drm_fb_get_from_bo(bo, device, true, BUFFER_GBM_SURFACE);
/* Output transparent/opaque image according to the format required by
* the client. */
ret = drm_fb_get_from_bo(bo, device, !output->format->opaque_substitute,
BUFFER_GBM_SURFACE);
if (!ret) {
weston_log("failed to get drm_fb for bo\n");
gbm_surface_release_buffer(output->gbm_surface, bo);
......
......@@ -257,6 +257,9 @@ struct drm_backend {
uint32_t pageflip_timeout;
/* True, if underlay planes exist. */
bool has_underlay;
struct weston_log_scope *debug;
};
......@@ -414,6 +417,8 @@ struct drm_plane {
uint32_t crtc_id;
struct drm_property_info props[WDRM_PLANE__COUNT];
/* True if the plane's zpos_max < primary plane's zpos_min. */
bool is_underlay;
/* The last state submitted to the kernel for this plane. */
struct drm_plane_state *state_cur;
......@@ -651,7 +656,7 @@ drm_output_get_plane_type_name(struct drm_plane *p)
case WDRM_PLANE_TYPE_CURSOR:
return "cursor";
case WDRM_PLANE_TYPE_OVERLAY:
return "overlay";
return p->is_underlay ? "underlay" : "overlay";
default:
assert(0);
break;
......
......@@ -1155,6 +1155,7 @@ drm_plane_create(struct drm_device *device, const drmModePlane *kplane)
plane->possible_crtcs = kplane->possible_crtcs;
plane->plane_id = kplane->plane_id;
plane->crtc_id = kplane->crtc_id;
plane->is_underlay = false;
weston_drm_format_array_init(&plane->formats);
......@@ -1328,6 +1329,7 @@ create_sprites(struct drm_device *device)
struct drm_plane *drm_plane;
uint32_t i;
uint32_t next_plane_idx = 0;
uint64_t primary_plane_zpos_min = DRM_PLANE_ZPOS_INVALID_PLANE;
kplane_res = drmModeGetPlaneResources(device->drm.fd);
if (!kplane_res) {
......@@ -1350,11 +1352,30 @@ create_sprites(struct drm_device *device)
weston_compositor_stack_plane(b->compositor,
&drm_plane->base,
NULL);
if (drm_plane->type == WDRM_PLANE_TYPE_PRIMARY)
primary_plane_zpos_min = drm_plane->zpos_min;
}
wl_list_for_each (drm_plane, &device->plane_list, link)
wl_list_for_each (drm_plane, &device->plane_list, link) {
drm_plane->plane_idx = next_plane_idx++;
if (primary_plane_zpos_min != DRM_PLANE_ZPOS_INVALID_PLANE &&
drm_plane->zpos_max != DRM_PLANE_ZPOS_INVALID_PLANE &&
drm_plane->zpos_max < primary_plane_zpos_min) {
drm_plane->is_underlay = true;
b->has_underlay = true;
}
}
if (b->has_underlay && !b->format->opaque_substitute) {
weston_log("WARNING: Unable to use hardware underlay "
"planes as the output format is opaque. In "
"order to make use of hardware overlay planes "
"adjust the output format.\n");
b->has_underlay = false;
}
drmModeFreePlaneResources(kplane_res);
}
......@@ -3974,6 +3995,7 @@ drm_backend_create(struct weston_compositor *compositor,
b->compositor = compositor;
b->pageflip_timeout = config->pageflip_timeout;
b->use_pixman_shadow = config->use_pixman_shadow;
b->has_underlay = false;
b->debug = weston_compositor_add_log_scope(compositor, "drm-backend",
"Debug messages from DRM/KMS backend\n",
......
......@@ -64,6 +64,20 @@ drm_propose_state_mode_to_string(enum drm_output_propose_state_mode mode)
return drm_output_propose_state_mode_as_string[mode];
}
static bool
drm_mixed_mode_check_underlay(enum drm_output_propose_state_mode mode,
struct drm_plane_state *scanout_state,
uint64_t zpos)
{
if (mode == DRM_OUTPUT_PROPOSE_STATE_MIXED) {
assert(scanout_state != NULL);
if (scanout_state->zpos >= zpos)
return true;
}
return false;
}
static bool
drm_output_check_plane_has_view_assigned(struct drm_plane *plane,
struct drm_output_state *output_state)
......@@ -379,7 +393,9 @@ drm_output_find_plane_for_view(struct drm_output_state *state,
struct weston_paint_node *pnode,
enum drm_output_propose_state_mode mode,
struct drm_plane_state *scanout_state,
uint64_t current_lowest_zpos)
uint64_t current_lowest_zpos_overlay,
uint64_t current_lowest_zpos_underlay,
bool need_underlay)
{
struct drm_output *output = state->output;
struct drm_device *device = output->device;
......@@ -391,6 +407,9 @@ drm_output_find_plane_for_view(struct drm_output_state *state,
struct weston_view *ev = pnode->view;
struct weston_buffer *buffer;
struct drm_fb *fb = NULL;
uint64_t current_lowest_zpos = need_underlay ?
current_lowest_zpos_underlay :
current_lowest_zpos_overlay;
bool view_matches_entire_output, scanout_has_view_assigned;
uint32_t possible_plane_mask = 0;
......@@ -484,6 +503,7 @@ drm_output_find_plane_for_view(struct drm_output_state *state,
wl_list_for_each(plane, &device->plane_list, link) {
const char *p_name = drm_output_get_plane_type_name(plane);
uint64_t zpos;
bool mm_has_underlay = false;
if (possible_plane_mask == 0)
break;
......@@ -492,6 +512,8 @@ drm_output_find_plane_for_view(struct drm_output_state *state,
continue;
possible_plane_mask &= ~(1 << plane->plane_idx);
mm_has_underlay =
drm_mixed_mode_check_underlay(mode, scanout_state, plane->zpos_max);
switch (plane->type) {
case WDRM_PLANE_TYPE_CURSOR:
......@@ -516,6 +538,10 @@ drm_output_find_plane_for_view(struct drm_output_state *state,
weston_view_is_opaque(ev, &ev->transform.boundingbox) &&
!scanout_has_view_assigned)
continue;
/* for alpha views, avoid placing them on the HW planes that
* are below the primary plane. */
if (mm_has_underlay && !weston_view_is_opaque(ev, &ev->transform.boundingbox))
continue;
break;
default:
assert(false && "unknown plane type");
......@@ -539,6 +565,21 @@ drm_output_find_plane_for_view(struct drm_output_state *state,
continue;
}
/* Pre-judge whether the plane will be set as underlay plane. If so, start
* trying to find underlay plane based on 'current_lowest_zpos_underlay'. */
if (!need_underlay) {
uint64_t tmp_next_lowest_zpos;
if (current_lowest_zpos == DRM_PLANE_ZPOS_INVALID_PLANE)
tmp_next_lowest_zpos = plane->zpos_max;
else
tmp_next_lowest_zpos = current_lowest_zpos - 1;
if (drm_mixed_mode_check_underlay(mode, scanout_state, tmp_next_lowest_zpos)) {
drm_debug(b, "\t\t\t\t[plane] could not use overlay planes, "
"attempting to find underlay plane\n");
current_lowest_zpos = current_lowest_zpos_underlay;
}
}
if (plane->zpos_min >= current_lowest_zpos) {
drm_debug(b, "\t\t\t\t[plane] not trying plane %d: "
"plane's minimum zpos (%"PRIu64") above "
......@@ -557,17 +598,14 @@ drm_output_find_plane_for_view(struct drm_output_state *state,
return NULL;
}
if (mode == DRM_OUTPUT_PROPOSE_STATE_MIXED) {
assert(scanout_state != NULL);
if (scanout_state->zpos >= plane->zpos_max) {
drm_debug(b, "\t\t\t\t[plane] not adding plane %d to "
"candidate list: primary's zpos "
"value (%"PRIu64") higher than "
"plane's maximum value (%"PRIu64")\n",
plane->plane_id, scanout_state->zpos,
plane->zpos_max);
continue;
}
if (!b->has_underlay && mm_has_underlay) {
drm_debug(b, "\t\t\t\t[plane] not adding plane %d to "
"candidate list: plane is below the primary "
"plane and backend format (%s) is opaque, "
"hole on primary plane will not work\n",
plane->plane_id, b->format->drm_format_name);
continue;
}
if (current_lowest_zpos == DRM_PLANE_ZPOS_INVALID_PLANE)
......@@ -588,6 +626,11 @@ drm_output_find_plane_for_view(struct drm_output_state *state,
}
if (ps) {
/* Check if this ps is underlay plane, if so, the view
* needs through hole on primary plane. */
if (drm_mixed_mode_check_underlay(mode, scanout_state, ps->zpos))
pnode->need_hole = true;
drm_debug(b, "\t\t\t\t[view] view %p has been placed to "
"%s plane with computed zpos %"PRIu64"\n",
ev, p_name, zpos);
......@@ -626,8 +669,12 @@ drm_output_propose_state(struct weston_output *output_base,
pixman_region32_t occluded_region;
bool renderer_ok = (mode != DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY);
bool need_underlay = false;
int ret;
uint64_t current_lowest_zpos = DRM_PLANE_ZPOS_INVALID_PLANE;
/* Record the current lowest zpos of the overlay planes */
uint64_t current_lowest_zpos_overlay = DRM_PLANE_ZPOS_INVALID_PLANE;
/* Record the current lowest zpos of the underlay plane */
uint64_t current_lowest_zpos_underlay = DRM_PLANE_ZPOS_INVALID_PLANE;
assert(!output->state_last);
state = drm_output_state_duplicate(output->state_cur,
......@@ -681,6 +728,12 @@ drm_output_propose_state(struct weston_output *output_base,
plane->state_cur);
/* assign the primary the lowest zpos value */
scanout_state->zpos = plane->zpos_min;
/* Set the initial lowest zpos used for the underlay plane
* (asuming capable platform) to the that of the the primary
* plane, matching the lowest possible value. As we parse views
* from top to bottom we also need a start-up point for
* underlays, below this initial lowest zpos value. */
current_lowest_zpos_underlay = scanout_state->zpos;
drm_debug(b, "\t\t[state] using renderer FB ID %lu for mixed "
"mode for output %s (%lu)\n",
(unsigned long) scanout_fb->fb_id, output->base.name,
......@@ -690,7 +743,7 @@ drm_output_propose_state(struct weston_output *output_base,
}
/* - renderer_region contains the total region which which will be
* covered by the renderer
* covered by the renderer and underlay region.
* - occluded_region contains the total region which which will be
* covered by the renderer and hardware planes, where the view's
* visible-and-opaque region is added in both cases (the view's
......@@ -777,13 +830,20 @@ drm_output_propose_state(struct weston_output *output_base,
/* Since we process views from top to bottom, we know that if
* the view intersects the calculated renderer region, it must
* be part of, or occluded by, it, and cannot go on a plane. */
* be part of, or occluded by, it, and cannot go on an overlay
* plane. */
pixman_region32_intersect(&surface_overlap, &renderer_region,
&clipped_view);
if (pixman_region32_not_empty(&surface_overlap)) {
drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
"(occluded by renderer views)\n", ev);
force_renderer = true;
if (b->has_underlay) {
need_underlay = true;
} else {
force_renderer = true;
drm_debug(b, "\t\t\t\t[view] not assigning view %p to a "
"plane (occluded by renderer views), current lowest "
"zpos change to %"PRIu64"\n", ev,
current_lowest_zpos_underlay);
}
}
pixman_region32_fini(&surface_overlap);
......@@ -805,10 +865,13 @@ drm_output_propose_state(struct weston_output *output_base,
/* Now try to place it on a plane if we can. */
if (!force_renderer) {
drm_debug(b, "\t\t\t[plane] started with zpos %"PRIu64"\n",
current_lowest_zpos);
need_underlay ? current_lowest_zpos_underlay :
current_lowest_zpos_overlay);
ps = drm_output_find_plane_for_view(state, pnode, mode,
scanout_state,
current_lowest_zpos);
current_lowest_zpos_overlay,
current_lowest_zpos_underlay,
need_underlay);
} else {
/* We are forced to place the view in the renderer, set
* the failure reason accordingly. */
......@@ -817,9 +880,14 @@ drm_output_propose_state(struct weston_output *output_base,
}
if (ps) {
current_lowest_zpos = ps->zpos;
drm_debug(b, "\t\t\t[plane] next zpos to use %"PRIu64"\n",
current_lowest_zpos);
if (drm_mixed_mode_check_underlay(mode, scanout_state, ps->zpos))
current_lowest_zpos_underlay = ps->zpos;
else
current_lowest_zpos_overlay = ps->zpos;
drm_debug(b, "\t\t\t[plane] next overlay zpos to use %"PRIu64","
" next underlay zpos to use %"PRIu64"\n",
current_lowest_zpos_overlay,
current_lowest_zpos_underlay);
} else if (!ps && !renderer_ok) {
drm_debug(b, "\t\t[view] failing state generation: "
"placing view %p to renderer not allowed\n",
......@@ -827,14 +895,16 @@ drm_output_propose_state(struct weston_output *output_base,
pixman_region32_fini(&clipped_view);
goto err_region;
} else if (!ps) {
drm_debug(b, "\t\t\t\t[view] view %p will be placed "
"on the renderer\n", ev);
}
if (!ps || drm_mixed_mode_check_underlay(mode, scanout_state, ps->zpos)) {
/* clipped_view contains the area that's going to be
* visible on screen; add this to the renderer region */
pixman_region32_union(&renderer_region,
&renderer_region,
&clipped_view);
drm_debug(b, "\t\t\t\t[view] view %p will be placed "
"on the renderer\n", ev);
}
/* Opaque areas of our clipped view occlude areas behind it;
......@@ -993,13 +1063,14 @@ drm_assign_planes(struct weston_output *output_base)
if (target_plane) {
drm_debug(b, "\t[repaint] view %p on %s plane %lu\n",
ev, plane_type_enums[target_plane->type].name,
ev, drm_output_get_plane_type_name(target_plane),
(unsigned long) target_plane->plane_id);
weston_paint_node_move_to_plane(pnode, &target_plane->base);
} else {
drm_debug(b, "\t[repaint] view %p using renderer "
"composition\n", ev);
weston_paint_node_move_to_plane(pnode, primary);
pnode->need_hole = false;
}
if (!target_plane ||
......
......@@ -225,6 +225,15 @@ maybe_replace_paint_node(struct weston_paint_node *pnode)
pnode->solid = placeholder_color;
return;
}
if (pnode->need_hole) {
pnode->draw_solid = true;
pnode->is_fully_opaque = true;
pnode->is_fully_blended = false;
pnode->solid = (struct weston_solid_buffer_values) {
0.0, 0.0, 0.0, 0.0
};
return;
}
if (surface->protection_mode !=
WESTON_SURFACE_PROTECTION_MODE_ENFORCED)
return;
......@@ -380,6 +389,7 @@ weston_paint_node_create(struct weston_surface *surface,
pnode->plane = &pnode->output->primary_plane;
pnode->plane_next = NULL;
pnode->need_hole = false;
pnode->status = PAINT_NODE_ALL_DIRTY & ~PAINT_NODE_PLANE_DIRTY;
return pnode;
......@@ -3600,8 +3610,13 @@ weston_output_flush_damage_for_plane(struct weston_output *output,
wl_list_for_each(pnode, &output->paint_node_z_order_list,
z_order_link) {
if (pnode->plane != plane)
continue;
if (pnode->plane != plane) {
if (plane != &output->primary_plane)
continue;
/* For primary plane, add the damage of nodes need holes. */
if (!pnode->need_hole)
continue;
}
changed = true;
/* We can safely clip paint node damage to visible region
......
......@@ -561,6 +561,8 @@ struct weston_paint_node {
bool is_direct;
bool draw_solid;
struct weston_solid_buffer_values solid;
bool need_hole;
};
struct weston_paint_node *
......
......@@ -1665,7 +1665,8 @@ repaint_views(struct weston_output *output, pixman_region32_t *damage)
wl_list_for_each_reverse(pnode, &output->paint_node_z_order_list,
z_order_link) {
if (pnode->plane == &output->primary_plane)
if (pnode->plane == &output->primary_plane ||
pnode->need_hole)
draw_paint_node(pnode, damage);
}
......
......@@ -60,7 +60,10 @@ and some of their permutations.
The formats supported with GL-renderer depend on the EGL and OpenGL ES 2 or 3
implementations. The names are case-insensitive. This setting applies only to
.RB "outputs in SDR mode, see " eotf-mode " in " weston.ini (5).
If the hardware platform supports hardware planes placed under the DRM primary plane
type (underlays), specifying
.BR argb8888
would be needed for Weston to display content lifted into such hardware planes.
.RB "If not specified, " xrgb8888 " is used. See also " gbm-format " in"
.BR output " section."
.TP
......