libliftoff/plane.c
Roman Gilg 138f2f2ac5
feat: add log format flags
With these flags API consumers can optimize the depiction of libliftoff's debug
log.

For now the two flags for a section start and end are introduced. It is
guaranteed that one section always ends before the next one begins.

Is no callback function setup section starts and ends in the default stderr
output will be marked with an empty line.

BREAKING CHANGE: The signature of the log callback changes.
2020-03-10 11:59:42 +01:00

267 lines
6.6 KiB
C

#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include "private.h"
static int guess_plane_zpos_from_type(struct liftoff_device *device,
uint32_t plane_id, uint32_t type)
{
struct liftoff_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 (liftoff_list_empty(&device->planes)) {
return 0; /* No primary plane, shouldn't happen */
}
primary = liftoff_container_of(device->planes.next,
primary, link);
if (plane_id < primary->id) {
return -1;
} else {
return 1;
}
}
return 0;
}
static void log_plane(struct liftoff_device *device,
struct liftoff_plane *plane)
{
size_t i;
int per_line = 0;
if (!log_has(LIFTOFF_DEBUG)) {
return;
}
debug_cnt(device, " type: ");
if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
debug_cnt(device, "Primary");
} else if (plane->type == DRM_PLANE_TYPE_CURSOR) {
debug_cnt(device, "Cursor");
} else {
debug_cnt(device, "Overlay");
}
debug_end(device, 0);
liftoff_log(LIFTOFF_DEBUG, " zpos: %"PRIu32, plane->zpos);
debug_cnt(device, " props:");
for (i = 0; i < plane->props_len; i++) {
if (per_line == 5) {
debug_end(device, 0);
debug_cnt(device, " ");
per_line = 0;
}
debug_cnt(device, " %s", plane->props[i].name);
per_line++;
}
debug_end(device, 0);
}
struct liftoff_plane *plane_create(struct liftoff_device *device, uint32_t id)
{
struct liftoff_plane *plane, *cur;
drmModePlane *drm_plane;
drmModeObjectProperties *drm_props;
uint32_t i;
drmModePropertyRes *drm_prop;
struct liftoff_plane_property *prop;
uint64_t value;
bool has_type = false, has_zpos = false;
debug_cnt(device, "Plane %"PRIu32, id);
debug_end(device, 0);
plane = calloc(1, sizeof(*plane));
if (plane == NULL) {
liftoff_log_errno(LIFTOFF_ERROR, "calloc");
return NULL;
}
drm_plane = drmModeGetPlane(device->drm_fd, id);
if (drm_plane == NULL) {
liftoff_log_errno(LIFTOFF_ERROR, "drmModeGetPlane");
return NULL;
}
plane->id = drm_plane->plane_id;
plane->possible_crtcs = drm_plane->possible_crtcs;
drmModeFreePlane(drm_plane);
drm_props = drmModeObjectGetProperties(device->drm_fd, id,
DRM_MODE_OBJECT_PLANE);
if (drm_props == NULL) {
liftoff_log_errno(LIFTOFF_ERROR, "drmModeObjectGetProperties");
return NULL;
}
plane->props = calloc(drm_props->count_props,
sizeof(struct liftoff_plane_property));
if (plane->props == NULL) {
liftoff_log_errno(LIFTOFF_ERROR, "calloc");
drmModeFreeObjectProperties(drm_props);
return NULL;
}
for (i = 0; i < drm_props->count_props; i++) {
drm_prop = drmModeGetProperty(device->drm_fd,
drm_props->props[i]);
if (drm_prop == NULL) {
liftoff_log_errno(LIFTOFF_ERROR, "drmModeGetProperty");
drmModeFreeObjectProperties(drm_props);
return NULL;
}
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++;
value = drm_props->prop_values[i];
if (strcmp(prop->name, "type") == 0) {
plane->type = value;
has_type = true;
} else if (strcmp(prop->name, "zpos") == 0) {
plane->zpos = value;
has_zpos = true;
}
}
drmModeFreeObjectProperties(drm_props);
if (!has_type) {
liftoff_log(LIFTOFF_ERROR,
"plane %"PRIu32" is missing the 'type' property",
plane->id);
free(plane);
return NULL;
} else if (!has_zpos) {
plane->zpos = guess_plane_zpos_from_type(device, 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) {
liftoff_list_insert(&device->planes, &plane->link);
} else {
liftoff_list_for_each(cur, &device->planes, link) {
if (cur->type != DRM_PLANE_TYPE_PRIMARY &&
plane->zpos >= cur->zpos) {
liftoff_list_insert(cur->link.prev, &plane->link);
break;
}
}
if (plane->link.next == NULL) { /* not inserted */
liftoff_list_insert(device->planes.prev, &plane->link);
}
}
log_plane(device, plane);
return plane;
}
void plane_destroy(struct liftoff_plane *plane)
{
if (plane->layer != NULL) {
plane->layer->plane = NULL;
}
liftoff_list_remove(&plane->link);
free(plane->props);
free(plane);
}
struct liftoff_plane_property *plane_get_property(struct liftoff_plane *plane,
const char *name)
{
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;
}
static bool plane_set_prop(struct liftoff_plane *plane, drmModeAtomicReq *req,
struct liftoff_plane_property *prop, uint64_t value)
{
int ret;
ret = drmModeAtomicAddProperty(req, plane->id, prop->id, value);
if (ret < 0) {
liftoff_log_errno(LIFTOFF_ERROR, "drmModeAtomicAddProperty");
return false;
}
return true;
}
static bool set_plane_prop_str(struct liftoff_plane *plane,
drmModeAtomicReq *req, const char *name,
uint64_t value)
{
struct liftoff_plane_property *prop;
prop = plane_get_property(plane, name);
if (prop == NULL) {
liftoff_log(LIFTOFF_DEBUG,
"plane %"PRIu32" is missing the %s property",
plane->id, name);
return false;
}
return plane_set_prop(plane, req, prop, value);
}
bool plane_apply(struct liftoff_plane *plane, struct liftoff_layer *layer,
drmModeAtomicReq *req, bool *compatible)
{
int cursor;
size_t i;
struct liftoff_layer_property *layer_prop;
struct liftoff_plane_property *plane_prop;
*compatible = true;
cursor = drmModeAtomicGetCursor(req);
if (layer == NULL) {
return set_plane_prop_str(plane, req, "FB_ID", 0) &&
set_plane_prop_str(plane, req, "CRTC_ID", 0);
}
if (!set_plane_prop_str(plane, req, "CRTC_ID", layer->output->crtc_id)) {
return false;
}
for (i = 0; i < layer->props_len; i++) {
layer_prop = &layer->props[i];
if (strcmp(layer_prop->name, "zpos") == 0) {
/* We don't yet support setting the zpos property. We
* only use it (read-only) during plane allocation. */
continue;
}
plane_prop = plane_get_property(plane, layer_prop->name);
if (plane_prop == NULL) {
*compatible = false;
drmModeAtomicSetCursor(req, cursor);
return true;
}
if (!plane_set_prop(plane, req, plane_prop, layer_prop->value)) {
drmModeAtomicSetCursor(req, cursor);
return false;
}
}
return true;
}