vl/dri3: fix warning about incompatible pointer type
[mesa.git] / src / gallium / auxiliary / vl / vl_winsys_dri3.c
1 /**************************************************************************
2 *
3 * Copyright 2016 Advanced Micro Devices, Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 #include <fcntl.h>
29
30 #include <X11/Xlib-xcb.h>
31 #include <X11/xshmfence.h>
32 #include <xcb/dri3.h>
33 #include <xcb/present.h>
34
35 #include "loader.h"
36
37 #include "pipe/p_screen.h"
38 #include "pipe/p_state.h"
39 #include "pipe-loader/pipe_loader.h"
40
41 #include "util/u_memory.h"
42 #include "util/u_inlines.h"
43
44 #include "vl/vl_compositor.h"
45 #include "vl/vl_winsys.h"
46
47 #define BACK_BUFFER_NUM 3
48
49 struct vl_dri3_buffer
50 {
51 struct pipe_resource *texture;
52 struct pipe_resource *linear_texture;
53
54 uint32_t pixmap;
55 uint32_t sync_fence;
56 struct xshmfence *shm_fence;
57
58 bool busy;
59 uint32_t width, height, pitch;
60 };
61
62 struct vl_dri3_screen
63 {
64 struct vl_screen base;
65 xcb_connection_t *conn;
66 xcb_drawable_t drawable;
67
68 uint32_t width, height, depth;
69
70 xcb_present_event_t eid;
71 xcb_special_event_t *special_event;
72
73 struct pipe_context *pipe;
74
75 struct vl_dri3_buffer *back_buffers[BACK_BUFFER_NUM];
76 int cur_back;
77
78 struct u_rect dirty_areas[BACK_BUFFER_NUM];
79
80 struct vl_dri3_buffer *front_buffer;
81 bool is_pixmap;
82
83 uint32_t send_msc_serial, recv_msc_serial;
84 uint64_t send_sbc, recv_sbc;
85 int64_t last_ust, ns_frame, last_msc, next_msc;
86
87 bool flushed;
88 int is_different_gpu;
89 };
90
91 static void
92 dri3_free_front_buffer(struct vl_dri3_screen *scrn,
93 struct vl_dri3_buffer *buffer)
94 {
95 xcb_sync_destroy_fence(scrn->conn, buffer->sync_fence);
96 xshmfence_unmap_shm(buffer->shm_fence);
97 pipe_resource_reference(&buffer->texture, NULL);
98 FREE(buffer);
99 }
100
101 static void
102 dri3_free_back_buffer(struct vl_dri3_screen *scrn,
103 struct vl_dri3_buffer *buffer)
104 {
105 xcb_free_pixmap(scrn->conn, buffer->pixmap);
106 xcb_sync_destroy_fence(scrn->conn, buffer->sync_fence);
107 xshmfence_unmap_shm(buffer->shm_fence);
108 pipe_resource_reference(&buffer->texture, NULL);
109 if (buffer->linear_texture)
110 pipe_resource_reference(&buffer->linear_texture, NULL);
111 FREE(buffer);
112 }
113
114 static void
115 dri3_handle_stamps(struct vl_dri3_screen *scrn, uint64_t ust, uint64_t msc)
116 {
117 int64_t ust_ns = ust * 1000;
118
119 if (scrn->last_ust && (ust_ns > scrn->last_ust) &&
120 scrn->last_msc && (msc > scrn->last_msc))
121 scrn->ns_frame = (ust_ns - scrn->last_ust) / (msc - scrn->last_msc);
122
123 scrn->last_ust = ust_ns;
124 scrn->last_msc = msc;
125 }
126
127 static void
128 dri3_handle_present_event(struct vl_dri3_screen *scrn,
129 xcb_present_generic_event_t *ge)
130 {
131 switch (ge->evtype) {
132 case XCB_PRESENT_CONFIGURE_NOTIFY: {
133 xcb_present_configure_notify_event_t *ce = (void *) ge;
134 scrn->width = ce->width;
135 scrn->height = ce->height;
136 break;
137 }
138 case XCB_PRESENT_COMPLETE_NOTIFY: {
139 xcb_present_complete_notify_event_t *ce = (void *) ge;
140 if (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP) {
141 scrn->recv_sbc = (scrn->send_sbc & 0xffffffff00000000LL) | ce->serial;
142 if (scrn->recv_sbc > scrn->send_sbc)
143 scrn->recv_sbc -= 0x100000000;
144 dri3_handle_stamps(scrn, ce->ust, ce->msc);
145 } else if (ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC) {
146 scrn->recv_msc_serial = ce->serial;
147 dri3_handle_stamps(scrn, ce->ust, ce->msc);
148 }
149 break;
150 }
151 case XCB_PRESENT_EVENT_IDLE_NOTIFY: {
152 xcb_present_idle_notify_event_t *ie = (void *) ge;
153 int b;
154 for (b = 0; b < BACK_BUFFER_NUM; b++) {
155 struct vl_dri3_buffer *buf = scrn->back_buffers[b];
156 if (buf && buf->pixmap == ie->pixmap) {
157 buf->busy = false;
158 break;
159 }
160 }
161 break;
162 }
163 }
164 free(ge);
165 }
166
167 static void
168 dri3_flush_present_events(struct vl_dri3_screen *scrn)
169 {
170 if (scrn->special_event) {
171 xcb_generic_event_t *ev;
172 while ((ev = xcb_poll_for_special_event(
173 scrn->conn, scrn->special_event)) != NULL)
174 dri3_handle_present_event(scrn, (xcb_present_generic_event_t *)ev);
175 }
176 }
177
178 static bool
179 dri3_wait_present_events(struct vl_dri3_screen *scrn)
180 {
181 if (scrn->special_event) {
182 xcb_generic_event_t *ev;
183 ev = xcb_wait_for_special_event(scrn->conn, scrn->special_event);
184 if (!ev)
185 return false;
186 dri3_handle_present_event(scrn, (xcb_present_generic_event_t *)ev);
187 return true;
188 }
189 return false;
190 }
191
192 static int
193 dri3_find_back(struct vl_dri3_screen *scrn)
194 {
195 int b;
196
197 for (;;) {
198 for (b = 0; b < BACK_BUFFER_NUM; b++) {
199 int id = (b + scrn->cur_back) % BACK_BUFFER_NUM;
200 struct vl_dri3_buffer *buffer = scrn->back_buffers[id];
201 if (!buffer || !buffer->busy)
202 return id;
203 }
204 xcb_flush(scrn->conn);
205 if (!dri3_wait_present_events(scrn))
206 return -1;
207 }
208 }
209
210 static struct vl_dri3_buffer *
211 dri3_alloc_back_buffer(struct vl_dri3_screen *scrn)
212 {
213 struct vl_dri3_buffer *buffer;
214 xcb_pixmap_t pixmap;
215 xcb_sync_fence_t sync_fence;
216 struct xshmfence *shm_fence;
217 int buffer_fd, fence_fd;
218 struct pipe_resource templ, *pixmap_buffer_texture;
219 struct winsys_handle whandle;
220 unsigned usage;
221
222 buffer = CALLOC_STRUCT(vl_dri3_buffer);
223 if (!buffer)
224 return NULL;
225
226 fence_fd = xshmfence_alloc_shm();
227 if (fence_fd < 0)
228 goto free_buffer;
229
230 shm_fence = xshmfence_map_shm(fence_fd);
231 if (!shm_fence)
232 goto close_fd;
233
234 memset(&templ, 0, sizeof(templ));
235 templ.bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
236 templ.format = PIPE_FORMAT_B8G8R8X8_UNORM;
237 templ.target = PIPE_TEXTURE_2D;
238 templ.last_level = 0;
239 templ.width0 = scrn->width;
240 templ.height0 = scrn->height;
241 templ.depth0 = 1;
242 templ.array_size = 1;
243
244 if (scrn->is_different_gpu) {
245 buffer->texture = scrn->base.pscreen->resource_create(scrn->base.pscreen,
246 &templ);
247 if (!buffer->texture)
248 goto unmap_shm;
249
250 templ.bind |= PIPE_BIND_SCANOUT | PIPE_BIND_SHARED |
251 PIPE_BIND_LINEAR;
252 buffer->linear_texture = scrn->base.pscreen->resource_create(scrn->base.pscreen,
253 &templ);
254 pixmap_buffer_texture = buffer->linear_texture;
255
256 if (!buffer->linear_texture)
257 goto no_linear_texture;
258 } else {
259 templ.bind |= PIPE_BIND_SCANOUT | PIPE_BIND_SHARED;
260 buffer->texture = scrn->base.pscreen->resource_create(scrn->base.pscreen,
261 &templ);
262 if (!buffer->texture)
263 goto unmap_shm;
264 pixmap_buffer_texture = buffer->texture;
265 }
266 memset(&whandle, 0, sizeof(whandle));
267 whandle.type= DRM_API_HANDLE_TYPE_FD;
268 usage = PIPE_HANDLE_USAGE_EXPLICIT_FLUSH | PIPE_HANDLE_USAGE_READ;
269 scrn->base.pscreen->resource_get_handle(scrn->base.pscreen, NULL,
270 pixmap_buffer_texture, &whandle,
271 usage);
272 buffer_fd = whandle.handle;
273 buffer->pitch = whandle.stride;
274 xcb_dri3_pixmap_from_buffer(scrn->conn,
275 (pixmap = xcb_generate_id(scrn->conn)),
276 scrn->drawable,
277 0,
278 scrn->width, scrn->height, buffer->pitch,
279 scrn->depth, 32,
280 buffer_fd);
281 xcb_dri3_fence_from_fd(scrn->conn,
282 pixmap,
283 (sync_fence = xcb_generate_id(scrn->conn)),
284 false,
285 fence_fd);
286
287 buffer->pixmap = pixmap;
288 buffer->sync_fence = sync_fence;
289 buffer->shm_fence = shm_fence;
290 buffer->width = scrn->width;
291 buffer->height = scrn->height;
292
293 xshmfence_trigger(buffer->shm_fence);
294
295 return buffer;
296
297 no_linear_texture:
298 pipe_resource_reference(&buffer->texture, NULL);
299 unmap_shm:
300 xshmfence_unmap_shm(shm_fence);
301 close_fd:
302 close(fence_fd);
303 free_buffer:
304 FREE(buffer);
305 return NULL;
306 }
307
308 static struct vl_dri3_buffer *
309 dri3_get_back_buffer(struct vl_dri3_screen *scrn)
310 {
311 struct vl_dri3_buffer *buffer;
312 struct pipe_resource *texture = NULL;
313
314 assert(scrn);
315
316 scrn->cur_back = dri3_find_back(scrn);
317 if (scrn->cur_back < 0)
318 return NULL;
319 buffer = scrn->back_buffers[scrn->cur_back];
320
321 if (!buffer || buffer->width != scrn->width ||
322 buffer->height != scrn->height) {
323 struct vl_dri3_buffer *new_buffer;
324
325 new_buffer = dri3_alloc_back_buffer(scrn);
326 if (!new_buffer)
327 return NULL;
328
329 if (buffer)
330 dri3_free_back_buffer(scrn, buffer);
331
332 vl_compositor_reset_dirty_area(&scrn->dirty_areas[scrn->cur_back]);
333 buffer = new_buffer;
334 scrn->back_buffers[scrn->cur_back] = buffer;
335 }
336
337 pipe_resource_reference(&texture, buffer->texture);
338 xcb_flush(scrn->conn);
339 xshmfence_await(buffer->shm_fence);
340
341 return buffer;
342 }
343
344 static bool
345 dri3_set_drawable(struct vl_dri3_screen *scrn, Drawable drawable)
346 {
347 xcb_get_geometry_cookie_t geom_cookie;
348 xcb_get_geometry_reply_t *geom_reply;
349 xcb_void_cookie_t cookie;
350 xcb_generic_error_t *error;
351 bool ret = true;
352
353 assert(drawable);
354
355 if (scrn->drawable == drawable)
356 return true;
357
358 scrn->drawable = drawable;
359
360 geom_cookie = xcb_get_geometry(scrn->conn, scrn->drawable);
361 geom_reply = xcb_get_geometry_reply(scrn->conn, geom_cookie, NULL);
362 if (!geom_reply)
363 return false;
364
365 scrn->width = geom_reply->width;
366 scrn->height = geom_reply->height;
367 scrn->depth = geom_reply->depth;
368 free(geom_reply);
369
370 if (scrn->special_event) {
371 xcb_unregister_for_special_event(scrn->conn, scrn->special_event);
372 scrn->special_event = NULL;
373 cookie = xcb_present_select_input_checked(scrn->conn, scrn->eid,
374 scrn->drawable,
375 XCB_PRESENT_EVENT_MASK_NO_EVENT);
376 xcb_discard_reply(scrn->conn, cookie.sequence);
377 }
378
379 scrn->is_pixmap = false;
380 scrn->eid = xcb_generate_id(scrn->conn);
381 cookie =
382 xcb_present_select_input_checked(scrn->conn, scrn->eid, scrn->drawable,
383 XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY |
384 XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY |
385 XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY);
386
387 error = xcb_request_check(scrn->conn, cookie);
388 if (error) {
389 if (error->error_code != BadWindow)
390 ret = false;
391 else {
392 scrn->is_pixmap = true;
393 if (scrn->front_buffer) {
394 dri3_free_front_buffer(scrn, scrn->front_buffer);
395 scrn->front_buffer = NULL;
396 }
397 }
398 free(error);
399 } else
400 scrn->special_event =
401 xcb_register_for_special_xge(scrn->conn, &xcb_present_id, scrn->eid, 0);
402
403 dri3_flush_present_events(scrn);
404
405 return ret;
406 }
407
408 static struct vl_dri3_buffer *
409 dri3_get_front_buffer(struct vl_dri3_screen *scrn)
410 {
411 xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie;
412 xcb_dri3_buffer_from_pixmap_reply_t *bp_reply;
413 xcb_sync_fence_t sync_fence;
414 struct xshmfence *shm_fence;
415 int fence_fd, *fds;
416 struct winsys_handle whandle;
417 struct pipe_resource templ, *texture = NULL;
418
419 if (scrn->front_buffer) {
420 pipe_resource_reference(&texture, scrn->front_buffer->texture);
421 return scrn->front_buffer;
422 }
423
424 scrn->front_buffer = CALLOC_STRUCT(vl_dri3_buffer);
425 if (!scrn->front_buffer)
426 return NULL;
427
428 fence_fd = xshmfence_alloc_shm();
429 if (fence_fd < 0)
430 goto free_buffer;
431
432 shm_fence = xshmfence_map_shm(fence_fd);
433 if (!shm_fence)
434 goto close_fd;
435
436 bp_cookie = xcb_dri3_buffer_from_pixmap(scrn->conn, scrn->drawable);
437 bp_reply = xcb_dri3_buffer_from_pixmap_reply(scrn->conn, bp_cookie, NULL);
438 if (!bp_reply)
439 goto unmap_shm;
440
441 fds = xcb_dri3_buffer_from_pixmap_reply_fds(scrn->conn, bp_reply);
442 if (fds[0] < 0)
443 goto free_reply;
444
445 memset(&whandle, 0, sizeof(whandle));
446 whandle.type = DRM_API_HANDLE_TYPE_FD;
447 whandle.handle = (unsigned)fds[0];
448 whandle.stride = bp_reply->stride;
449 memset(&templ, 0, sizeof(templ));
450 templ.bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
451 templ.format = PIPE_FORMAT_B8G8R8X8_UNORM;
452 templ.target = PIPE_TEXTURE_2D;
453 templ.last_level = 0;
454 templ.width0 = bp_reply->width;
455 templ.height0 = bp_reply->height;
456 templ.depth0 = 1;
457 templ.array_size = 1;
458 scrn->front_buffer->texture =
459 scrn->base.pscreen->resource_from_handle(scrn->base.pscreen,
460 &templ, &whandle,
461 PIPE_HANDLE_USAGE_READ_WRITE);
462 close(fds[0]);
463 if (!scrn->front_buffer->texture)
464 goto free_reply;
465
466 xcb_dri3_fence_from_fd(scrn->conn,
467 scrn->drawable,
468 (sync_fence = xcb_generate_id(scrn->conn)),
469 false,
470 fence_fd);
471
472 pipe_resource_reference(&texture, scrn->front_buffer->texture);
473 scrn->front_buffer->pixmap = scrn->drawable;
474 scrn->front_buffer->width = bp_reply->width;
475 scrn->front_buffer->height = bp_reply->height;
476 scrn->front_buffer->shm_fence = shm_fence;
477 scrn->front_buffer->sync_fence = sync_fence;
478 free(bp_reply);
479
480 return scrn->front_buffer;
481
482 free_reply:
483 free(bp_reply);
484 unmap_shm:
485 xshmfence_unmap_shm(shm_fence);
486 close_fd:
487 close(fence_fd);
488 free_buffer:
489 FREE(scrn->front_buffer);
490 return NULL;
491 }
492
493 static void
494 vl_dri3_flush_frontbuffer(struct pipe_screen *screen,
495 struct pipe_resource *resource,
496 unsigned level, unsigned layer,
497 void *context_private, struct pipe_box *sub_box)
498 {
499 struct vl_dri3_screen *scrn = (struct vl_dri3_screen *)context_private;
500 uint32_t options = XCB_PRESENT_OPTION_NONE;
501 struct vl_dri3_buffer *back;
502 struct pipe_box src_box;
503
504 back = scrn->back_buffers[scrn->cur_back];
505 if (!back)
506 return;
507
508 if (scrn->flushed) {
509 while (scrn->special_event && scrn->recv_sbc < scrn->send_sbc)
510 if (!dri3_wait_present_events(scrn))
511 return;
512 }
513
514 if (scrn->is_different_gpu) {
515 u_box_origin_2d(scrn->width, scrn->height, &src_box);
516 scrn->pipe->resource_copy_region(scrn->pipe,
517 back->linear_texture,
518 0, 0, 0, 0,
519 back->texture,
520 0, &src_box);
521
522 scrn->pipe->flush(scrn->pipe, NULL, 0);
523 }
524 xshmfence_reset(back->shm_fence);
525 back->busy = true;
526
527 xcb_present_pixmap(scrn->conn,
528 scrn->drawable,
529 back->pixmap,
530 (uint32_t)(++scrn->send_sbc),
531 0, 0, 0, 0,
532 None, None,
533 back->sync_fence,
534 options,
535 scrn->next_msc,
536 0, 0, 0, NULL);
537
538 xcb_flush(scrn->conn);
539
540 scrn->flushed = true;
541
542 return;
543 }
544
545 static struct pipe_resource *
546 vl_dri3_screen_texture_from_drawable(struct vl_screen *vscreen, void *drawable)
547 {
548 struct vl_dri3_screen *scrn = (struct vl_dri3_screen *)vscreen;
549 struct vl_dri3_buffer *buffer;
550
551 assert(scrn);
552
553 if (!dri3_set_drawable(scrn, (Drawable)drawable))
554 return NULL;
555
556 if (scrn->flushed) {
557 while (scrn->special_event && scrn->recv_sbc < scrn->send_sbc)
558 if (!dri3_wait_present_events(scrn))
559 return NULL;
560 }
561 scrn->flushed = false;
562
563 buffer = (scrn->is_pixmap) ?
564 dri3_get_front_buffer(scrn) :
565 dri3_get_back_buffer(scrn);
566 if (!buffer)
567 return NULL;
568
569 return buffer->texture;
570 }
571
572 static struct u_rect *
573 vl_dri3_screen_get_dirty_area(struct vl_screen *vscreen)
574 {
575 struct vl_dri3_screen *scrn = (struct vl_dri3_screen *)vscreen;
576
577 assert(scrn);
578
579 return &scrn->dirty_areas[scrn->cur_back];
580 }
581
582 static uint64_t
583 vl_dri3_screen_get_timestamp(struct vl_screen *vscreen, void *drawable)
584 {
585 struct vl_dri3_screen *scrn = (struct vl_dri3_screen *)vscreen;
586
587 assert(scrn);
588
589 if (!dri3_set_drawable(scrn, (Drawable)drawable))
590 return 0;
591
592 if (!scrn->last_ust) {
593 xcb_present_notify_msc(scrn->conn,
594 scrn->drawable,
595 ++scrn->send_msc_serial,
596 0, 0, 0);
597 xcb_flush(scrn->conn);
598
599 while (scrn->special_event &&
600 scrn->send_msc_serial > scrn->recv_msc_serial) {
601 if (!dri3_wait_present_events(scrn))
602 return 0;
603 }
604 }
605
606 return scrn->last_ust;
607 }
608
609 static void
610 vl_dri3_screen_set_next_timestamp(struct vl_screen *vscreen, uint64_t stamp)
611 {
612 struct vl_dri3_screen *scrn = (struct vl_dri3_screen *)vscreen;
613
614 assert(scrn);
615
616 if (stamp && scrn->last_ust && scrn->ns_frame && scrn->last_msc)
617 scrn->next_msc = ((int64_t)stamp - scrn->last_ust + scrn->ns_frame/2) /
618 scrn->ns_frame + scrn->last_msc;
619 else
620 scrn->next_msc = 0;
621 }
622
623 static void *
624 vl_dri3_screen_get_private(struct vl_screen *vscreen)
625 {
626 return vscreen;
627 }
628
629 static void
630 vl_dri3_screen_destroy(struct vl_screen *vscreen)
631 {
632 struct vl_dri3_screen *scrn = (struct vl_dri3_screen *)vscreen;
633 int i;
634
635 assert(vscreen);
636
637 dri3_flush_present_events(scrn);
638
639 if (scrn->front_buffer) {
640 dri3_free_front_buffer(scrn, scrn->front_buffer);
641 scrn->front_buffer = NULL;
642 return;
643 }
644
645 for (i = 0; i < BACK_BUFFER_NUM; ++i) {
646 if (scrn->back_buffers[i]) {
647 dri3_free_back_buffer(scrn, scrn->back_buffers[i]);
648 scrn->back_buffers[i] = NULL;
649 }
650 }
651
652 if (scrn->special_event) {
653 xcb_void_cookie_t cookie =
654 xcb_present_select_input_checked(scrn->conn, scrn->eid,
655 scrn->drawable,
656 XCB_PRESENT_EVENT_MASK_NO_EVENT);
657
658 xcb_discard_reply(scrn->conn, cookie.sequence);
659 xcb_unregister_for_special_event(scrn->conn, scrn->special_event);
660 }
661 scrn->pipe->destroy(scrn->pipe);
662 scrn->base.pscreen->destroy(scrn->base.pscreen);
663 pipe_loader_release(&scrn->base.dev, 1);
664 FREE(scrn);
665
666 return;
667 }
668
669 struct vl_screen *
670 vl_dri3_screen_create(Display *display, int screen)
671 {
672 struct vl_dri3_screen *scrn;
673 const xcb_query_extension_reply_t *extension;
674 xcb_dri3_open_cookie_t open_cookie;
675 xcb_dri3_open_reply_t *open_reply;
676 xcb_get_geometry_cookie_t geom_cookie;
677 xcb_get_geometry_reply_t *geom_reply;
678 int fd;
679
680 assert(display);
681
682 scrn = CALLOC_STRUCT(vl_dri3_screen);
683 if (!scrn)
684 return NULL;
685
686 scrn->conn = XGetXCBConnection(display);
687 if (!scrn->conn)
688 goto free_screen;
689
690 xcb_prefetch_extension_data(scrn->conn , &xcb_dri3_id);
691 xcb_prefetch_extension_data(scrn->conn, &xcb_present_id);
692 extension = xcb_get_extension_data(scrn->conn, &xcb_dri3_id);
693 if (!(extension && extension->present))
694 goto free_screen;
695 extension = xcb_get_extension_data(scrn->conn, &xcb_present_id);
696 if (!(extension && extension->present))
697 goto free_screen;
698
699 open_cookie = xcb_dri3_open(scrn->conn, RootWindow(display, screen), None);
700 open_reply = xcb_dri3_open_reply(scrn->conn, open_cookie, NULL);
701 if (!open_reply)
702 goto free_screen;
703 if (open_reply->nfd != 1) {
704 free(open_reply);
705 goto free_screen;
706 }
707
708 fd = xcb_dri3_open_reply_fds(scrn->conn, open_reply)[0];
709 if (fd < 0) {
710 free(open_reply);
711 goto free_screen;
712 }
713 fcntl(fd, F_SETFD, FD_CLOEXEC);
714 free(open_reply);
715
716 fd = loader_get_user_preferred_fd(fd, &scrn->is_different_gpu);
717
718 geom_cookie = xcb_get_geometry(scrn->conn, RootWindow(display, screen));
719 geom_reply = xcb_get_geometry_reply(scrn->conn, geom_cookie, NULL);
720 if (!geom_reply)
721 goto close_fd;
722 /* TODO support depth other than 24 */
723 if (geom_reply->depth != 24) {
724 free(geom_reply);
725 goto close_fd;
726 }
727 free(geom_reply);
728
729 if (pipe_loader_drm_probe_fd(&scrn->base.dev, fd))
730 scrn->base.pscreen = pipe_loader_create_screen(scrn->base.dev);
731
732 if (!scrn->base.pscreen)
733 goto release_pipe;
734
735 scrn->pipe = scrn->base.pscreen->context_create(scrn->base.pscreen,
736 &scrn->base, 0);
737 if (!scrn->pipe)
738 goto no_context;
739
740 scrn->base.destroy = vl_dri3_screen_destroy;
741 scrn->base.texture_from_drawable = vl_dri3_screen_texture_from_drawable;
742 scrn->base.get_dirty_area = vl_dri3_screen_get_dirty_area;
743 scrn->base.get_timestamp = vl_dri3_screen_get_timestamp;
744 scrn->base.set_next_timestamp = vl_dri3_screen_set_next_timestamp;
745 scrn->base.get_private = vl_dri3_screen_get_private;
746 scrn->base.pscreen->flush_frontbuffer = vl_dri3_flush_frontbuffer;
747
748 return &scrn->base;
749
750 no_context:
751 scrn->base.pscreen->destroy(scrn->base.pscreen);
752 release_pipe:
753 if (scrn->base.dev) {
754 pipe_loader_release(&scrn->base.dev, 1);
755 fd = -1;
756 }
757 close_fd:
758 if (fd != -1)
759 close(fd);
760 free_screen:
761 FREE(scrn);
762 return NULL;
763 }