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>
main
Ville Syrjälä 2015-06-22 17:26:02 +01:00 committed by Emil Velikov
parent 5b0e76f143
commit ed44e0b958
4 changed files with 283 additions and 0 deletions

View File

@ -635,6 +635,13 @@ struct drm_get_cap {
*/
#define DRM_CLIENT_CAP_UNIVERSAL_PLANES 2
/**
* DRM_CLIENT_CAP_ATOMIC
*
* If set to 1, the DRM core will allow atomic modesetting requests.
*/
#define DRM_CLIENT_CAP_ATOMIC 3
/** DRM_IOCTL_SET_CLIENT_CAP ioctl argument type */
struct drm_set_client_cap {
__u64 capability;
@ -758,6 +765,7 @@ struct drm_prime_handle {
#define DRM_IOCTL_MODE_OBJ_GETPROPERTIES DRM_IOWR(0xB9, struct drm_mode_obj_get_properties)
#define DRM_IOCTL_MODE_OBJ_SETPROPERTY DRM_IOWR(0xBA, struct drm_mode_obj_set_property)
#define DRM_IOCTL_MODE_CURSOR2 DRM_IOWR(0xBB, struct drm_mode_cursor2)
#define DRM_IOCTL_MODE_ATOMIC DRM_IOWR(0xBC, struct drm_mode_atomic)
/**
* Device specific ioctls should only be in their respective headers

View File

@ -507,4 +507,20 @@ struct drm_mode_destroy_dumb {
__u32 handle;
};
/* page-flip flags are valid, plus: */
#define DRM_MODE_ATOMIC_TEST_ONLY 0x0100
#define DRM_MODE_ATOMIC_NONBLOCK 0x0200
#define DRM_MODE_ATOMIC_ALLOW_MODESET 0x0400
struct drm_mode_atomic {
__u32 flags;
__u32 count_objs;
__u64 objs_ptr;
__u64 count_props_ptr;
__u64 props_ptr;
__u64 prop_values_ptr;
__u64 reserved;
__u64 user_data;
};
#endif

View File

@ -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;
}

View File

@ -484,6 +484,25 @@ extern int drmModeObjectSetProperty(int fd, uint32_t object_id,
uint32_t object_type, uint32_t property_id,
uint64_t value);
typedef struct _drmModeAtomicReq drmModeAtomicReq, *drmModeAtomicReqPtr;
extern drmModeAtomicReqPtr drmModeAtomicAlloc(void);
extern drmModeAtomicReqPtr drmModeAtomicDuplicate(drmModeAtomicReqPtr req);
extern int drmModeAtomicMerge(drmModeAtomicReqPtr base,
drmModeAtomicReqPtr augment);
extern void drmModeAtomicFree(drmModeAtomicReqPtr req);
extern int drmModeAtomicGetCursor(drmModeAtomicReqPtr req);
extern void drmModeAtomicSetCursor(drmModeAtomicReqPtr req, int cursor);
extern int drmModeAtomicAddProperty(drmModeAtomicReqPtr req,
uint32_t object_id,
uint32_t property_id,
uint64_t value);
extern int drmModeAtomicCommit(int fd,
drmModeAtomicReqPtr req,
uint32_t flags,
void *user_data);
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif