glx-multithread-texture: Avoid front-buffer rendering.
[piglit.git] / tests / util / piglit-framework-gl / piglit_drm_dma_buf.c
blob135567f365a2142b0a1b2a2fe4aaaef17fcb5108
1 /*
2 * Copyright © 2013 Intel Corporation
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
24 #include "piglit-util-gl.h"
25 #include "piglit_drm_dma_buf.h"
26 #include "drm_fourcc.h"
27 #ifdef PIGLIT_HAS_GBM_BO_MAP
28 #include <gbm.h>
29 #endif
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #include <string.h>
34 #include <xf86drm.h>
35 #include <stdbool.h>
36 #include <xcb/dri2.h>
37 #include <drm.h>
38 #include <unistd.h>
40 #define ALIGN(value, alignment) (((value) + alignment - 1) & ~(alignment - 1))
42 struct piglit_drm_driver {
43 int fd;
44 char *name;
46 bool
47 (*create)(unsigned w, unsigned h, unsigned cpp,
48 const unsigned char *src_data,
49 struct piglit_dma_buf *buf);
51 bool
52 (*export)(struct piglit_dma_buf *buf);
54 void
55 (*destroy)(struct piglit_dma_buf *buf);
58 static const struct piglit_drm_driver *piglit_drm_get_driver(void);
60 static bool
61 piglit_drm_x11_authenticate(int fd)
63 drm_magic_t magic;
64 xcb_connection_t *conn;
65 int screen;
66 const xcb_setup_t *setup;
67 xcb_screen_iterator_t screen_iter;
68 xcb_dri2_authenticate_cookie_t auth_cookie;
69 xcb_dri2_authenticate_reply_t *auth_reply;
70 int ret = 0;
72 conn = xcb_connect(NULL, &screen);
73 if (!conn) {
74 printf("piglit: failed to connect to X server for DRI2 "
75 "authentication\n");
76 return false;
79 ret = drmGetMagic(fd, &magic);
80 if (ret) {
81 printf("piglit: failed to get DRM magic\n");
82 return false;
85 setup = xcb_get_setup(conn);
86 if (!setup) {
87 printf("piglit: xcb_get_setup() failed\n");
88 return false;
91 screen_iter = xcb_setup_roots_iterator(setup);
92 auth_cookie = xcb_dri2_authenticate_unchecked(conn,
93 screen_iter.data->root,
94 magic);
95 auth_reply = xcb_dri2_authenticate_reply(conn, auth_cookie, NULL);
97 if (auth_reply == NULL || !auth_reply->authenticated) {
98 printf("piglit: failed to authenticate with DRI2\n");
99 return false;
101 free(auth_reply);
103 return true;
106 #ifdef PIGLIT_HAS_GBM_BO_MAP
107 static struct gbm_device *
108 piglit_gbm_get(void)
110 const struct piglit_drm_driver *drv = piglit_drm_get_driver();
111 static struct gbm_device *gbm = NULL;
113 if (gbm)
114 return gbm;
116 gbm = gbm_create_device(drv->fd);
118 return gbm;
121 static bool
122 piglit_gbm_buf_create(unsigned w, unsigned h, unsigned fourcc,
123 const unsigned char *src_data, struct piglit_dma_buf *buf)
125 unsigned i;
126 struct gbm_bo *bo;
127 uint32_t dst_stride;
128 struct gbm_device *gbm = piglit_gbm_get();
129 void *dst_data;
130 void *map_data = NULL;
131 enum gbm_bo_format format;
132 unsigned cpp = 0, src_stride;
133 unsigned buf_w = w;
134 unsigned buf_h = h;
136 if (!gbm || h % 2 || w % 2)
137 return false;
139 switch (fourcc) {
140 case DRM_FORMAT_R8:
141 format = GBM_FORMAT_R8;
142 cpp = 1;
143 src_stride = cpp * w;
144 break;
145 case DRM_FORMAT_GR88:
146 case DRM_FORMAT_RG88:
147 case DRM_FORMAT_YUYV:
148 case DRM_FORMAT_UYVY:
149 format = GBM_FORMAT_GR88;
150 cpp = 2;
151 src_stride = cpp * w;
152 break;
153 case DRM_FORMAT_XRGB8888:
154 case DRM_FORMAT_XBGR8888:
155 case DRM_FORMAT_RGBX8888:
156 case DRM_FORMAT_BGRX8888:
157 case DRM_FORMAT_ARGB8888:
158 case DRM_FORMAT_ABGR8888:
159 case DRM_FORMAT_RGBA8888:
160 case DRM_FORMAT_BGRA8888:
161 case DRM_FORMAT_AYUV:
162 case DRM_FORMAT_XYUV8888:
163 format = GBM_BO_FORMAT_ARGB8888;
164 cpp = 4;
165 src_stride = cpp * w;
166 break;
167 case DRM_FORMAT_Y410:
168 format = GBM_FORMAT_ABGR2101010;
169 cpp = 4;
170 src_stride = cpp * w;
171 break;
172 case DRM_FORMAT_Y412:
173 case DRM_FORMAT_Y416:
174 format = GBM_BO_FORMAT_ARGB8888;
175 buf_w = w * 2;
176 cpp = 8;
177 src_stride = cpp * w;
178 break;
179 case DRM_FORMAT_Y210:
180 case DRM_FORMAT_Y212:
181 case DRM_FORMAT_Y216:
182 format = GBM_BO_FORMAT_ARGB8888;
183 cpp = 4;
184 src_stride = cpp * w;
185 break;
187 /* For YUV formats, the U/V planes might have a greater relative
188 * pitch. For example, if the driver needs pitch aligned to 32
189 * pixels, for a 4x4 YUV image, the stride of both the Y and U/V
190 * planes will be 32 bytes. Not 32 for Y and 16 for U/V. To
191 * account for this, use a 2cpp format with half the width. For
192 * hardware that only has stride requirements in bytes (rather
193 * than pixels) this will work out the same. For hardware that
194 * has pitch alignment requirements in pixels, this will give an
195 * overly conservative alignment for Y but a sufficient alignment
196 * for U/V.
198 case DRM_FORMAT_NV12:
199 format = GBM_FORMAT_GR88;
200 buf_w = w / 2;
201 buf_h = h * 3 / 2;
202 src_stride = w;
203 cpp = 1;
204 break;
205 case DRM_FORMAT_P010:
206 case DRM_FORMAT_P012:
207 case DRM_FORMAT_P016:
208 format = GBM_FORMAT_GR88;
209 buf_h = h * 3 / 2;
210 cpp = 2;
211 src_stride = cpp * w;
212 break;
213 case DRM_FORMAT_YUV420:
214 case DRM_FORMAT_YVU420:
215 format = GBM_FORMAT_GR88;
216 buf_w = w / 2;
217 buf_h = h * 2; /* U/V not interleaved */
218 src_stride = w;
219 cpp = 1;
220 break;
221 default:
222 fprintf(stderr, "invalid fourcc: %.4s\n", (char *)&fourcc);
223 return false;
226 bo = gbm_bo_create(gbm, buf_w, buf_h, format,
227 GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR);
228 if (!bo)
229 return false;
231 dst_data = gbm_bo_map(bo, 0, 0, buf_w, buf_h, GBM_BO_TRANSFER_WRITE,
232 &dst_stride, &map_data);
233 if (!dst_data) {
234 fprintf(stderr, "Failed to map GBM bo\n");
235 gbm_bo_destroy(bo);
236 return NULL;
239 buf->w = w;
240 buf->h = h;
241 buf->offset[0] = gbm_bo_get_offset(bo, 0);
242 buf->stride[0] = gbm_bo_get_stride_for_plane(bo, 0);
243 buf->fd = -1;
244 buf->priv = bo;
246 for (i = 0; i < h; ++i) {
247 memcpy((char *)dst_data + i * dst_stride,
248 src_data + i * src_stride,
249 w * cpp);
252 switch (fourcc) {
253 case DRM_FORMAT_NV12:
254 case DRM_FORMAT_P010:
255 case DRM_FORMAT_P012:
256 case DRM_FORMAT_P016:
257 for (i = 0; i < h/2; ++i) {
258 memcpy(((char *)dst_data + dst_stride * h) + i * dst_stride,
259 (src_data + (w * h * cpp)) + i * src_stride, w * cpp);
261 buf->offset[1] = buf->stride[0] * h;
262 buf->stride[1] = buf->stride[0];
263 break;
264 case DRM_FORMAT_YUV420:
265 case DRM_FORMAT_YVU420:
266 for (i = 0; i < h/2; ++i) {
267 memcpy(((char *)dst_data + dst_stride * h) + i * dst_stride,
268 (src_data + (w*h)) + i * src_stride / 2, w / 2);
270 unsigned cpu_offset2 = dst_stride * h + dst_stride * h / 2;
271 for (i = 0; i < h/2; ++i) {
272 memcpy(((char *)dst_data + cpu_offset2) + i * dst_stride,
273 (src_data + (w*h) + (w*h/4)) + i * src_stride / 2, w / 2);
275 buf->offset[1] = buf->stride[0] * h;
276 buf->stride[1] = buf->stride[0];
277 buf->offset[2] = buf->stride[0] * h + buf->stride[0] * h / 2;
278 buf->stride[2] = buf->stride[1];
279 break;
280 default:
281 break;
284 gbm_bo_unmap(bo, map_data);
287 return true;
290 static bool
291 piglit_gbm_buf_export(struct piglit_dma_buf *buf)
293 struct gbm_bo *bo = buf->priv;
295 buf->fd = gbm_bo_get_fd(bo);
297 return buf->fd >= 0;
300 static void
301 piglit_gbm_buf_destroy(struct piglit_dma_buf *buf)
303 struct gbm_bo *bo = buf->priv;
305 gbm_bo_destroy(bo);
307 #endif /* PIGLIT_HAS_GBM_BO_MAP */
309 static int
310 piglit_drm_get_user_fd(void)
312 int fd_res = -1;
313 char *nodename = getenv("WAFFLE_GBM_DEVICE");
314 if (nodename && strlen(nodename))
315 fd_res = open(nodename, O_RDWR);
317 return fd_res;
320 static const struct piglit_drm_driver *
321 piglit_drm_get_driver(void)
323 static struct piglit_drm_driver drv = { /* fd */ -1 };
324 drmVersionPtr version = NULL;
326 if (drv.fd != -1)
327 return &drv;
329 drv.fd = piglit_drm_get_user_fd();
330 if (drv.fd == -1) {
331 drv.fd = open("/dev/dri/renderD128", O_RDWR);
333 if (drv.fd == -1) {
334 drv.fd = open("/dev/dri/card0", O_RDWR);
335 if (drv.fd == -1) {
336 fprintf(stderr, "error: failed to open /dev/dri/renderD128 and "
337 "/dev/dri/card0\n");
338 goto fail;
342 if (!piglit_drm_x11_authenticate(drv.fd))
343 goto fail;
346 version = drmGetVersion(drv.fd);
348 if (!version || !version->name) {
349 fprintf(stderr, "error: drmGetVersion() failed\n");
350 goto fail;
351 } else {
352 #if 0
353 fprintf(stderr, "version: %s %d:%d\n",
354 version->name, version->version_major, version->version_minor);
355 #endif
358 drv.name = strdup(version->name);
359 if (!drv.name) {
360 drmFreeVersion(version);
361 fprintf(stderr, "out of memory\n");
362 abort();
365 if (0) {
366 /* empty */
368 #ifdef PIGLIT_HAS_GBM_BO_MAP
369 else if (true) {
370 drv.create = piglit_gbm_buf_create;
371 drv.export = piglit_gbm_buf_export;
372 drv.destroy = piglit_gbm_buf_destroy;
374 #endif
375 else {
376 fprintf(stderr, "error: unrecognized DRM driver name %s\n",
377 version->name);
378 goto fail;
381 drmFreeVersion(version);
382 return &drv;
384 fail:
385 if (drv.fd != -1) {
386 close(drv.fd);
387 drv.fd = -1;
390 if (drv.name) {
391 free(drv.name);
392 drv.name = NULL;
395 drmFreeVersion(version);
396 return NULL;
399 enum piglit_result
400 piglit_drm_create_dma_buf(unsigned w, unsigned h, unsigned fourcc,
401 const void *src_data, struct piglit_dma_buf **buf)
403 struct piglit_dma_buf *drm_buf;
404 const struct piglit_drm_driver *drv = piglit_drm_get_driver();
406 if (!drv)
407 return PIGLIT_SKIP;
409 drm_buf = calloc(sizeof(struct piglit_dma_buf), 1);
410 if (!drm_buf)
411 return PIGLIT_FAIL;
413 if (!drv->create(w, h, fourcc, src_data, drm_buf)) {
414 free(drm_buf);
415 return PIGLIT_FAIL;
418 if (!drv->export(drm_buf)) {
419 free(drm_buf);
420 return PIGLIT_FAIL;
423 *buf = drm_buf;
425 return PIGLIT_PASS;
428 void
429 piglit_drm_destroy_dma_buf(struct piglit_dma_buf *buf)
431 const struct piglit_drm_driver *drv;
433 if (!buf)
434 return;
436 drv = piglit_drm_get_driver();
437 if (!drv)
438 return;
440 drv->destroy(buf);
441 free(buf);