summaryrefslogtreecommitdiff
path: root/overlay/x11
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2013-08-17 11:12:07 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2013-08-17 11:21:51 +0100
commitf9a50de3dcc501e930de6c60983a4feb57121e7e (patch)
treee2a65ef9a1ce5c15faf8e95e0337e821e2579ac7 /overlay/x11
parent7df9caeea1606b4f0272de35f0d7f70eedd5ec30 (diff)
Introduce intel-gpu-overlay
A realtime display of GPU activity. Note, this is just at the point of minimum usability... Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'overlay/x11')
-rw-r--r--overlay/x11/dri2.c169
-rw-r--r--overlay/x11/dri2.h1
-rw-r--r--overlay/x11/rgb2yuv.c105
-rw-r--r--overlay/x11/rgb2yuv.h7
-rw-r--r--overlay/x11/x11-overlay.c383
5 files changed, 665 insertions, 0 deletions
diff --git a/overlay/x11/dri2.c b/overlay/x11/dri2.c
new file mode 100644
index 00000000..0aa0cf53
--- /dev/null
+++ b/overlay/x11/dri2.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright © 2008 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Soft-
+ * ware"), to deal in the Software without restriction, including without
+ * limitation the rights to use, copy, modify, merge, publish, distribute,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, provided that the above copyright
+ * notice(s) and this permission notice appear in all copies of the Soft-
+ * ware and that both the above copyright notice(s) and this permission
+ * notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
+ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
+ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
+ * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
+ * MANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder shall
+ * not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization of
+ * the copyright holder.
+ *
+ * Authors:
+ * Kristian Høgsberg (krh@redhat.com)
+ */
+
+#include <stdio.h>
+#include <X11/Xlibint.h>
+#include <X11/extensions/Xext.h>
+#include <X11/extensions/extutil.h>
+#include <X11/extensions/dri2proto.h>
+#include <X11/extensions/dri2tokens.h>
+#include <xf86drm.h>
+#include <drm.h>
+#include <fcntl.h>
+
+#include "dri2.h"
+
+static char dri2ExtensionName[] = DRI2_NAME;
+static XExtensionInfo *dri2Info;
+static XEXT_GENERATE_CLOSE_DISPLAY (DRI2CloseDisplay, dri2Info)
+
+static /* const */ XExtensionHooks dri2ExtensionHooks = {
+ NULL, /* create_gc */
+ NULL, /* copy_gc */
+ NULL, /* flush_gc */
+ NULL, /* free_gc */
+ NULL, /* create_font */
+ NULL, /* free_font */
+ DRI2CloseDisplay, /* close_display */
+};
+
+static XEXT_GENERATE_FIND_DISPLAY (DRI2FindDisplay,
+ dri2Info,
+ dri2ExtensionName,
+ &dri2ExtensionHooks,
+ 0, NULL)
+
+static Bool
+DRI2Connect(Display *dpy, XID window, char **driverName, char **deviceName)
+{
+ XExtDisplayInfo *info = DRI2FindDisplay(dpy);
+ xDRI2ConnectReply rep;
+ xDRI2ConnectReq *req;
+
+ XextCheckExtension(dpy, info, dri2ExtensionName, False);
+
+ LockDisplay(dpy);
+ GetReq(DRI2Connect, req);
+ req->reqType = info->codes->major_opcode;
+ req->dri2ReqType = X_DRI2Connect;
+ req->window = window;
+ req->driverType = DRI2DriverDRI;
+ if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return False;
+ }
+
+ if (rep.driverNameLength == 0 && rep.deviceNameLength == 0) {
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return False;
+ }
+
+ *driverName = Xmalloc(rep.driverNameLength + 1);
+ if (*driverName == NULL) {
+ _XEatData(dpy,
+ ((rep.driverNameLength + 3) & ~3) +
+ ((rep.deviceNameLength + 3) & ~3));
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return False;
+ }
+ _XReadPad(dpy, *driverName, rep.driverNameLength);
+ (*driverName)[rep.driverNameLength] = '\0';
+
+ *deviceName = Xmalloc(rep.deviceNameLength + 1);
+ if (*deviceName == NULL) {
+ Xfree(*driverName);
+ _XEatData(dpy, ((rep.deviceNameLength + 3) & ~3));
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return False;
+ }
+ _XReadPad(dpy, *deviceName, rep.deviceNameLength);
+ (*deviceName)[rep.deviceNameLength] = '\0';
+
+ UnlockDisplay(dpy);
+ SyncHandle();
+
+ return True;
+}
+
+static Bool
+DRI2Authenticate(Display * dpy, XID window, unsigned int magic)
+{
+ XExtDisplayInfo *info = DRI2FindDisplay(dpy);
+ xDRI2AuthenticateReq *req;
+ xDRI2AuthenticateReply rep;
+
+ XextCheckExtension(dpy, info, dri2ExtensionName, False);
+
+ LockDisplay(dpy);
+ GetReq(DRI2Authenticate, req);
+ req->reqType = info->codes->major_opcode;
+ req->dri2ReqType = X_DRI2Authenticate;
+ req->window = window;
+ req->magic = magic;
+
+ if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return False;
+ }
+
+ UnlockDisplay(dpy);
+ SyncHandle();
+
+ return rep.authenticated;
+}
+
+int dri2_open(Display *dpy)
+{
+ drm_auth_t auth;
+ char *driver, *device;
+ int fd;
+
+ if (!DRI2Connect(dpy, DefaultRootWindow(dpy), &driver, &device))
+ return -1;
+
+ fd = open(device, O_RDWR);
+ if (fd < 0)
+ return -1;
+
+ if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth))
+ return -1;
+
+ if (!DRI2Authenticate(dpy, DefaultRootWindow(dpy), auth.magic))
+ return -1;
+
+ return fd;
+}
diff --git a/overlay/x11/dri2.h b/overlay/x11/dri2.h
new file mode 100644
index 00000000..cb66b469
--- /dev/null
+++ b/overlay/x11/dri2.h
@@ -0,0 +1 @@
+int dri2_open(Display *dpy);
diff --git a/overlay/x11/rgb2yuv.c b/overlay/x11/rgb2yuv.c
new file mode 100644
index 00000000..8e0c080e
--- /dev/null
+++ b/overlay/x11/rgb2yuv.c
@@ -0,0 +1,105 @@
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "rgb2yuv.h"
+
+static int RGB2YUV_YR[256], RGB2YUV_YG[256], RGB2YUV_YB[256];
+static int RGB2YUV_UR[256], RGB2YUV_UG[256], RGB2YUV_UBVR[256];
+static int RGB2YUV_VG[256], RGB2YUV_VB[256];
+
+void rgb2yuv_init(void)
+{
+ int i;
+
+ for (i = 0; i < 256; i++)
+ RGB2YUV_YR[i] = 65.481 * (i << 8);
+
+ for (i = 0; i < 256; i++)
+ RGB2YUV_YG[i] = 128.553 * (i << 8);
+
+ for (i = 0; i < 256; i++)
+ RGB2YUV_YB[i] = 24.966 * (i << 8);
+
+ for (i = 0; i < 256; i++)
+ RGB2YUV_UR[i] = 37.797 * (i << 8);
+
+ for (i = 0; i < 256; i++)
+ RGB2YUV_UG[i] = 74.203 * (i << 8);
+
+ for (i = 0; i < 256; i++)
+ RGB2YUV_VG[i] = 93.786 * (i << 8);
+
+ for (i = 0; i < 256; i++)
+ RGB2YUV_VB[i] = 18.214 * (i << 8);
+
+ for (i = 0; i < 256; i++)
+ RGB2YUV_UBVR[i] = 112 * (i << 8);
+}
+
+int rgb2yuv(cairo_surface_t *surface, XvImage *image, uint8_t *yuv)
+{
+ uint8_t *data = cairo_image_surface_get_data(surface);
+ int rgb_stride = cairo_image_surface_get_stride(surface);
+ int width = cairo_image_surface_get_width(surface);
+ int height = cairo_image_surface_get_height(surface);
+ int y_stride = image->pitches[0];
+ int uv_stride = image->pitches[1];
+ uint8_t *tmp, *tl, *tr, *bl, *br;
+ int i, j;
+
+ tmp = malloc(2*width*height);
+ if (tmp == NULL)
+ return 0;
+
+ tl = tmp;
+ bl = tmp + width*height;
+
+ for (i = 0; i < height; i++) {
+ uint16_t *rgb = (uint16_t *)(data + i * rgb_stride);
+ for (j = 0; j < width; j++) {
+ uint8_t r = (rgb[j] >> 11) & 0x1f;
+ uint8_t g = (rgb[j] >> 5) & 0x3f;
+ uint8_t b = (rgb[j] >> 0) & 0x1f;
+
+ r = r<<3 | r>>2;
+ g = g<<2 | g>>4;
+ b = b<<3 | b>>2;
+
+ yuv[j] = (RGB2YUV_YR[r] + RGB2YUV_YG[g] + RGB2YUV_YB[b] + 1048576) >> 16;
+ *tl++ = (-RGB2YUV_UR[r] - RGB2YUV_UG[g] + RGB2YUV_UBVR[b] + 8388608) >> 16;
+ *bl++ = (RGB2YUV_UBVR[r] - RGB2YUV_VG[g] - RGB2YUV_VB[b] + 8388608) >> 16;
+ }
+ yuv += y_stride;
+ }
+
+ tl = tmp; tr = tl + 1;
+ bl = tl + width; br = bl + 1;
+ for (i = 0; i < height/2; i ++) {
+ for (j = 0; j < width/2; j ++) {
+ yuv[j] = ((int)*tl + *tr + *bl + *br) >> 2;
+ tl += 2; tr += 2;
+ bl += 2; br += 2;
+ }
+ yuv += uv_stride;
+
+ tl += width; tr += width;
+ bl += width; br += width;
+ }
+
+ tl = tmp + width*height; tr = tl + 1;
+ bl = tl + width; br = bl + 1;
+ for (i = 0; i < height/2; i++) {
+ for (j = 0; j < width/2; j++) {
+ yuv[j] = ((int)*tl + *tr + *bl + *br) >> 2;
+ tl += 2; tr += 2;
+ bl += 2; br += 2;
+ }
+ yuv += uv_stride;
+
+ tl += width; tr += width;
+ bl += width; br += width;
+ }
+
+ free(tmp);
+ return 1;
+}
diff --git a/overlay/x11/rgb2yuv.h b/overlay/x11/rgb2yuv.h
new file mode 100644
index 00000000..835899c5
--- /dev/null
+++ b/overlay/x11/rgb2yuv.h
@@ -0,0 +1,7 @@
+#include <X11/Xlib.h>
+#include <X11/extensions/Xvlib.h>
+#include <cairo.h>
+#include <stdint.h>
+
+void rgb2yuv_init(void);
+int rgb2yuv(cairo_surface_t *rgb, XvImage *image, uint8_t *yuv);
diff --git a/overlay/x11/x11-overlay.c b/overlay/x11/x11-overlay.c
new file mode 100644
index 00000000..b9144087
--- /dev/null
+++ b/overlay/x11/x11-overlay.c
@@ -0,0 +1,383 @@
+#include <X11/Xlib.h>
+#include <X11/extensions/Xvlib.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <cairo.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <drm.h>
+#include <xf86drm.h>
+#include <i915_drm.h>
+#include "../overlay.h"
+#include "dri2.h"
+#include "rgb2yuv.h"
+
+#ifndef ALIGN
+#define ALIGN(i,m) (((i) + (m) - 1) & ~((m) - 1))
+#endif
+
+#define FOURCC_XVMC (('C' << 24) + ('M' << 16) + ('V' << 8) + 'X')
+#define FOURCC_RGB565 ((16 << 24) + ('B' << 16) + ('G' << 8) + 'R')
+#define FOURCC_RGB888 ((24 << 24) + ('B' << 16) + ('G' << 8) + 'R')
+
+struct x11_overlay {
+ struct overlay base;
+ Display *dpy;
+ GC gc;
+ XvPortID port;
+ XvImage *image;
+ void *map, *mem;
+ int size;
+ unsigned name;
+ int x, y;
+ int visible;
+};
+static inline struct x11_overlay *to_x11_overlay(struct overlay *o)
+{
+ return (struct x11_overlay *)o;
+}
+
+static int noop(Display *dpy, XErrorEvent *event)
+{
+ return 0;
+}
+
+static void x11_overlay_show(struct overlay *overlay)
+{
+ struct x11_overlay *priv = to_x11_overlay(overlay);
+
+ if (priv->image->id == FOURCC_XVMC)
+ rgb2yuv(priv->base.surface, priv->image, priv->map);
+ else
+ memcpy(priv->map, priv->mem, priv->size);
+
+ if (!priv->visible) {
+ XvPutImage(priv->dpy, priv->port, DefaultRootWindow(priv->dpy),
+ priv->gc, priv->image,
+ 0, 0,
+ priv->image->width, priv->image->height,
+ priv->x, priv->y,
+ priv->image->width, priv->image->height);
+ XFlush(priv->dpy);
+ priv->visible = true;
+ }
+}
+
+static void x11_overlay_position(struct overlay *overlay,
+ enum position p)
+{
+ struct x11_overlay *priv = to_x11_overlay(overlay);
+ Screen *scr = ScreenOfDisplay(priv->dpy, DefaultScreen(priv->dpy));
+
+ switch (p & 7) {
+ default:
+ case 0: priv->x = 0; break;
+ case 1: priv->x = (scr->width - priv->image->width)/2; break;
+ case 2: priv->x = scr->width - priv->image->width; break;
+ }
+
+ switch ((p >> 4) & 7) {
+ default:
+ case 0: priv->y = 0; break;
+ case 1: priv->y = (scr->height - priv->image->height)/2; break;
+ case 2: priv->y = scr->height - priv->image->height; break;
+ }
+
+ if (priv->visible) {
+ XvPutImage(priv->dpy, priv->port, DefaultRootWindow(priv->dpy),
+ priv->gc, priv->image,
+ 0, 0,
+ priv->image->width, priv->image->height,
+ priv->x, priv->y,
+ priv->image->width, priv->image->height);
+ XFlush(priv->dpy);
+ }
+}
+
+static void x11_overlay_hide(struct overlay *overlay)
+{
+ struct x11_overlay *priv = to_x11_overlay(overlay);
+ if (priv->visible) {
+ XClearWindow(priv->dpy, DefaultRootWindow(priv->dpy));
+ XFlush(priv->dpy);
+ priv->visible = false;
+ }
+}
+
+static void x11_overlay_destroy(void *data)
+{
+ struct x11_overlay *priv = data;
+ munmap(priv->map, priv->size);
+ free(priv->mem);
+ XCloseDisplay(priv->dpy);
+ free(priv);
+}
+
+cairo_surface_t *
+x11_overlay_create(enum position position, int max_width, int max_height)
+{
+ Display *dpy;
+ Screen *scr;
+ cairo_surface_t *surface;
+ struct drm_i915_gem_create create;
+ struct drm_gem_flink flink;
+ struct drm_i915_gem_mmap_gtt map;
+ struct x11_overlay *priv;
+ unsigned int count, i, j;
+ int fd, w, h;
+ XvAdaptorInfo *info;
+ XvImage *image;
+ XvPortID port = -1;
+ void *ptr, *mem;
+
+ dpy = XOpenDisplay(NULL);
+ if (dpy == NULL)
+ return NULL;
+
+ scr = ScreenOfDisplay(dpy, DefaultScreen(dpy));
+
+ fd = dri2_open(dpy);
+ if (fd < 0)
+ goto err_dpy;
+
+ if (XvQueryAdaptors(dpy, DefaultRootWindow(dpy), &count, &info) != Success)
+ goto err_fd;
+
+ for (i = 0; i < count; i++) {
+ unsigned long visual = 0;
+
+ if (info[i].num_ports != 1)
+ continue;
+
+ for (j = 0; j < info[j].num_formats; j++) {
+ if (info[i].formats[j].depth == 24) {
+ visual = info[i].formats[j].visual_id;
+ break;
+ }
+ }
+
+ if (visual == 0)
+ continue;
+
+ port = info[i].base_id;
+ }
+ XvFreeAdaptorInfo(info);
+ if (port == -1)
+ goto err_fd;
+
+ XSetErrorHandler(noop);
+
+ w = scr->width;
+ switch (position & 7) {
+ default:
+ case 0:
+ case 2: w >>= 1; break;
+ }
+ if (max_width > 0 && w > max_width)
+ w = max_width;
+
+ h = scr->height;
+ switch ((position >> 4) & 7) {
+ default:
+ case 0:
+ case 2: h >>= 1; break;
+ }
+ if (max_height > 0 && h > max_height)
+ h = max_height;
+
+ image = XvCreateImage(dpy, port, FOURCC_RGB565, NULL, w, h);
+ if (image == NULL)
+ image = XvCreateImage(dpy, port, FOURCC_RGB888, NULL, w, h);
+ if (image == NULL) {
+ image = XvCreateImage(dpy, port, FOURCC_XVMC, NULL, w, h);
+ if (image->pitches[0] == 4) {
+ image->pitches[0] = ALIGN(image->width, 1024);
+ image->pitches[1] = ALIGN(image->width/2, 1024);
+ image->pitches[2] = ALIGN(image->width/2, 1024);
+ image->offsets[0] = 0;
+ image->offsets[1] = image->pitches[0] * image->height;
+ image->offsets[2] = image->offsets[1] + image->pitches[1] * image->height/2;
+ }
+ rgb2yuv_init();
+ }
+ if (image == NULL)
+ goto err_fd;
+
+ switch (image->id) {
+ case FOURCC_RGB888:
+ case FOURCC_RGB565:
+ create.size = image->pitches[0] * image->height;
+ break;
+ case FOURCC_XVMC:
+ create.size = image->pitches[0] * image->height;
+ create.size += image->pitches[1] * image->height;
+ break;
+ }
+
+ create.handle = 0;
+ create.size = ALIGN(create.size, 4096);
+ drmIoctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create);
+ if (create.handle == 0)
+ goto err_image;
+
+ flink.handle = create.handle;
+ if (drmIoctl(fd, DRM_IOCTL_GEM_FLINK, &flink))
+ goto err_create;
+
+ map.handle = create.handle;
+ if (drmIoctl(fd, DRM_IOCTL_I915_GEM_MMAP_GTT, &map))
+ goto err_create;
+
+ ptr = mmap(0, create.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, map.offset);
+ if (ptr == (void *)-1)
+ goto err_create;
+
+ mem = malloc(create.size);
+ if (mem == NULL)
+ goto err_map;
+
+ switch (image->id) {
+ default:
+ case FOURCC_RGB888:
+ i = CAIRO_FORMAT_RGB24;
+ j = image->pitches[0];
+ break;
+ case FOURCC_RGB565:
+ i = CAIRO_FORMAT_RGB16_565;
+ j = image->pitches[0];
+ break;
+ case FOURCC_XVMC:
+ i = CAIRO_FORMAT_RGB16_565;
+ j = cairo_format_stride_for_width(i, image->width);
+ break;
+ }
+
+ surface = cairo_image_surface_create_for_data(mem, i, image->width, image->height, j);
+ if (cairo_surface_status(surface))
+ goto err_mem;
+
+ priv = malloc(sizeof(*priv));
+ if (priv == NULL)
+ goto err_surface;
+
+ priv->base.surface = surface;
+ priv->base.show = x11_overlay_show;
+ priv->base.position = x11_overlay_position;
+ priv->base.hide = x11_overlay_hide;
+
+ priv->dpy = dpy;
+ priv->gc = XCreateGC(dpy, DefaultRootWindow(dpy), 0, NULL);
+ priv->port = port;
+ priv->map = ptr;
+ priv->mem = mem;
+ priv->size = create.size;
+ priv->name = flink.name;
+ priv->visible = false;
+
+ switch (position & 7) {
+ default:
+ case 0: priv->x = 0; break;
+ case 1: priv->x = (scr->width - image->width)/2; break;
+ case 2: priv->x = scr->width - image->width; break;
+ }
+
+ switch ((position >> 4) & 7) {
+ default:
+ case 0: priv->y = 0; break;
+ case 1: priv->y = (scr->height - image->height)/2; break;
+ case 2: priv->y = scr->height - image->height; break;
+ }
+
+
+ priv->image = image;
+ priv->image->data = (void *)&priv->name;
+
+ cairo_surface_set_user_data(surface, &overlay_key, priv, x11_overlay_destroy);
+
+ XvSetPortAttribute(dpy, port, XInternAtom(dpy, "XV_ALWAYS_ON_TOP", True), 1);
+
+ close(fd);
+ return surface;
+
+err_surface:
+ cairo_surface_destroy(surface);
+err_mem:
+ free(mem);
+err_map:
+ munmap(ptr, create.size);
+err_create:
+ drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &create.handle);
+err_image:
+err_fd:
+ close(fd);
+err_dpy:
+ XCloseDisplay(dpy);
+ return NULL;
+}
+
+void x11_overlay_stop(void)
+{
+ Display *dpy;
+ unsigned int count, i, j;
+ XvAdaptorInfo *info;
+ XvImage *image;
+ XvPortID port = -1;
+ uint32_t name;
+
+ dpy = XOpenDisplay(NULL);
+ if (dpy == NULL)
+ return;
+
+ if (XvQueryAdaptors(dpy, DefaultRootWindow(dpy), &count, &info) != Success)
+ goto close;
+
+ for (i = 0; i < count; i++) {
+ unsigned long visual = 0;
+
+ if (info[i].num_ports != 1)
+ continue;
+
+ for (j = 0; j < info[j].num_formats; j++) {
+ if (info[i].formats[j].depth == 24) {
+ visual = info[i].formats[j].visual_id;
+ break;
+ }
+ }
+
+ if (visual == 0)
+ continue;
+
+ port = info[i].base_id;
+ }
+ XvFreeAdaptorInfo(info);
+ if (port == -1)
+ goto close;
+
+ XSetErrorHandler(noop);
+
+ image = XvCreateImage(dpy, port, FOURCC_RGB565, NULL, 16, 16);
+ if (image == NULL)
+ image = XvCreateImage(dpy, port, FOURCC_RGB888, NULL, 16, 16);
+ if (image == NULL)
+ image = XvCreateImage(dpy, port, FOURCC_XVMC, NULL, 16, 16);
+ if (image == NULL)
+ goto close;
+
+ name = 0;
+ image->data = (void *)&name;
+
+ XvPutImage(dpy, port, DefaultRootWindow(dpy),
+ XCreateGC(dpy, DefaultRootWindow(dpy), 0, NULL), image,
+ 0, 0,
+ 1, 1,
+ 0, 0,
+ 1, 1);
+ XSync(dpy, True);
+
+close:
+ XCloseDisplay(dpy);
+}