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>
69 #include "glxclient.h"
74 #include <sys/types.h>
79 #include "dri_common.h"
80 #include "dri3_priv.h"
82 static const struct glx_context_vtable dri3_context_vtable
;
85 dri3_fence_reset(xcb_connection_t
*c
, struct dri3_buffer
*buffer
)
87 xshmfence_reset(buffer
->shm_fence
);
91 dri3_fence_set(struct dri3_buffer
*buffer
)
93 xshmfence_trigger(buffer
->shm_fence
);
97 dri3_fence_trigger(xcb_connection_t
*c
, struct dri3_buffer
*buffer
)
99 xcb_sync_trigger_fence(c
, buffer
->sync_fence
);
103 dri3_fence_await(xcb_connection_t
*c
, struct dri3_buffer
*buffer
)
106 xshmfence_await(buffer
->shm_fence
);
110 dri3_fence_triggered(struct dri3_buffer
*buffer
)
112 return xshmfence_query(buffer
->shm_fence
);
116 dri3_destroy_context(struct glx_context
*context
)
118 struct dri3_context
*pcp
= (struct dri3_context
*) context
;
119 struct dri3_screen
*psc
= (struct dri3_screen
*) context
->psc
;
121 driReleaseDrawables(&pcp
->base
);
123 free((char *) context
->extensions
);
125 (*psc
->core
->destroyContext
) (pcp
->driContext
);
131 dri3_bind_context(struct glx_context
*context
, struct glx_context
*old
,
132 GLXDrawable draw
, GLXDrawable read
)
134 struct dri3_context
*pcp
= (struct dri3_context
*) context
;
135 struct dri3_screen
*psc
= (struct dri3_screen
*) pcp
->base
.psc
;
136 struct dri3_drawable
*pdraw
, *pread
;
138 pdraw
= (struct dri3_drawable
*) driFetchDrawable(context
, draw
);
139 pread
= (struct dri3_drawable
*) driFetchDrawable(context
, read
);
141 driReleaseDrawables(&pcp
->base
);
143 if (pdraw
== NULL
|| pread
== NULL
)
144 return GLXBadDrawable
;
146 if (!(*psc
->core
->bindContext
) (pcp
->driContext
,
147 pdraw
->driDrawable
, pread
->driDrawable
))
148 return GLXBadContext
;
154 dri3_unbind_context(struct glx_context
*context
, struct glx_context
*new)
156 struct dri3_context
*pcp
= (struct dri3_context
*) context
;
157 struct dri3_screen
*psc
= (struct dri3_screen
*) pcp
->base
.psc
;
159 (*psc
->core
->unbindContext
) (pcp
->driContext
);
162 static struct glx_context
*
163 dri3_create_context(struct glx_screen
*base
,
164 struct glx_config
*config_base
,
165 struct glx_context
*shareList
, int renderType
)
167 struct dri3_context
*pcp
, *pcp_shared
;
168 struct dri3_screen
*psc
= (struct dri3_screen
*) base
;
169 __GLXDRIconfigPrivate
*config
= (__GLXDRIconfigPrivate
*) config_base
;
170 __DRIcontext
*shared
= NULL
;
173 /* If the shareList context is not a DRI3 context, we cannot possibly
174 * create a DRI3 context that shares it.
176 if (shareList
->vtable
->destroy
!= dri3_destroy_context
) {
180 pcp_shared
= (struct dri3_context
*) shareList
;
181 shared
= pcp_shared
->driContext
;
184 pcp
= calloc(1, sizeof *pcp
);
188 if (!glx_context_init(&pcp
->base
, &psc
->base
, &config
->base
)) {
194 (*psc
->image_driver
->createNewContext
) (psc
->driScreen
,
195 config
->driConfig
, shared
, pcp
);
197 if (pcp
->driContext
== NULL
) {
202 pcp
->base
.vtable
= &dri3_context_vtable
;
207 static struct glx_context
*
208 dri3_create_context_attribs(struct glx_screen
*base
,
209 struct glx_config
*config_base
,
210 struct glx_context
*shareList
,
211 unsigned num_attribs
,
212 const uint32_t *attribs
,
215 struct dri3_context
*pcp
= NULL
;
216 struct dri3_context
*pcp_shared
= NULL
;
217 struct dri3_screen
*psc
= (struct dri3_screen
*) base
;
218 __GLXDRIconfigPrivate
*config
= (__GLXDRIconfigPrivate
*) config_base
;
219 __DRIcontext
*shared
= NULL
;
221 uint32_t minor_ver
= 1;
222 uint32_t major_ver
= 2;
225 int reset
= __DRI_CTX_RESET_NO_NOTIFICATION
;
226 uint32_t ctx_attribs
[2 * 5];
227 unsigned num_ctx_attribs
= 0;
228 uint32_t render_type
;
230 /* Remap the GLX tokens to DRI2 tokens.
232 if (!dri2_convert_glx_attribs(num_attribs
, attribs
,
233 &major_ver
, &minor_ver
,
234 &render_type
, &flags
, &api
,
238 /* Check the renderType value */
239 if (!validate_renderType_against_config(config_base
, render_type
))
243 pcp_shared
= (struct dri3_context
*) shareList
;
244 shared
= pcp_shared
->driContext
;
247 pcp
= calloc(1, sizeof *pcp
);
249 *error
= __DRI_CTX_ERROR_NO_MEMORY
;
253 if (!glx_context_init(&pcp
->base
, &psc
->base
, &config
->base
))
256 ctx_attribs
[num_ctx_attribs
++] = __DRI_CTX_ATTRIB_MAJOR_VERSION
;
257 ctx_attribs
[num_ctx_attribs
++] = major_ver
;
258 ctx_attribs
[num_ctx_attribs
++] = __DRI_CTX_ATTRIB_MINOR_VERSION
;
259 ctx_attribs
[num_ctx_attribs
++] = minor_ver
;
261 /* Only send a value when the non-default value is requested. By doing
262 * this we don't have to check the driver's DRI3 version before sending the
265 if (reset
!= __DRI_CTX_RESET_NO_NOTIFICATION
) {
266 ctx_attribs
[num_ctx_attribs
++] = __DRI_CTX_ATTRIB_RESET_STRATEGY
;
267 ctx_attribs
[num_ctx_attribs
++] = reset
;
271 ctx_attribs
[num_ctx_attribs
++] = __DRI_CTX_ATTRIB_FLAGS
;
273 /* The current __DRI_CTX_FLAG_* values are identical to the
274 * GLX_CONTEXT_*_BIT values.
276 ctx_attribs
[num_ctx_attribs
++] = flags
;
280 (*psc
->image_driver
->createContextAttribs
) (psc
->driScreen
,
289 if (pcp
->driContext
== NULL
)
292 pcp
->base
.vtable
= &dri3_context_vtable
;
303 dri3_destroy_drawable(__GLXDRIdrawable
*base
)
305 struct dri3_screen
*psc
= (struct dri3_screen
*) base
->psc
;
306 struct dri3_drawable
*pdraw
= (struct dri3_drawable
*) base
;
308 (*psc
->core
->destroyDrawable
) (pdraw
->driDrawable
);
313 static __GLXDRIdrawable
*
314 dri3_create_drawable(struct glx_screen
*base
, XID xDrawable
,
315 GLXDrawable drawable
, struct glx_config
*config_base
)
317 struct dri3_drawable
*pdraw
;
318 struct dri3_screen
*psc
= (struct dri3_screen
*) base
;
319 __GLXDRIconfigPrivate
*config
= (__GLXDRIconfigPrivate
*) config_base
;
320 GLint vblank_mode
= DRI_CONF_VBLANK_DEF_INTERVAL_1
;
322 pdraw
= calloc(1, sizeof(*pdraw
));
326 pdraw
->base
.destroyDrawable
= dri3_destroy_drawable
;
327 pdraw
->base
.xDrawable
= xDrawable
;
328 pdraw
->base
.drawable
= drawable
;
329 pdraw
->base
.psc
= &psc
->base
;
330 pdraw
->swap_interval
= 1; /* default may be overridden below */
331 pdraw
->have_back
= 0;
332 pdraw
->have_fake_front
= 0;
335 psc
->config
->configQueryi(psc
->driScreen
,
336 "vblank_mode", &vblank_mode
);
338 switch (vblank_mode
) {
339 case DRI_CONF_VBLANK_NEVER
:
340 case DRI_CONF_VBLANK_DEF_INTERVAL_0
:
341 pdraw
->swap_interval
= 0;
343 case DRI_CONF_VBLANK_DEF_INTERVAL_1
:
344 case DRI_CONF_VBLANK_ALWAYS_SYNC
:
346 pdraw
->swap_interval
= 1;
350 (void) __glXInitialize(psc
->base
.dpy
);
352 /* Create a new drawable */
354 (*psc
->image_driver
->createNewDrawable
) (psc
->driScreen
,
355 config
->driConfig
, pdraw
);
357 if (!pdraw
->driDrawable
) {
363 * Make sure server has the same swap interval we do for the new
366 if (psc
->vtable
.setSwapInterval
)
367 psc
->vtable
.setSwapInterval(&pdraw
->base
, pdraw
->swap_interval
);
373 * Process one Present event
376 dri3_handle_present_event(struct dri3_drawable
*priv
, xcb_present_generic_event_t
*ge
)
378 switch (ge
->evtype
) {
379 case XCB_PRESENT_CONFIGURE_NOTIFY
: {
380 xcb_present_configure_notify_event_t
*ce
= (void *) ge
;
382 priv
->width
= ce
->width
;
383 priv
->height
= ce
->height
;
386 case XCB_PRESENT_COMPLETE_NOTIFY
: {
387 xcb_present_complete_notify_event_t
*ce
= (void *) ge
;
389 if (ce
->kind
== XCB_PRESENT_COMPLETE_KIND_PIXMAP
)
390 priv
->present_event_serial
= ce
->serial
;
392 priv
->present_msc_event_serial
= ce
->serial
;
397 case XCB_PRESENT_EVENT_IDLE_NOTIFY
: {
398 xcb_present_idle_notify_event_t
*ie
= (void *) ge
;
401 for (b
= 0; b
< sizeof (priv
->buffers
) / sizeof (priv
->buffers
[0]); b
++) {
402 struct dri3_buffer
*buf
= priv
->buffers
[b
];
404 if (buf
&& buf
->pixmap
== ie
->pixmap
) {
416 dri3_wait_for_msc(__GLXDRIdrawable
*pdraw
, int64_t target_msc
, int64_t divisor
,
417 int64_t remainder
, int64_t *ust
, int64_t *msc
, int64_t *sbc
)
419 xcb_connection_t
*c
= XGetXCBConnection(pdraw
->psc
->dpy
);
420 struct dri3_drawable
*priv
= (struct dri3_drawable
*) pdraw
;
421 xcb_generic_event_t
*ev
;
422 xcb_present_generic_event_t
*ge
;
424 /* Ask for the an event for the target MSC */
425 ++priv
->present_msc_request_serial
;
426 xcb_present_notify_msc(c
,
427 priv
->base
.xDrawable
,
428 priv
->present_msc_request_serial
,
435 /* Wait for the event */
436 if (priv
->special_event
) {
437 while (priv
->present_msc_request_serial
!= priv
->present_msc_event_serial
) {
438 ev
= xcb_wait_for_special_event(c
, priv
->special_event
);
442 dri3_handle_present_event(priv
, ge
);
454 dri3_drawable_get_msc(struct glx_screen
*psc
, __GLXDRIdrawable
*pdraw
,
455 int64_t *ust
, int64_t *msc
, int64_t *sbc
)
457 return dri3_wait_for_msc(pdraw
, 0, 0, 0, ust
, msc
,sbc
);
460 /** dri3_wait_for_sbc
462 * Wait for the swap buffer count to increase. The only way this
463 * can happen is if some other thread is doing swap buffers as
464 * we no longer share swap buffer counts with other processes.
466 * I'm not sure this is actually useful as such, and so this
467 * implementation is a kludge that just polls once a second
470 dri3_wait_for_sbc(__GLXDRIdrawable
*pdraw
, int64_t target_sbc
, int64_t *ust
,
471 int64_t *msc
, int64_t *sbc
)
473 struct dri3_drawable
*priv
= (struct dri3_drawable
*) pdraw
;
475 while (priv
->sbc
< target_sbc
) {
478 return dri3_wait_for_msc(pdraw
, 0, 0, 0, ust
, msc
, sbc
);
482 * Asks the driver to flush any queued work necessary for serializing with the
483 * X command stream, and optionally the slightly more strict requirement of
484 * glFlush() equivalence (which would require flushing even if nothing had
485 * been drawn to a window system framebuffer, for example).
488 dri3_flush(struct dri3_screen
*psc
,
489 struct dri3_drawable
*draw
,
491 enum __DRI2throttleReason throttle_reason
)
493 struct glx_context
*gc
= __glXGetCurrentContext();
496 struct dri3_context
*dri3Ctx
= (struct dri3_context
*)gc
;
498 (*psc
->f
->flush_with_flags
)(dri3Ctx
->driContext
, draw
->driDrawable
, flags
, throttle_reason
);
502 static xcb_gcontext_t
503 dri3_drawable_gc(struct dri3_drawable
*priv
)
507 xcb_connection_t
*c
= XGetXCBConnection(priv
->base
.psc
->dpy
);
511 (priv
->gc
= xcb_generate_id(c
)),
512 priv
->base
.xDrawable
,
513 XCB_GC_GRAPHICS_EXPOSURES
,
519 static struct dri3_buffer
*
520 dri3_back_buffer(struct dri3_drawable
*priv
)
522 return priv
->buffers
[DRI3_BACK_ID(priv
->cur_back
)];
525 static struct dri3_buffer
*
526 dri3_fake_front_buffer(struct dri3_drawable
*priv
)
528 return priv
->buffers
[DRI3_FRONT_ID
];
532 dri3_copy_area (xcb_connection_t
*c
/**< */,
533 xcb_drawable_t src_drawable
/**< */,
534 xcb_drawable_t dst_drawable
/**< */,
535 xcb_gcontext_t gc
/**< */,
536 int16_t src_x
/**< */,
537 int16_t src_y
/**< */,
538 int16_t dst_x
/**< */,
539 int16_t dst_y
/**< */,
540 uint16_t width
/**< */,
541 uint16_t height
/**< */)
543 xcb_void_cookie_t cookie
;
545 cookie
= xcb_copy_area_checked(c
,
555 xcb_discard_reply(c
, cookie
.sequence
);
559 dri3_copy_sub_buffer(__GLXDRIdrawable
*pdraw
, int x
, int y
,
560 int width
, int height
,
563 struct dri3_drawable
*priv
= (struct dri3_drawable
*) pdraw
;
564 struct dri3_screen
*psc
= (struct dri3_screen
*) pdraw
->psc
;
565 xcb_connection_t
*c
= XGetXCBConnection(priv
->base
.psc
->dpy
);
566 struct dri3_buffer
*back
= dri3_back_buffer(priv
);
570 /* Check we have the right attachments */
571 if (!priv
->have_back
|| priv
->is_pixmap
)
574 flags
= __DRI2_FLUSH_DRAWABLE
;
576 flags
|= __DRI2_FLUSH_CONTEXT
;
577 dri3_flush(psc
, priv
, flags
, __DRI2_THROTTLE_SWAPBUFFER
);
579 y
= priv
->height
- y
- height
;
581 dri3_fence_reset(c
, back
);
583 dri3_back_buffer(priv
)->pixmap
,
584 priv
->base
.xDrawable
,
585 dri3_drawable_gc(priv
),
586 x
, y
, x
, y
, width
, height
);
587 dri3_fence_trigger(c
, back
);
588 /* Refresh the fake front (if present) after we just damaged the real
591 if (priv
->have_fake_front
) {
592 dri3_fence_reset(c
, dri3_fake_front_buffer(priv
));
594 dri3_back_buffer(priv
)->pixmap
,
595 dri3_fake_front_buffer(priv
)->pixmap
,
596 dri3_drawable_gc(priv
),
597 x
, y
, x
, y
, width
, height
);
598 dri3_fence_trigger(c
, dri3_fake_front_buffer(priv
));
599 dri3_fence_await(c
, dri3_fake_front_buffer(priv
));
601 dri3_fence_await(c
, back
);
605 dri3_copy_drawable(struct dri3_drawable
*priv
, Drawable dest
, Drawable src
)
607 struct dri3_screen
*psc
= (struct dri3_screen
*) priv
->base
.psc
;
608 xcb_connection_t
*c
= XGetXCBConnection(priv
->base
.psc
->dpy
);
610 dri3_flush(psc
, priv
, __DRI2_FLUSH_DRAWABLE
, 0);
612 dri3_fence_reset(c
, dri3_fake_front_buffer(priv
));
615 dri3_drawable_gc(priv
),
616 0, 0, 0, 0, priv
->width
, priv
->height
);
617 dri3_fence_trigger(c
, dri3_fake_front_buffer(priv
));
618 dri3_fence_await(c
, dri3_fake_front_buffer(priv
));
622 dri3_wait_x(struct glx_context
*gc
)
624 struct dri3_drawable
*priv
= (struct dri3_drawable
*)
625 GetGLXDRIDrawable(gc
->currentDpy
, gc
->currentDrawable
);
627 if (priv
== NULL
|| !priv
->have_fake_front
)
630 dri3_copy_drawable(priv
, dri3_fake_front_buffer(priv
)->pixmap
, priv
->base
.xDrawable
);
634 dri3_wait_gl(struct glx_context
*gc
)
636 struct dri3_drawable
*priv
= (struct dri3_drawable
*)
637 GetGLXDRIDrawable(gc
->currentDpy
, gc
->currentDrawable
);
639 if (priv
== NULL
|| !priv
->have_fake_front
)
642 dri3_copy_drawable(priv
, priv
->base
.xDrawable
, dri3_fake_front_buffer(priv
)->pixmap
);
646 * Called by the driver when it needs to update the real front buffer with the
647 * contents of its fake front buffer.
650 dri3_flush_front_buffer(__DRIdrawable
*driDrawable
, void *loaderPrivate
)
652 struct glx_context
*gc
;
653 struct dri3_drawable
*pdraw
= loaderPrivate
;
654 struct dri3_screen
*psc
;
659 if (!pdraw
->base
.psc
)
662 psc
= (struct dri3_screen
*) pdraw
->base
.psc
;
664 (void) __glXInitialize(psc
->base
.dpy
);
666 gc
= __glXGetCurrentContext();
668 dri3_flush(psc
, pdraw
, __DRI2_FLUSH_DRAWABLE
, __DRI2_THROTTLE_FLUSHFRONT
);
674 dri3_cpp_for_format(uint32_t format
) {
676 case __DRI_IMAGE_FORMAT_R8
:
678 case __DRI_IMAGE_FORMAT_RGB565
:
679 case __DRI_IMAGE_FORMAT_GR88
:
681 case __DRI_IMAGE_FORMAT_XRGB8888
:
682 case __DRI_IMAGE_FORMAT_ARGB8888
:
683 case __DRI_IMAGE_FORMAT_ABGR8888
:
684 case __DRI_IMAGE_FORMAT_XBGR8888
:
685 case __DRI_IMAGE_FORMAT_XRGB2101010
:
686 case __DRI_IMAGE_FORMAT_ARGB2101010
:
687 case __DRI_IMAGE_FORMAT_SARGB8
:
689 case __DRI_IMAGE_FORMAT_NONE
:
696 /** dri3_alloc_render_buffer
698 * Use the driver createImage function to construct a __DRIimage, then
699 * get a file descriptor for that and create an X pixmap from that
701 * Allocate an xshmfence for synchronization
703 static struct dri3_buffer
*
704 dri3_alloc_render_buffer(struct glx_screen
*glx_screen
, Drawable draw
,
705 unsigned int format
, int width
, int height
, int depth
)
707 struct dri3_screen
*psc
= (struct dri3_screen
*) glx_screen
;
708 Display
*dpy
= glx_screen
->dpy
;
709 struct dri3_buffer
*buffer
;
710 xcb_connection_t
*c
= XGetXCBConnection(dpy
);
712 xcb_sync_fence_t sync_fence
;
714 int buffer_fd
, fence_fd
;
717 /* Create an xshmfence object and
718 * prepare to send that to the X server
721 fence_fd
= xshmfence_alloc_shm();
724 shm_fence
= xshmfence_map_shm(fence_fd
);
725 if (shm_fence
== NULL
)
728 /* Allocate the image from the driver
730 buffer
= calloc(1, sizeof (struct dri3_buffer
));
734 buffer
->cpp
= dri3_cpp_for_format(format
);
738 buffer
->image
= (*psc
->image
->createImage
) (psc
->driScreen
,
741 __DRI_IMAGE_USE_SHARE
|__DRI_IMAGE_USE_SCANOUT
,
748 /* X wants the stride, so ask the image for it
750 if (!(*psc
->image
->queryImage
)(buffer
->image
, __DRI_IMAGE_ATTRIB_STRIDE
, &stride
))
751 goto no_buffer_attrib
;
753 buffer
->pitch
= stride
;
755 if (!(*psc
->image
->queryImage
)(buffer
->image
, __DRI_IMAGE_ATTRIB_FD
, &buffer_fd
))
756 goto no_buffer_attrib
;
758 xcb_dri3_pixmap_from_buffer(c
,
759 (pixmap
= xcb_generate_id(c
)),
762 width
, height
, buffer
->pitch
,
763 depth
, buffer
->cpp
* 8,
766 xcb_dri3_fence_from_fd(c
,
768 (sync_fence
= xcb_generate_id(c
)),
772 buffer
->pixmap
= pixmap
;
773 buffer
->sync_fence
= sync_fence
;
774 buffer
->shm_fence
= shm_fence
;
775 buffer
->width
= width
;
776 buffer
->height
= height
;
778 /* Mark the buffer as idle
780 dri3_fence_set(buffer
);
785 (*psc
->image
->destroyImage
)(buffer
->image
);
789 xshmfence_unmap_shm(shm_fence
);
795 /** dri3_free_render_buffer
797 * Free everything associated with one render buffer including pixmap, fence
798 * stuff and the driver image
801 dri3_free_render_buffer(struct dri3_drawable
*pdraw
, struct dri3_buffer
*buffer
)
803 struct dri3_screen
*psc
= (struct dri3_screen
*) pdraw
->base
.psc
;
804 xcb_connection_t
*c
= XGetXCBConnection(pdraw
->base
.psc
->dpy
);
806 xcb_free_pixmap(c
, buffer
->pixmap
);
807 xcb_sync_destroy_fence(c
, buffer
->sync_fence
);
808 xshmfence_unmap_shm(buffer
->shm_fence
);
809 (*psc
->image
->destroyImage
)(buffer
->image
);
814 /** dri3_flush_present_events
816 * Process any present events that have been received from the X server
819 dri3_flush_present_events(struct dri3_drawable
*priv
)
821 xcb_connection_t
*c
= XGetXCBConnection(priv
->base
.psc
->dpy
);
823 /* Check to see if any configuration changes have occurred
824 * since we were last invoked
826 if (priv
->special_event
) {
827 xcb_generic_event_t
*ev
;
829 while ((ev
= xcb_poll_for_special_event(c
, priv
->special_event
)) != NULL
) {
830 xcb_present_generic_event_t
*ge
= (void *) ev
;
831 dri3_handle_present_event(priv
, ge
);
836 /** dri3_update_drawable
838 * Called the first time we use the drawable and then
839 * after we receive present configure notify events to
840 * track the geometry of the drawable
843 dri3_update_drawable(__DRIdrawable
*driDrawable
, void *loaderPrivate
)
845 struct dri3_drawable
*priv
= loaderPrivate
;
846 xcb_connection_t
*c
= XGetXCBConnection(priv
->base
.psc
->dpy
);
848 /* First time through, go get the current drawable geometry
850 if (priv
->width
== 0 || priv
->height
== 0 || priv
->depth
== 0) {
851 xcb_get_geometry_cookie_t geom_cookie
;
852 xcb_get_geometry_reply_t
*geom_reply
;
853 xcb_void_cookie_t cookie
;
854 xcb_generic_error_t
*error
;
856 /* Try to select for input on the window.
858 * If the drawable is a window, this will get our events
861 * Otherwise, we'll get a BadWindow error back from this request which
862 * will let us know that the drawable is a pixmap instead.
866 cookie
= xcb_present_select_input_checked(c
,
867 (priv
->eid
= xcb_generate_id(c
)),
868 priv
->base
.xDrawable
,
869 XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY
|
870 XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY
|
871 XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY
);
873 /* Create an XCB event queue to hold present events outside of the usual
874 * application event queue
876 priv
->special_event
= xcb_register_for_special_xge(c
,
881 geom_cookie
= xcb_get_geometry(c
, priv
->base
.xDrawable
);
883 geom_reply
= xcb_get_geometry_reply(c
, geom_cookie
, NULL
);
888 priv
->width
= geom_reply
->width
;
889 priv
->height
= geom_reply
->height
;
890 priv
->depth
= geom_reply
->depth
;
891 priv
->is_pixmap
= false;
895 /* Check to see if our select input call failed. If it failed with a
896 * BadWindow error, then assume the drawable is a pixmap. Destroy the
897 * special event queue created above and mark the drawable as a pixmap
900 error
= xcb_request_check(c
, cookie
);
903 if (error
->error_code
!= BadWindow
) {
907 priv
->is_pixmap
= true;
908 xcb_unregister_for_special_event(c
, priv
->special_event
);
909 priv
->special_event
= NULL
;
912 dri3_flush_present_events(priv
);
916 /* the DRIimage createImage function takes __DRI_IMAGE_FORMAT codes, while
917 * the createImageFromFds call takes __DRI_IMAGE_FOURCC codes. To avoid
918 * complete confusion, just deal in __DRI_IMAGE_FORMAT codes for now and
919 * translate to __DRI_IMAGE_FOURCC codes in the call to createImageFromFds
922 image_format_to_fourcc(int format
)
925 /* Convert from __DRI_IMAGE_FORMAT to __DRI_IMAGE_FOURCC (sigh) */
927 case __DRI_IMAGE_FORMAT_RGB565
: return __DRI_IMAGE_FOURCC_RGB565
;
928 case __DRI_IMAGE_FORMAT_XRGB8888
: return __DRI_IMAGE_FOURCC_XRGB8888
;
929 case __DRI_IMAGE_FORMAT_ARGB8888
: return __DRI_IMAGE_FOURCC_ARGB8888
;
930 case __DRI_IMAGE_FORMAT_ABGR8888
: return __DRI_IMAGE_FOURCC_ABGR8888
;
931 case __DRI_IMAGE_FORMAT_XBGR8888
: return __DRI_IMAGE_FOURCC_XBGR8888
;
936 /** dri3_get_pixmap_buffer
938 * Get the DRM object for a pixmap from the X server and
939 * wrap that with a __DRIimage structure using createImageFromFds
941 static struct dri3_buffer
*
942 dri3_get_pixmap_buffer(__DRIdrawable
*driDrawable
,
944 enum dri3_buffer_type buffer_type
,
947 struct dri3_drawable
*pdraw
= loaderPrivate
;
948 int buf_id
= dri3_pixmap_buf_id(buffer_type
);
949 struct dri3_buffer
*buffer
= pdraw
->buffers
[buf_id
];
951 xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie
;
952 xcb_dri3_buffer_from_pixmap_reply_t
*bp_reply
;
955 struct dri3_screen
*psc
;
957 xcb_sync_fence_t sync_fence
;
960 __DRIimage
*image_planar
;
966 pixmap
= pdraw
->base
.xDrawable
;
967 psc
= (struct dri3_screen
*) pdraw
->base
.psc
;
969 c
= XGetXCBConnection(dpy
);
971 buffer
= calloc(1, sizeof (struct dri3_buffer
));
975 fence_fd
= xshmfence_alloc_shm();
978 shm_fence
= xshmfence_map_shm(fence_fd
);
979 if (shm_fence
== NULL
) {
984 xcb_dri3_fence_from_fd(c
,
986 (sync_fence
= xcb_generate_id(c
)),
990 /* Get an FD for the pixmap object
992 bp_cookie
= xcb_dri3_buffer_from_pixmap(c
, pixmap
);
993 bp_reply
= xcb_dri3_buffer_from_pixmap_reply(c
, bp_cookie
, NULL
);
996 fds
= xcb_dri3_buffer_from_pixmap_reply_fds(c
, bp_reply
);
998 stride
= bp_reply
->stride
;
1001 /* createImageFromFds creates a wrapper __DRIimage structure which
1002 * can deal with multiple planes for things like Yuv images. So, once
1003 * we've gotten the planar wrapper, pull the single plane out of it and
1004 * discard the wrapper.
1006 image_planar
= (*psc
->image
->createImageFromFds
) (psc
->driScreen
,
1009 image_format_to_fourcc(format
),
1011 &stride
, &offset
, buffer
);
1016 buffer
->image
= (*psc
->image
->fromPlanar
)(image_planar
, 0, buffer
);
1018 (*psc
->image
->destroyImage
)(image_planar
);
1023 buffer
->pixmap
= pixmap
;
1024 buffer
->width
= bp_reply
->width
;
1025 buffer
->height
= bp_reply
->height
;
1026 buffer
->buffer_type
= buffer_type
;
1027 buffer
->shm_fence
= shm_fence
;
1028 buffer
->sync_fence
= sync_fence
;
1030 pdraw
->buffers
[buf_id
] = buffer
;
1034 xcb_sync_destroy_fence(c
, sync_fence
);
1035 xshmfence_unmap_shm(shm_fence
);
1044 * Find an idle back buffer. If there isn't one, then
1045 * wait for a present idle notify event from the X server
1048 dri3_find_back(xcb_connection_t
*c
, struct dri3_drawable
*priv
)
1051 xcb_generic_event_t
*ev
;
1052 xcb_present_generic_event_t
*ge
;
1056 for (b
= 0; b
< DRI3_MAX_BACK
; b
++) {
1057 int id
= DRI3_BACK_ID(b
);
1058 struct dri3_buffer
*buffer
= priv
->buffers
[id
];
1065 ev
= xcb_wait_for_special_event(c
, priv
->special_event
);
1069 dri3_handle_present_event(priv
, ge
);
1075 * Find a front or back buffer, allocating new ones as necessary
1077 static struct dri3_buffer
*
1078 dri3_get_buffer(__DRIdrawable
*driDrawable
,
1079 unsigned int format
,
1080 enum dri3_buffer_type buffer_type
,
1081 void *loaderPrivate
)
1083 struct dri3_drawable
*priv
= loaderPrivate
;
1084 xcb_connection_t
*c
= XGetXCBConnection(priv
->base
.psc
->dpy
);
1085 struct dri3_buffer
*buffer
;
1088 if (buffer_type
== dri3_buffer_back
) {
1089 int back
= dri3_find_back(c
, priv
);
1094 priv
->cur_back
= back
;
1095 buf_id
= DRI3_BACK_ID(priv
->cur_back
);
1097 buf_id
= DRI3_FRONT_ID
;
1100 buffer
= priv
->buffers
[buf_id
];
1102 /* Allocate a new buffer if there isn't an old one, or if that
1103 * old one is the wrong size
1105 if (!buffer
|| buffer
->width
!= priv
->width
|| buffer
->height
!= priv
->height
) {
1106 struct dri3_buffer
*new_buffer
;
1108 /* Allocate the new buffers
1110 new_buffer
= dri3_alloc_render_buffer(priv
->base
.psc
,
1111 priv
->base
.xDrawable
,
1112 format
, priv
->width
, priv
->height
, priv
->depth
);
1116 /* When resizing, copy the contents of the old buffer, waiting for that
1117 * copy to complete using our fences before proceeding
1119 switch (buffer_type
) {
1120 case dri3_buffer_back
:
1122 dri3_fence_reset(c
, new_buffer
);
1123 dri3_fence_await(c
, buffer
);
1127 dri3_drawable_gc(priv
),
1128 0, 0, 0, 0, priv
->width
, priv
->height
);
1129 dri3_fence_trigger(c
, new_buffer
);
1130 dri3_free_render_buffer(priv
, buffer
);
1133 case dri3_buffer_front
:
1134 dri3_fence_reset(c
, new_buffer
);
1136 priv
->base
.xDrawable
,
1138 dri3_drawable_gc(priv
),
1139 0, 0, 0, 0, priv
->width
, priv
->height
);
1140 dri3_fence_trigger(c
, new_buffer
);
1143 buffer
= new_buffer
;
1144 buffer
->buffer_type
= buffer_type
;
1145 priv
->buffers
[buf_id
] = buffer
;
1147 dri3_fence_await(c
, buffer
);
1149 /* Return the requested buffer */
1153 /** dri3_free_buffers
1155 * Free the front bufffer or all of the back buffers. Used
1156 * when the application changes which buffers it needs
1159 dri3_free_buffers(__DRIdrawable
*driDrawable
,
1160 enum dri3_buffer_type buffer_type
,
1161 void *loaderPrivate
)
1163 struct dri3_drawable
*priv
= loaderPrivate
;
1164 struct dri3_buffer
*buffer
;
1169 switch (buffer_type
) {
1170 case dri3_buffer_back
:
1171 first_id
= DRI3_BACK_ID(0);
1172 n_id
= DRI3_MAX_BACK
;
1174 case dri3_buffer_front
:
1175 first_id
= DRI3_FRONT_ID
;
1179 for (buf_id
= first_id
; buf_id
< first_id
+ n_id
; buf_id
++) {
1180 buffer
= priv
->buffers
[buf_id
];
1182 dri3_free_render_buffer(priv
, buffer
);
1183 priv
->buffers
[buf_id
] = NULL
;
1188 /** dri3_get_buffers
1190 * The published buffer allocation API.
1191 * Returns all of the necessary buffers, allocating
1195 dri3_get_buffers(__DRIdrawable
*driDrawable
,
1196 unsigned int format
,
1198 void *loaderPrivate
,
1199 uint32_t buffer_mask
,
1200 struct __DRIimageList
*buffers
)
1202 struct dri3_drawable
*priv
= loaderPrivate
;
1203 struct dri3_buffer
*front
, *back
;
1205 buffers
->image_mask
= 0;
1206 buffers
->front
= NULL
;
1207 buffers
->back
= NULL
;
1212 if (!dri3_update_drawable(driDrawable
, loaderPrivate
))
1215 /* pixmaps always have front buffers */
1216 if (priv
->is_pixmap
)
1217 buffer_mask
|= __DRI_IMAGE_BUFFER_FRONT
;
1219 if (buffer_mask
& __DRI_IMAGE_BUFFER_FRONT
) {
1220 if (priv
->is_pixmap
)
1221 front
= dri3_get_pixmap_buffer(driDrawable
,
1226 front
= dri3_get_buffer(driDrawable
,
1234 dri3_free_buffers(driDrawable
, dri3_buffer_front
, loaderPrivate
);
1235 priv
->have_fake_front
= 0;
1238 if (buffer_mask
& __DRI_IMAGE_BUFFER_BACK
) {
1239 back
= dri3_get_buffer(driDrawable
,
1245 priv
->have_back
= 1;
1247 dri3_free_buffers(driDrawable
, dri3_buffer_back
, loaderPrivate
);
1248 priv
->have_back
= 0;
1252 buffers
->image_mask
|= __DRI_IMAGE_BUFFER_FRONT
;
1253 buffers
->front
= front
->image
;
1254 priv
->have_fake_front
= !priv
->is_pixmap
;
1258 buffers
->image_mask
|= __DRI_IMAGE_BUFFER_BACK
;
1259 buffers
->back
= back
->image
;
1262 priv
->stamp
= stamp
;
1267 /* The image loader extension record for DRI3
1269 static const __DRIimageLoaderExtension imageLoaderExtension
= {
1270 {__DRI_IMAGE_LOADER
, __DRI_IMAGE_LOADER_VERSION
},
1271 .getBuffers
= dri3_get_buffers
,
1272 .flushFrontBuffer
= dri3_flush_front_buffer
,
1275 /** dri3_swap_buffers
1277 * Make the current back buffer visible using the present extension
1280 dri3_swap_buffers(__GLXDRIdrawable
*pdraw
, int64_t target_msc
, int64_t divisor
,
1281 int64_t remainder
, Bool flush
)
1283 struct dri3_drawable
*priv
= (struct dri3_drawable
*) pdraw
;
1284 struct dri3_screen
*psc
= (struct dri3_screen
*) priv
->base
.psc
;
1285 Display
*dpy
= priv
->base
.psc
->dpy
;
1286 xcb_connection_t
*c
= XGetXCBConnection(dpy
);
1287 int buf_id
= DRI3_BACK_ID(priv
->cur_back
);
1290 unsigned flags
= __DRI2_FLUSH_DRAWABLE
;
1292 flags
|= __DRI2_FLUSH_CONTEXT
;
1293 dri3_flush(psc
, priv
, flags
, __DRI2_THROTTLE_SWAPBUFFER
);
1295 dri3_flush_present_events(priv
);
1297 if (priv
->buffers
[buf_id
] && !priv
->is_pixmap
) {
1298 dri3_fence_reset(c
, priv
->buffers
[buf_id
]);
1300 /* Compute when we want the frame shown by taking the last known successful
1301 * MSC and adding in a swap interval for each outstanding swap request
1303 ++priv
->present_request_serial
;
1304 if (target_msc
== 0)
1305 target_msc
= priv
->msc
+ priv
->swap_interval
* (priv
->present_request_serial
- priv
->present_event_serial
);
1307 priv
->buffers
[buf_id
]->busy
= 1;
1308 xcb_present_pixmap(c
,
1309 priv
->base
.xDrawable
,
1310 priv
->buffers
[buf_id
]->pixmap
,
1311 priv
->present_request_serial
,
1316 None
, /* target_crtc */
1318 priv
->buffers
[buf_id
]->sync_fence
,
1319 XCB_PRESENT_OPTION_NONE
,
1322 remainder
, 0, NULL
);
1325 /* If there's a fake front, then copy the source back buffer
1326 * to the fake front to keep it up to date. This needs
1327 * to reset the fence and make future users block until
1328 * the X server is done copying the bits
1330 if (priv
->have_fake_front
) {
1331 dri3_fence_reset(c
, priv
->buffers
[DRI3_FRONT_ID
]);
1333 priv
->buffers
[buf_id
]->pixmap
,
1334 priv
->buffers
[DRI3_FRONT_ID
]->pixmap
,
1335 dri3_drawable_gc(priv
),
1336 0, 0, 0, 0, priv
->width
, priv
->height
);
1337 dri3_fence_trigger(c
, priv
->buffers
[DRI3_FRONT_ID
]);
1349 * Wrapper around xcb_dri3_open
1352 dri3_open(Display
*dpy
,
1356 xcb_dri3_open_cookie_t cookie
;
1357 xcb_dri3_open_reply_t
*reply
;
1358 xcb_connection_t
*c
= XGetXCBConnection(dpy
);
1359 xcb_generic_error_t
*error
;
1362 cookie
= xcb_dri3_open(c
,
1366 reply
= xcb_dri3_open_reply(c
, cookie
, &error
);
1370 if (reply
->nfd
!= 1) {
1375 fd
= xcb_dri3_open_reply_fds(c
, reply
)[0];
1376 fcntl(fd
, F_SETFD
, FD_CLOEXEC
);
1382 /** dri3_destroy_screen
1385 dri3_destroy_screen(struct glx_screen
*base
)
1387 struct dri3_screen
*psc
= (struct dri3_screen
*) base
;
1389 /* Free the direct rendering per screen data */
1390 (*psc
->core
->destroyScreen
) (psc
->driScreen
);
1391 driDestroyConfigs(psc
->driver_configs
);
1396 /** dri3_set_swap_interval
1398 * Record the application swap interval specification,
1401 dri3_set_swap_interval(__GLXDRIdrawable
*pdraw
, int interval
)
1403 struct dri3_drawable
*priv
= (struct dri3_drawable
*) pdraw
;
1404 GLint vblank_mode
= DRI_CONF_VBLANK_DEF_INTERVAL_1
;
1405 struct dri3_screen
*psc
= (struct dri3_screen
*) priv
->base
.psc
;
1408 psc
->config
->configQueryi(psc
->driScreen
,
1409 "vblank_mode", &vblank_mode
);
1411 switch (vblank_mode
) {
1412 case DRI_CONF_VBLANK_NEVER
:
1414 return GLX_BAD_VALUE
;
1416 case DRI_CONF_VBLANK_ALWAYS_SYNC
:
1418 return GLX_BAD_VALUE
;
1424 priv
->swap_interval
= interval
;
1429 /** dri3_get_swap_interval
1431 * Return the stored swap interval
1434 dri3_get_swap_interval(__GLXDRIdrawable
*pdraw
)
1436 struct dri3_drawable
*priv
= (struct dri3_drawable
*) pdraw
;
1438 return priv
->swap_interval
;
1442 dri3_bind_tex_image(Display
* dpy
,
1443 GLXDrawable drawable
,
1444 int buffer
, const int *attrib_list
)
1446 struct glx_context
*gc
= __glXGetCurrentContext();
1447 struct dri3_context
*pcp
= (struct dri3_context
*) gc
;
1448 __GLXDRIdrawable
*base
= GetGLXDRIDrawable(dpy
, drawable
);
1449 struct dri3_drawable
*pdraw
= (struct dri3_drawable
*) base
;
1450 struct dri3_screen
*psc
;
1452 if (pdraw
!= NULL
) {
1453 psc
= (struct dri3_screen
*) base
->psc
;
1455 (*psc
->f
->invalidate
)(pdraw
->driDrawable
);
1459 (*psc
->texBuffer
->setTexBuffer2
) (pcp
->driContext
,
1460 pdraw
->base
.textureTarget
,
1461 pdraw
->base
.textureFormat
,
1462 pdraw
->driDrawable
);
1467 dri3_release_tex_image(Display
* dpy
, GLXDrawable drawable
, int buffer
)
1469 struct glx_context
*gc
= __glXGetCurrentContext();
1470 struct dri3_context
*pcp
= (struct dri3_context
*) gc
;
1471 __GLXDRIdrawable
*base
= GetGLXDRIDrawable(dpy
, drawable
);
1472 struct dri3_drawable
*pdraw
= (struct dri3_drawable
*) base
;
1473 struct dri3_screen
*psc
;
1475 if (pdraw
!= NULL
) {
1476 psc
= (struct dri3_screen
*) base
->psc
;
1478 if (psc
->texBuffer
->releaseTexBuffer
)
1479 (*psc
->texBuffer
->releaseTexBuffer
) (pcp
->driContext
,
1480 pdraw
->base
.textureTarget
,
1481 pdraw
->driDrawable
);
1485 static const struct glx_context_vtable dri3_context_vtable
= {
1486 dri3_destroy_context
,
1488 dri3_unbind_context
,
1492 dri3_bind_tex_image
,
1493 dri3_release_tex_image
,
1494 NULL
, /* get_proc_address */
1497 /** dri3_bind_extensions
1499 * Enable all of the extensions supported on DRI3
1502 dri3_bind_extensions(struct dri3_screen
*psc
, struct glx_display
* priv
,
1503 const char *driverName
)
1505 const __DRIextension
**extensions
;
1509 extensions
= psc
->core
->getExtensions(psc
->driScreen
);
1511 __glXEnableDirectExtension(&psc
->base
, "GLX_SGI_video_sync");
1512 __glXEnableDirectExtension(&psc
->base
, "GLX_SGI_swap_control");
1513 __glXEnableDirectExtension(&psc
->base
, "GLX_MESA_swap_control");
1514 __glXEnableDirectExtension(&psc
->base
, "GLX_SGI_make_current_read");
1517 * GLX_INTEL_swap_event is broken on the server side, where it's
1518 * currently unconditionally enabled. This completely breaks
1519 * systems running on drivers which don't support that extension.
1520 * There's no way to test for its presence on this side, so instead
1521 * of disabling it unconditionally, just disable it for drivers
1522 * which are known to not support it, or for DDX drivers supporting
1523 * only an older (pre-ScheduleSwap) version of DRI2.
1525 * This is a hack which is required until:
1526 * http://lists.x.org/archives/xorg-devel/2013-February/035449.html
1527 * is merged and updated xserver makes it's way into distros:
1529 // if (pdp->swapAvailable && strcmp(driverName, "vmwgfx") != 0) {
1530 // __glXEnableDirectExtension(&psc->base, "GLX_INTEL_swap_event");
1533 mask
= psc
->image_driver
->getAPIMask(psc
->driScreen
);
1535 __glXEnableDirectExtension(&psc
->base
, "GLX_ARB_create_context");
1536 __glXEnableDirectExtension(&psc
->base
, "GLX_ARB_create_context_profile");
1538 if ((mask
& (1 << __DRI_API_GLES2
)) != 0)
1539 __glXEnableDirectExtension(&psc
->base
,
1540 "GLX_EXT_create_context_es2_profile");
1542 for (i
= 0; extensions
[i
]; i
++) {
1543 if ((strcmp(extensions
[i
]->name
, __DRI_TEX_BUFFER
) == 0)) {
1544 psc
->texBuffer
= (__DRItexBufferExtension
*) extensions
[i
];
1545 __glXEnableDirectExtension(&psc
->base
, "GLX_EXT_texture_from_pixmap");
1548 if ((strcmp(extensions
[i
]->name
, __DRI2_FLUSH
) == 0)) {
1549 psc
->f
= (__DRI2flushExtension
*) extensions
[i
];
1550 /* internal driver extension, no GL extension exposed */
1553 if ((strcmp(extensions
[i
]->name
, __DRI2_CONFIG_QUERY
) == 0))
1554 psc
->config
= (__DRI2configQueryExtension
*) extensions
[i
];
1556 if (strcmp(extensions
[i
]->name
, __DRI2_ROBUSTNESS
) == 0)
1557 __glXEnableDirectExtension(&psc
->base
,
1558 "GLX_ARB_create_context_robustness");
1562 static const struct glx_screen_vtable dri3_screen_vtable
= {
1563 dri3_create_context
,
1564 dri3_create_context_attribs
1567 /** dri3_create_screen
1569 * Initialize DRI3 on the specified screen.
1571 * Opens the DRI device, locates the appropriate DRI driver
1574 * Checks to see if the driver supports the necessary extensions
1576 * Initializes the driver for the screen and sets up our structures
1579 static struct glx_screen
*
1580 dri3_create_screen(int screen
, struct glx_display
* priv
)
1582 xcb_connection_t
*c
= XGetXCBConnection(priv
->dpy
);
1583 const __DRIconfig
**driver_configs
;
1584 const __DRIextension
**extensions
;
1585 const struct dri3_display
*const pdp
= (struct dri3_display
*)
1587 struct dri3_screen
*psc
;
1588 __GLXDRIscreen
*psp
;
1589 struct glx_config
*configs
= NULL
, *visuals
= NULL
;
1590 char *driverName
, *deviceName
;
1593 psc
= calloc(1, sizeof *psc
);
1599 if (!glx_screen_init(&psc
->base
, screen
, priv
)) {
1604 psc
->fd
= dri3_open(priv
->dpy
, RootWindow(priv
->dpy
, screen
), None
);
1606 int conn_error
= xcb_connection_has_error(c
);
1608 glx_screen_cleanup(&psc
->base
);
1610 InfoMessageF("screen %d does not appear to be DRI3 capable\n", screen
);
1613 ErrorMessageF("Connection closed during DRI3 initialization failure");
1619 driverName
= dri3_get_driver_for_fd(psc
->fd
);
1621 ErrorMessageF("No driver found\n");
1625 psc
->driver
= driOpenDriver(driverName
);
1626 if (psc
->driver
== NULL
) {
1627 ErrorMessageF("driver pointer missing\n");
1631 extensions
= driGetDriverExtensions(psc
->driver
, driverName
);
1632 if (extensions
== NULL
)
1635 for (i
= 0; extensions
[i
]; i
++) {
1636 if (strcmp(extensions
[i
]->name
, __DRI_CORE
) == 0)
1637 psc
->core
= (__DRIcoreExtension
*) extensions
[i
];
1638 if (strcmp(extensions
[i
]->name
, __DRI_IMAGE_DRIVER
) == 0)
1639 psc
->image_driver
= (__DRIimageDriverExtension
*) extensions
[i
];
1643 if (psc
->core
== NULL
) {
1644 ErrorMessageF("core dri driver extension not found\n");
1648 if (psc
->image_driver
== NULL
) {
1649 ErrorMessageF("image driver extension not found\n");
1654 psc
->image_driver
->createNewScreen2(screen
, psc
->fd
,
1655 (const __DRIextension
**)
1656 &pdp
->loader_extensions
[0],
1658 &driver_configs
, psc
);
1660 if (psc
->driScreen
== NULL
) {
1661 ErrorMessageF("failed to create dri screen\n");
1665 extensions
= (*psc
->core
->getExtensions
)(psc
->driScreen
);
1667 for (i
= 0; extensions
[i
]; i
++) {
1668 if (strcmp(extensions
[i
]->name
, __DRI_IMAGE
) == 0)
1669 psc
->image
= (__DRIimageExtension
*) extensions
[i
];
1672 if (psc
->image
== NULL
) {
1673 ErrorMessageF("image extension not found\n");
1677 dri3_bind_extensions(psc
, priv
, driverName
);
1679 if (!psc
->f
|| psc
->f
->base
.version
< 4) {
1680 ErrorMessageF("Version 4 or later of flush extension not found\n");
1684 if (!psc
->texBuffer
|| psc
->texBuffer
->base
.version
< 2 ||
1685 !psc
->texBuffer
->setTexBuffer2
)
1687 ErrorMessageF("Version 2 or later of texBuffer extension not found\n");
1691 configs
= driConvertConfigs(psc
->core
, psc
->base
.configs
, driver_configs
);
1692 visuals
= driConvertConfigs(psc
->core
, psc
->base
.visuals
, driver_configs
);
1694 if (!configs
|| !visuals
)
1697 glx_config_destroy_list(psc
->base
.configs
);
1698 psc
->base
.configs
= configs
;
1699 glx_config_destroy_list(psc
->base
.visuals
);
1700 psc
->base
.visuals
= visuals
;
1702 psc
->driver_configs
= driver_configs
;
1704 psc
->base
.vtable
= &dri3_screen_vtable
;
1706 psc
->base
.driScreen
= psp
;
1707 psp
->destroyScreen
= dri3_destroy_screen
;
1708 psp
->createDrawable
= dri3_create_drawable
;
1709 psp
->swapBuffers
= dri3_swap_buffers
;
1711 psp
->getDrawableMSC
= dri3_drawable_get_msc
;
1712 psp
->waitForMSC
= dri3_wait_for_msc
;
1713 psp
->waitForSBC
= dri3_wait_for_sbc
;
1714 psp
->setSwapInterval
= dri3_set_swap_interval
;
1715 psp
->getSwapInterval
= dri3_get_swap_interval
;
1716 __glXEnableDirectExtension(&psc
->base
, "GLX_OML_sync_control");
1718 psp
->copySubBuffer
= dri3_copy_sub_buffer
;
1719 __glXEnableDirectExtension(&psc
->base
, "GLX_MESA_copy_sub_buffer");
1727 CriticalErrorMessageF("failed to load driver: %s\n", driverName
);
1730 glx_config_destroy_list(configs
);
1732 glx_config_destroy_list(visuals
);
1734 psc
->core
->destroyScreen(psc
->driScreen
);
1735 psc
->driScreen
= NULL
;
1739 dlclose(psc
->driver
);
1743 glx_screen_cleanup(&psc
->base
);
1749 /** dri_destroy_display
1751 * Called from __glXFreeDisplayPrivate.
1754 dri3_destroy_display(__GLXDRIdisplay
* dpy
)
1759 /** dri3_create_display
1761 * Allocate, initialize and return a __DRIdisplayPrivate object.
1762 * This is called from __glXInitialize() when we are given a new
1763 * display pointer. This is public to that function, but hidden from
1766 _X_HIDDEN __GLXDRIdisplay
*
1767 dri3_create_display(Display
* dpy
)
1769 struct dri3_display
*pdp
;
1771 xcb_connection_t
*c
= XGetXCBConnection(dpy
);
1772 xcb_dri3_query_version_cookie_t dri3_cookie
;
1773 xcb_dri3_query_version_reply_t
*dri3_reply
;
1774 xcb_present_query_version_cookie_t present_cookie
;
1775 xcb_present_query_version_reply_t
*present_reply
;
1776 xcb_generic_error_t
*error
;
1777 const xcb_query_extension_reply_t
*extension
;
1779 xcb_prefetch_extension_data(c
, &xcb_dri3_id
);
1780 xcb_prefetch_extension_data(c
, &xcb_present_id
);
1782 extension
= xcb_get_extension_data(c
, &xcb_dri3_id
);
1783 if (!(extension
&& extension
->present
))
1786 extension
= xcb_get_extension_data(c
, &xcb_present_id
);
1787 if (!(extension
&& extension
->present
))
1790 dri3_cookie
= xcb_dri3_query_version(c
,
1791 XCB_DRI3_MAJOR_VERSION
,
1792 XCB_DRI3_MINOR_VERSION
);
1795 present_cookie
= xcb_present_query_version(c
,
1796 XCB_PRESENT_MAJOR_VERSION
,
1797 XCB_PRESENT_MINOR_VERSION
);
1799 pdp
= malloc(sizeof *pdp
);
1803 dri3_reply
= xcb_dri3_query_version_reply(c
, dri3_cookie
, &error
);
1809 pdp
->dri3Major
= dri3_reply
->major_version
;
1810 pdp
->dri3Minor
= dri3_reply
->minor_version
;
1813 present_reply
= xcb_present_query_version_reply(c
, present_cookie
, &error
);
1814 if (!present_reply
) {
1818 pdp
->presentMajor
= present_reply
->major_version
;
1819 pdp
->presentMinor
= present_reply
->minor_version
;
1821 pdp
->base
.destroyDisplay
= dri3_destroy_display
;
1822 pdp
->base
.createScreen
= dri3_create_screen
;
1826 pdp
->loader_extensions
[i
++] = &imageLoaderExtension
.base
;
1828 pdp
->loader_extensions
[i
++] = &systemTimeExtension
.base
;
1830 pdp
->loader_extensions
[i
++] = NULL
;
1838 #endif /* GLX_DIRECT_RENDERING */