2019-08-23 17:48:13 +02:00
|
|
|
#include <assert.h>
|
2019-08-21 22:07:37 +02:00
|
|
|
#include <errno.h>
|
|
|
|
#include <inttypes.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include "private.h"
|
|
|
|
|
2019-09-08 17:33:09 +02:00
|
|
|
static int guess_plane_zpos_from_type(struct hwc_display *display,
|
2019-09-09 19:55:43 +02:00
|
|
|
uint32_t plane_id, uint32_t type)
|
2019-09-08 17:33:09 +02:00
|
|
|
{
|
|
|
|
struct hwc_plane *primary;
|
|
|
|
|
|
|
|
/* From far to close to the eye: primary, overlay, cursor. Unless
|
|
|
|
* the overlay ID < primary ID. */
|
|
|
|
switch (type) {
|
|
|
|
case DRM_PLANE_TYPE_PRIMARY:
|
|
|
|
return 0;
|
|
|
|
case DRM_PLANE_TYPE_CURSOR:
|
|
|
|
return 2;
|
|
|
|
case DRM_PLANE_TYPE_OVERLAY:
|
|
|
|
if (hwc_list_empty(&display->planes)) {
|
|
|
|
return 0; /* No primary plane, shouldn't happen */
|
|
|
|
}
|
|
|
|
primary = hwc_container_of(display->planes.next, primary, link);
|
|
|
|
if (plane_id < primary->id) {
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct hwc_plane *plane_create(struct hwc_display *display, uint32_t id)
|
2019-08-21 22:07:37 +02:00
|
|
|
{
|
2019-09-09 19:55:43 +02:00
|
|
|
struct hwc_plane *plane, *cur;
|
2019-08-21 22:07:37 +02:00
|
|
|
drmModePlane *drm_plane;
|
|
|
|
drmModeObjectProperties *drm_props;
|
|
|
|
uint32_t i;
|
|
|
|
drmModePropertyRes *drm_prop;
|
|
|
|
struct hwc_plane_property *prop;
|
2019-09-09 18:46:44 +02:00
|
|
|
uint64_t value;
|
2019-09-09 19:55:43 +02:00
|
|
|
bool has_type = false, has_zpos = false;
|
2019-08-21 22:07:37 +02:00
|
|
|
|
2019-09-08 14:26:50 +02:00
|
|
|
plane = calloc(1, sizeof(*plane));
|
|
|
|
if (plane == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-08-21 22:07:37 +02:00
|
|
|
drm_plane = drmModeGetPlane(display->drm_fd, id);
|
|
|
|
if (drm_plane == NULL) {
|
2019-09-08 14:26:50 +02:00
|
|
|
return NULL;
|
2019-08-21 22:07:37 +02:00
|
|
|
}
|
|
|
|
plane->id = drm_plane->plane_id;
|
|
|
|
plane->possible_crtcs = drm_plane->possible_crtcs;
|
|
|
|
drmModeFreePlane(drm_plane);
|
|
|
|
|
|
|
|
drm_props = drmModeObjectGetProperties(display->drm_fd, id,
|
|
|
|
DRM_MODE_OBJECT_PLANE);
|
|
|
|
if (drm_props == NULL) {
|
2019-09-08 14:26:50 +02:00
|
|
|
return NULL;
|
2019-08-21 22:07:37 +02:00
|
|
|
}
|
|
|
|
plane->props = calloc(drm_props->count_props,
|
|
|
|
sizeof(struct hwc_plane_property));
|
|
|
|
if (plane->props == NULL) {
|
|
|
|
drmModeFreeObjectProperties(drm_props);
|
2019-09-08 14:26:50 +02:00
|
|
|
return NULL;
|
2019-08-21 22:07:37 +02:00
|
|
|
}
|
|
|
|
for (i = 0; i < drm_props->count_props; i++) {
|
|
|
|
drm_prop = drmModeGetProperty(display->drm_fd,
|
|
|
|
drm_props->props[i]);
|
|
|
|
if (drm_prop == NULL) {
|
|
|
|
drmModeFreeObjectProperties(drm_props);
|
2019-09-08 14:26:50 +02:00
|
|
|
return NULL;
|
2019-08-21 22:07:37 +02:00
|
|
|
}
|
|
|
|
prop = &plane->props[i];
|
|
|
|
memcpy(prop->name, drm_prop->name, sizeof(prop->name));
|
|
|
|
prop->id = drm_prop->prop_id;
|
|
|
|
drmModeFreeProperty(drm_prop);
|
|
|
|
plane->props_len++;
|
2019-09-08 17:33:09 +02:00
|
|
|
|
2019-09-09 18:46:44 +02:00
|
|
|
value = drm_props->prop_values[i];
|
2019-09-09 19:55:43 +02:00
|
|
|
if (strcmp(prop->name, "type") == 0) {
|
|
|
|
plane->type = value;
|
|
|
|
has_type = true;
|
2019-09-09 18:46:44 +02:00
|
|
|
} else if (strcmp(prop->name, "zpos") == 0) {
|
2019-09-09 19:55:43 +02:00
|
|
|
plane->zpos = value;
|
2019-09-09 18:46:44 +02:00
|
|
|
has_zpos = true;
|
2019-09-08 17:33:09 +02:00
|
|
|
}
|
2019-08-21 22:07:37 +02:00
|
|
|
}
|
|
|
|
drmModeFreeObjectProperties(drm_props);
|
|
|
|
|
2019-09-09 19:55:43 +02:00
|
|
|
if (!has_type) {
|
|
|
|
fprintf(stderr, "plane %d is missing the 'type' property\n",
|
|
|
|
plane->id);
|
|
|
|
free(plane);
|
|
|
|
return NULL;
|
|
|
|
} else if (!has_zpos) {
|
|
|
|
plane->zpos = guess_plane_zpos_from_type(display, plane->id,
|
|
|
|
plane->type);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* During plane allocation, we will use the plane list order to fill
|
|
|
|
* planes with FBs. Primary planes need to be filled first, then planes
|
|
|
|
* far from the primary planes, then planes closer and closer to the
|
|
|
|
* primary plane. */
|
|
|
|
if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
|
|
|
|
hwc_list_insert(&display->planes, &plane->link);
|
|
|
|
} else {
|
|
|
|
hwc_list_for_each(cur, &display->planes, link) {
|
|
|
|
if (cur->type != DRM_PLANE_TYPE_PRIMARY &&
|
|
|
|
plane->zpos >= cur->zpos) {
|
|
|
|
hwc_list_insert(cur->link.prev, &plane->link);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (plane->link.next == NULL) { /* not inserted */
|
|
|
|
hwc_list_insert(display->planes.prev, &plane->link);
|
|
|
|
}
|
|
|
|
}
|
2019-09-08 14:26:50 +02:00
|
|
|
|
|
|
|
return plane;
|
2019-08-21 22:07:37 +02:00
|
|
|
}
|
|
|
|
|
2019-09-08 14:26:50 +02:00
|
|
|
static void plane_destroy(struct hwc_plane *plane)
|
2019-08-21 22:07:37 +02:00
|
|
|
{
|
2019-09-08 14:26:50 +02:00
|
|
|
hwc_list_remove(&plane->link);
|
2019-08-21 22:07:37 +02:00
|
|
|
free(plane->props);
|
2019-09-08 14:26:50 +02:00
|
|
|
free(plane);
|
2019-08-21 22:07:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
struct hwc_display *hwc_display_create(int drm_fd)
|
|
|
|
{
|
|
|
|
struct hwc_display *display;
|
2019-09-08 16:41:25 +02:00
|
|
|
drmModeRes *drm_res;
|
2019-08-21 22:07:37 +02:00
|
|
|
drmModePlaneRes *drm_plane_res;
|
|
|
|
uint32_t i;
|
|
|
|
|
|
|
|
display = calloc(1, sizeof(*display));
|
|
|
|
if (display == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
display->drm_fd = dup(drm_fd);
|
|
|
|
if (display->drm_fd < 0) {
|
|
|
|
hwc_display_destroy(display);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-09-08 14:26:50 +02:00
|
|
|
hwc_list_init(&display->planes);
|
2019-08-21 22:07:37 +02:00
|
|
|
hwc_list_init(&display->outputs);
|
|
|
|
|
2019-09-08 16:41:25 +02:00
|
|
|
drm_res = drmModeGetResources(drm_fd);
|
|
|
|
if (drm_res == NULL) {
|
|
|
|
hwc_display_destroy(display);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
display->crtcs = malloc(drm_res->count_crtcs * sizeof(uint32_t));
|
|
|
|
if (display->crtcs == NULL) {
|
|
|
|
drmModeFreeResources(drm_res);
|
|
|
|
hwc_display_destroy(display);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
display->crtcs_len = drm_res->count_crtcs;
|
|
|
|
memcpy(display->crtcs, drm_res->crtcs,
|
|
|
|
drm_res->count_crtcs * sizeof(uint32_t));
|
|
|
|
|
|
|
|
drmModeFreeResources(drm_res);
|
|
|
|
|
2019-08-21 22:07:37 +02:00
|
|
|
/* TODO: allow users to choose which layers to hand over */
|
|
|
|
drm_plane_res = drmModeGetPlaneResources(drm_fd);
|
|
|
|
if (drm_plane_res == NULL) {
|
|
|
|
hwc_display_destroy(display);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < drm_plane_res->count_planes; i++) {
|
2019-09-08 14:26:50 +02:00
|
|
|
if (plane_create(display, drm_plane_res->planes[i]) == NULL) {
|
2019-08-21 22:07:37 +02:00
|
|
|
hwc_display_destroy(display);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
drmModeFreePlaneResources(drm_plane_res);
|
|
|
|
|
|
|
|
return display;
|
|
|
|
}
|
|
|
|
|
|
|
|
void hwc_display_destroy(struct hwc_display *display)
|
|
|
|
{
|
2019-09-08 14:26:50 +02:00
|
|
|
struct hwc_plane *plane, *tmp;
|
2019-08-21 22:07:37 +02:00
|
|
|
|
|
|
|
close(display->drm_fd);
|
2019-09-08 14:26:50 +02:00
|
|
|
hwc_list_for_each_safe(plane, tmp, &display->planes, link) {
|
|
|
|
plane_destroy(plane);
|
2019-08-21 22:07:37 +02:00
|
|
|
}
|
2019-09-08 16:41:25 +02:00
|
|
|
free(display->crtcs);
|
2019-08-21 22:07:37 +02:00
|
|
|
free(display);
|
|
|
|
}
|
|
|
|
|
2019-08-23 17:20:42 +02:00
|
|
|
static struct hwc_plane_property *plane_get_property(struct hwc_plane *plane,
|
|
|
|
const char *name)
|
2019-08-21 22:07:37 +02:00
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < plane->props_len; i++) {
|
|
|
|
if (strcmp(plane->props[i].name, name) == 0) {
|
|
|
|
return &plane->props[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-08-23 17:48:13 +02:00
|
|
|
static bool plane_set_prop(struct hwc_plane *plane, drmModeAtomicReq *req,
|
|
|
|
struct hwc_plane_property *prop, uint64_t value)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
fprintf(stderr, " Setting %s = %"PRIu64"\n", prop->name, value);
|
|
|
|
ret = drmModeAtomicAddProperty(req, plane->id, prop->id, value);
|
|
|
|
if (ret < 0) {
|
|
|
|
perror("drmModeAtomicAddProperty");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool plane_apply(struct hwc_plane *plane, struct hwc_layer *layer,
|
2019-09-10 21:58:29 +02:00
|
|
|
drmModeAtomicReq *req, bool *compatible)
|
2019-08-21 22:07:37 +02:00
|
|
|
{
|
2019-09-10 21:58:29 +02:00
|
|
|
int cursor;
|
2019-08-21 22:07:37 +02:00
|
|
|
size_t i;
|
|
|
|
struct hwc_layer_property *layer_prop;
|
|
|
|
struct hwc_plane_property *plane_prop;
|
|
|
|
|
2019-09-10 21:58:29 +02:00
|
|
|
*compatible = true;
|
|
|
|
cursor = drmModeAtomicGetCursor(req);
|
|
|
|
|
2019-08-23 17:48:13 +02:00
|
|
|
if (layer == NULL) {
|
|
|
|
plane_prop = plane_get_property(plane, "FB_ID");
|
2019-09-10 21:58:29 +02:00
|
|
|
if (plane_prop == NULL) {
|
|
|
|
fprintf(stderr, "plane is missing the FB_ID property\n");
|
|
|
|
return false;
|
|
|
|
}
|
2019-08-23 17:48:13 +02:00
|
|
|
return plane_set_prop(plane, req, plane_prop, 0);
|
|
|
|
}
|
2019-08-21 22:07:37 +02:00
|
|
|
|
|
|
|
plane_prop = plane_get_property(plane, "CRTC_ID");
|
2019-09-10 21:58:29 +02:00
|
|
|
if (plane_prop == NULL) {
|
|
|
|
fprintf(stderr, "plane is missing the CRTC_ID property\n");
|
|
|
|
return false;
|
|
|
|
}
|
2019-08-23 17:48:13 +02:00
|
|
|
if (!plane_set_prop(plane, req, plane_prop, layer->output->crtc_id)) {
|
2019-08-21 22:07:37 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < layer->props_len; i++) {
|
|
|
|
layer_prop = &layer->props[i];
|
|
|
|
plane_prop = plane_get_property(plane, layer_prop->name);
|
|
|
|
if (plane_prop == NULL) {
|
2019-09-10 21:58:29 +02:00
|
|
|
*compatible = false;
|
|
|
|
drmModeAtomicSetCursor(req, cursor);
|
|
|
|
return true;
|
2019-08-21 22:07:37 +02:00
|
|
|
}
|
|
|
|
|
2019-08-23 17:48:13 +02:00
|
|
|
if (!plane_set_prop(plane, req, plane_prop, layer_prop->value)) {
|
2019-09-10 21:58:29 +02:00
|
|
|
drmModeAtomicSetCursor(req, cursor);
|
2019-08-21 22:07:37 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-09-11 18:23:35 +02:00
|
|
|
/* Global data for the allocation algorithm */
|
2019-09-08 15:32:38 +02:00
|
|
|
struct plane_alloc {
|
|
|
|
drmModeAtomicReq *req;
|
|
|
|
size_t planes_len;
|
2019-09-11 18:23:35 +02:00
|
|
|
|
2019-09-08 15:32:38 +02:00
|
|
|
struct hwc_layer **best;
|
|
|
|
int best_score;
|
|
|
|
};
|
|
|
|
|
2019-09-11 18:23:35 +02:00
|
|
|
/* Transient data, arguments for each step */
|
|
|
|
struct plane_data {
|
|
|
|
struct hwc_list *plane_link; /* hwc_plane.link */
|
|
|
|
size_t plane_idx;
|
|
|
|
|
|
|
|
struct hwc_layer **alloc; /* only items up to plane_idx are valid */
|
|
|
|
int score;
|
|
|
|
};
|
|
|
|
|
2019-09-08 15:32:38 +02:00
|
|
|
bool output_choose_layers(struct hwc_output *output, struct plane_alloc *alloc,
|
2019-09-11 18:23:35 +02:00
|
|
|
struct plane_data *data)
|
2019-08-21 22:07:37 +02:00
|
|
|
{
|
|
|
|
struct hwc_display *display;
|
|
|
|
struct hwc_plane *plane;
|
2019-09-08 15:32:38 +02:00
|
|
|
struct hwc_layer *layer;
|
|
|
|
int cursor, ret;
|
|
|
|
size_t remaining_planes, i;
|
2019-09-10 21:58:29 +02:00
|
|
|
bool found, compatible;
|
2019-09-11 18:23:35 +02:00
|
|
|
struct plane_data next_data;
|
2019-09-08 15:32:38 +02:00
|
|
|
|
|
|
|
display = output->display;
|
|
|
|
|
2019-09-11 18:23:35 +02:00
|
|
|
if (data->plane_link == &display->planes) { /* Allocation finished */
|
|
|
|
if (data->score > alloc->best_score) {
|
2019-09-08 15:32:38 +02:00
|
|
|
/* We found a better allocation */
|
2019-09-11 18:23:35 +02:00
|
|
|
alloc->best_score = data->score;
|
|
|
|
memcpy(alloc->best, data->alloc,
|
2019-09-08 15:32:38 +02:00
|
|
|
alloc->planes_len * sizeof(struct hwc_layer *));
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2019-09-11 18:23:35 +02:00
|
|
|
plane = hwc_container_of(data->plane_link, plane, link);
|
|
|
|
|
|
|
|
next_data.plane_link = data->plane_link->next;
|
|
|
|
next_data.plane_idx = data->plane_idx + 1;
|
|
|
|
next_data.alloc = data->alloc;
|
2019-09-08 15:32:38 +02:00
|
|
|
|
2019-09-11 18:23:35 +02:00
|
|
|
remaining_planes = alloc->planes_len - data->plane_idx;
|
2019-09-12 09:17:03 +02:00
|
|
|
if (alloc->best_score >= data->score + (int)remaining_planes) {
|
2019-09-08 15:32:38 +02:00
|
|
|
/* Even if we find a layer for all remaining planes, we won't
|
|
|
|
* find a better allocation. Give up. */
|
|
|
|
return true;
|
|
|
|
}
|
2019-08-21 22:07:37 +02:00
|
|
|
|
2019-09-08 15:32:38 +02:00
|
|
|
cursor = drmModeAtomicGetCursor(alloc->req);
|
2019-08-21 22:07:37 +02:00
|
|
|
|
2019-09-08 15:32:38 +02:00
|
|
|
if (plane->layer != NULL) {
|
|
|
|
goto skip;
|
|
|
|
}
|
2019-09-08 16:41:25 +02:00
|
|
|
if ((plane->possible_crtcs & (1 << output->crtc_index)) == 0) {
|
|
|
|
goto skip;
|
|
|
|
}
|
2019-09-08 15:32:38 +02:00
|
|
|
|
|
|
|
hwc_list_for_each(layer, &output->layers, link) {
|
|
|
|
if (layer->plane != NULL) {
|
2019-08-23 17:59:20 +02:00
|
|
|
continue;
|
|
|
|
}
|
2019-08-21 22:07:37 +02:00
|
|
|
|
2019-09-08 15:32:38 +02:00
|
|
|
found = false;
|
2019-09-11 18:23:35 +02:00
|
|
|
for (i = 0; i < data->plane_idx; i++) {
|
|
|
|
if (data->alloc[i] == layer) {
|
2019-09-08 15:32:38 +02:00
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (found) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Try to use this layer for the current plane */
|
2019-09-11 18:23:35 +02:00
|
|
|
data->alloc[data->plane_idx] = layer;
|
2019-08-21 22:07:37 +02:00
|
|
|
fprintf(stderr, "Trying to apply layer %p with plane %d...\n",
|
|
|
|
(void *)layer, plane->id);
|
2019-09-10 21:58:29 +02:00
|
|
|
if (!plane_apply(plane, layer, alloc->req, &compatible)) {
|
2019-08-21 22:07:37 +02:00
|
|
|
return false;
|
|
|
|
}
|
2019-09-10 21:58:29 +02:00
|
|
|
if (!compatible) {
|
|
|
|
continue;
|
|
|
|
}
|
2019-08-21 22:07:37 +02:00
|
|
|
|
2019-09-08 15:32:38 +02:00
|
|
|
ret = drmModeAtomicCommit(display->drm_fd, alloc->req,
|
2019-08-21 22:07:37 +02:00
|
|
|
DRM_MODE_ATOMIC_TEST_ONLY, NULL);
|
|
|
|
if (ret == 0) {
|
|
|
|
fprintf(stderr, "Success\n");
|
2019-09-08 15:32:38 +02:00
|
|
|
/* Continue with the next plane */
|
2019-09-11 18:23:35 +02:00
|
|
|
next_data.score = data->score + 1;
|
|
|
|
if (!output_choose_layers(output, alloc, &next_data)) {
|
2019-09-08 15:32:38 +02:00
|
|
|
return false;
|
|
|
|
}
|
2019-08-21 22:07:37 +02:00
|
|
|
} else if (-ret != EINVAL && -ret != ERANGE) {
|
|
|
|
perror("drmModeAtomicCommit");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-09-08 15:32:38 +02:00
|
|
|
drmModeAtomicSetCursor(alloc->req, cursor);
|
2019-08-21 22:07:37 +02:00
|
|
|
}
|
|
|
|
|
2019-09-08 15:32:38 +02:00
|
|
|
skip:
|
|
|
|
/* Try not to use the current plane */
|
2019-09-11 18:23:35 +02:00
|
|
|
data->alloc[data->plane_idx] = NULL;
|
|
|
|
next_data.score = data->score;
|
|
|
|
if (!output_choose_layers(output, alloc, &next_data)) {
|
2019-09-08 15:32:38 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
drmModeAtomicSetCursor(alloc->req, cursor);
|
|
|
|
|
2019-08-23 18:27:13 +02:00
|
|
|
return true;
|
2019-08-21 22:07:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool hwc_display_apply(struct hwc_display *display, drmModeAtomicReq *req)
|
|
|
|
{
|
|
|
|
struct hwc_output *output;
|
2019-08-23 17:48:13 +02:00
|
|
|
struct hwc_plane *plane;
|
2019-09-08 15:32:38 +02:00
|
|
|
struct hwc_layer *layer;
|
|
|
|
struct plane_alloc alloc;
|
2019-09-11 18:23:35 +02:00
|
|
|
struct plane_data data;
|
2019-09-08 15:32:38 +02:00
|
|
|
size_t i;
|
2019-09-10 21:58:29 +02:00
|
|
|
bool compatible;
|
2019-08-21 22:07:37 +02:00
|
|
|
|
2019-08-23 18:20:05 +02:00
|
|
|
/* Unset all existing plane and layer mappings.
|
|
|
|
TODO: incremental updates keeping old configuration if possible */
|
2019-09-08 14:26:50 +02:00
|
|
|
hwc_list_for_each(plane, &display->planes, link) {
|
2019-08-23 17:56:44 +02:00
|
|
|
if (plane->layer != NULL) {
|
|
|
|
plane->layer->plane = NULL;
|
|
|
|
plane->layer = NULL;
|
|
|
|
}
|
|
|
|
}
|
2019-08-21 22:07:37 +02:00
|
|
|
|
2019-08-23 18:20:05 +02:00
|
|
|
/* Disable all planes. Do it before building mappings to make sure not
|
|
|
|
to hit bandwidth limits because too many planes are enabled. */
|
2019-09-08 14:26:50 +02:00
|
|
|
hwc_list_for_each(plane, &display->planes, link) {
|
2019-08-23 18:20:05 +02:00
|
|
|
if (plane->layer == NULL) {
|
|
|
|
fprintf(stderr, "Disabling plane %d\n", plane->id);
|
2019-09-10 21:58:29 +02:00
|
|
|
if (!plane_apply(plane, NULL, req, &compatible)) {
|
2019-08-23 18:27:13 +02:00
|
|
|
return false;
|
|
|
|
}
|
2019-09-10 21:58:29 +02:00
|
|
|
assert(compatible);
|
2019-08-23 18:20:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-08 15:32:38 +02:00
|
|
|
alloc.req = req;
|
|
|
|
alloc.planes_len = hwc_list_length(&display->planes);
|
2019-09-11 18:23:35 +02:00
|
|
|
|
|
|
|
data.alloc = malloc(alloc.planes_len * sizeof(*data.alloc));
|
2019-09-08 15:32:38 +02:00
|
|
|
alloc.best = malloc(alloc.planes_len * sizeof(*alloc.best));
|
2019-09-11 18:23:35 +02:00
|
|
|
if (data.alloc == NULL || alloc.best == NULL) {
|
2019-09-08 15:32:38 +02:00
|
|
|
perror("malloc");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* TODO: maybe start by allocating the primary plane on each output to
|
|
|
|
* make sure we can display at least something without hitting bandwidth
|
|
|
|
* issues? Also: be fair when mapping planes to outputs, don't give all
|
|
|
|
* planes to a single output. Also: don't treat each output separately,
|
|
|
|
* allocate planes for all outputs at once. */
|
2019-08-21 22:07:37 +02:00
|
|
|
hwc_list_for_each(output, &display->outputs, link) {
|
2019-09-08 15:32:38 +02:00
|
|
|
/* For each plane, try to find a layer. Don't do it the other
|
|
|
|
* way around (ie. for each layer, try to find a plane) because
|
|
|
|
* some drivers want user-space to enable the primary plane
|
|
|
|
* before any other plane. */
|
|
|
|
|
|
|
|
alloc.best_score = 0;
|
2019-09-08 16:39:55 +02:00
|
|
|
memset(alloc.best, 0, alloc.planes_len * sizeof(*alloc.best));
|
2019-09-11 18:23:35 +02:00
|
|
|
data.plane_link = display->planes.next;
|
|
|
|
data.plane_idx = 0;
|
|
|
|
data.score = 0;
|
|
|
|
if (!output_choose_layers(output, &alloc, &data)) {
|
2019-09-08 15:32:38 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(stderr, "Found plane allocation for output %p "
|
|
|
|
"with score=%d\n", (void *)output, alloc.best_score);
|
|
|
|
|
|
|
|
/* Apply the best allocation */
|
|
|
|
i = 0;
|
|
|
|
hwc_list_for_each(plane, &display->planes, link) {
|
|
|
|
layer = alloc.best[i];
|
|
|
|
i++;
|
|
|
|
if (layer == NULL) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(stderr, "Assigning layer %p to plane %d\n",
|
|
|
|
(void *)layer, plane->id);
|
2019-09-10 21:58:29 +02:00
|
|
|
if (!plane_apply(plane, layer, req, &compatible)) {
|
2019-08-23 18:27:13 +02:00
|
|
|
return false;
|
2019-08-21 22:07:37 +02:00
|
|
|
}
|
2019-09-10 21:58:29 +02:00
|
|
|
assert(compatible);
|
2019-09-08 15:32:38 +02:00
|
|
|
|
|
|
|
assert(plane->layer == NULL);
|
|
|
|
assert(layer->plane == NULL);
|
|
|
|
plane->layer = layer;
|
|
|
|
layer->plane = plane;
|
2019-08-21 22:07:37 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-11 18:23:35 +02:00
|
|
|
free(data.alloc);
|
2019-09-08 15:32:38 +02:00
|
|
|
free(alloc.best);
|
|
|
|
|
2019-08-21 22:07:37 +02:00
|
|
|
return true;
|
|
|
|
}
|