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
|
#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 */
|
/** DRM_IOCTL_SET_CLIENT_CAP ioctl argument type */
|
||||||
struct drm_set_client_cap {
|
struct drm_set_client_cap {
|
||||||
__u64 capability;
|
__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_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_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_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
|
* Device specific ioctls should only be in their respective headers
|
||||||
|
|
|
@ -507,4 +507,20 @@ struct drm_mode_destroy_dumb {
|
||||||
__u32 handle;
|
__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
|
#endif
|
||||||
|
|
240
xf86drmMode.c
240
xf86drmMode.c
|
@ -37,9 +37,12 @@
|
||||||
* TODO the types we are after are defined in diffrent headers on diffrent
|
* TODO the types we are after are defined in diffrent headers on diffrent
|
||||||
* platforms find which headers to include to get uint32_t
|
* platforms find which headers to include to get uint32_t
|
||||||
*/
|
*/
|
||||||
|
#include <limits.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "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);
|
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,
|
uint32_t object_type, uint32_t property_id,
|
||||||
uint64_t value);
|
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)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue