1 /**************************************************************************
3 * Copyright 2016 Advanced Micro Devices, Inc.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
30 #include <X11/Xlib-xcb.h>
31 #include <X11/xshmfence.h>
33 #include <xcb/present.h>
34 #include <xcb/xfixes.h>
38 #include "pipe/p_screen.h"
39 #include "pipe/p_state.h"
40 #include "pipe-loader/pipe_loader.h"
42 #include "util/u_memory.h"
43 #include "util/u_inlines.h"
45 #include "vl/vl_compositor.h"
46 #include "vl/vl_winsys.h"
48 #define BACK_BUFFER_NUM 3
52 struct pipe_resource
*texture
;
53 struct pipe_resource
*linear_texture
;
57 struct xshmfence
*shm_fence
;
60 uint32_t width
, height
, pitch
;
65 struct vl_screen base
;
66 xcb_connection_t
*conn
;
67 xcb_drawable_t drawable
;
69 uint32_t width
, height
, depth
;
71 xcb_present_event_t eid
;
72 xcb_special_event_t
*special_event
;
74 struct pipe_context
*pipe
;
75 struct pipe_resource
*output_texture
;
76 uint32_t clip_width
, clip_height
;
78 struct vl_dri3_buffer
*back_buffers
[BACK_BUFFER_NUM
];
82 struct u_rect dirty_areas
[BACK_BUFFER_NUM
];
84 struct vl_dri3_buffer
*front_buffer
;
87 uint32_t send_msc_serial
, recv_msc_serial
;
88 uint64_t send_sbc
, recv_sbc
;
89 int64_t last_ust
, ns_frame
, last_msc
, next_msc
;
91 bool is_different_gpu
;
95 dri3_free_front_buffer(struct vl_dri3_screen
*scrn
,
96 struct vl_dri3_buffer
*buffer
)
98 xcb_sync_destroy_fence(scrn
->conn
, buffer
->sync_fence
);
99 xshmfence_unmap_shm(buffer
->shm_fence
);
100 pipe_resource_reference(&buffer
->texture
, NULL
);
105 dri3_free_back_buffer(struct vl_dri3_screen
*scrn
,
106 struct vl_dri3_buffer
*buffer
)
108 xcb_free_pixmap(scrn
->conn
, buffer
->pixmap
);
109 xcb_sync_destroy_fence(scrn
->conn
, buffer
->sync_fence
);
110 xshmfence_unmap_shm(buffer
->shm_fence
);
111 if (!scrn
->output_texture
)
112 pipe_resource_reference(&buffer
->texture
, NULL
);
113 if (buffer
->linear_texture
)
114 pipe_resource_reference(&buffer
->linear_texture
, NULL
);
119 dri3_handle_stamps(struct vl_dri3_screen
*scrn
, uint64_t ust
, uint64_t msc
)
121 int64_t ust_ns
= ust
* 1000;
123 if (scrn
->last_ust
&& (ust_ns
> scrn
->last_ust
) &&
124 scrn
->last_msc
&& (msc
> scrn
->last_msc
))
125 scrn
->ns_frame
= (ust_ns
- scrn
->last_ust
) / (msc
- scrn
->last_msc
);
127 scrn
->last_ust
= ust_ns
;
128 scrn
->last_msc
= msc
;
132 dri3_handle_present_event(struct vl_dri3_screen
*scrn
,
133 xcb_present_generic_event_t
*ge
)
135 switch (ge
->evtype
) {
136 case XCB_PRESENT_CONFIGURE_NOTIFY
: {
137 xcb_present_configure_notify_event_t
*ce
= (void *) ge
;
138 scrn
->width
= ce
->width
;
139 scrn
->height
= ce
->height
;
142 case XCB_PRESENT_COMPLETE_NOTIFY
: {
143 xcb_present_complete_notify_event_t
*ce
= (void *) ge
;
144 if (ce
->kind
== XCB_PRESENT_COMPLETE_KIND_PIXMAP
) {
145 scrn
->recv_sbc
= (scrn
->send_sbc
& 0xffffffff00000000LL
) | ce
->serial
;
146 if (scrn
->recv_sbc
> scrn
->send_sbc
)
147 scrn
->recv_sbc
-= 0x100000000;
148 dri3_handle_stamps(scrn
, ce
->ust
, ce
->msc
);
149 } else if (ce
->kind
== XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC
) {
150 scrn
->recv_msc_serial
= ce
->serial
;
151 dri3_handle_stamps(scrn
, ce
->ust
, ce
->msc
);
155 case XCB_PRESENT_EVENT_IDLE_NOTIFY
: {
156 xcb_present_idle_notify_event_t
*ie
= (void *) ge
;
158 for (b
= 0; b
< BACK_BUFFER_NUM
; b
++) {
159 struct vl_dri3_buffer
*buf
= scrn
->back_buffers
[b
];
160 if (buf
&& buf
->pixmap
== ie
->pixmap
) {
172 dri3_flush_present_events(struct vl_dri3_screen
*scrn
)
174 if (scrn
->special_event
) {
175 xcb_generic_event_t
*ev
;
176 while ((ev
= xcb_poll_for_special_event(
177 scrn
->conn
, scrn
->special_event
)) != NULL
)
178 dri3_handle_present_event(scrn
, (xcb_present_generic_event_t
*)ev
);
183 dri3_wait_present_events(struct vl_dri3_screen
*scrn
)
185 if (scrn
->special_event
) {
186 xcb_generic_event_t
*ev
;
187 ev
= xcb_wait_for_special_event(scrn
->conn
, scrn
->special_event
);
190 dri3_handle_present_event(scrn
, (xcb_present_generic_event_t
*)ev
);
197 dri3_find_back(struct vl_dri3_screen
*scrn
)
202 for (b
= 0; b
< BACK_BUFFER_NUM
; b
++) {
203 int id
= (b
+ scrn
->cur_back
) % BACK_BUFFER_NUM
;
204 struct vl_dri3_buffer
*buffer
= scrn
->back_buffers
[id
];
205 if (!buffer
|| !buffer
->busy
)
208 xcb_flush(scrn
->conn
);
209 if (!dri3_wait_present_events(scrn
))
214 static struct vl_dri3_buffer
*
215 dri3_alloc_back_buffer(struct vl_dri3_screen
*scrn
)
217 struct vl_dri3_buffer
*buffer
;
219 xcb_sync_fence_t sync_fence
;
220 struct xshmfence
*shm_fence
;
221 int buffer_fd
, fence_fd
;
222 struct pipe_resource templ
, *pixmap_buffer_texture
;
223 struct winsys_handle whandle
;
226 buffer
= CALLOC_STRUCT(vl_dri3_buffer
);
230 fence_fd
= xshmfence_alloc_shm();
234 shm_fence
= xshmfence_map_shm(fence_fd
);
238 memset(&templ
, 0, sizeof(templ
));
239 templ
.bind
= PIPE_BIND_RENDER_TARGET
| PIPE_BIND_SAMPLER_VIEW
;
240 templ
.format
= vl_dri2_format_for_depth(&scrn
->base
, scrn
->depth
);
241 templ
.target
= PIPE_TEXTURE_2D
;
242 templ
.last_level
= 0;
243 templ
.width0
= (scrn
->output_texture
) ?
244 scrn
->output_texture
->width0
: scrn
->width
;
245 templ
.height0
= (scrn
->output_texture
) ?
246 scrn
->output_texture
->height0
: scrn
->height
;
248 templ
.array_size
= 1;
250 if (scrn
->is_different_gpu
) {
251 buffer
->texture
= (scrn
->output_texture
) ? scrn
->output_texture
:
252 scrn
->base
.pscreen
->resource_create(scrn
->base
.pscreen
, &templ
);
253 if (!buffer
->texture
)
256 templ
.bind
|= PIPE_BIND_SCANOUT
| PIPE_BIND_SHARED
|
258 buffer
->linear_texture
=
259 scrn
->base
.pscreen
->resource_create(scrn
->base
.pscreen
, &templ
);
260 pixmap_buffer_texture
= buffer
->linear_texture
;
262 if (!buffer
->linear_texture
)
263 goto no_linear_texture
;
265 templ
.bind
|= PIPE_BIND_SCANOUT
| PIPE_BIND_SHARED
;
266 buffer
->texture
= (scrn
->output_texture
) ? scrn
->output_texture
:
267 scrn
->base
.pscreen
->resource_create(scrn
->base
.pscreen
, &templ
);
268 if (!buffer
->texture
)
270 pixmap_buffer_texture
= buffer
->texture
;
272 memset(&whandle
, 0, sizeof(whandle
));
273 whandle
.type
= WINSYS_HANDLE_TYPE_FD
;
274 usage
= PIPE_HANDLE_USAGE_EXPLICIT_FLUSH
;
275 scrn
->base
.pscreen
->resource_get_handle(scrn
->base
.pscreen
, NULL
,
276 pixmap_buffer_texture
, &whandle
,
278 buffer_fd
= whandle
.handle
;
279 buffer
->pitch
= whandle
.stride
;
280 buffer
->width
= templ
.width0
;
281 buffer
->height
= templ
.height0
;
283 xcb_dri3_pixmap_from_buffer(scrn
->conn
,
284 (pixmap
= xcb_generate_id(scrn
->conn
)),
287 buffer
->width
, buffer
->height
, buffer
->pitch
,
290 xcb_dri3_fence_from_fd(scrn
->conn
,
292 (sync_fence
= xcb_generate_id(scrn
->conn
)),
296 buffer
->pixmap
= pixmap
;
297 buffer
->sync_fence
= sync_fence
;
298 buffer
->shm_fence
= shm_fence
;
300 xshmfence_trigger(buffer
->shm_fence
);
305 pipe_resource_reference(&buffer
->texture
, NULL
);
307 xshmfence_unmap_shm(shm_fence
);
315 static struct vl_dri3_buffer
*
316 dri3_get_back_buffer(struct vl_dri3_screen
*scrn
)
318 struct vl_dri3_buffer
*buffer
;
319 struct pipe_resource
*texture
= NULL
;
320 bool allocate_new_buffer
= false;
325 scrn
->cur_back
= dri3_find_back(scrn
);
326 if (scrn
->cur_back
< 0)
328 buffer
= scrn
->back_buffers
[scrn
->cur_back
];
330 if (scrn
->output_texture
) {
331 if (!buffer
|| buffer
->width
< scrn
->width
||
332 buffer
->height
< scrn
->height
)
333 allocate_new_buffer
= true;
334 else if (scrn
->is_different_gpu
)
335 /* In case of different gpu we can reuse the linear
336 * texture so we only need to set the external
337 * texture for copying
339 buffer
->texture
= scrn
->output_texture
;
341 /* In case of a single gpu we search if the texture is
342 * already present as buffer if not we get the
343 * handle and pixmap for the texture that is set
345 for (b
= 0; b
< BACK_BUFFER_NUM
; b
++) {
346 id
= (b
+ scrn
->cur_back
) % BACK_BUFFER_NUM
;
347 buffer
= scrn
->back_buffers
[id
];
348 if (buffer
&& !buffer
->busy
&&
349 buffer
->texture
== scrn
->output_texture
) {
355 if (b
== BACK_BUFFER_NUM
) {
356 allocate_new_buffer
= true;
357 scrn
->cur_back
= scrn
->next_back
;
358 scrn
->next_back
= (scrn
->next_back
+ 1) % BACK_BUFFER_NUM
;
359 buffer
= scrn
->back_buffers
[scrn
->cur_back
];
364 if (!buffer
|| buffer
->width
!= scrn
->width
||
365 buffer
->height
!= scrn
->height
)
366 allocate_new_buffer
= true;
369 if (allocate_new_buffer
) {
370 struct vl_dri3_buffer
*new_buffer
;
372 new_buffer
= dri3_alloc_back_buffer(scrn
);
377 dri3_free_back_buffer(scrn
, buffer
);
379 if (!scrn
->output_texture
)
380 vl_compositor_reset_dirty_area(&scrn
->dirty_areas
[scrn
->cur_back
]);
382 scrn
->back_buffers
[scrn
->cur_back
] = buffer
;
385 pipe_resource_reference(&texture
, buffer
->texture
);
386 xcb_flush(scrn
->conn
);
387 xshmfence_await(buffer
->shm_fence
);
393 dri3_set_drawable(struct vl_dri3_screen
*scrn
, Drawable drawable
)
395 xcb_get_geometry_cookie_t geom_cookie
;
396 xcb_get_geometry_reply_t
*geom_reply
;
397 xcb_void_cookie_t cookie
;
398 xcb_generic_error_t
*error
;
403 if (scrn
->drawable
== drawable
)
406 scrn
->drawable
= drawable
;
408 geom_cookie
= xcb_get_geometry(scrn
->conn
, scrn
->drawable
);
409 geom_reply
= xcb_get_geometry_reply(scrn
->conn
, geom_cookie
, NULL
);
413 scrn
->width
= geom_reply
->width
;
414 scrn
->height
= geom_reply
->height
;
415 scrn
->depth
= geom_reply
->depth
;
418 if (scrn
->special_event
) {
419 xcb_unregister_for_special_event(scrn
->conn
, scrn
->special_event
);
420 scrn
->special_event
= NULL
;
421 cookie
= xcb_present_select_input_checked(scrn
->conn
, scrn
->eid
,
423 XCB_PRESENT_EVENT_MASK_NO_EVENT
);
424 xcb_discard_reply(scrn
->conn
, cookie
.sequence
);
427 scrn
->is_pixmap
= false;
428 scrn
->eid
= xcb_generate_id(scrn
->conn
);
430 xcb_present_select_input_checked(scrn
->conn
, scrn
->eid
, scrn
->drawable
,
431 XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY
|
432 XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY
|
433 XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY
);
435 error
= xcb_request_check(scrn
->conn
, cookie
);
437 if (error
->error_code
!= BadWindow
)
440 scrn
->is_pixmap
= true;
441 if (scrn
->front_buffer
) {
442 dri3_free_front_buffer(scrn
, scrn
->front_buffer
);
443 scrn
->front_buffer
= NULL
;
448 scrn
->special_event
=
449 xcb_register_for_special_xge(scrn
->conn
, &xcb_present_id
, scrn
->eid
, 0);
451 dri3_flush_present_events(scrn
);
456 static struct vl_dri3_buffer
*
457 dri3_get_front_buffer(struct vl_dri3_screen
*scrn
)
459 xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie
;
460 xcb_dri3_buffer_from_pixmap_reply_t
*bp_reply
;
461 xcb_sync_fence_t sync_fence
;
462 struct xshmfence
*shm_fence
;
464 struct winsys_handle whandle
;
465 struct pipe_resource templ
, *texture
= NULL
;
467 if (scrn
->front_buffer
) {
468 pipe_resource_reference(&texture
, scrn
->front_buffer
->texture
);
469 return scrn
->front_buffer
;
472 scrn
->front_buffer
= CALLOC_STRUCT(vl_dri3_buffer
);
473 if (!scrn
->front_buffer
)
476 fence_fd
= xshmfence_alloc_shm();
480 shm_fence
= xshmfence_map_shm(fence_fd
);
484 bp_cookie
= xcb_dri3_buffer_from_pixmap(scrn
->conn
, scrn
->drawable
);
485 bp_reply
= xcb_dri3_buffer_from_pixmap_reply(scrn
->conn
, bp_cookie
, NULL
);
489 fds
= xcb_dri3_buffer_from_pixmap_reply_fds(scrn
->conn
, bp_reply
);
493 memset(&whandle
, 0, sizeof(whandle
));
494 whandle
.type
= WINSYS_HANDLE_TYPE_FD
;
495 whandle
.handle
= (unsigned)fds
[0];
496 whandle
.stride
= bp_reply
->stride
;
497 memset(&templ
, 0, sizeof(templ
));
498 templ
.bind
= PIPE_BIND_RENDER_TARGET
| PIPE_BIND_SAMPLER_VIEW
;
499 templ
.format
= vl_dri2_format_for_depth(&scrn
->base
, bp_reply
->depth
);
500 templ
.target
= PIPE_TEXTURE_2D
;
501 templ
.last_level
= 0;
502 templ
.width0
= bp_reply
->width
;
503 templ
.height0
= bp_reply
->height
;
505 templ
.array_size
= 1;
506 scrn
->front_buffer
->texture
=
507 scrn
->base
.pscreen
->resource_from_handle(scrn
->base
.pscreen
,
509 PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE
);
511 if (!scrn
->front_buffer
->texture
)
514 xcb_dri3_fence_from_fd(scrn
->conn
,
516 (sync_fence
= xcb_generate_id(scrn
->conn
)),
520 pipe_resource_reference(&texture
, scrn
->front_buffer
->texture
);
521 scrn
->front_buffer
->pixmap
= scrn
->drawable
;
522 scrn
->front_buffer
->width
= bp_reply
->width
;
523 scrn
->front_buffer
->height
= bp_reply
->height
;
524 scrn
->front_buffer
->shm_fence
= shm_fence
;
525 scrn
->front_buffer
->sync_fence
= sync_fence
;
528 return scrn
->front_buffer
;
533 xshmfence_unmap_shm(shm_fence
);
537 FREE(scrn
->front_buffer
);
541 static xcb_screen_t
*
542 dri3_get_screen_for_root(xcb_connection_t
*conn
, xcb_window_t root
)
544 xcb_screen_iterator_t screen_iter
=
545 xcb_setup_roots_iterator(xcb_get_setup(conn
));
547 for (; screen_iter
.rem
; xcb_screen_next (&screen_iter
)) {
548 if (screen_iter
.data
->root
== root
)
549 return screen_iter
.data
;
556 vl_dri3_flush_frontbuffer(struct pipe_screen
*screen
,
557 struct pipe_resource
*resource
,
558 unsigned level
, unsigned layer
,
559 void *context_private
, struct pipe_box
*sub_box
)
561 struct vl_dri3_screen
*scrn
= (struct vl_dri3_screen
*)context_private
;
562 uint32_t options
= XCB_PRESENT_OPTION_NONE
;
563 struct vl_dri3_buffer
*back
;
564 struct pipe_box src_box
;
565 xcb_xfixes_region_t region
;
566 xcb_rectangle_t rectangle
;
568 back
= scrn
->back_buffers
[scrn
->cur_back
];
572 while (scrn
->special_event
&& scrn
->recv_sbc
< scrn
->send_sbc
)
573 if (!dri3_wait_present_events(scrn
))
578 rectangle
.width
= (scrn
->output_texture
) ? scrn
->clip_width
: scrn
->width
;
579 rectangle
.height
= (scrn
->output_texture
) ? scrn
->clip_height
: scrn
->height
;
581 region
= xcb_generate_id(scrn
->conn
);
582 xcb_xfixes_create_region(scrn
->conn
, region
, 2, &rectangle
);
584 if (scrn
->is_different_gpu
) {
585 u_box_origin_2d(back
->width
, back
->height
, &src_box
);
586 scrn
->pipe
->resource_copy_region(scrn
->pipe
,
587 back
->linear_texture
,
592 scrn
->pipe
->flush(scrn
->pipe
, NULL
, 0);
594 xshmfence_reset(back
->shm_fence
);
597 xcb_present_pixmap(scrn
->conn
,
600 (uint32_t)(++scrn
->send_sbc
),
608 xcb_flush(scrn
->conn
);
613 static struct pipe_resource
*
614 vl_dri3_screen_texture_from_drawable(struct vl_screen
*vscreen
, void *drawable
)
616 struct vl_dri3_screen
*scrn
= (struct vl_dri3_screen
*)vscreen
;
617 struct vl_dri3_buffer
*buffer
;
621 if (!dri3_set_drawable(scrn
, (Drawable
)drawable
))
624 buffer
= (scrn
->is_pixmap
) ?
625 dri3_get_front_buffer(scrn
) :
626 dri3_get_back_buffer(scrn
);
630 return buffer
->texture
;
633 static struct u_rect
*
634 vl_dri3_screen_get_dirty_area(struct vl_screen
*vscreen
)
636 struct vl_dri3_screen
*scrn
= (struct vl_dri3_screen
*)vscreen
;
640 return &scrn
->dirty_areas
[scrn
->cur_back
];
644 vl_dri3_screen_get_timestamp(struct vl_screen
*vscreen
, void *drawable
)
646 struct vl_dri3_screen
*scrn
= (struct vl_dri3_screen
*)vscreen
;
650 if (!dri3_set_drawable(scrn
, (Drawable
)drawable
))
653 if (!scrn
->last_ust
) {
654 xcb_present_notify_msc(scrn
->conn
,
656 ++scrn
->send_msc_serial
,
658 xcb_flush(scrn
->conn
);
660 while (scrn
->special_event
&&
661 scrn
->send_msc_serial
> scrn
->recv_msc_serial
) {
662 if (!dri3_wait_present_events(scrn
))
667 return scrn
->last_ust
;
671 vl_dri3_screen_set_next_timestamp(struct vl_screen
*vscreen
, uint64_t stamp
)
673 struct vl_dri3_screen
*scrn
= (struct vl_dri3_screen
*)vscreen
;
677 if (stamp
&& scrn
->last_ust
&& scrn
->ns_frame
&& scrn
->last_msc
)
678 scrn
->next_msc
= ((int64_t)stamp
- scrn
->last_ust
+ scrn
->ns_frame
/2) /
679 scrn
->ns_frame
+ scrn
->last_msc
;
685 vl_dri3_screen_get_private(struct vl_screen
*vscreen
)
691 vl_dri3_screen_set_back_texture_from_output(struct vl_screen
*vscreen
,
692 struct pipe_resource
*buffer
,
693 uint32_t width
, uint32_t height
)
695 struct vl_dri3_screen
*scrn
= (struct vl_dri3_screen
*)vscreen
;
699 scrn
->output_texture
= buffer
;
700 scrn
->clip_width
= (width
) ? width
: scrn
->width
;
701 scrn
->clip_height
= (height
) ? height
: scrn
->height
;
705 vl_dri3_screen_destroy(struct vl_screen
*vscreen
)
707 struct vl_dri3_screen
*scrn
= (struct vl_dri3_screen
*)vscreen
;
712 dri3_flush_present_events(scrn
);
714 if (scrn
->front_buffer
) {
715 dri3_free_front_buffer(scrn
, scrn
->front_buffer
);
716 scrn
->front_buffer
= NULL
;
719 for (i
= 0; i
< BACK_BUFFER_NUM
; ++i
) {
720 if (scrn
->back_buffers
[i
]) {
721 dri3_free_back_buffer(scrn
, scrn
->back_buffers
[i
]);
722 scrn
->back_buffers
[i
] = NULL
;
726 if (scrn
->special_event
) {
727 xcb_void_cookie_t cookie
=
728 xcb_present_select_input_checked(scrn
->conn
, scrn
->eid
,
730 XCB_PRESENT_EVENT_MASK_NO_EVENT
);
732 xcb_discard_reply(scrn
->conn
, cookie
.sequence
);
733 xcb_unregister_for_special_event(scrn
->conn
, scrn
->special_event
);
735 scrn
->pipe
->destroy(scrn
->pipe
);
736 scrn
->base
.pscreen
->destroy(scrn
->base
.pscreen
);
737 pipe_loader_release(&scrn
->base
.dev
, 1);
744 vl_dri3_screen_create(Display
*display
, int screen
)
746 struct vl_dri3_screen
*scrn
;
747 const xcb_query_extension_reply_t
*extension
;
748 xcb_dri3_open_cookie_t open_cookie
;
749 xcb_dri3_open_reply_t
*open_reply
;
750 xcb_get_geometry_cookie_t geom_cookie
;
751 xcb_get_geometry_reply_t
*geom_reply
;
752 xcb_xfixes_query_version_cookie_t xfixes_cookie
;
753 xcb_xfixes_query_version_reply_t
*xfixes_reply
;
754 xcb_generic_error_t
*error
;
759 scrn
= CALLOC_STRUCT(vl_dri3_screen
);
763 scrn
->conn
= XGetXCBConnection(display
);
767 xcb_prefetch_extension_data(scrn
->conn
, &xcb_dri3_id
);
768 xcb_prefetch_extension_data(scrn
->conn
, &xcb_present_id
);
769 xcb_prefetch_extension_data (scrn
->conn
, &xcb_xfixes_id
);
770 extension
= xcb_get_extension_data(scrn
->conn
, &xcb_dri3_id
);
771 if (!(extension
&& extension
->present
))
773 extension
= xcb_get_extension_data(scrn
->conn
, &xcb_present_id
);
774 if (!(extension
&& extension
->present
))
776 extension
= xcb_get_extension_data(scrn
->conn
, &xcb_xfixes_id
);
777 if (!(extension
&& extension
->present
))
780 xfixes_cookie
= xcb_xfixes_query_version(scrn
->conn
, XCB_XFIXES_MAJOR_VERSION
,
781 XCB_XFIXES_MINOR_VERSION
);
782 xfixes_reply
= xcb_xfixes_query_version_reply(scrn
->conn
, xfixes_cookie
, &error
);
783 if (!xfixes_reply
|| error
|| xfixes_reply
->major_version
< 2) {
790 open_cookie
= xcb_dri3_open(scrn
->conn
, RootWindow(display
, screen
), None
);
791 open_reply
= xcb_dri3_open_reply(scrn
->conn
, open_cookie
, NULL
);
794 if (open_reply
->nfd
!= 1) {
799 fd
= xcb_dri3_open_reply_fds(scrn
->conn
, open_reply
)[0];
804 fcntl(fd
, F_SETFD
, FD_CLOEXEC
);
807 fd
= loader_get_user_preferred_fd(fd
, &scrn
->is_different_gpu
);
809 geom_cookie
= xcb_get_geometry(scrn
->conn
, RootWindow(display
, screen
));
810 geom_reply
= xcb_get_geometry_reply(scrn
->conn
, geom_cookie
, NULL
);
814 scrn
->base
.xcb_screen
= dri3_get_screen_for_root(scrn
->conn
, geom_reply
->root
);
815 if (!scrn
->base
.xcb_screen
) {
820 /* TODO support depth other than 24 or 30 */
821 if (geom_reply
->depth
!= 24 && geom_reply
->depth
!= 30) {
825 scrn
->base
.color_depth
= geom_reply
->depth
;
828 if (pipe_loader_drm_probe_fd(&scrn
->base
.dev
, fd
))
829 scrn
->base
.pscreen
= pipe_loader_create_screen(scrn
->base
.dev
);
831 if (!scrn
->base
.pscreen
)
834 scrn
->pipe
= scrn
->base
.pscreen
->context_create(scrn
->base
.pscreen
,
839 scrn
->base
.destroy
= vl_dri3_screen_destroy
;
840 scrn
->base
.texture_from_drawable
= vl_dri3_screen_texture_from_drawable
;
841 scrn
->base
.get_dirty_area
= vl_dri3_screen_get_dirty_area
;
842 scrn
->base
.get_timestamp
= vl_dri3_screen_get_timestamp
;
843 scrn
->base
.set_next_timestamp
= vl_dri3_screen_set_next_timestamp
;
844 scrn
->base
.get_private
= vl_dri3_screen_get_private
;
845 scrn
->base
.pscreen
->flush_frontbuffer
= vl_dri3_flush_frontbuffer
;
846 scrn
->base
.set_back_texture_from_output
= vl_dri3_screen_set_back_texture_from_output
;
852 scrn
->base
.pscreen
->destroy(scrn
->base
.pscreen
);
854 if (scrn
->base
.dev
) {
855 pipe_loader_release(&scrn
->base
.dev
, 1);