Add support for vblank events
The kernel will now write data to the DRM fd for various event types if requested. Currently, the only supported event is a vblank event: it contains the vblank count for the event as well as a timestamp from when the event ocurred. Since the DRM fd is now pollable, it's easy to integrate into existing event loops.main
parent
0d7ad7e43c
commit
b0b96636db
|
@ -271,6 +271,7 @@ typedef struct _drmTextureRegion {
|
||||||
typedef enum {
|
typedef enum {
|
||||||
DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */
|
DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */
|
||||||
DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */
|
DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */
|
||||||
|
DRM_VBLANK_EVENT = 0x4000000, /**< Send event instead of blocking */
|
||||||
DRM_VBLANK_FLIP = 0x8000000, /**< Scheduled buffer swap should flip */
|
DRM_VBLANK_FLIP = 0x8000000, /**< Scheduled buffer swap should flip */
|
||||||
DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */
|
DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */
|
||||||
DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */
|
DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */
|
||||||
|
@ -667,4 +668,22 @@ extern void drmMsg(const char *format, ...);
|
||||||
extern int drmSetMaster(int fd);
|
extern int drmSetMaster(int fd);
|
||||||
extern int drmDropMaster(int fd);
|
extern int drmDropMaster(int fd);
|
||||||
|
|
||||||
|
#define DRM_EVENT_CONTEXT_VERSION 1
|
||||||
|
|
||||||
|
typedef struct _drmEventContext {
|
||||||
|
|
||||||
|
/* This struct is versioned so we can add more pointers if we
|
||||||
|
* add more events. */
|
||||||
|
int version;
|
||||||
|
|
||||||
|
void (*vblank_handler)(int fd,
|
||||||
|
unsigned int sequence,
|
||||||
|
unsigned int tv_sec,
|
||||||
|
unsigned int tv_usec,
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
|
} drmEventContext, *drmEventContextPtr;
|
||||||
|
|
||||||
|
extern int drmHandleEvent(int fd, drmEventContextPtr evctx);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
#include <drm.h>
|
#include <drm.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#define U642VOID(x) ((void *)(unsigned long)(x))
|
#define U642VOID(x) ((void *)(unsigned long)(x))
|
||||||
|
@ -667,3 +668,45 @@ int drmModeCrtcSetGamma(int fd, uint32_t crtc_id, uint32_t size,
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int drmHandleEvent(int fd, drmEventContextPtr evctx)
|
||||||
|
{
|
||||||
|
char buffer[1024];
|
||||||
|
int len, i;
|
||||||
|
struct drm_event *e;
|
||||||
|
struct drm_event_vblank *vblank;
|
||||||
|
|
||||||
|
/* The DRM read semantics guarantees that we always get only
|
||||||
|
* complete events. */
|
||||||
|
|
||||||
|
len = read(fd, buffer, sizeof buffer);
|
||||||
|
if (len == 0)
|
||||||
|
return 0;
|
||||||
|
if (len < sizeof *e)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (i < len) {
|
||||||
|
e = (struct drm_event *) &buffer[i];
|
||||||
|
switch (e->type) {
|
||||||
|
case DRM_EVENT_VBLANK:
|
||||||
|
if (evctx->version < 1 ||
|
||||||
|
evctx->vblank_handler == NULL)
|
||||||
|
break;
|
||||||
|
vblank = (struct drm_event_vblank *) e;
|
||||||
|
evctx->vblank_handler(fd,
|
||||||
|
vblank->sequence,
|
||||||
|
vblank->tv_sec,
|
||||||
|
vblank->tv_usec,
|
||||||
|
U642VOID (vblank->user_data));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i += e->length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -809,6 +809,34 @@ struct drm_gem_open {
|
||||||
#define DRM_COMMAND_BASE 0x40
|
#define DRM_COMMAND_BASE 0x40
|
||||||
#define DRM_COMMAND_END 0xA0
|
#define DRM_COMMAND_END 0xA0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Header for events written back to userspace on the drm fd. The
|
||||||
|
* type defines the type of event, the length specifies the total
|
||||||
|
* length of the event (including the header), and user_data is
|
||||||
|
* typically a 64 bit value passed with the ioctl that triggered the
|
||||||
|
* event. A read on the drm fd will always only return complete
|
||||||
|
* events, that is, if for example the read buffer is 100 bytes, and
|
||||||
|
* there are two 64 byte events pending, only one will be returned.
|
||||||
|
*
|
||||||
|
* Event types 0 - 0x7fffffff are generic drm events, 0x80000000 and
|
||||||
|
* up are chipset specific.
|
||||||
|
*/
|
||||||
|
struct drm_event {
|
||||||
|
uint32_t type;
|
||||||
|
uint32_t length;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DRM_EVENT_VBLANK 0x01
|
||||||
|
|
||||||
|
struct drm_event_vblank {
|
||||||
|
struct drm_event base;
|
||||||
|
uint64_t user_data;
|
||||||
|
uint32_t tv_sec;
|
||||||
|
uint32_t tv_usec;
|
||||||
|
uint32_t sequence;
|
||||||
|
uint32_t reserved;
|
||||||
|
};
|
||||||
|
|
||||||
/* typedef area */
|
/* typedef area */
|
||||||
#ifndef __KERNEL__
|
#ifndef __KERNEL__
|
||||||
typedef struct drm_clip_rect drm_clip_rect_t;
|
typedef struct drm_clip_rect drm_clip_rect_t;
|
||||||
|
|
Loading…
Reference in New Issue