142542f5fSchristos/*
242542f5fSchristos * Copyright (c) 2014 Intel Corporation
342542f5fSchristos *
442542f5fSchristos * Permission is hereby granted, free of charge, to any person obtaining a
542542f5fSchristos * copy of this software and associated documentation files (the "Software"),
642542f5fSchristos * to deal in the Software without restriction, including without limitation
742542f5fSchristos * the rights to use, copy, modify, merge, publish, distribute, sublicense,
842542f5fSchristos * and/or sell copies of the Software, and to permit persons to whom the
942542f5fSchristos * Software is furnished to do so, subject to the following conditions:
1042542f5fSchristos *
1142542f5fSchristos * The above copyright notice and this permission notice (including the next
1242542f5fSchristos * paragraph) shall be included in all copies or substantial portions of the
1342542f5fSchristos * Software.
1442542f5fSchristos *
1542542f5fSchristos * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1642542f5fSchristos * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1742542f5fSchristos * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1842542f5fSchristos * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1942542f5fSchristos * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2042542f5fSchristos * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2142542f5fSchristos * SOFTWARE.
2242542f5fSchristos *
2342542f5fSchristos */
2442542f5fSchristos
2542542f5fSchristos#include <X11/Xlib.h>
2642542f5fSchristos#include <X11/Xlib-xcb.h>
2742542f5fSchristos#include <X11/xshmfence.h>
2842542f5fSchristos#include <xcb/xcb.h>
2942542f5fSchristos#include <xcb/dri3.h>
3042542f5fSchristos#include <xcb/sync.h>
3142542f5fSchristos#include <unistd.h>
32fe8aea9eSmrg#include <stdlib.h>
3342542f5fSchristos
3442542f5fSchristos#include "dri3.h"
3542542f5fSchristos
3642542f5fSchristosPixmap dri3_create_pixmap(Display *dpy,
3742542f5fSchristos			  Drawable draw,
3842542f5fSchristos			  int width, int height, int depth,
3942542f5fSchristos			  int fd, int bpp, int stride, int size)
4042542f5fSchristos{
4142542f5fSchristos	xcb_connection_t *c = XGetXCBConnection(dpy);
4242542f5fSchristos	if (fd >= 0) {
4342542f5fSchristos		xcb_pixmap_t pixmap = xcb_generate_id(c);
4442542f5fSchristos		xcb_dri3_pixmap_from_buffer(c, pixmap, draw, size, width, height, stride, depth, bpp, fd);
4542542f5fSchristos		return pixmap;
4642542f5fSchristos	}
4742542f5fSchristos	return 0;
4842542f5fSchristos}
4942542f5fSchristos
5042542f5fSchristosint dri3_create_fd(Display *dpy,
5142542f5fSchristos		   Pixmap pixmap,
5242542f5fSchristos		   int *stride)
5342542f5fSchristos{
5442542f5fSchristos	xcb_connection_t *c = XGetXCBConnection(dpy);
5542542f5fSchristos	xcb_dri3_buffer_from_pixmap_cookie_t cookie;
5642542f5fSchristos	xcb_dri3_buffer_from_pixmap_reply_t *reply;
5742542f5fSchristos
5842542f5fSchristos	cookie = xcb_dri3_buffer_from_pixmap(c, pixmap);
5942542f5fSchristos	reply = xcb_dri3_buffer_from_pixmap_reply(c, cookie, NULL);
6042542f5fSchristos	if (!reply)
6142542f5fSchristos		return -1;
6242542f5fSchristos
6342542f5fSchristos	if (reply->nfd != 1)
6442542f5fSchristos		return -1;
6542542f5fSchristos
6642542f5fSchristos	*stride = reply->stride;
6742542f5fSchristos	return xcb_dri3_buffer_from_pixmap_reply_fds(c, reply)[0];
6842542f5fSchristos}
6942542f5fSchristos
7042542f5fSchristosint dri3_create_fence(Display *dpy, Pixmap pixmap, struct dri3_fence *fence)
7142542f5fSchristos{
7242542f5fSchristos	xcb_connection_t *c = XGetXCBConnection(dpy);
7342542f5fSchristos	struct dri3_fence f;
7442542f5fSchristos	int fd;
7542542f5fSchristos
7642542f5fSchristos	fd = xshmfence_alloc_shm();
7742542f5fSchristos	if (fd < 0)
7842542f5fSchristos		return -1;
7942542f5fSchristos
8042542f5fSchristos	f.addr = xshmfence_map_shm(fd);
8142542f5fSchristos	if (f.addr == NULL) {
8242542f5fSchristos		close(fd);
8342542f5fSchristos		return -1;
8442542f5fSchristos	}
8542542f5fSchristos
8642542f5fSchristos	f.xid = xcb_generate_id(c);
8742542f5fSchristos	xcb_dri3_fence_from_fd(c, pixmap, f.xid, 0, fd);
8842542f5fSchristos
8942542f5fSchristos	*fence = f;
9042542f5fSchristos	return 0;
9142542f5fSchristos}
9242542f5fSchristos
9342542f5fSchristosvoid dri3_fence_sync(Display *dpy, struct dri3_fence *fence)
9442542f5fSchristos{
9542542f5fSchristos	xcb_connection_t *c = XGetXCBConnection(dpy);
9642542f5fSchristos
9742542f5fSchristos	xshmfence_reset(fence->addr);
9842542f5fSchristos
9942542f5fSchristos	xcb_sync_trigger_fence(c, fence->xid);
10042542f5fSchristos	xcb_flush(c);
10142542f5fSchristos
10242542f5fSchristos	xshmfence_await(fence->addr);
10342542f5fSchristos}
10442542f5fSchristos
10542542f5fSchristosvoid dri3_fence_free(Display *dpy, struct dri3_fence *fence)
10642542f5fSchristos{
10742542f5fSchristos	xcb_connection_t *c = XGetXCBConnection(dpy);
10842542f5fSchristos
10942542f5fSchristos	xshmfence_unmap_shm(fence->addr);
11042542f5fSchristos	xcb_sync_destroy_fence(c, fence->xid);
11142542f5fSchristos}
11242542f5fSchristos
113fe8aea9eSmrgstatic void dri3_query_version(xcb_connection_t *c, int *major, int *minor)
114fe8aea9eSmrg{
115fe8aea9eSmrg	xcb_dri3_query_version_reply_t *reply;
116fe8aea9eSmrg
117fe8aea9eSmrg	reply = xcb_dri3_query_version_reply(c,
118fe8aea9eSmrg					     xcb_dri3_query_version(c,
119fe8aea9eSmrg								    XCB_DRI3_MAJOR_VERSION,
120fe8aea9eSmrg								    XCB_DRI3_MINOR_VERSION),
121fe8aea9eSmrg					     NULL);
122fe8aea9eSmrg	if (reply != NULL) {
123fe8aea9eSmrg		*major = reply->major_version;
124fe8aea9eSmrg		*minor = reply->minor_version;
125fe8aea9eSmrg		free(reply);
126fe8aea9eSmrg	}
127fe8aea9eSmrg}
128fe8aea9eSmrg
129fe8aea9eSmrgstatic int dri3_exists(xcb_connection_t *c)
130fe8aea9eSmrg{
131fe8aea9eSmrg	const xcb_query_extension_reply_t *ext;
132fe8aea9eSmrg	int major, minor;
133fe8aea9eSmrg
134fe8aea9eSmrg	major = minor = -1;
135fe8aea9eSmrg
136fe8aea9eSmrg	ext = xcb_get_extension_data(c, &xcb_dri3_id);
137fe8aea9eSmrg	if (ext != NULL && ext->present)
138fe8aea9eSmrg		dri3_query_version(c, &major, &minor);
139fe8aea9eSmrg
140fe8aea9eSmrg	return major >= 0;
141fe8aea9eSmrg}
142fe8aea9eSmrg
14342542f5fSchristosint dri3_open__full(Display *dpy, Window root, unsigned provider)
14442542f5fSchristos{
14542542f5fSchristos	xcb_connection_t *c = XGetXCBConnection(dpy);
14642542f5fSchristos	xcb_dri3_open_cookie_t cookie;
14742542f5fSchristos	xcb_dri3_open_reply_t *reply;
14842542f5fSchristos
149fe8aea9eSmrg	if (!dri3_exists(c))
150fe8aea9eSmrg		return -1;
151fe8aea9eSmrg
15242542f5fSchristos	cookie = xcb_dri3_open(c, root, provider);
15342542f5fSchristos	reply = xcb_dri3_open_reply(c, cookie, NULL);
15442542f5fSchristos
15542542f5fSchristos	if (!reply)
15642542f5fSchristos		return -1;
15742542f5fSchristos
15842542f5fSchristos	if (reply->nfd != 1)
15942542f5fSchristos		return -1;
16042542f5fSchristos
16142542f5fSchristos	return xcb_dri3_open_reply_fds(c, reply)[0];
16242542f5fSchristos}
16342542f5fSchristos
16442542f5fSchristosint dri3_open(Display *dpy)
16542542f5fSchristos{
16642542f5fSchristos	return dri3_open__full(dpy, RootWindow(dpy, DefaultScreen(dpy)), None);
16742542f5fSchristos}
168