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
parent
5b0e76f143
commit
ed44e0b958
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
240
xf86drmMode.c
240
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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue