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
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
24 #include "piglit-util-gl.h"
25 #include "piglit_drm_dma_buf.h"
26 #include "drm-uapi/drm_fourcc.h"
27 #ifdef PIGLIT_HAS_GBM_BO_MAP
30 #include <sys/types.h>
40 #define ALIGN(value, alignment) (((value) + alignment - 1) & ~(alignment - 1))
42 struct piglit_drm_driver
{
47 (*create
)(unsigned w
, unsigned h
, unsigned cpp
,
48 const unsigned char *src_data
,
49 struct piglit_dma_buf
*buf
);
52 (*export
)(struct piglit_dma_buf
*buf
);
55 (*destroy
)(struct piglit_dma_buf
*buf
);
58 static const struct piglit_drm_driver
*piglit_drm_get_driver(void);
61 piglit_drm_x11_authenticate(int fd
)
64 xcb_connection_t
*conn
;
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
;
72 conn
= xcb_connect(NULL
, &screen
);
74 printf("piglit: failed to connect to X server for DRI2 "
79 ret
= drmGetMagic(fd
, &magic
);
81 printf("piglit: failed to get DRM magic\n");
85 setup
= xcb_get_setup(conn
);
87 printf("piglit: xcb_get_setup() failed\n");
91 screen_iter
= xcb_setup_roots_iterator(setup
);
92 auth_cookie
= xcb_dri2_authenticate_unchecked(conn
,
93 screen_iter
.data
->root
,
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");
106 #ifdef PIGLIT_HAS_GBM_BO_MAP
107 static struct gbm_device
*
110 const struct piglit_drm_driver
*drv
= piglit_drm_get_driver();
111 static struct gbm_device
*gbm
= NULL
;
116 gbm
= gbm_create_device(drv
->fd
);
122 piglit_gbm_buf_create(unsigned w
, unsigned h
, unsigned fourcc
,
123 const unsigned char *src_data
, struct piglit_dma_buf
*buf
)
128 struct gbm_device
*gbm
= piglit_gbm_get();
130 void *map_data
= NULL
;
131 enum gbm_bo_format format
;
132 unsigned cpp
= 0, src_stride
;
135 unsigned n_planes
= 0;
137 if (!gbm
|| h
% 2 || w
% 2)
142 format
= GBM_FORMAT_R8
;
144 src_stride
= cpp
* w
;
147 case DRM_FORMAT_GR88
:
148 case DRM_FORMAT_RG88
:
149 case DRM_FORMAT_YUYV
:
150 case DRM_FORMAT_YVYU
:
151 case DRM_FORMAT_UYVY
:
152 case DRM_FORMAT_VYUY
:
153 format
= GBM_FORMAT_GR88
;
155 src_stride
= cpp
* w
;
158 case DRM_FORMAT_XRGB8888
:
159 case DRM_FORMAT_XBGR8888
:
160 case DRM_FORMAT_RGBX8888
:
161 case DRM_FORMAT_BGRX8888
:
162 case DRM_FORMAT_ARGB8888
:
163 case DRM_FORMAT_ABGR8888
:
164 case DRM_FORMAT_RGBA8888
:
165 case DRM_FORMAT_BGRA8888
:
166 case DRM_FORMAT_AYUV
:
167 case DRM_FORMAT_XYUV8888
:
168 format
= GBM_BO_FORMAT_ARGB8888
;
170 src_stride
= cpp
* w
;
173 case DRM_FORMAT_Y410
:
174 format
= GBM_FORMAT_ABGR2101010
;
176 src_stride
= cpp
* w
;
179 case DRM_FORMAT_Y412
:
180 case DRM_FORMAT_Y416
:
181 format
= GBM_BO_FORMAT_ARGB8888
;
184 src_stride
= cpp
* w
;
187 case DRM_FORMAT_Y210
:
188 case DRM_FORMAT_Y212
:
189 case DRM_FORMAT_Y216
:
190 format
= GBM_BO_FORMAT_ARGB8888
;
192 src_stride
= cpp
* w
;
196 /* For YUV formats, the U/V planes might have a greater relative
197 * pitch. For example, if the driver needs pitch aligned to 32
198 * pixels, for a 4x4 YUV image, the stride of both the Y and U/V
199 * planes will be 32 bytes. Not 32 for Y and 16 for U/V. To
200 * account for this, use a 2cpp format with half the width. For
201 * hardware that only has stride requirements in bytes (rather
202 * than pixels) this will work out the same. For hardware that
203 * has pitch alignment requirements in pixels, this will give an
204 * overly conservative alignment for Y but a sufficient alignment
207 case DRM_FORMAT_NV12
:
208 case DRM_FORMAT_NV21
:
209 format
= GBM_FORMAT_GR88
;
216 case DRM_FORMAT_P010
:
217 case DRM_FORMAT_P012
:
218 case DRM_FORMAT_P016
:
219 format
= GBM_FORMAT_GR88
;
222 src_stride
= cpp
* w
;
225 case DRM_FORMAT_YUV420
:
226 case DRM_FORMAT_YVU420
:
227 format
= GBM_FORMAT_GR88
;
229 buf_h
= h
* 2; /* U/V not interleaved */
235 fprintf(stderr
, "invalid fourcc: %.4s\n", (char *)&fourcc
);
239 bo
= gbm_bo_create(gbm
, buf_w
, buf_h
, format
,
240 GBM_BO_USE_RENDERING
| GBM_BO_USE_LINEAR
);
244 dst_data
= gbm_bo_map(bo
, 0, 0, buf_w
, buf_h
, GBM_BO_TRANSFER_WRITE
,
245 &dst_stride
, &map_data
);
247 fprintf(stderr
, "Failed to map GBM bo\n");
254 buf
->n_planes
= n_planes
;
255 buf
->offset
[0] = gbm_bo_get_offset(bo
, 0);
256 buf
->stride
[0] = gbm_bo_get_stride_for_plane(bo
, 0);
260 for (i
= 0; i
< h
; ++i
) {
261 memcpy((char *)dst_data
+ i
* dst_stride
,
262 src_data
+ i
* src_stride
,
267 case DRM_FORMAT_NV12
:
268 case DRM_FORMAT_NV21
:
269 case DRM_FORMAT_P010
:
270 case DRM_FORMAT_P012
:
271 case DRM_FORMAT_P016
:
272 for (i
= 0; i
< h
/2; ++i
) {
273 memcpy(((char *)dst_data
+ dst_stride
* h
) + i
* dst_stride
,
274 (src_data
+ (w
* h
* cpp
)) + i
* src_stride
, w
* cpp
);
276 buf
->offset
[1] = buf
->stride
[0] * h
;
277 buf
->stride
[1] = buf
->stride
[0];
279 case DRM_FORMAT_YUV420
:
280 case DRM_FORMAT_YVU420
:
281 for (i
= 0; i
< h
/2; ++i
) {
282 memcpy(((char *)dst_data
+ dst_stride
* h
) + i
* dst_stride
,
283 (src_data
+ (w
*h
)) + i
* src_stride
/ 2, w
/ 2);
285 unsigned cpu_offset2
= dst_stride
* h
+ dst_stride
* h
/ 2;
286 for (i
= 0; i
< h
/2; ++i
) {
287 memcpy(((char *)dst_data
+ cpu_offset2
) + i
* dst_stride
,
288 (src_data
+ (w
*h
) + (w
*h
/4)) + i
* src_stride
/ 2, w
/ 2);
290 buf
->offset
[1] = buf
->stride
[0] * h
;
291 buf
->stride
[1] = buf
->stride
[0];
292 buf
->offset
[2] = buf
->stride
[0] * h
+ buf
->stride
[0] * h
/ 2;
293 buf
->stride
[2] = buf
->stride
[1];
299 gbm_bo_unmap(bo
, map_data
);
306 piglit_gbm_buf_export(struct piglit_dma_buf
*buf
)
308 struct gbm_bo
*bo
= buf
->priv
;
310 buf
->fd
= gbm_bo_get_fd(bo
);
316 piglit_gbm_buf_destroy(struct piglit_dma_buf
*buf
)
318 struct gbm_bo
*bo
= buf
->priv
;
322 #endif /* PIGLIT_HAS_GBM_BO_MAP */
325 piglit_drm_get_user_fd(void)
328 char *nodename
= getenv("WAFFLE_GBM_DEVICE");
329 if (nodename
&& strlen(nodename
))
330 fd_res
= open(nodename
, O_RDWR
);
335 static const struct piglit_drm_driver
*
336 piglit_drm_get_driver(void)
338 static struct piglit_drm_driver drv
= { /* fd */ -1 };
339 drmVersionPtr version
= NULL
;
344 drv
.fd
= piglit_drm_get_user_fd();
346 drv
.fd
= open("/dev/dri/renderD128", O_RDWR
);
349 drv
.fd
= open("/dev/dri/card0", O_RDWR
);
351 fprintf(stderr
, "error: failed to open /dev/dri/renderD128 and "
357 if (!piglit_drm_x11_authenticate(drv
.fd
))
361 version
= drmGetVersion(drv
.fd
);
363 if (!version
|| !version
->name
) {
364 fprintf(stderr
, "error: drmGetVersion() failed\n");
368 fprintf(stderr
, "version: %s %d:%d\n",
369 version
->name
, version
->version_major
, version
->version_minor
);
373 drv
.name
= strdup(version
->name
);
375 drmFreeVersion(version
);
376 fprintf(stderr
, "out of memory\n");
383 #ifdef PIGLIT_HAS_GBM_BO_MAP
385 drv
.create
= piglit_gbm_buf_create
;
386 drv
.export
= piglit_gbm_buf_export
;
387 drv
.destroy
= piglit_gbm_buf_destroy
;
391 fprintf(stderr
, "error: unrecognized DRM driver name %s\n",
396 drmFreeVersion(version
);
410 drmFreeVersion(version
);
415 drm_create_dma_buf_modifiers(unsigned w
, unsigned h
, unsigned fourcc
,
416 uint64_t modifier
, const unsigned char *src_data
,
417 struct piglit_dma_buf
*buf
)
422 struct gbm_device
*gbm
= piglit_gbm_get();
424 void *map_data
= NULL
;
425 unsigned cpp
= 0, src_stride
;
437 case DRM_FORMAT_XBGR8888
:
438 case DRM_FORMAT_XRGB8888
:
439 case DRM_FORMAT_ABGR8888
:
440 case DRM_FORMAT_ARGB8888
:
444 fprintf(stderr
, "invalid fourcc: %.4s\n", (char *)&fourcc
);
448 bo
= gbm_bo_create_with_modifiers(gbm
, w
, h
, fourcc
, &modifier
, 1);
452 dst_data
= gbm_bo_map(bo
, 0, 0, w
, h
, GBM_BO_TRANSFER_WRITE
,
453 &dst_stride
, &map_data
);
455 fprintf(stderr
, "Failed to map GBM bo\n");
460 src_stride
= cpp
* w
;
465 buf
->n_planes
= gbm_bo_get_plane_count(bo
);
466 assert(buf
->n_planes
<= ARRAY_SIZE(buf
->offset
));
467 for (int i
= 0; i
< buf
->n_planes
; i
++) {
468 buf
->offset
[i
] = gbm_bo_get_offset(bo
, i
);
469 buf
->stride
[i
] = gbm_bo_get_stride_for_plane(bo
, i
);
475 for (i
= 0; i
< h
; ++i
) {
476 memcpy((char *)dst_data
+ i
* dst_stride
,
477 src_data
+ i
* src_stride
,
481 gbm_bo_unmap(bo
, map_data
);
487 piglit_drm_create_dma_buf_modifiers(unsigned w
, unsigned h
, unsigned fourcc
,
488 uint64_t modifier
, const void *src_data
,
489 struct piglit_dma_buf
**buf
)
491 struct piglit_dma_buf
*drm_buf
;
492 const struct piglit_drm_driver
*drv
= piglit_drm_get_driver();
497 drm_buf
= calloc(sizeof(struct piglit_dma_buf
), 1);
501 if (!drm_create_dma_buf_modifiers(w
, h
, fourcc
, modifier
, src_data
,
507 if (!drv
->export(drm_buf
)) {
519 piglit_drm_create_dma_buf(unsigned w
, unsigned h
, unsigned fourcc
,
520 const void *src_data
, struct piglit_dma_buf
**buf
)
522 struct piglit_dma_buf
*drm_buf
;
523 const struct piglit_drm_driver
*drv
= piglit_drm_get_driver();
528 drm_buf
= calloc(sizeof(struct piglit_dma_buf
), 1);
532 if (!drv
->create(w
, h
, fourcc
, src_data
, drm_buf
)) {
537 if (!drv
->export(drm_buf
)) {
548 piglit_drm_destroy_dma_buf(struct piglit_dma_buf
*buf
)
550 const struct piglit_drm_driver
*drv
;
555 drv
= piglit_drm_get_driver();