2 * Copyright © 2013 Keith Packard
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
24 * Portions of this code were adapted from dri2_glx.c which carries the
25 * following copyright:
27 * Copyright © 2008 Red Hat, Inc.
29 * Permission is hereby granted, free of charge, to any person obtaining a
30 * copy of this software and associated documentation files (the "Soft-
31 * ware"), to deal in the Software without restriction, including without
32 * limitation the rights to use, copy, modify, merge, publish, distribute,
33 * and/or sell copies of the Software, and to permit persons to whom the
34 * Software is furnished to do so, provided that the above copyright
35 * notice(s) and this permission notice appear in all copies of the Soft-
36 * ware and that both the above copyright notice(s) and this permission
37 * notice appear in supporting documentation.
39 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
40 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
41 * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
42 * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
43 * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
44 * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
45 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
46 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
47 * MANCE OF THIS SOFTWARE.
49 * Except as contained in this notice, the name of a copyright holder shall
50 * not be used in advertising or otherwise to promote the sale, use or
51 * other dealings in this Software without prior written authorization of
52 * the copyright holder.
55 * Kristian Høgsberg (krh@redhat.com)
58 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
61 #include <X11/extensions/Xfixes.h>
62 #include <X11/Xlib-xcb.h>
63 #include <X11/xshmfence.h>
66 #include <xcb/present.h>
68 #include "glxclient.h"
72 #include <sys/types.h>
76 #include "dri_common.h"
77 #include "dri3_priv.h"
81 static const struct glx_context_vtable dri3_context_vtable
;
84 dri3_fence_reset(xcb_connection_t
*c
, struct dri3_buffer
*buffer
)
86 xshmfence_reset(buffer
->shm_fence
);
90 dri3_fence_set(struct dri3_buffer
*buffer
)
92 xshmfence_trigger(buffer
->shm_fence
);
96 dri3_fence_trigger(xcb_connection_t
*c
, struct dri3_buffer
*buffer
)
98 xcb_sync_trigger_fence(c
, buffer
->sync_fence
);
102 dri3_fence_await(xcb_connection_t
*c
, struct dri3_buffer
*buffer
)
105 xshmfence_await(buffer
->shm_fence
);
109 dri3_fence_triggered(struct dri3_buffer
*buffer
)
111 return xshmfence_query(buffer
->shm_fence
);
115 dri3_destroy_context(struct glx_context
*context
)
117 struct dri3_context
*pcp
= (struct dri3_context
*) context
;
118 struct dri3_screen
*psc
= (struct dri3_screen
*) context
->psc
;
120 driReleaseDrawables(&pcp
->base
);
122 free((char *) context
->extensions
);
124 (*psc
->core
->destroyContext
) (pcp
->driContext
);
130 dri3_bind_context(struct glx_context
*context
, struct glx_context
*old
,
131 GLXDrawable draw
, GLXDrawable read
)
133 struct dri3_context
*pcp
= (struct dri3_context
*) context
;
134 struct dri3_screen
*psc
= (struct dri3_screen
*) pcp
->base
.psc
;
135 struct dri3_drawable
*pdraw
, *pread
;
137 pdraw
= (struct dri3_drawable
*) driFetchDrawable(context
, draw
);
138 pread
= (struct dri3_drawable
*) driFetchDrawable(context
, read
);
140 driReleaseDrawables(&pcp
->base
);
142 if (pdraw
== NULL
|| pread
== NULL
)
143 return GLXBadDrawable
;
145 if (!(*psc
->core
->bindContext
) (pcp
->driContext
,
146 pdraw
->driDrawable
, pread
->driDrawable
))
147 return GLXBadContext
;
153 dri3_unbind_context(struct glx_context
*context
, struct glx_context
*new)
155 struct dri3_context
*pcp
= (struct dri3_context
*) context
;
156 struct dri3_screen
*psc
= (struct dri3_screen
*) pcp
->base
.psc
;
158 (*psc
->core
->unbindContext
) (pcp
->driContext
);
161 static struct glx_context
*
162 dri3_create_context_attribs(struct glx_screen
*base
,
163 struct glx_config
*config_base
,
164 struct glx_context
*shareList
,
165 unsigned num_attribs
,
166 const uint32_t *attribs
,
169 struct dri3_context
*pcp
= NULL
;
170 struct dri3_context
*pcp_shared
= NULL
;
171 struct dri3_screen
*psc
= (struct dri3_screen
*) base
;
172 __GLXDRIconfigPrivate
*config
= (__GLXDRIconfigPrivate
*) config_base
;
173 __DRIcontext
*shared
= NULL
;
175 uint32_t minor_ver
= 1;
176 uint32_t major_ver
= 2;
179 int reset
= __DRI_CTX_RESET_NO_NOTIFICATION
;
180 uint32_t ctx_attribs
[2 * 5];
181 unsigned num_ctx_attribs
= 0;
182 uint32_t render_type
;
184 /* Remap the GLX tokens to DRI2 tokens.
186 if (!dri2_convert_glx_attribs(num_attribs
, attribs
,
187 &major_ver
, &minor_ver
,
188 &render_type
, &flags
, &api
,
192 /* Check the renderType value */
193 if (!validate_renderType_against_config(config_base
, render_type
))
197 pcp_shared
= (struct dri3_context
*) shareList
;
198 shared
= pcp_shared
->driContext
;
201 pcp
= calloc(1, sizeof *pcp
);
203 *error
= __DRI_CTX_ERROR_NO_MEMORY
;
207 if (!glx_context_init(&pcp
->base
, &psc
->base
, &config
->base
))
210 ctx_attribs
[num_ctx_attribs
++] = __DRI_CTX_ATTRIB_MAJOR_VERSION
;
211 ctx_attribs
[num_ctx_attribs
++] = major_ver
;
212 ctx_attribs
[num_ctx_attribs
++] = __DRI_CTX_ATTRIB_MINOR_VERSION
;
213 ctx_attribs
[num_ctx_attribs
++] = minor_ver
;
215 /* Only send a value when the non-default value is requested. By doing
216 * this we don't have to check the driver's DRI3 version before sending the
219 if (reset
!= __DRI_CTX_RESET_NO_NOTIFICATION
) {
220 ctx_attribs
[num_ctx_attribs
++] = __DRI_CTX_ATTRIB_RESET_STRATEGY
;
221 ctx_attribs
[num_ctx_attribs
++] = reset
;
225 ctx_attribs
[num_ctx_attribs
++] = __DRI_CTX_ATTRIB_FLAGS
;
227 /* The current __DRI_CTX_FLAG_* values are identical to the
228 * GLX_CONTEXT_*_BIT values.
230 ctx_attribs
[num_ctx_attribs
++] = flags
;
234 (*psc
->image_driver
->createContextAttribs
) (psc
->driScreen
,
243 if (pcp
->driContext
== NULL
)
246 pcp
->base
.vtable
= &dri3_context_vtable
;
256 static struct glx_context
*
257 dri3_create_context(struct glx_screen
*base
,
258 struct glx_config
*config_base
,
259 struct glx_context
*shareList
, int renderType
)
263 return dri3_create_context_attribs(base
, config_base
, shareList
,
268 dri3_free_render_buffer(struct dri3_drawable
*pdraw
, struct dri3_buffer
*buffer
);
271 dri3_update_num_back(struct dri3_drawable
*priv
)
274 if (priv
->flipping
) {
275 if (!priv
->is_pixmap
&& !(priv
->present_capabilities
& XCB_PRESENT_CAPABILITY_ASYNC
))
279 if (priv
->swap_interval
== 0)
284 dri3_destroy_drawable(__GLXDRIdrawable
*base
)
286 struct dri3_screen
*psc
= (struct dri3_screen
*) base
->psc
;
287 struct dri3_drawable
*pdraw
= (struct dri3_drawable
*) base
;
288 xcb_connection_t
*c
= XGetXCBConnection(pdraw
->base
.psc
->dpy
);
291 (*psc
->core
->destroyDrawable
) (pdraw
->driDrawable
);
293 for (i
= 0; i
< DRI3_NUM_BUFFERS
; i
++) {
294 if (pdraw
->buffers
[i
])
295 dri3_free_render_buffer(pdraw
, pdraw
->buffers
[i
]);
298 if (pdraw
->special_event
)
299 xcb_unregister_for_special_event(c
, pdraw
->special_event
);
303 static __GLXDRIdrawable
*
304 dri3_create_drawable(struct glx_screen
*base
, XID xDrawable
,
305 GLXDrawable drawable
, struct glx_config
*config_base
)
307 struct dri3_drawable
*pdraw
;
308 struct dri3_screen
*psc
= (struct dri3_screen
*) base
;
309 __GLXDRIconfigPrivate
*config
= (__GLXDRIconfigPrivate
*) config_base
;
310 GLint vblank_mode
= DRI_CONF_VBLANK_DEF_INTERVAL_1
;
312 pdraw
= calloc(1, sizeof(*pdraw
));
316 pdraw
->base
.destroyDrawable
= dri3_destroy_drawable
;
317 pdraw
->base
.xDrawable
= xDrawable
;
318 pdraw
->base
.drawable
= drawable
;
319 pdraw
->base
.psc
= &psc
->base
;
320 pdraw
->swap_interval
= 1; /* default may be overridden below */
321 pdraw
->have_back
= 0;
322 pdraw
->have_fake_front
= 0;
325 psc
->config
->configQueryi(psc
->driScreen
,
326 "vblank_mode", &vblank_mode
);
328 switch (vblank_mode
) {
329 case DRI_CONF_VBLANK_NEVER
:
330 case DRI_CONF_VBLANK_DEF_INTERVAL_0
:
331 pdraw
->swap_interval
= 0;
333 case DRI_CONF_VBLANK_DEF_INTERVAL_1
:
334 case DRI_CONF_VBLANK_ALWAYS_SYNC
:
336 pdraw
->swap_interval
= 1;
340 dri3_update_num_back(pdraw
);
342 (void) __glXInitialize(psc
->base
.dpy
);
344 /* Create a new drawable */
346 (*psc
->image_driver
->createNewDrawable
) (psc
->driScreen
,
347 config
->driConfig
, pdraw
);
349 if (!pdraw
->driDrawable
) {
355 * Make sure server has the same swap interval we do for the new
358 if (psc
->vtable
.setSwapInterval
)
359 psc
->vtable
.setSwapInterval(&pdraw
->base
, pdraw
->swap_interval
);
365 show_fps(struct dri3_drawable
*draw
, uint64_t current_ust
)
367 const uint64_t interval
=
368 ((struct dri3_screen
*) draw
->base
.psc
)->show_fps_interval
;
372 /* DRI3+Present together uses microseconds for UST. */
373 if (draw
->previous_ust
+ interval
* 1000000 <= current_ust
) {
374 if (draw
->previous_ust
) {
375 fprintf(stderr
, "libGL: FPS = %.1f\n",
376 ((uint64_t) draw
->frames
* 1000000) /
377 (double)(current_ust
- draw
->previous_ust
));
380 draw
->previous_ust
= current_ust
;
385 * Process one Present event
388 dri3_handle_present_event(struct dri3_drawable
*priv
, xcb_present_generic_event_t
*ge
)
390 struct dri3_screen
*psc
= (struct dri3_screen
*) priv
->base
.psc
;
392 switch (ge
->evtype
) {
393 case XCB_PRESENT_CONFIGURE_NOTIFY
: {
394 xcb_present_configure_notify_event_t
*ce
= (void *) ge
;
396 priv
->width
= ce
->width
;
397 priv
->height
= ce
->height
;
400 case XCB_PRESENT_COMPLETE_NOTIFY
: {
401 xcb_present_complete_notify_event_t
*ce
= (void *) ge
;
403 /* Compute the processed SBC number from the received 32-bit serial number merged
404 * with the upper 32-bits of the sent 64-bit serial number while checking for
407 if (ce
->kind
== XCB_PRESENT_COMPLETE_KIND_PIXMAP
) {
408 priv
->recv_sbc
= (priv
->send_sbc
& 0xffffffff00000000LL
) | ce
->serial
;
409 if (priv
->recv_sbc
> priv
->send_sbc
)
410 priv
->recv_sbc
-= 0x100000000;
412 case XCB_PRESENT_COMPLETE_MODE_FLIP
:
413 priv
->flipping
= true;
415 case XCB_PRESENT_COMPLETE_MODE_COPY
:
416 priv
->flipping
= false;
419 dri3_update_num_back(priv
);
421 if (psc
->show_fps_interval
)
422 show_fps(priv
, ce
->ust
);
427 priv
->recv_msc_serial
= ce
->serial
;
428 priv
->notify_ust
= ce
->ust
;
429 priv
->notify_msc
= ce
->msc
;
433 case XCB_PRESENT_EVENT_IDLE_NOTIFY
: {
434 xcb_present_idle_notify_event_t
*ie
= (void *) ge
;
437 for (b
= 0; b
< sizeof (priv
->buffers
) / sizeof (priv
->buffers
[0]); b
++) {
438 struct dri3_buffer
*buf
= priv
->buffers
[b
];
440 if (buf
&& buf
->pixmap
== ie
->pixmap
) {
442 if (priv
->num_back
<= b
&& b
< DRI3_MAX_BACK
) {
443 dri3_free_render_buffer(priv
, buf
);
444 priv
->buffers
[b
] = NULL
;
456 dri3_wait_for_event(__GLXDRIdrawable
*pdraw
)
458 xcb_connection_t
*c
= XGetXCBConnection(pdraw
->psc
->dpy
);
459 struct dri3_drawable
*priv
= (struct dri3_drawable
*) pdraw
;
460 xcb_generic_event_t
*ev
;
461 xcb_present_generic_event_t
*ge
;
464 ev
= xcb_wait_for_special_event(c
, priv
->special_event
);
468 dri3_handle_present_event(priv
, ge
);
472 /** dri3_wait_for_msc
474 * Get the X server to send an event when the target msc/divisor/remainder is
478 dri3_wait_for_msc(__GLXDRIdrawable
*pdraw
, int64_t target_msc
, int64_t divisor
,
479 int64_t remainder
, int64_t *ust
, int64_t *msc
, int64_t *sbc
)
481 xcb_connection_t
*c
= XGetXCBConnection(pdraw
->psc
->dpy
);
482 struct dri3_drawable
*priv
= (struct dri3_drawable
*) pdraw
;
485 /* Ask for the an event for the target MSC */
486 msc_serial
= ++priv
->send_msc_serial
;
487 xcb_present_notify_msc(c
,
488 priv
->base
.xDrawable
,
496 /* Wait for the event */
497 if (priv
->special_event
) {
498 while ((int32_t) (msc_serial
- priv
->recv_msc_serial
) > 0) {
499 if (!dri3_wait_for_event(pdraw
))
504 *ust
= priv
->notify_ust
;
505 *msc
= priv
->notify_msc
;
506 *sbc
= priv
->recv_sbc
;
511 /** dri3_drawable_get_msc
513 * Return the current UST/MSC/SBC triplet by asking the server
517 dri3_drawable_get_msc(struct glx_screen
*psc
, __GLXDRIdrawable
*pdraw
,
518 int64_t *ust
, int64_t *msc
, int64_t *sbc
)
520 return dri3_wait_for_msc(pdraw
, 0, 0, 0, ust
, msc
,sbc
);
523 /** dri3_wait_for_sbc
525 * Wait for the completed swap buffer count to reach the specified
526 * target. Presumably the application knows that this will be reached with
527 * outstanding complete events, or we're going to be here awhile.
530 dri3_wait_for_sbc(__GLXDRIdrawable
*pdraw
, int64_t target_sbc
, int64_t *ust
,
531 int64_t *msc
, int64_t *sbc
)
533 struct dri3_drawable
*priv
= (struct dri3_drawable
*) pdraw
;
535 /* From the GLX_OML_sync_control spec:
537 * "If <target_sbc> = 0, the function will block until all previous
538 * swaps requested with glXSwapBuffersMscOML for that window have
542 target_sbc
= priv
->send_sbc
;
544 while (priv
->recv_sbc
< target_sbc
) {
545 if (!dri3_wait_for_event(pdraw
))
551 *sbc
= priv
->recv_sbc
;
556 * Asks the driver to flush any queued work necessary for serializing with the
557 * X command stream, and optionally the slightly more strict requirement of
558 * glFlush() equivalence (which would require flushing even if nothing had
559 * been drawn to a window system framebuffer, for example).
562 dri3_flush(struct dri3_screen
*psc
,
563 struct dri3_drawable
*draw
,
565 enum __DRI2throttleReason throttle_reason
)
567 struct glx_context
*gc
= __glXGetCurrentContext();
570 struct dri3_context
*dri3Ctx
= (struct dri3_context
*)gc
;
572 (*psc
->f
->flush_with_flags
)(dri3Ctx
->driContext
, draw
->driDrawable
, flags
, throttle_reason
);
576 static xcb_gcontext_t
577 dri3_drawable_gc(struct dri3_drawable
*priv
)
581 xcb_connection_t
*c
= XGetXCBConnection(priv
->base
.psc
->dpy
);
585 (priv
->gc
= xcb_generate_id(c
)),
586 priv
->base
.xDrawable
,
587 XCB_GC_GRAPHICS_EXPOSURES
,
593 static struct dri3_buffer
*
594 dri3_back_buffer(struct dri3_drawable
*priv
)
596 return priv
->buffers
[DRI3_BACK_ID(priv
->cur_back
)];
599 static struct dri3_buffer
*
600 dri3_fake_front_buffer(struct dri3_drawable
*priv
)
602 return priv
->buffers
[DRI3_FRONT_ID
];
606 dri3_copy_area (xcb_connection_t
*c
/**< */,
607 xcb_drawable_t src_drawable
/**< */,
608 xcb_drawable_t dst_drawable
/**< */,
609 xcb_gcontext_t gc
/**< */,
610 int16_t src_x
/**< */,
611 int16_t src_y
/**< */,
612 int16_t dst_x
/**< */,
613 int16_t dst_y
/**< */,
614 uint16_t width
/**< */,
615 uint16_t height
/**< */)
617 xcb_void_cookie_t cookie
;
619 cookie
= xcb_copy_area_checked(c
,
629 xcb_discard_reply(c
, cookie
.sequence
);
633 dri3_copy_sub_buffer(__GLXDRIdrawable
*pdraw
, int x
, int y
,
634 int width
, int height
,
637 struct dri3_drawable
*priv
= (struct dri3_drawable
*) pdraw
;
638 struct dri3_screen
*psc
= (struct dri3_screen
*) pdraw
->psc
;
639 struct dri3_context
*pcp
= (struct dri3_context
*) __glXGetCurrentContext();
640 xcb_connection_t
*c
= XGetXCBConnection(priv
->base
.psc
->dpy
);
641 struct dri3_buffer
*back
;
643 unsigned flags
= __DRI2_FLUSH_DRAWABLE
;
645 /* Check we have the right attachments */
646 if (!priv
->have_back
|| priv
->is_pixmap
)
650 flags
|= __DRI2_FLUSH_CONTEXT
;
651 dri3_flush(psc
, priv
, flags
, __DRI2_THROTTLE_SWAPBUFFER
);
653 back
= dri3_back_buffer(priv
);
654 y
= priv
->height
- y
- height
;
656 if (psc
->is_different_gpu
&& (&pcp
->base
!= &dummyContext
) && pcp
->base
.psc
== &psc
->base
) {
657 /* Update the linear buffer part of the back buffer
658 * for the dri3_copy_area operation
660 psc
->image
->blitImage(pcp
->driContext
,
666 back
->height
, __BLIT_FLAG_FLUSH
);
667 /* We use blitImage to update our fake front,
669 if (priv
->have_fake_front
)
670 psc
->image
->blitImage(pcp
->driContext
,
671 dri3_fake_front_buffer(priv
)->image
,
674 x
, y
, width
, height
, __BLIT_FLAG_FLUSH
);
677 dri3_fence_reset(c
, back
);
679 dri3_back_buffer(priv
)->pixmap
,
680 priv
->base
.xDrawable
,
681 dri3_drawable_gc(priv
),
682 x
, y
, x
, y
, width
, height
);
683 dri3_fence_trigger(c
, back
);
684 /* Refresh the fake front (if present) after we just damaged the real
687 if (priv
->have_fake_front
&& !psc
->is_different_gpu
) {
688 dri3_fence_reset(c
, dri3_fake_front_buffer(priv
));
690 dri3_back_buffer(priv
)->pixmap
,
691 dri3_fake_front_buffer(priv
)->pixmap
,
692 dri3_drawable_gc(priv
),
693 x
, y
, x
, y
, width
, height
);
694 dri3_fence_trigger(c
, dri3_fake_front_buffer(priv
));
695 dri3_fence_await(c
, dri3_fake_front_buffer(priv
));
697 dri3_fence_await(c
, back
);
701 dri3_copy_drawable(struct dri3_drawable
*priv
, Drawable dest
, Drawable src
)
703 struct dri3_screen
*psc
= (struct dri3_screen
*) priv
->base
.psc
;
704 xcb_connection_t
*c
= XGetXCBConnection(priv
->base
.psc
->dpy
);
706 dri3_flush(psc
, priv
, __DRI2_FLUSH_DRAWABLE
, 0);
708 dri3_fence_reset(c
, dri3_fake_front_buffer(priv
));
711 dri3_drawable_gc(priv
),
712 0, 0, 0, 0, priv
->width
, priv
->height
);
713 dri3_fence_trigger(c
, dri3_fake_front_buffer(priv
));
714 dri3_fence_await(c
, dri3_fake_front_buffer(priv
));
718 dri3_wait_x(struct glx_context
*gc
)
720 struct dri3_context
*pcp
= (struct dri3_context
*) gc
;
721 struct dri3_drawable
*priv
= (struct dri3_drawable
*)
722 GetGLXDRIDrawable(gc
->currentDpy
, gc
->currentDrawable
);
723 struct dri3_screen
*psc
;
724 struct dri3_buffer
*front
;
726 if (priv
== NULL
|| !priv
->have_fake_front
)
729 psc
= (struct dri3_screen
*) priv
->base
.psc
;
730 front
= dri3_fake_front_buffer(priv
);
732 dri3_copy_drawable(priv
, front
->pixmap
, priv
->base
.xDrawable
);
734 /* In the psc->is_different_gpu case, the linear buffer has been updated,
735 * but not yet the tiled buffer.
736 * Copy back to the tiled buffer we use for rendering.
737 * Note that we don't need flushing.
739 if (psc
->is_different_gpu
&& (&pcp
->base
!= &dummyContext
) && pcp
->base
.psc
== &psc
->base
)
740 psc
->image
->blitImage(pcp
->driContext
,
742 front
->linear_buffer
,
750 dri3_wait_gl(struct glx_context
*gc
)
752 struct dri3_context
*pcp
= (struct dri3_context
*) gc
;
753 struct dri3_drawable
*priv
= (struct dri3_drawable
*)
754 GetGLXDRIDrawable(gc
->currentDpy
, gc
->currentDrawable
);
755 struct dri3_screen
*psc
;
756 struct dri3_buffer
*front
;
758 if (priv
== NULL
|| !priv
->have_fake_front
)
761 psc
= (struct dri3_screen
*) priv
->base
.psc
;
762 front
= dri3_fake_front_buffer(priv
);
764 /* In the psc->is_different_gpu case, we update the linear_buffer
765 * before updating the real front.
767 if (psc
->is_different_gpu
&& (&pcp
->base
!= &dummyContext
) && pcp
->base
.psc
== &psc
->base
)
768 psc
->image
->blitImage(pcp
->driContext
,
769 front
->linear_buffer
,
774 front
->height
, __BLIT_FLAG_FLUSH
);
775 dri3_copy_drawable(priv
, priv
->base
.xDrawable
, front
->pixmap
);
779 * Called by the driver when it needs to update the real front buffer with the
780 * contents of its fake front buffer.
783 dri3_flush_front_buffer(__DRIdrawable
*driDrawable
, void *loaderPrivate
)
785 struct glx_context
*gc
;
786 struct dri3_drawable
*pdraw
= loaderPrivate
;
787 struct dri3_screen
*psc
;
792 if (!pdraw
->base
.psc
)
795 psc
= (struct dri3_screen
*) pdraw
->base
.psc
;
797 (void) __glXInitialize(psc
->base
.dpy
);
799 gc
= __glXGetCurrentContext();
801 dri3_flush(psc
, pdraw
, __DRI2_FLUSH_DRAWABLE
, __DRI2_THROTTLE_FLUSHFRONT
);
807 dri3_cpp_for_format(uint32_t format
) {
809 case __DRI_IMAGE_FORMAT_R8
:
811 case __DRI_IMAGE_FORMAT_RGB565
:
812 case __DRI_IMAGE_FORMAT_GR88
:
814 case __DRI_IMAGE_FORMAT_XRGB8888
:
815 case __DRI_IMAGE_FORMAT_ARGB8888
:
816 case __DRI_IMAGE_FORMAT_ABGR8888
:
817 case __DRI_IMAGE_FORMAT_XBGR8888
:
818 case __DRI_IMAGE_FORMAT_XRGB2101010
:
819 case __DRI_IMAGE_FORMAT_ARGB2101010
:
820 case __DRI_IMAGE_FORMAT_SARGB8
:
822 case __DRI_IMAGE_FORMAT_NONE
:
829 /** dri3_alloc_render_buffer
831 * Use the driver createImage function to construct a __DRIimage, then
832 * get a file descriptor for that and create an X pixmap from that
834 * Allocate an xshmfence for synchronization
836 static struct dri3_buffer
*
837 dri3_alloc_render_buffer(struct glx_screen
*glx_screen
, Drawable draw
,
838 unsigned int format
, int width
, int height
, int depth
)
840 struct dri3_screen
*psc
= (struct dri3_screen
*) glx_screen
;
841 Display
*dpy
= glx_screen
->dpy
;
842 struct dri3_buffer
*buffer
;
843 __DRIimage
*pixmap_buffer
;
844 xcb_connection_t
*c
= XGetXCBConnection(dpy
);
846 xcb_sync_fence_t sync_fence
;
847 struct xshmfence
*shm_fence
;
848 int buffer_fd
, fence_fd
;
851 /* Create an xshmfence object and
852 * prepare to send that to the X server
855 fence_fd
= xshmfence_alloc_shm();
857 ErrorMessageF("DRI3 Fence object allocation failure %s\n", strerror(errno
));
860 shm_fence
= xshmfence_map_shm(fence_fd
);
861 if (shm_fence
== NULL
) {
862 ErrorMessageF("DRI3 Fence object map failure %s\n", strerror(errno
));
866 /* Allocate the image from the driver
868 buffer
= calloc(1, sizeof (struct dri3_buffer
));
872 buffer
->cpp
= dri3_cpp_for_format(format
);
874 ErrorMessageF("DRI3 buffer format %d invalid\n", format
);
878 if (!psc
->is_different_gpu
) {
879 buffer
->image
= (*psc
->image
->createImage
) (psc
->driScreen
,
882 __DRI_IMAGE_USE_SHARE
|
883 __DRI_IMAGE_USE_SCANOUT
,
885 pixmap_buffer
= buffer
->image
;
887 if (!buffer
->image
) {
888 ErrorMessageF("DRI3 gpu image creation failure\n");
892 buffer
->image
= (*psc
->image
->createImage
) (psc
->driScreen
,
898 if (!buffer
->image
) {
899 ErrorMessageF("DRI3 other gpu image creation failure\n");
903 buffer
->linear_buffer
= (*psc
->image
->createImage
) (psc
->driScreen
,
906 __DRI_IMAGE_USE_SHARE
|
907 __DRI_IMAGE_USE_LINEAR
,
909 pixmap_buffer
= buffer
->linear_buffer
;
911 if (!buffer
->linear_buffer
) {
912 ErrorMessageF("DRI3 gpu linear image creation failure\n");
913 goto no_linear_buffer
;
917 /* X wants the stride, so ask the image for it
919 if (!(*psc
->image
->queryImage
)(pixmap_buffer
, __DRI_IMAGE_ATTRIB_STRIDE
, &stride
)) {
920 ErrorMessageF("DRI3 get image stride failed\n");
921 goto no_buffer_attrib
;
924 buffer
->pitch
= stride
;
926 if (!(*psc
->image
->queryImage
)(pixmap_buffer
, __DRI_IMAGE_ATTRIB_FD
, &buffer_fd
)) {
927 ErrorMessageF("DRI3 get image FD failed\n");
928 goto no_buffer_attrib
;
931 xcb_dri3_pixmap_from_buffer(c
,
932 (pixmap
= xcb_generate_id(c
)),
935 width
, height
, buffer
->pitch
,
936 depth
, buffer
->cpp
* 8,
939 xcb_dri3_fence_from_fd(c
,
941 (sync_fence
= xcb_generate_id(c
)),
945 buffer
->pixmap
= pixmap
;
946 buffer
->own_pixmap
= true;
947 buffer
->sync_fence
= sync_fence
;
948 buffer
->shm_fence
= shm_fence
;
949 buffer
->width
= width
;
950 buffer
->height
= height
;
952 /* Mark the buffer as idle
954 dri3_fence_set(buffer
);
959 (*psc
->image
->destroyImage
)(pixmap_buffer
);
961 if (psc
->is_different_gpu
)
962 (*psc
->image
->destroyImage
)(buffer
->image
);
966 xshmfence_unmap_shm(shm_fence
);
969 ErrorMessageF("DRI3 alloc_render_buffer failed\n");
973 /** dri3_free_render_buffer
975 * Free everything associated with one render buffer including pixmap, fence
976 * stuff and the driver image
979 dri3_free_render_buffer(struct dri3_drawable
*pdraw
, struct dri3_buffer
*buffer
)
981 struct dri3_screen
*psc
= (struct dri3_screen
*) pdraw
->base
.psc
;
982 xcb_connection_t
*c
= XGetXCBConnection(pdraw
->base
.psc
->dpy
);
984 if (buffer
->own_pixmap
)
985 xcb_free_pixmap(c
, buffer
->pixmap
);
986 xcb_sync_destroy_fence(c
, buffer
->sync_fence
);
987 xshmfence_unmap_shm(buffer
->shm_fence
);
988 (*psc
->image
->destroyImage
)(buffer
->image
);
989 if (buffer
->linear_buffer
)
990 (*psc
->image
->destroyImage
)(buffer
->linear_buffer
);
995 /** dri3_flush_present_events
997 * Process any present events that have been received from the X server
1000 dri3_flush_present_events(struct dri3_drawable
*priv
)
1002 xcb_connection_t
*c
= XGetXCBConnection(priv
->base
.psc
->dpy
);
1004 /* Check to see if any configuration changes have occurred
1005 * since we were last invoked
1007 if (priv
->special_event
) {
1008 xcb_generic_event_t
*ev
;
1010 while ((ev
= xcb_poll_for_special_event(c
, priv
->special_event
)) != NULL
) {
1011 xcb_present_generic_event_t
*ge
= (void *) ev
;
1012 dri3_handle_present_event(priv
, ge
);
1017 /** dri3_update_drawable
1019 * Called the first time we use the drawable and then
1020 * after we receive present configure notify events to
1021 * track the geometry of the drawable
1024 dri3_update_drawable(__DRIdrawable
*driDrawable
, void *loaderPrivate
)
1026 struct dri3_drawable
*priv
= loaderPrivate
;
1027 xcb_connection_t
*c
= XGetXCBConnection(priv
->base
.psc
->dpy
);
1029 /* First time through, go get the current drawable geometry
1031 if (priv
->width
== 0 || priv
->height
== 0 || priv
->depth
== 0) {
1032 xcb_get_geometry_cookie_t geom_cookie
;
1033 xcb_get_geometry_reply_t
*geom_reply
;
1034 xcb_void_cookie_t cookie
;
1035 xcb_generic_error_t
*error
;
1036 xcb_present_query_capabilities_cookie_t present_capabilities_cookie
;
1037 xcb_present_query_capabilities_reply_t
*present_capabilities_reply
;
1040 /* Try to select for input on the window.
1042 * If the drawable is a window, this will get our events
1045 * Otherwise, we'll get a BadWindow error back from this request which
1046 * will let us know that the drawable is a pixmap instead.
1050 cookie
= xcb_present_select_input_checked(c
,
1051 (priv
->eid
= xcb_generate_id(c
)),
1052 priv
->base
.xDrawable
,
1053 XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY
|
1054 XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY
|
1055 XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY
);
1057 present_capabilities_cookie
= xcb_present_query_capabilities(c
, priv
->base
.xDrawable
);
1059 /* Create an XCB event queue to hold present events outside of the usual
1060 * application event queue
1062 priv
->special_event
= xcb_register_for_special_xge(c
,
1067 geom_cookie
= xcb_get_geometry(c
, priv
->base
.xDrawable
);
1069 geom_reply
= xcb_get_geometry_reply(c
, geom_cookie
, NULL
);
1074 priv
->width
= geom_reply
->width
;
1075 priv
->height
= geom_reply
->height
;
1076 priv
->depth
= geom_reply
->depth
;
1077 priv
->is_pixmap
= false;
1081 /* Check to see if our select input call failed. If it failed with a
1082 * BadWindow error, then assume the drawable is a pixmap. Destroy the
1083 * special event queue created above and mark the drawable as a pixmap
1086 error
= xcb_request_check(c
, cookie
);
1088 present_capabilities_reply
= xcb_present_query_capabilities_reply(c
,
1089 present_capabilities_cookie
,
1092 if (present_capabilities_reply
) {
1093 priv
->present_capabilities
= present_capabilities_reply
->capabilities
;
1094 free(present_capabilities_reply
);
1096 priv
->present_capabilities
= 0;
1099 if (error
->error_code
!= BadWindow
) {
1103 priv
->is_pixmap
= true;
1104 xcb_unregister_for_special_event(c
, priv
->special_event
);
1105 priv
->special_event
= NULL
;
1108 dri3_flush_present_events(priv
);
1112 /* the DRIimage createImage function takes __DRI_IMAGE_FORMAT codes, while
1113 * the createImageFromFds call takes __DRI_IMAGE_FOURCC codes. To avoid
1114 * complete confusion, just deal in __DRI_IMAGE_FORMAT codes for now and
1115 * translate to __DRI_IMAGE_FOURCC codes in the call to createImageFromFds
1118 image_format_to_fourcc(int format
)
1121 /* Convert from __DRI_IMAGE_FORMAT to __DRI_IMAGE_FOURCC (sigh) */
1123 case __DRI_IMAGE_FORMAT_SARGB8
: return __DRI_IMAGE_FOURCC_SARGB8888
;
1124 case __DRI_IMAGE_FORMAT_RGB565
: return __DRI_IMAGE_FOURCC_RGB565
;
1125 case __DRI_IMAGE_FORMAT_XRGB8888
: return __DRI_IMAGE_FOURCC_XRGB8888
;
1126 case __DRI_IMAGE_FORMAT_ARGB8888
: return __DRI_IMAGE_FOURCC_ARGB8888
;
1127 case __DRI_IMAGE_FORMAT_ABGR8888
: return __DRI_IMAGE_FOURCC_ABGR8888
;
1128 case __DRI_IMAGE_FORMAT_XBGR8888
: return __DRI_IMAGE_FOURCC_XBGR8888
;
1133 /** dri3_get_pixmap_buffer
1135 * Get the DRM object for a pixmap from the X server and
1136 * wrap that with a __DRIimage structure using createImageFromFds
1138 static struct dri3_buffer
*
1139 dri3_get_pixmap_buffer(__DRIdrawable
*driDrawable
,
1140 unsigned int format
,
1141 enum dri3_buffer_type buffer_type
,
1142 void *loaderPrivate
)
1144 struct dri3_drawable
*pdraw
= loaderPrivate
;
1145 int buf_id
= dri3_pixmap_buf_id(buffer_type
);
1146 struct dri3_buffer
*buffer
= pdraw
->buffers
[buf_id
];
1148 xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie
;
1149 xcb_dri3_buffer_from_pixmap_reply_t
*bp_reply
;
1152 struct dri3_screen
*psc
;
1153 xcb_connection_t
*c
;
1154 xcb_sync_fence_t sync_fence
;
1155 struct xshmfence
*shm_fence
;
1157 __DRIimage
*image_planar
;
1163 pixmap
= pdraw
->base
.xDrawable
;
1164 psc
= (struct dri3_screen
*) pdraw
->base
.psc
;
1165 dpy
= psc
->base
.dpy
;
1166 c
= XGetXCBConnection(dpy
);
1168 buffer
= calloc(1, sizeof (struct dri3_buffer
));
1172 fence_fd
= xshmfence_alloc_shm();
1175 shm_fence
= xshmfence_map_shm(fence_fd
);
1176 if (shm_fence
== NULL
) {
1181 xcb_dri3_fence_from_fd(c
,
1183 (sync_fence
= xcb_generate_id(c
)),
1187 /* Get an FD for the pixmap object
1189 bp_cookie
= xcb_dri3_buffer_from_pixmap(c
, pixmap
);
1190 bp_reply
= xcb_dri3_buffer_from_pixmap_reply(c
, bp_cookie
, NULL
);
1193 fds
= xcb_dri3_buffer_from_pixmap_reply_fds(c
, bp_reply
);
1195 stride
= bp_reply
->stride
;
1198 /* createImageFromFds creates a wrapper __DRIimage structure which
1199 * can deal with multiple planes for things like Yuv images. So, once
1200 * we've gotten the planar wrapper, pull the single plane out of it and
1201 * discard the wrapper.
1203 image_planar
= (*psc
->image
->createImageFromFds
) (psc
->driScreen
,
1206 image_format_to_fourcc(format
),
1208 &stride
, &offset
, buffer
);
1213 buffer
->image
= (*psc
->image
->fromPlanar
)(image_planar
, 0, buffer
);
1215 (*psc
->image
->destroyImage
)(image_planar
);
1220 buffer
->pixmap
= pixmap
;
1221 buffer
->own_pixmap
= false;
1222 buffer
->width
= bp_reply
->width
;
1223 buffer
->height
= bp_reply
->height
;
1224 buffer
->buffer_type
= buffer_type
;
1225 buffer
->shm_fence
= shm_fence
;
1226 buffer
->sync_fence
= sync_fence
;
1228 pdraw
->buffers
[buf_id
] = buffer
;
1232 xcb_sync_destroy_fence(c
, sync_fence
);
1233 xshmfence_unmap_shm(shm_fence
);
1242 * Find an idle back buffer. If there isn't one, then
1243 * wait for a present idle notify event from the X server
1246 dri3_find_back(xcb_connection_t
*c
, struct dri3_drawable
*priv
)
1249 xcb_generic_event_t
*ev
;
1250 xcb_present_generic_event_t
*ge
;
1253 for (b
= 0; b
< priv
->num_back
; b
++) {
1254 int id
= DRI3_BACK_ID((b
+ priv
->cur_back
) % priv
->num_back
);
1255 struct dri3_buffer
*buffer
= priv
->buffers
[id
];
1257 if (!buffer
|| !buffer
->busy
) {
1258 priv
->cur_back
= id
;
1263 ev
= xcb_wait_for_special_event(c
, priv
->special_event
);
1267 dri3_handle_present_event(priv
, ge
);
1273 * Find a front or back buffer, allocating new ones as necessary
1275 static struct dri3_buffer
*
1276 dri3_get_buffer(__DRIdrawable
*driDrawable
,
1277 unsigned int format
,
1278 enum dri3_buffer_type buffer_type
,
1279 void *loaderPrivate
)
1281 struct dri3_context
*pcp
= (struct dri3_context
*) __glXGetCurrentContext();
1282 struct dri3_drawable
*priv
= loaderPrivate
;
1283 struct dri3_screen
*psc
= (struct dri3_screen
*) priv
->base
.psc
;
1284 xcb_connection_t
*c
= XGetXCBConnection(priv
->base
.psc
->dpy
);
1285 struct dri3_buffer
*buffer
;
1288 if (buffer_type
== dri3_buffer_back
) {
1289 buf_id
= dri3_find_back(c
, priv
);
1294 buf_id
= DRI3_FRONT_ID
;
1297 buffer
= priv
->buffers
[buf_id
];
1299 /* Allocate a new buffer if there isn't an old one, or if that
1300 * old one is the wrong size
1302 if (!buffer
|| buffer
->width
!= priv
->width
|| buffer
->height
!= priv
->height
) {
1303 struct dri3_buffer
*new_buffer
;
1305 /* Allocate the new buffers
1307 new_buffer
= dri3_alloc_render_buffer(priv
->base
.psc
,
1308 priv
->base
.xDrawable
,
1309 format
, priv
->width
, priv
->height
, priv
->depth
);
1313 /* When resizing, copy the contents of the old buffer, waiting for that
1314 * copy to complete using our fences before proceeding
1316 switch (buffer_type
) {
1317 case dri3_buffer_back
:
1319 if (!buffer
->linear_buffer
) {
1320 dri3_fence_reset(c
, new_buffer
);
1321 dri3_fence_await(c
, buffer
);
1325 dri3_drawable_gc(priv
),
1326 0, 0, 0, 0, priv
->width
, priv
->height
);
1327 dri3_fence_trigger(c
, new_buffer
);
1328 } else if ((&pcp
->base
!= &dummyContext
) && pcp
->base
.psc
== &psc
->base
) {
1329 psc
->image
->blitImage(pcp
->driContext
,
1337 dri3_free_render_buffer(priv
, buffer
);
1340 case dri3_buffer_front
:
1341 dri3_fence_reset(c
, new_buffer
);
1343 priv
->base
.xDrawable
,
1345 dri3_drawable_gc(priv
),
1346 0, 0, 0, 0, priv
->width
, priv
->height
);
1347 dri3_fence_trigger(c
, new_buffer
);
1349 if (new_buffer
->linear_buffer
&& (&pcp
->base
!= &dummyContext
) && pcp
->base
.psc
== &psc
->base
) {
1350 dri3_fence_await(c
, new_buffer
);
1351 psc
->image
->blitImage(pcp
->driContext
,
1353 new_buffer
->linear_buffer
,
1361 buffer
= new_buffer
;
1362 buffer
->buffer_type
= buffer_type
;
1363 priv
->buffers
[buf_id
] = buffer
;
1365 dri3_fence_await(c
, buffer
);
1367 /* Return the requested buffer */
1371 /** dri3_free_buffers
1373 * Free the front bufffer or all of the back buffers. Used
1374 * when the application changes which buffers it needs
1377 dri3_free_buffers(__DRIdrawable
*driDrawable
,
1378 enum dri3_buffer_type buffer_type
,
1379 void *loaderPrivate
)
1381 struct dri3_drawable
*priv
= loaderPrivate
;
1382 struct dri3_buffer
*buffer
;
1387 switch (buffer_type
) {
1388 case dri3_buffer_back
:
1389 first_id
= DRI3_BACK_ID(0);
1390 n_id
= DRI3_MAX_BACK
;
1392 case dri3_buffer_front
:
1393 first_id
= DRI3_FRONT_ID
;
1397 for (buf_id
= first_id
; buf_id
< first_id
+ n_id
; buf_id
++) {
1398 buffer
= priv
->buffers
[buf_id
];
1400 dri3_free_render_buffer(priv
, buffer
);
1401 priv
->buffers
[buf_id
] = NULL
;
1406 /** dri3_get_buffers
1408 * The published buffer allocation API.
1409 * Returns all of the necessary buffers, allocating
1413 dri3_get_buffers(__DRIdrawable
*driDrawable
,
1414 unsigned int format
,
1416 void *loaderPrivate
,
1417 uint32_t buffer_mask
,
1418 struct __DRIimageList
*buffers
)
1420 struct dri3_drawable
*priv
= loaderPrivate
;
1421 struct dri3_screen
*psc
= (struct dri3_screen
*) priv
->base
.psc
;
1422 struct dri3_buffer
*front
, *back
;
1424 buffers
->image_mask
= 0;
1425 buffers
->front
= NULL
;
1426 buffers
->back
= NULL
;
1431 if (!dri3_update_drawable(driDrawable
, loaderPrivate
))
1434 /* pixmaps always have front buffers */
1435 if (priv
->is_pixmap
)
1436 buffer_mask
|= __DRI_IMAGE_BUFFER_FRONT
;
1438 if (buffer_mask
& __DRI_IMAGE_BUFFER_FRONT
) {
1439 /* All pixmaps are owned by the server gpu.
1440 * When we use a different gpu, we can't use the pixmap
1441 * as buffer since it is potentially tiled a way
1442 * our device can't understand. In this case, use
1443 * a fake front buffer. Hopefully the pixmap
1444 * content will get synced with the fake front
1447 if (priv
->is_pixmap
&& !psc
->is_different_gpu
)
1448 front
= dri3_get_pixmap_buffer(driDrawable
,
1453 front
= dri3_get_buffer(driDrawable
,
1461 dri3_free_buffers(driDrawable
, dri3_buffer_front
, loaderPrivate
);
1462 priv
->have_fake_front
= 0;
1465 if (buffer_mask
& __DRI_IMAGE_BUFFER_BACK
) {
1466 back
= dri3_get_buffer(driDrawable
,
1472 priv
->have_back
= 1;
1474 dri3_free_buffers(driDrawable
, dri3_buffer_back
, loaderPrivate
);
1475 priv
->have_back
= 0;
1479 buffers
->image_mask
|= __DRI_IMAGE_BUFFER_FRONT
;
1480 buffers
->front
= front
->image
;
1481 priv
->have_fake_front
= psc
->is_different_gpu
|| !priv
->is_pixmap
;
1485 buffers
->image_mask
|= __DRI_IMAGE_BUFFER_BACK
;
1486 buffers
->back
= back
->image
;
1489 priv
->stamp
= stamp
;
1494 /* The image loader extension record for DRI3
1496 static const __DRIimageLoaderExtension imageLoaderExtension
= {
1497 .base
= { __DRI_IMAGE_LOADER
, 1 },
1499 .getBuffers
= dri3_get_buffers
,
1500 .flushFrontBuffer
= dri3_flush_front_buffer
,
1503 const __DRIuseInvalidateExtension dri3UseInvalidate
= {
1504 .base
= { __DRI_USE_INVALIDATE
, 1 }
1507 static const __DRIextension
*loader_extensions
[] = {
1508 &imageLoaderExtension
.base
,
1509 &systemTimeExtension
.base
,
1510 &dri3UseInvalidate
.base
,
1514 /** dri3_swap_buffers
1516 * Make the current back buffer visible using the present extension
1519 dri3_swap_buffers(__GLXDRIdrawable
*pdraw
, int64_t target_msc
, int64_t divisor
,
1520 int64_t remainder
, Bool flush
)
1522 struct dri3_context
*pcp
= (struct dri3_context
*) __glXGetCurrentContext();
1523 struct dri3_drawable
*priv
= (struct dri3_drawable
*) pdraw
;
1524 struct dri3_screen
*psc
= (struct dri3_screen
*) priv
->base
.psc
;
1525 Display
*dpy
= priv
->base
.psc
->dpy
;
1526 xcb_connection_t
*c
= XGetXCBConnection(dpy
);
1527 struct dri3_buffer
*back
;
1529 uint32_t options
= XCB_PRESENT_OPTION_NONE
;
1531 unsigned flags
= __DRI2_FLUSH_DRAWABLE
;
1533 flags
|= __DRI2_FLUSH_CONTEXT
;
1534 dri3_flush(psc
, priv
, flags
, __DRI2_THROTTLE_SWAPBUFFER
);
1536 back
= priv
->buffers
[DRI3_BACK_ID(priv
->cur_back
)];
1537 if (psc
->is_different_gpu
&& back
) {
1538 /* Update the linear buffer before presenting the pixmap */
1539 psc
->image
->blitImage(pcp
->driContext
,
1540 back
->linear_buffer
,
1545 back
->height
, __BLIT_FLAG_FLUSH
);
1546 /* Update the fake front */
1547 if (priv
->have_fake_front
)
1548 psc
->image
->blitImage(pcp
->driContext
,
1549 priv
->buffers
[DRI3_FRONT_ID
]->image
,
1554 priv
->height
, __BLIT_FLAG_FLUSH
);
1557 dri3_flush_present_events(priv
);
1559 if (back
&& !priv
->is_pixmap
) {
1560 dri3_fence_reset(c
, back
);
1562 /* Compute when we want the frame shown by taking the last known successful
1563 * MSC and adding in a swap interval for each outstanding swap request.
1564 * target_msc=divisor=remainder=0 means "Use glXSwapBuffers() semantic"
1567 if (target_msc
== 0 && divisor
== 0 && remainder
== 0)
1568 target_msc
= priv
->msc
+ priv
->swap_interval
* (priv
->send_sbc
- priv
->recv_sbc
);
1569 else if (divisor
== 0 && remainder
> 0) {
1570 /* From the GLX_OML_sync_control spec:
1572 * "If <divisor> = 0, the swap will occur when MSC becomes
1573 * greater than or equal to <target_msc>."
1575 * Note that there's no mention of the remainder. The Present extension
1576 * throws BadValue for remainder != 0 with divisor == 0, so just drop
1577 * the passed in value.
1582 /* From the GLX_EXT_swap_control spec:
1584 * "If <interval> is set to a value of 0, buffer swaps are not
1585 * synchronized to a video frame."
1587 * Implementation note: It is possible to enable triple buffering behaviour
1588 * by not using XCB_PRESENT_OPTION_ASYNC, but this should not be the default.
1590 if (priv
->swap_interval
== 0)
1591 options
|= XCB_PRESENT_OPTION_ASYNC
;
1594 back
->last_swap
= priv
->send_sbc
;
1595 xcb_present_pixmap(c
,
1596 priv
->base
.xDrawable
,
1598 (uint32_t) priv
->send_sbc
,
1603 None
, /* target_crtc */
1609 remainder
, 0, NULL
);
1610 ret
= (int64_t) priv
->send_sbc
;
1612 /* If there's a fake front, then copy the source back buffer
1613 * to the fake front to keep it up to date. This needs
1614 * to reset the fence and make future users block until
1615 * the X server is done copying the bits
1617 if (priv
->have_fake_front
&& !psc
->is_different_gpu
) {
1618 dri3_fence_reset(c
, priv
->buffers
[DRI3_FRONT_ID
]);
1621 priv
->buffers
[DRI3_FRONT_ID
]->pixmap
,
1622 dri3_drawable_gc(priv
),
1623 0, 0, 0, 0, priv
->width
, priv
->height
);
1624 dri3_fence_trigger(c
, priv
->buffers
[DRI3_FRONT_ID
]);
1631 (*psc
->f
->invalidate
)(priv
->driDrawable
);
1637 dri3_get_buffer_age(__GLXDRIdrawable
*pdraw
)
1639 xcb_connection_t
*c
= XGetXCBConnection(pdraw
->psc
->dpy
);
1640 struct dri3_drawable
*priv
= (struct dri3_drawable
*) pdraw
;
1641 int back_id
= DRI3_BACK_ID(dri3_find_back(c
, priv
));
1643 if (back_id
< 0 || !priv
->buffers
[back_id
])
1646 if (priv
->buffers
[back_id
]->last_swap
!= 0)
1647 return priv
->send_sbc
- priv
->buffers
[back_id
]->last_swap
+ 1;
1654 * Wrapper around xcb_dri3_open
1657 dri3_open(Display
*dpy
,
1661 xcb_dri3_open_cookie_t cookie
;
1662 xcb_dri3_open_reply_t
*reply
;
1663 xcb_connection_t
*c
= XGetXCBConnection(dpy
);
1666 cookie
= xcb_dri3_open(c
,
1670 reply
= xcb_dri3_open_reply(c
, cookie
, NULL
);
1674 if (reply
->nfd
!= 1) {
1679 fd
= xcb_dri3_open_reply_fds(c
, reply
)[0];
1680 fcntl(fd
, F_SETFD
, FD_CLOEXEC
);
1688 /** dri3_destroy_screen
1691 dri3_destroy_screen(struct glx_screen
*base
)
1693 struct dri3_screen
*psc
= (struct dri3_screen
*) base
;
1695 /* Free the direct rendering per screen data */
1696 (*psc
->core
->destroyScreen
) (psc
->driScreen
);
1697 driDestroyConfigs(psc
->driver_configs
);
1702 /** dri3_set_swap_interval
1704 * Record the application swap interval specification,
1707 dri3_set_swap_interval(__GLXDRIdrawable
*pdraw
, int interval
)
1709 struct dri3_drawable
*priv
= (struct dri3_drawable
*) pdraw
;
1710 GLint vblank_mode
= DRI_CONF_VBLANK_DEF_INTERVAL_1
;
1711 struct dri3_screen
*psc
= (struct dri3_screen
*) priv
->base
.psc
;
1714 psc
->config
->configQueryi(psc
->driScreen
,
1715 "vblank_mode", &vblank_mode
);
1717 switch (vblank_mode
) {
1718 case DRI_CONF_VBLANK_NEVER
:
1720 return GLX_BAD_VALUE
;
1722 case DRI_CONF_VBLANK_ALWAYS_SYNC
:
1724 return GLX_BAD_VALUE
;
1730 priv
->swap_interval
= interval
;
1731 dri3_update_num_back(priv
);
1736 /** dri3_get_swap_interval
1738 * Return the stored swap interval
1741 dri3_get_swap_interval(__GLXDRIdrawable
*pdraw
)
1743 struct dri3_drawable
*priv
= (struct dri3_drawable
*) pdraw
;
1745 return priv
->swap_interval
;
1749 dri3_bind_tex_image(Display
* dpy
,
1750 GLXDrawable drawable
,
1751 int buffer
, const int *attrib_list
)
1753 struct glx_context
*gc
= __glXGetCurrentContext();
1754 struct dri3_context
*pcp
= (struct dri3_context
*) gc
;
1755 __GLXDRIdrawable
*base
= GetGLXDRIDrawable(dpy
, drawable
);
1756 struct dri3_drawable
*pdraw
= (struct dri3_drawable
*) base
;
1757 struct dri3_screen
*psc
;
1759 if (pdraw
!= NULL
) {
1760 psc
= (struct dri3_screen
*) base
->psc
;
1762 (*psc
->f
->invalidate
)(pdraw
->driDrawable
);
1766 (*psc
->texBuffer
->setTexBuffer2
) (pcp
->driContext
,
1767 pdraw
->base
.textureTarget
,
1768 pdraw
->base
.textureFormat
,
1769 pdraw
->driDrawable
);
1774 dri3_release_tex_image(Display
* dpy
, GLXDrawable drawable
, int buffer
)
1776 struct glx_context
*gc
= __glXGetCurrentContext();
1777 struct dri3_context
*pcp
= (struct dri3_context
*) gc
;
1778 __GLXDRIdrawable
*base
= GetGLXDRIDrawable(dpy
, drawable
);
1779 struct dri3_drawable
*pdraw
= (struct dri3_drawable
*) base
;
1780 struct dri3_screen
*psc
;
1782 if (pdraw
!= NULL
) {
1783 psc
= (struct dri3_screen
*) base
->psc
;
1785 if (psc
->texBuffer
->base
.version
>= 3 &&
1786 psc
->texBuffer
->releaseTexBuffer
!= NULL
)
1787 (*psc
->texBuffer
->releaseTexBuffer
) (pcp
->driContext
,
1788 pdraw
->base
.textureTarget
,
1789 pdraw
->driDrawable
);
1793 static const struct glx_context_vtable dri3_context_vtable
= {
1794 .destroy
= dri3_destroy_context
,
1795 .bind
= dri3_bind_context
,
1796 .unbind
= dri3_unbind_context
,
1797 .wait_gl
= dri3_wait_gl
,
1798 .wait_x
= dri3_wait_x
,
1799 .use_x_font
= DRI_glXUseXFont
,
1800 .bind_tex_image
= dri3_bind_tex_image
,
1801 .release_tex_image
= dri3_release_tex_image
,
1802 .get_proc_address
= NULL
,
1805 /** dri3_bind_extensions
1807 * Enable all of the extensions supported on DRI3
1810 dri3_bind_extensions(struct dri3_screen
*psc
, struct glx_display
* priv
,
1811 const char *driverName
)
1813 const __DRIextension
**extensions
;
1817 extensions
= psc
->core
->getExtensions(psc
->driScreen
);
1819 __glXEnableDirectExtension(&psc
->base
, "GLX_SGI_video_sync");
1820 __glXEnableDirectExtension(&psc
->base
, "GLX_SGI_swap_control");
1821 __glXEnableDirectExtension(&psc
->base
, "GLX_MESA_swap_control");
1822 __glXEnableDirectExtension(&psc
->base
, "GLX_SGI_make_current_read");
1823 __glXEnableDirectExtension(&psc
->base
, "GLX_INTEL_swap_event");
1825 mask
= psc
->image_driver
->getAPIMask(psc
->driScreen
);
1827 __glXEnableDirectExtension(&psc
->base
, "GLX_ARB_create_context");
1828 __glXEnableDirectExtension(&psc
->base
, "GLX_ARB_create_context_profile");
1830 if ((mask
& (1 << __DRI_API_GLES2
)) != 0)
1831 __glXEnableDirectExtension(&psc
->base
,
1832 "GLX_EXT_create_context_es2_profile");
1834 for (i
= 0; extensions
[i
]; i
++) {
1835 /* when on a different gpu than the server, the server pixmaps
1836 * can have a tiling mode we can't read. Thus we can't create
1837 * a texture from them.
1839 if (!psc
->is_different_gpu
&&
1840 (strcmp(extensions
[i
]->name
, __DRI_TEX_BUFFER
) == 0)) {
1841 psc
->texBuffer
= (__DRItexBufferExtension
*) extensions
[i
];
1842 __glXEnableDirectExtension(&psc
->base
, "GLX_EXT_texture_from_pixmap");
1845 if ((strcmp(extensions
[i
]->name
, __DRI2_FLUSH
) == 0)) {
1846 psc
->f
= (__DRI2flushExtension
*) extensions
[i
];
1847 /* internal driver extension, no GL extension exposed */
1850 if (strcmp(extensions
[i
]->name
, __DRI_IMAGE
) == 0)
1851 psc
->image
= (__DRIimageExtension
*) extensions
[i
];
1853 if ((strcmp(extensions
[i
]->name
, __DRI2_CONFIG_QUERY
) == 0))
1854 psc
->config
= (__DRI2configQueryExtension
*) extensions
[i
];
1856 if (strcmp(extensions
[i
]->name
, __DRI2_ROBUSTNESS
) == 0)
1857 __glXEnableDirectExtension(&psc
->base
,
1858 "GLX_ARB_create_context_robustness");
1860 if (strcmp(extensions
[i
]->name
, __DRI2_RENDERER_QUERY
) == 0) {
1861 psc
->rendererQuery
= (__DRI2rendererQueryExtension
*) extensions
[i
];
1862 __glXEnableDirectExtension(&psc
->base
, "GLX_MESA_query_renderer");
1867 static const struct glx_screen_vtable dri3_screen_vtable
= {
1868 .create_context
= dri3_create_context
,
1869 .create_context_attribs
= dri3_create_context_attribs
,
1870 .query_renderer_integer
= dri3_query_renderer_integer
,
1871 .query_renderer_string
= dri3_query_renderer_string
,
1874 /** dri3_create_screen
1876 * Initialize DRI3 on the specified screen.
1878 * Opens the DRI device, locates the appropriate DRI driver
1881 * Checks to see if the driver supports the necessary extensions
1883 * Initializes the driver for the screen and sets up our structures
1886 static struct glx_screen
*
1887 dri3_create_screen(int screen
, struct glx_display
* priv
)
1889 xcb_connection_t
*c
= XGetXCBConnection(priv
->dpy
);
1890 const __DRIconfig
**driver_configs
;
1891 const __DRIextension
**extensions
;
1892 const struct dri3_display
*const pdp
= (struct dri3_display
*)
1894 struct dri3_screen
*psc
;
1895 __GLXDRIscreen
*psp
;
1896 struct glx_config
*configs
= NULL
, *visuals
= NULL
;
1897 char *driverName
, *deviceName
, *tmp
;
1900 psc
= calloc(1, sizeof *psc
);
1906 if (!glx_screen_init(&psc
->base
, screen
, priv
)) {
1911 psc
->fd
= dri3_open(priv
->dpy
, RootWindow(priv
->dpy
, screen
), None
);
1913 int conn_error
= xcb_connection_has_error(c
);
1915 glx_screen_cleanup(&psc
->base
);
1917 InfoMessageF("screen %d does not appear to be DRI3 capable\n", screen
);
1920 ErrorMessageF("Connection closed during DRI3 initialization failure");
1925 psc
->fd
= loader_get_user_preferred_fd(psc
->fd
, &psc
->is_different_gpu
);
1928 driverName
= loader_get_driver_for_fd(psc
->fd
, 0);
1930 ErrorMessageF("No driver found\n");
1934 psc
->driver
= driOpenDriver(driverName
);
1935 if (psc
->driver
== NULL
) {
1936 ErrorMessageF("driver pointer missing\n");
1940 extensions
= driGetDriverExtensions(psc
->driver
, driverName
);
1941 if (extensions
== NULL
)
1944 for (i
= 0; extensions
[i
]; i
++) {
1945 if (strcmp(extensions
[i
]->name
, __DRI_CORE
) == 0)
1946 psc
->core
= (__DRIcoreExtension
*) extensions
[i
];
1947 if (strcmp(extensions
[i
]->name
, __DRI_IMAGE_DRIVER
) == 0)
1948 psc
->image_driver
= (__DRIimageDriverExtension
*) extensions
[i
];
1952 if (psc
->core
== NULL
) {
1953 ErrorMessageF("core dri driver extension not found\n");
1957 if (psc
->image_driver
== NULL
) {
1958 ErrorMessageF("image driver extension not found\n");
1963 psc
->image_driver
->createNewScreen2(screen
, psc
->fd
,
1964 pdp
->loader_extensions
,
1966 &driver_configs
, psc
);
1968 if (psc
->driScreen
== NULL
) {
1969 ErrorMessageF("failed to create dri screen\n");
1973 dri3_bind_extensions(psc
, priv
, driverName
);
1975 if (!psc
->image
|| psc
->image
->base
.version
< 7 || !psc
->image
->createImageFromFds
) {
1976 ErrorMessageF("Version 7 or imageFromFds image extension not found\n");
1980 if (!psc
->f
|| psc
->f
->base
.version
< 4) {
1981 ErrorMessageF("Version 4 or later of flush extension not found\n");
1985 if (psc
->is_different_gpu
&& psc
->image
->base
.version
< 9) {
1986 ErrorMessageF("Different GPU, but image extension version 9 or later not found\n");
1990 if (psc
->is_different_gpu
&& !psc
->image
->blitImage
) {
1991 ErrorMessageF("Different GPU, but blitImage not implemented for this driver\n");
1995 if (!psc
->is_different_gpu
&& (
1996 !psc
->texBuffer
|| psc
->texBuffer
->base
.version
< 2 ||
1997 !psc
->texBuffer
->setTexBuffer2
1999 ErrorMessageF("Version 2 or later of texBuffer extension not found\n");
2003 configs
= driConvertConfigs(psc
->core
, psc
->base
.configs
, driver_configs
);
2004 visuals
= driConvertConfigs(psc
->core
, psc
->base
.visuals
, driver_configs
);
2006 if (!configs
|| !visuals
) {
2007 ErrorMessageF("No matching fbConfigs or visuals found\n");
2011 glx_config_destroy_list(psc
->base
.configs
);
2012 psc
->base
.configs
= configs
;
2013 glx_config_destroy_list(psc
->base
.visuals
);
2014 psc
->base
.visuals
= visuals
;
2016 psc
->driver_configs
= driver_configs
;
2018 psc
->base
.vtable
= &dri3_screen_vtable
;
2020 psc
->base
.driScreen
= psp
;
2021 psp
->destroyScreen
= dri3_destroy_screen
;
2022 psp
->createDrawable
= dri3_create_drawable
;
2023 psp
->swapBuffers
= dri3_swap_buffers
;
2025 psp
->getDrawableMSC
= dri3_drawable_get_msc
;
2026 psp
->waitForMSC
= dri3_wait_for_msc
;
2027 psp
->waitForSBC
= dri3_wait_for_sbc
;
2028 psp
->setSwapInterval
= dri3_set_swap_interval
;
2029 psp
->getSwapInterval
= dri3_get_swap_interval
;
2030 __glXEnableDirectExtension(&psc
->base
, "GLX_OML_sync_control");
2032 psp
->copySubBuffer
= dri3_copy_sub_buffer
;
2033 __glXEnableDirectExtension(&psc
->base
, "GLX_MESA_copy_sub_buffer");
2035 psp
->getBufferAge
= dri3_get_buffer_age
;
2036 __glXEnableDirectExtension(&psc
->base
, "GLX_EXT_buffer_age");
2041 tmp
= getenv("LIBGL_SHOW_FPS");
2042 psc
->show_fps_interval
= tmp
? atoi(tmp
) : 0;
2043 if (psc
->show_fps_interval
< 0)
2044 psc
->show_fps_interval
= 0;
2046 InfoMessageF("Using DRI3 for screen %d\n", screen
);
2051 CriticalErrorMessageF("failed to load driver: %s\n", driverName
);
2054 glx_config_destroy_list(configs
);
2056 glx_config_destroy_list(visuals
);
2058 psc
->core
->destroyScreen(psc
->driScreen
);
2059 psc
->driScreen
= NULL
;
2063 dlclose(psc
->driver
);
2067 glx_screen_cleanup(&psc
->base
);
2073 /** dri_destroy_display
2075 * Called from __glXFreeDisplayPrivate.
2078 dri3_destroy_display(__GLXDRIdisplay
* dpy
)
2083 /** dri3_create_display
2085 * Allocate, initialize and return a __DRIdisplayPrivate object.
2086 * This is called from __glXInitialize() when we are given a new
2087 * display pointer. This is public to that function, but hidden from
2090 _X_HIDDEN __GLXDRIdisplay
*
2091 dri3_create_display(Display
* dpy
)
2093 struct dri3_display
*pdp
;
2094 xcb_connection_t
*c
= XGetXCBConnection(dpy
);
2095 xcb_dri3_query_version_cookie_t dri3_cookie
;
2096 xcb_dri3_query_version_reply_t
*dri3_reply
;
2097 xcb_present_query_version_cookie_t present_cookie
;
2098 xcb_present_query_version_reply_t
*present_reply
;
2099 xcb_generic_error_t
*error
;
2100 const xcb_query_extension_reply_t
*extension
;
2102 xcb_prefetch_extension_data(c
, &xcb_dri3_id
);
2103 xcb_prefetch_extension_data(c
, &xcb_present_id
);
2105 extension
= xcb_get_extension_data(c
, &xcb_dri3_id
);
2106 if (!(extension
&& extension
->present
))
2109 extension
= xcb_get_extension_data(c
, &xcb_present_id
);
2110 if (!(extension
&& extension
->present
))
2113 dri3_cookie
= xcb_dri3_query_version(c
,
2114 XCB_DRI3_MAJOR_VERSION
,
2115 XCB_DRI3_MINOR_VERSION
);
2118 present_cookie
= xcb_present_query_version(c
,
2119 XCB_PRESENT_MAJOR_VERSION
,
2120 XCB_PRESENT_MINOR_VERSION
);
2122 pdp
= malloc(sizeof *pdp
);
2126 dri3_reply
= xcb_dri3_query_version_reply(c
, dri3_cookie
, &error
);
2132 pdp
->dri3Major
= dri3_reply
->major_version
;
2133 pdp
->dri3Minor
= dri3_reply
->minor_version
;
2136 present_reply
= xcb_present_query_version_reply(c
, present_cookie
, &error
);
2137 if (!present_reply
) {
2141 pdp
->presentMajor
= present_reply
->major_version
;
2142 pdp
->presentMinor
= present_reply
->minor_version
;
2143 free(present_reply
);
2145 pdp
->base
.destroyDisplay
= dri3_destroy_display
;
2146 pdp
->base
.createScreen
= dri3_create_screen
;
2148 loader_set_logger(dri_message
);
2150 pdp
->loader_extensions
= loader_extensions
;
2158 #endif /* GLX_DIRECT_RENDERING */