3 #include <X11/Xlib-xcb.h>
4 #include <X11/xshmfence.h>
7 #include <xcb/present.h>
13 #include "yagl_dri3.h"
14 #include "yagl_x11_drawable.h"
15 #include "yagl_x11_display.h"
16 #include "yagl_x11_image.h"
17 #include "yagl_malloc.h"
21 static inline void yagl_dri3_fence_reset(xcb_connection_t *c,
22 struct yagl_dri3_buffer *buffer)
24 xshmfence_reset(buffer->shm_fence);
27 static inline void yagl_dri3_fence_set(struct yagl_dri3_buffer *buffer)
29 xshmfence_trigger(buffer->shm_fence);
32 static inline void yagl_dri3_fence_trigger(xcb_connection_t *c,
33 struct yagl_dri3_buffer *buffer)
35 xcb_sync_trigger_fence(c, buffer->sync_fence);
38 static inline void yagl_dri3_fence_await(xcb_connection_t *c,
39 struct yagl_dri3_buffer *buffer)
42 xshmfence_await(buffer->shm_fence);
45 static inline Bool yagl_dri3_fence_triggered(struct yagl_dri3_buffer *buffer)
47 return xshmfence_query(buffer->shm_fence);
50 /** yagl_dri3_alloc_render_buffer
52 * Allocate a render buffer and create an X pixmap from that
54 * Allocate an xshmfence for synchronization
56 static struct yagl_dri3_buffer *yagl_dri3_alloc_render_buffer(struct yagl_dri3_drawable *drawable,
62 Drawable x_drawable = YAGL_X11_DRAWABLE(drawable->base.os_drawable);
63 Display *x_dpy = YAGL_X11_DPY(drawable->base.dpy->os_dpy);
64 xcb_connection_t *c = XGetXCBConnection(x_dpy);
65 struct yagl_dri3_buffer *buffer;
66 struct vigs_drm_surface *sfc;
68 xcb_sync_fence_t sync_fence;
69 xcb_void_cookie_t cookie;
70 xcb_generic_error_t *error;
71 struct xshmfence *shm_fence;
72 int buffer_fd, fence_fd;
75 YAGL_LOG_FUNC_SET(yagl_dri3_alloc_render_buffer);
77 fence_fd = xshmfence_alloc_shm();
80 YAGL_LOG_ERROR("DRI3 Fence object allocation failure %s",
85 shm_fence = xshmfence_map_shm(fence_fd);
87 if (shm_fence == NULL) {
88 YAGL_LOG_ERROR("DRI3 Fence object map failure %s",
93 buffer = yagl_malloc0(sizeof(*buffer));
96 YAGL_LOG_ERROR("DRI3 Buffer object allocation failure %s",
102 case vigs_drm_surface_bgrx8888:
103 case vigs_drm_surface_bgra8888:
105 stride = width * cpp;
113 YAGL_LOG_ERROR("DRI3 buffer format %d invalid", format);
117 ret = vigs_drm_surface_create(drawable->base.dpy->drm_dev,
126 YAGL_LOG_ERROR("DRI3 surface creation failure %s", strerror(errno));
130 /* Export allocated buffer */
131 ret = vigs_drm_prime_export_fd(drawable->base.dpy->drm_dev,
136 YAGL_LOG_ERROR("DRI3 fd export failure %s", strerror(errno));
140 /* Import fd at X side */
141 cookie = xcb_dri3_pixmap_from_buffer_checked(c,
142 (pixmap = xcb_generate_id(c)),
151 error = xcb_request_check(c, cookie);
154 YAGL_LOG_ERROR("DRI3 pixmap_from_buffer failed (pixmap = %p, errcode = %d)",
155 (void *)pixmap, (int)error->error_code);
160 cookie = xcb_dri3_fence_from_fd_checked(c,
162 (sync_fence = xcb_generate_id(c)),
165 error = xcb_request_check(c, cookie);
168 YAGL_LOG_ERROR("DRI3 fence_from_fd failed (pixmap = %p, errcode = %d)",
169 (void *)pixmap, (int)error->error_code);
174 buffer->pixmap = pixmap;
175 buffer->own_pixmap = true;
176 buffer->sync_fence = sync_fence;
177 buffer->shm_fence = shm_fence;
178 buffer->width = width;
179 buffer->height = height;
180 buffer->pitch = stride;
183 /* Mark the buffer as idle
185 yagl_dri3_fence_set(buffer);
190 vigs_drm_gem_unref(&sfc->gem);
193 /* nothing to do here */
199 xshmfence_unmap_shm(shm_fence);
204 YAGL_LOG_ERROR("DRI3 alloc_render_buffer failed\n");
209 /** yagl_dri3_free_render_buffer
211 * Free everything associated with one render buffer including pixmap, fence
212 * stuff and the driver surface
214 static void yagl_dri3_free_render_buffer(struct yagl_dri3_drawable *drawable,
215 struct yagl_dri3_buffer *buffer)
217 Display *x_dpy = YAGL_X11_DPY(drawable->base.dpy->os_dpy);
218 xcb_connection_t *c = XGetXCBConnection(x_dpy);
220 if (buffer->own_pixmap) {
221 xcb_free_pixmap(c, buffer->pixmap);
225 vigs_drm_gem_unref(&buffer->sfc->gem);
228 xcb_sync_destroy_fence(c, buffer->sync_fence);
229 xshmfence_unmap_shm(buffer->shm_fence);
234 static void yagl_dri3_update_num_back(struct yagl_dri3_drawable *drawable)
236 drawable->num_back = 1;
238 if (drawable->flipping) {
239 if (!drawable->is_pixmap && !(drawable->present_capabilities & XCB_PRESENT_CAPABILITY_ASYNC)) {
240 drawable->num_back++;
243 drawable->num_back++;
246 if (drawable->swap_interval == 0) {
247 drawable->num_back++;
250 if (drawable->num_back < 2) {
251 drawable->num_back = 2;
256 * Process one Present event
258 static void yagl_dri3_handle_present_event(struct yagl_dri3_drawable *drawable,
259 xcb_present_generic_event_t *ge)
261 YAGL_LOG_FUNC_SET(yagl_dri3_handle_present_event);
263 switch (ge->evtype) {
264 case XCB_PRESENT_CONFIGURE_NOTIFY: {
265 xcb_present_configure_notify_event_t *ce = (void *)ge;
267 YAGL_LOG_DEBUG("XCB_PRESENT_CONFIGURE_NOTIFY: %dx%d => %dx%d",
273 drawable->width = ce->width;
274 drawable->height = ce->height;
278 case XCB_PRESENT_COMPLETE_NOTIFY: {
279 xcb_present_complete_notify_event_t *ce = (void *)ge;
281 YAGL_LOG_DEBUG("XCB_PRESENT_COMPLETE_NOTIFY");
283 /* Compute the processed SBC number from the received 32-bit serial number merged
284 * with the upper 32-bits of the sent 64-bit serial number while checking for
287 if (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP) {
288 drawable->recv_sbc = (drawable->send_sbc & 0xffffffff00000000LL) | ce->serial;
289 if (drawable->recv_sbc > drawable->send_sbc) {
290 drawable->recv_sbc -= 0x100000000;
294 case XCB_PRESENT_COMPLETE_MODE_FLIP:
295 drawable->flipping = true;
297 case XCB_PRESENT_COMPLETE_MODE_COPY:
298 drawable->flipping = false;
302 yagl_dri3_update_num_back(drawable);
304 drawable->ust = ce->ust;
305 drawable->msc = ce->msc;
307 drawable->recv_msc_serial = ce->serial;
308 drawable->notify_ust = ce->ust;
309 drawable->notify_msc = ce->msc;
314 case XCB_PRESENT_EVENT_IDLE_NOTIFY: {
315 xcb_present_idle_notify_event_t *ie = (void *)ge;
318 YAGL_LOG_DEBUG("XCB_PRESENT_EVENT_IDLE_NOTIFY");
320 for (b = 0; b < sizeof(drawable->buffers) / sizeof(drawable->buffers[0]); b++) {
321 struct yagl_dri3_buffer *buf = drawable->buffers[b];
323 if (buf && buf->pixmap == ie->pixmap) {
326 if (drawable->num_back <= b && b < DRI3_MAX_BACK) {
327 yagl_dri3_free_render_buffer(drawable, buf);
328 drawable->buffers[b] = NULL;
342 /** yagl_dri3_flush_present_events
344 * Process any present events that have been received from the X server
346 static void yagl_dri3_flush_present_events(struct yagl_dri3_drawable *drawable)
348 Display *x_dpy = YAGL_X11_DPY(drawable->base.dpy->os_dpy);
349 xcb_connection_t *c = XGetXCBConnection(x_dpy);
351 /* Check to see if any configuration changes have occurred
352 * since we were last invoked
354 if (drawable->special_event) {
355 xcb_generic_event_t *ev;
357 while ((ev = xcb_poll_for_special_event(c, drawable->special_event)) != NULL) {
358 xcb_present_generic_event_t *ge = (void *)ev;
359 yagl_dri3_handle_present_event(drawable, ge);
364 /** yagl_dri3_update_drawable
366 * Called the first time we use the drawable and then
367 * after we receive present configure notify events to
368 * track the geometry of the drawable
370 static int yagl_dri3_update_drawable(struct yagl_dri3_drawable *drawable)
372 Display *x_dpy = YAGL_X11_DPY(drawable->base.dpy->os_dpy);
373 xcb_connection_t *c = XGetXCBConnection(x_dpy);
375 YAGL_LOG_FUNC_SET(yagl_dri3_update_drawable);
377 /* First time through, go get the current drawable geometry
379 if (drawable->width == 0 || drawable->height == 0 || drawable->depth == 0) {
380 xcb_get_geometry_cookie_t geom_cookie;
381 xcb_get_geometry_reply_t *geom_reply;
382 xcb_void_cookie_t cookie;
383 xcb_generic_error_t *error;
384 xcb_present_query_capabilities_cookie_t present_capabilities_cookie;
385 xcb_present_query_capabilities_reply_t *present_capabilities_reply;
386 Drawable x_drawable = YAGL_X11_DRAWABLE(drawable->base.os_drawable);
388 /* Try to select for input on the window.
390 * If the drawable is a window, this will get our events
393 * Otherwise, we'll get a BadWindow error back from this request which
394 * will let us know that the drawable is a pixmap instead.
397 cookie = xcb_present_select_input_checked(c,
398 (drawable->eid = xcb_generate_id(c)),
400 XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY|
401 XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY|
402 XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY);
404 present_capabilities_cookie = xcb_present_query_capabilities(c, x_drawable);
406 /* Create an XCB event queue to hold present events outside of the usual
407 * application event queue
409 drawable->special_event = xcb_register_for_special_xge(c,
412 &drawable->base.stamp);
414 geom_cookie = xcb_get_geometry(c, x_drawable);
415 geom_reply = xcb_get_geometry_reply(c, geom_cookie, NULL);
421 drawable->width = geom_reply->width;
422 drawable->height = geom_reply->height;
423 drawable->depth = geom_reply->depth;
424 drawable->is_pixmap = false;
428 /* Check to see if our select input call failed. If it failed with a
429 * BadWindow error, then assume the drawable is a pixmap. Destroy the
430 * special event queue created above and mark the drawable as a pixmap
433 error = xcb_request_check(c, cookie);
435 present_capabilities_reply = xcb_present_query_capabilities_reply(c,
436 present_capabilities_cookie,
439 if (present_capabilities_reply) {
440 drawable->present_capabilities = present_capabilities_reply->capabilities;
441 free(present_capabilities_reply);
443 drawable->present_capabilities = 0;
447 if (error->error_code != BadWindow) {
452 drawable->is_pixmap = true;
453 xcb_unregister_for_special_event(c, drawable->special_event);
454 drawable->special_event = NULL;
457 YAGL_LOG_DEBUG("%s 0x%X initial geometry: %ux%u %u",
458 drawable->is_pixmap ? "Pixmap": "Window",
465 yagl_dri3_flush_present_events(drawable);
470 static xcb_gcontext_t yagl_dri3_drawable_gc(struct yagl_dri3_drawable *drawable)
473 Display *x_dpy = YAGL_X11_DPY(drawable->base.dpy->os_dpy);
474 Drawable x_drawable = YAGL_X11_DRAWABLE(drawable->base.os_drawable);
475 xcb_connection_t *c = XGetXCBConnection(x_dpy);
479 (drawable->gc = xcb_generate_id(c)),
481 XCB_GC_GRAPHICS_EXPOSURES,
488 static struct yagl_dri3_buffer *yagl_dri3_back_buffer(struct yagl_dri3_drawable *drawable)
490 return drawable->buffers[DRI3_BACK_ID(drawable->cur_back)];
493 static struct yagl_dri3_buffer *yagl_dri3_front_buffer(struct yagl_dri3_drawable *drawable)
495 return drawable->buffers[DRI3_FRONT_ID];
498 static void yagl_dri3_copy_area(xcb_connection_t *c,
499 xcb_drawable_t src_drawable,
500 xcb_drawable_t dst_drawable,
509 xcb_void_cookie_t cookie;
511 cookie = xcb_copy_area_checked(c,
521 xcb_discard_reply(c, cookie.sequence);
524 static void yagl_dri3_copy_drawable(struct yagl_dri3_drawable *drawable,
528 Display *x_dpy = YAGL_X11_DPY(drawable->base.dpy->os_dpy);
529 xcb_connection_t *c = XGetXCBConnection(x_dpy);
530 struct yagl_dri3_buffer *front = yagl_dri3_front_buffer(drawable);
532 yagl_dri3_fence_reset(c, front);
533 yagl_dri3_copy_area(c,
536 yagl_dri3_drawable_gc(drawable),
543 yagl_dri3_fence_trigger(c, front);
544 yagl_dri3_fence_await(c, front);
547 static inline int yagl_dri3_pixmap_buf_id(enum yagl_dri3_buffer_type buffer_type)
549 if (buffer_type == yagl_dri3_buffer_back) {
550 return DRI3_BACK_ID(0);
552 return DRI3_FRONT_ID;
556 /** yagl_dri3_get_pixmap_buffer
558 * Get the DRM object for a pixmap from the X server
560 static struct yagl_dri3_buffer *yagl_dri3_get_pixmap_buffer(struct yagl_dri3_drawable *drawable,
562 enum yagl_dri3_buffer_type buffer_type)
564 Display *x_dpy = YAGL_X11_DPY(drawable->base.dpy->os_dpy);
565 xcb_connection_t *c = XGetXCBConnection(x_dpy);
566 int buf_id = yagl_dri3_pixmap_buf_id(buffer_type);
567 struct yagl_dri3_buffer *buffer = drawable->buffers[buf_id];
568 Pixmap pixmap = YAGL_X11_DRAWABLE(drawable->base.os_drawable);
569 xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie;
570 xcb_dri3_buffer_from_pixmap_reply_t *bp_reply;
571 xcb_sync_fence_t sync_fence;
572 struct xshmfence *shm_fence;
573 struct vigs_drm_surface *sfc;
577 YAGL_LOG_FUNC_SET(yagl_dri3_get_pixmap_buffer);
583 buffer = yagl_malloc0(sizeof(*buffer));
586 YAGL_LOG_ERROR("DRI3 buffer object allocation failure");
590 fence_fd = xshmfence_alloc_shm();
593 YAGL_LOG_ERROR("DRI3 Fence object allocation failure %s",
595 goto err_alloc_fence;
598 shm_fence = xshmfence_map_shm(fence_fd);
600 if (shm_fence == NULL) {
601 YAGL_LOG_ERROR("DRI3 Fence object map failure %s",
606 xcb_dri3_fence_from_fd(c,
608 (sync_fence = xcb_generate_id(c)),
612 /* Get an FD for the pixmap object
614 bp_cookie = xcb_dri3_buffer_from_pixmap(c, pixmap);
615 bp_reply = xcb_dri3_buffer_from_pixmap_reply(c, bp_cookie, NULL);
618 YAGL_LOG_ERROR("DRI3 buffer_from_pixmap failed");
622 fds = xcb_dri3_buffer_from_pixmap_reply_fds(c, bp_reply);
624 /* Import exported FD */
625 ret = vigs_drm_prime_import_fd(drawable->base.dpy->drm_dev,
630 YAGL_LOG_ERROR("DRI3 fd import failure %s", strerror(errno));
636 buffer->pixmap = pixmap;
637 buffer->own_pixmap = false;
638 buffer->sync_fence = sync_fence;
639 buffer->shm_fence = shm_fence;
640 buffer->width = bp_reply->width;
641 buffer->height = bp_reply->height;
642 buffer->pitch = bp_reply->stride;
643 buffer->buffer_type = buffer_type;
646 drawable->buffers[buf_id] = buffer;
654 /* nothing to do here */
665 /** yagl_dri3_find_back
667 * Find an idle back buffer. If there isn't one, then
668 * wait for a present idle notify event from the X server
670 static int yagl_dri3_find_back(xcb_connection_t *c,
671 struct yagl_dri3_drawable *drawable)
674 xcb_generic_event_t *ev;
675 xcb_present_generic_event_t *ge;
678 for (b = 0; b < drawable->num_back; b++) {
679 int id = DRI3_BACK_ID((b + drawable->cur_back) % drawable->num_back);
680 struct yagl_dri3_buffer *buffer = drawable->buffers[id];
682 if (!buffer || !buffer->busy) {
683 drawable->cur_back = id;
689 ev = xcb_wait_for_special_event(c, drawable->special_event);
696 yagl_dri3_handle_present_event(drawable, ge);
700 /** yagl_dri3_get_buffer
702 * Find a front or back buffer, allocating new ones as necessary
704 static struct yagl_dri3_buffer *yagl_dri3_get_buffer(struct yagl_dri3_drawable *drawable,
706 enum yagl_dri3_buffer_type buffer_type)
708 Display *x_dpy = YAGL_X11_DPY(drawable->base.dpy->os_dpy);
709 xcb_connection_t *c = XGetXCBConnection(x_dpy);
710 struct yagl_dri3_buffer *buffer;
713 YAGL_LOG_FUNC_SET(yagl_dri3_get_buffer);
715 if (buffer_type == yagl_dri3_buffer_back) {
716 buf_id = yagl_dri3_find_back(c, drawable);
722 buf_id = DRI3_FRONT_ID;
725 buffer = drawable->buffers[buf_id];
728 buffer->width != drawable->width ||
729 buffer->height != drawable->height) {
730 struct yagl_dri3_buffer *new_buffer = yagl_dri3_alloc_render_buffer(drawable,
737 YAGL_LOG_ERROR("DRI3 buffer object allocation failure");
741 /* When resizing, copy the contents of the old buffer, waiting for that
742 * copy to complete using our fences before proceeding
744 switch (buffer_type) {
745 case yagl_dri3_buffer_back:
747 yagl_dri3_fence_reset(c, new_buffer);
748 yagl_dri3_fence_await(c, buffer);
749 yagl_dri3_copy_area(c,
752 yagl_dri3_drawable_gc(drawable),
759 yagl_dri3_fence_trigger(c, new_buffer);
760 yagl_dri3_free_render_buffer(drawable, buffer);
763 case yagl_dri3_buffer_front:
764 yagl_dri3_fence_reset(c, new_buffer);
765 yagl_dri3_copy_area(c,
766 YAGL_X11_DRAWABLE(drawable->base.os_drawable),
768 yagl_dri3_drawable_gc(drawable),
775 yagl_dri3_fence_trigger(c, new_buffer);
781 buffer->buffer_type = buffer_type;
782 drawable->buffers[buf_id] = buffer;
785 yagl_dri3_fence_await(c, buffer);
790 static int yagl_dri3_drawable_get_buffer(struct yagl_native_drawable *drawable,
791 yagl_native_attachment attachment,
792 uint32_t *buffer_name,
793 struct vigs_drm_surface **buffer_sfc)
795 struct yagl_dri3_drawable *dri3_drawable = (struct yagl_dri3_drawable *)drawable;
796 struct yagl_dri3_buffer *buffer;
797 vigs_drm_surface_format format;
799 YAGL_LOG_FUNC_SET(yagl_dri3_drawable_get_buffer);
801 YAGL_LOG_DEBUG("enter: attachment = %d", attachment);
803 if (!yagl_dri3_update_drawable(dri3_drawable)) {
804 YAGL_LOG_ERROR("DRI3 drawable update failure");
808 switch (dri3_drawable->depth) {
810 format = vigs_drm_surface_bgrx8888;
813 format = vigs_drm_surface_bgra8888;
816 YAGL_LOG_ERROR("DRI3 bad drawable depth %d", dri3_drawable->depth);
820 switch (attachment) {
821 case yagl_native_attachment_front:
822 buffer = yagl_dri3_get_pixmap_buffer(dri3_drawable,
824 yagl_dri3_buffer_front);
826 case yagl_native_attachment_back:
827 buffer = yagl_dri3_get_buffer(dri3_drawable,
829 yagl_dri3_buffer_back);
832 YAGL_LOG_ERROR("DRI3 bad attachment %u", attachment);
837 YAGL_LOG_ERROR("DRI3 get_buffer failed for attachement %d", attachment);
841 vigs_drm_gem_ref(&buffer->sfc->gem);
842 *buffer_sfc = buffer->sfc;
847 static int yagl_dri3_drawable_get_buffer_age(struct yagl_native_drawable *drawable)
849 Display *x_dpy = YAGL_X11_DPY(drawable->dpy->os_dpy);
850 xcb_connection_t *c = XGetXCBConnection(x_dpy);
851 struct yagl_dri3_drawable *dri3_drawable = (struct yagl_dri3_drawable *)drawable;
852 int back_id = DRI3_BACK_ID(yagl_dri3_find_back(c, dri3_drawable));
853 struct yagl_dri3_buffer *back = dri3_drawable->buffers[back_id];
855 YAGL_LOG_FUNC_SET(yagl_dri3_drawable_get_buffer_age);
857 YAGL_LOG_DEBUG("enter");
859 if (back_id < 0 || !back) {
863 if (back->last_swap != 0) {
864 return dri3_drawable->send_sbc - back->last_swap + 1;
870 static void yagl_dri3_drawable_swap_buffers(struct yagl_native_drawable *drawable)
872 Display *x_dpy = YAGL_X11_DPY(drawable->dpy->os_dpy);
873 xcb_connection_t *c = XGetXCBConnection(x_dpy);
874 struct yagl_dri3_drawable *dri3_drawable = (struct yagl_dri3_drawable *)drawable;
875 struct yagl_dri3_buffer *back = yagl_dri3_back_buffer(dri3_drawable);
876 int64_t target_msc = 0;
878 int64_t remainder = 0;
880 YAGL_LOG_FUNC_SET(yagl_dri3_drawable_swap_buffers);
882 yagl_dri3_flush_present_events(dri3_drawable);
884 if (back && !dri3_drawable->is_pixmap) {
885 yagl_dri3_fence_reset(c, back);
887 ++dri3_drawable->send_sbc;
889 target_msc = dri3_drawable->msc + dri3_drawable->swap_interval *
890 (dri3_drawable->send_sbc - dri3_drawable->recv_sbc);
892 YAGL_LOG_DEBUG("msc = %llu, swap_interval = %d, "
893 "send_sbc = %llu, recv_sbc = %llu, "
896 dri3_drawable->swap_interval,
897 dri3_drawable->send_sbc,
898 dri3_drawable->recv_sbc,
902 back->last_swap = dri3_drawable->send_sbc;
904 xcb_present_pixmap(c,
905 YAGL_X11_DRAWABLE(drawable->os_drawable), /* dst*/
906 back->pixmap, /* src */
907 (uint32_t)dri3_drawable->send_sbc, /* serial */
912 None, /* target_crtc */
913 None, /* wait_fence */
914 back->sync_fence, /* idle_fence */
915 XCB_PRESENT_OPTION_NONE, /* options */
916 target_msc, /* target_msc */
917 divisor, /* divisor */
918 remainder, /* remainder */
919 0, /* notifies_len */
920 NULL /* notifies */);
928 static void yagl_dri3_drawable_wait(struct yagl_native_drawable *drawable,
932 struct yagl_dri3_drawable *dri3_drawable = (struct yagl_dri3_drawable *)drawable;
933 struct yagl_dri3_buffer *front;
935 YAGL_LOG_FUNC_SET(yagl_dri3_drawable_wait);
937 YAGL_LOG_DEBUG("enter");
939 if (!dri3_drawable->is_pixmap) {
943 front = yagl_dri3_front_buffer(dri3_drawable);
945 yagl_dri3_copy_drawable(dri3_drawable,
947 YAGL_X11_DRAWABLE(drawable->os_drawable));
950 static void yagl_dri3_drawable_copy_to_pixmap(struct yagl_native_drawable *drawable,
951 yagl_os_pixmap os_pixmap,
959 struct yagl_dri3_drawable *dri3_drawable = (struct yagl_dri3_drawable *)drawable;
960 struct yagl_dri3_buffer *front = yagl_dri3_front_buffer(dri3_drawable);
961 Display *x_dpy = YAGL_X11_DPY(drawable->dpy->os_dpy);
962 xcb_connection_t *c = XGetXCBConnection(x_dpy);
966 YAGL_LOG_FUNC_SET(yagl_dri3_drawable_copy_to_pixmap);
968 YAGL_LOG_DEBUG("enter");
971 (gc = xcb_generate_id(c)),
972 YAGL_X11_DRAWABLE(os_pixmap),
973 XCB_GC_GRAPHICS_EXPOSURES,
976 yagl_dri3_fence_reset(c, front);
977 yagl_dri3_copy_area(c,
978 YAGL_X11_DRAWABLE(drawable->os_drawable),
979 YAGL_X11_DRAWABLE(os_pixmap),
987 yagl_dri3_fence_trigger(c, front);
988 yagl_dri3_fence_await(c, front);
993 static void yagl_dri3_drawable_set_swap_interval(struct yagl_native_drawable *drawable,
996 struct yagl_dri3_drawable *dri3_drawable = (struct yagl_dri3_drawable *)drawable;
998 YAGL_LOG_FUNC_SET(yagl_dri3_drawable_set_swap_interval);
1000 YAGL_LOG_DEBUG("is_pixmap = %d, interval = %d",
1001 dri3_drawable->is_pixmap,
1004 if (dri3_drawable->is_pixmap) {
1008 dri3_drawable->swap_interval = interval;
1009 yagl_dri3_update_num_back(dri3_drawable);
1012 static void yagl_dri3_drawable_get_geometry(struct yagl_native_drawable *drawable,
1017 struct yagl_dri3_drawable *dri3_drawable = (struct yagl_dri3_drawable *)drawable;
1019 YAGL_LOG_FUNC_SET(yagl_dri3_drawable_get_geometry);
1021 YAGL_LOG_DEBUG("enter");
1023 *width = dri3_drawable->width;
1024 *height = dri3_drawable->height;
1025 *depth = dri3_drawable->depth;
1028 static struct yagl_native_image *yagl_dri3_drawable_get_image(struct yagl_native_drawable *drawable,
1035 static void yagl_dri3_drawable_destroy(struct yagl_native_drawable *drawable)
1037 struct yagl_dri3_drawable *dri3_drawable = (struct yagl_dri3_drawable *)drawable;
1038 Display *x_dpy = YAGL_X11_DPY(drawable->dpy->os_dpy);
1039 Drawable x_drawable = YAGL_X11_DRAWABLE(drawable->os_drawable);
1040 xcb_connection_t *c = XGetXCBConnection(x_dpy);
1043 YAGL_LOG_FUNC_SET(yagl_dri3_drawable_destroy);
1045 YAGL_LOG_DEBUG("enter");
1047 for (i = 0; i < DRI3_NUM_BUFFERS; i++) {
1048 if (dri3_drawable->buffers[i]) {
1049 yagl_dri3_free_render_buffer(dri3_drawable,
1050 dri3_drawable->buffers[i]);
1054 if (dri3_drawable->special_event) {
1055 xcb_unregister_for_special_event(c, dri3_drawable->special_event);
1058 if (dri3_drawable->gc) {
1059 xcb_free_gc(c, dri3_drawable->gc);
1062 if (dri3_drawable->own_drawable) {
1063 if (dri3_drawable->is_pixmap) {
1064 xcb_free_pixmap(c, x_drawable);
1066 xcb_destroy_window(c, x_drawable);
1070 yagl_native_drawable_cleanup(drawable);
1072 yagl_free(dri3_drawable);
1075 struct yagl_native_drawable *yagl_dri3_drawable_create(struct yagl_native_display *dpy,
1076 yagl_os_drawable os_drawable,
1080 struct yagl_dri3_drawable *drawable;
1082 YAGL_LOG_FUNC_SET(yagl_dri3_drawable_create);
1084 drawable = yagl_malloc0(sizeof(*drawable));
1087 YAGL_LOG_ERROR("DRI3 Drawable object allocation failure %s",
1092 yagl_native_drawable_init(&drawable->base,
1096 drawable->base.get_buffer = &yagl_dri3_drawable_get_buffer;
1097 drawable->base.get_buffer_age = &yagl_dri3_drawable_get_buffer_age;
1098 drawable->base.swap_buffers = &yagl_dri3_drawable_swap_buffers;
1099 drawable->base.wait = &yagl_dri3_drawable_wait;
1100 drawable->base.copy_to_pixmap = &yagl_dri3_drawable_copy_to_pixmap;
1101 drawable->base.set_swap_interval = &yagl_dri3_drawable_set_swap_interval;
1102 drawable->base.get_geometry = &yagl_dri3_drawable_get_geometry;
1103 drawable->base.get_image = &yagl_dri3_drawable_get_image;
1104 drawable->base.destroy = &yagl_dri3_drawable_destroy;
1106 drawable->swap_interval = 1; /* default */
1107 drawable->own_drawable = own_drawable;
1108 drawable->is_pixmap = is_pixmap;
1110 yagl_dri3_update_num_back(drawable);
1112 YAGL_LOG_DEBUG("os_drawable = %p, is_pixmap = %d, own_drawable = %d",
1113 (void *)os_drawable,
1117 return &drawable->base;
1120 static int yagl_dri3_display_check(Display *x_dpy)
1122 xcb_connection_t *c = XGetXCBConnection(x_dpy);
1123 xcb_dri3_query_version_cookie_t dri3_cookie;
1124 xcb_dri3_query_version_reply_t *dri3_reply;
1125 xcb_present_query_version_cookie_t present_cookie;
1126 xcb_present_query_version_reply_t *present_reply;
1127 xcb_generic_error_t *error;
1128 const xcb_query_extension_reply_t *extension;
1130 YAGL_LOG_FUNC_SET(yagl_dri3_display_check);
1132 xcb_prefetch_extension_data(c, &xcb_dri3_id);
1133 xcb_prefetch_extension_data(c, &xcb_present_id);
1135 extension = xcb_get_extension_data(c, &xcb_dri3_id);
1137 if (!(extension && extension->present)) {
1138 YAGL_LOG_DEBUG("dri3 extension not supported");
1142 extension = xcb_get_extension_data(c, &xcb_present_id);
1144 if (!(extension && extension->present)) {
1145 YAGL_LOG_DEBUG("present extension not supported");
1149 dri3_cookie = xcb_dri3_query_version(c,
1150 XCB_DRI3_MAJOR_VERSION,
1151 XCB_DRI3_MINOR_VERSION);
1154 present_cookie = xcb_present_query_version(c,
1155 XCB_PRESENT_MAJOR_VERSION,
1156 XCB_PRESENT_MINOR_VERSION);
1158 dri3_reply = xcb_dri3_query_version_reply(c, dri3_cookie, &error);
1161 YAGL_LOG_DEBUG("dri3: version query failed");
1166 YAGL_LOG_DEBUG("dri3: major = %d, minor = %d",
1167 dri3_reply->major_version,
1168 dri3_reply->minor_version);
1172 present_reply = xcb_present_query_version_reply(c, present_cookie, &error);
1174 if (!present_reply) {
1175 YAGL_LOG_DEBUG("present: version query failed");
1180 YAGL_LOG_DEBUG("present: major = %d, minor = %d",
1181 present_reply->major_version,
1182 present_reply->minor_version);
1184 free(present_reply);
1189 int yagl_dri3_display_init(Display *x_dpy, char **dri_device)
1191 xcb_dri3_open_cookie_t cookie;
1192 xcb_dri3_open_reply_t *reply;
1193 xcb_connection_t *c = XGetXCBConnection(x_dpy);
1196 YAGL_LOG_FUNC_SET(yagl_x11_display_dri3_init);
1198 if (!yagl_dri3_display_check(x_dpy)) {
1199 YAGL_LOG_ERROR("Error: yagl_dri3_display_check failed\n");
1203 cookie = xcb_dri3_open(c, RootWindow(x_dpy, DefaultScreen(x_dpy)), None);
1205 reply = xcb_dri3_open_reply(c, cookie, NULL);
1208 YAGL_LOG_ERROR("Error: xcb_dri3_open_reply failed\n");
1212 if (reply->nfd != 1) {
1213 YAGL_LOG_ERROR("Error: reply->nfd != 1 (%d)\n", reply->nfd);
1218 fd = xcb_dri3_open_reply_fds(c, reply)[0];
1219 fcntl(fd, F_SETFD, FD_CLOEXEC);
1220 *dri_device = drmGetDeviceNameFromFd(fd);
1222 YAGL_LOG_DEBUG("dri3 display init: fd = %d, dri_device = %s",