diff options
author | Ville Syrjälä <ville.syrjala@linux.intel.com> | 2015-06-22 17:26:02 +0100 |
---|---|---|
committer | Emil Velikov <emil.l.velikov@gmail.com> | 2015-06-29 19:01:19 +0100 |
commit | ed44e0b9585c563905447eceed12af9c1c7ca8d4 (patch) | |
tree | 99c759a7b1e2e24875ec32bef4d45115c891ea40 /xf86drmMode.c | |
parent | 5b0e76f143887c4ec7db45c54a7ba27a58f59227 (diff) |
Support atomic modesetting ioctl
Add support for the atomic modesetting ioctl through a property-set API.
v1: Squashed intermediate patches from Ville, Rob and myself. Updated
for current kernel interface (no blobs).
v2: Rewrite user-facing API to provide transactional/cursor interface.
Use memclear to zero out ioctl.
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Rob Clark <robclark@freedesktop.org>
Signed-off-by: Daniel Stone <daniels@collabora.com>
v3 [Emil Velikov]: Remove DRM_CAP_ATOMIC - superseded by
DRM_CLIENT_CAP_ATOMIC.
Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
Diffstat (limited to 'xf86drmMode.c')
-rw-r--r-- | xf86drmMode.c | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/xf86drmMode.c b/xf86drmMode.c index 1333da48..a75eca33 100644 --- a/xf86drmMode.c +++ b/xf86drmMode.c @@ -37,9 +37,12 @@ * TODO the types we are after are defined in diffrent headers on diffrent * platforms find which headers to include to get uint32_t */ +#include <limits.h> #include <stdint.h> +#include <stdlib.h> #include <sys/ioctl.h> #include <stdio.h> +#include <stdbool.h> #ifdef HAVE_CONFIG_H #include "config.h" @@ -1147,3 +1150,240 @@ int drmModeObjectSetProperty(int fd, uint32_t object_id, uint32_t object_type, return DRM_IOCTL(fd, DRM_IOCTL_MODE_OBJ_SETPROPERTY, &prop); } + +typedef struct _drmModeAtomicReqItem drmModeAtomicReqItem, *drmModeAtomicReqItemPtr; + +struct _drmModeAtomicReqItem { + uint32_t object_id; + uint32_t property_id; + uint64_t value; +}; + +struct _drmModeAtomicReq { + uint32_t cursor; + uint32_t size_items; + drmModeAtomicReqItemPtr items; +}; + +drmModeAtomicReqPtr drmModeAtomicAlloc(void) +{ + drmModeAtomicReqPtr req; + + req = drmMalloc(sizeof *req); + if (!req) + return NULL; + + req->items = NULL; + req->cursor = 0; + req->size_items = 0; + + return req; +} + +drmModeAtomicReqPtr drmModeAtomicDuplicate(drmModeAtomicReqPtr old) +{ + drmModeAtomicReqPtr new; + + new = drmMalloc(sizeof *new); + if (!new) + return NULL; + + new->cursor = old->cursor; + new->size_items = old->size_items; + + if (old->size_items) { + new->items = drmMalloc(old->size_items * sizeof(*new->items)); + if (!new->items) { + free(new); + return NULL; + } + memcpy(new->items, old->items, + old->size_items * sizeof(*new->items)); + } else { + new->items = NULL; + } + + return new; +} + +int drmModeAtomicMerge(drmModeAtomicReqPtr base, drmModeAtomicReqPtr augment) +{ + if (!augment || augment->cursor == 0) + return 0; + + if (base->cursor + augment->cursor >= base->size_items) { + drmModeAtomicReqItemPtr new; + int saved_size = base->size_items; + + base->size_items = base->cursor + augment->cursor; + new = realloc(base->items, + base->size_items * sizeof(*base->items)); + if (!new) { + base->size_items = saved_size; + return -ENOMEM; + } + base->items = new; + } + + memcpy(&base->items[base->cursor], augment->items, + augment->cursor * sizeof(*augment->items)); + base->cursor += augment->cursor; + + return 0; +} + +int drmModeAtomicGetCursor(drmModeAtomicReqPtr req) +{ + return req->cursor; +} + +void drmModeAtomicSetCursor(drmModeAtomicReqPtr req, int cursor) +{ + req->cursor = cursor; +} + +int drmModeAtomicAddProperty(drmModeAtomicReqPtr req, + uint32_t object_id, + uint32_t property_id, + uint64_t value) +{ + if (req->cursor >= req->size_items) { + drmModeAtomicReqItemPtr new; + + req->size_items += 16; + new = realloc(req->items, req->size_items * sizeof(*req->items)); + if (!new) { + req->size_items -= 16; + return -ENOMEM; + } + req->items = new; + } + + req->items[req->cursor].object_id = object_id; + req->items[req->cursor].property_id = property_id; + req->items[req->cursor].value = value; + req->cursor++; + + return req->cursor; +} + +void drmModeAtomicFree(drmModeAtomicReqPtr req) +{ + if (!req) + return; + + if (req->items) + drmFree(req->items); + drmFree(req); +} + +static int sort_req_list(const void *misc, const void *other) +{ + const drmModeAtomicReqItem *first = misc; + const drmModeAtomicReqItem *second = other; + + if (first->object_id < second->object_id) + return -1; + else if (first->object_id > second->object_id) + return 1; + else + return second->property_id - first->property_id; +} + +int drmModeAtomicCommit(int fd, drmModeAtomicReqPtr req, uint32_t flags, + void *user_data) +{ + drmModeAtomicReqPtr sorted = drmModeAtomicDuplicate(req); + struct drm_mode_atomic atomic; + uint32_t *objs_ptr = NULL; + uint32_t *count_props_ptr = NULL; + uint32_t *props_ptr = NULL; + uint64_t *prop_values_ptr = NULL; + uint32_t last_obj_id = 0; + uint32_t i; + int obj_idx = -1; + int ret = -1; + + if (!sorted) + return -ENOMEM; + + memclear(atomic); + + /* Sort the list by object ID, then by property ID. */ + qsort(sorted->items, sorted->cursor, sizeof(*sorted->items), + sort_req_list); + + /* Now the list is sorted, eliminate duplicate property sets. */ + for (i = 0; i < sorted->cursor; i++) { + if (sorted->items[i].object_id != last_obj_id) { + atomic.count_objs++; + last_obj_id = sorted->items[i].object_id; + } + + if (i == sorted->cursor - 1) + continue; + + if (sorted->items[i].object_id != sorted->items[i + 1].object_id || + sorted->items[i].property_id != sorted->items[i + 1].property_id) + continue; + + memmove(&sorted->items[i], &sorted->items[i + 1], + (sorted->cursor - i - 1) * sizeof(*sorted->items)); + sorted->cursor--; + } + + objs_ptr = drmMalloc(atomic.count_objs * sizeof objs_ptr[0]); + if (!objs_ptr) { + errno = ENOMEM; + goto out; + } + + count_props_ptr = drmMalloc(atomic.count_objs * sizeof count_props_ptr[0]); + if (!count_props_ptr) { + errno = ENOMEM; + goto out; + } + + props_ptr = drmMalloc(sorted->cursor * sizeof props_ptr[0]); + if (!props_ptr) { + errno = ENOMEM; + goto out; + } + + prop_values_ptr = drmMalloc(sorted->cursor * sizeof prop_values_ptr[0]); + if (!prop_values_ptr) { + errno = ENOMEM; + goto out; + } + + for (i = 0, last_obj_id = 0; i < sorted->cursor; i++) { + if (sorted->items[i].object_id != last_obj_id) { + obj_idx++; + objs_ptr[obj_idx] = sorted->items[i].object_id; + last_obj_id = objs_ptr[obj_idx]; + } + + count_props_ptr[obj_idx]++; + props_ptr[i] = sorted->items[i].property_id; + prop_values_ptr[i] = sorted->items[i].value; + + } + + atomic.flags = flags; + atomic.objs_ptr = VOID2U64(objs_ptr); + atomic.count_props_ptr = VOID2U64(count_props_ptr); + atomic.props_ptr = VOID2U64(props_ptr); + atomic.prop_values_ptr = VOID2U64(prop_values_ptr); + atomic.user_data = VOID2U64(user_data); + + ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_ATOMIC, &atomic); + +out: + drmFree(objs_ptr); + drmFree(count_props_ptr); + drmFree(props_ptr); + drmFree(prop_values_ptr); + drmModeAtomicFree(sorted); + + return ret; +} |