1 /*
2 * Copyright © 2008 Red Hat, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Soft-
6 * ware"), to deal in the Software without restriction, including without
7 * limitation the rights to use, copy, modify, merge, publish, distribute,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, provided that the above copyright
10 * notice(s) and this permission notice appear in all copies of the Soft-
11 * ware and that both the above copyright notice(s) and this permission
12 * notice appear in supporting documentation.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
16 * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
17 * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
18 * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
19 * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
22 * MANCE OF THIS SOFTWARE.
23 *
24 * Except as contained in this notice, the name of a copyright holder shall
25 * not be used in advertising or otherwise to promote the sale, use or
26 * other dealings in this Software without prior written authorization of
27 * the copyright holder.
28 *
29 * Authors:
30 * Kristian Høgsberg ([email protected])
31 */
32
33 #if defined(GLX_DIRECT_RENDERING) && (!defined(GLX_USE_APPLEGL) || defined(GLX_USE_APPLE))
34
35 #include <X11/Xlib.h>
36 #include <X11/extensions/Xfixes.h>
37 #include <X11/Xlib-xcb.h>
38 #include <xcb/xcb.h>
39 #include <xcb/dri2.h>
40 #include "glxclient.h"
41 #include <X11/extensions/dri2proto.h>
42 #include <dlfcn.h>
43 #include <fcntl.h>
44 #include <unistd.h>
45 #include <sys/types.h>
46 #include <sys/mman.h>
47 #include <sys/time.h>
48 #include "dri2.h"
49 #include "dri_common.h"
50 #include "dri2_priv.h"
51 #include "loader.h"
52 #include "loader_dri_helper.h"
53 #include "dri_util.h"
54
55 #undef DRI2_MINOR
56 #define DRI2_MINOR 1
57
58 struct dri2_drawable
59 {
60 __GLXDRIdrawable base;
61 __DRIbuffer buffers[5];
62 int bufferCount;
63 int width, height;
64 int have_back;
65 int have_fake_front;
66 int swap_interval;
67
68 uint64_t previous_time;
69 unsigned frames;
70 };
71
72 static const struct glx_context_vtable dri2_context_vtable;
73
74 /* For XCB's handling of ust/msc/sbc counters, we have to hand it the high and
75 * low halves separately. This helps you split them.
76 */
77 static void
split_counter(uint64_t counter,uint32_t * hi,uint32_t * lo)78 split_counter(uint64_t counter, uint32_t *hi, uint32_t *lo)
79 {
80 *hi = (counter >> 32);
81 *lo = counter & 0xffffffff;
82 }
83
84 static uint64_t
merge_counter(uint32_t hi,uint32_t lo)85 merge_counter(uint32_t hi, uint32_t lo)
86 {
87 return ((uint64_t)hi << 32) | lo;
88 }
89
90 static void
dri2DestroyDrawable(__GLXDRIdrawable * base)91 dri2DestroyDrawable(__GLXDRIdrawable *base)
92 {
93 struct dri2_screen *psc = (struct dri2_screen *) base->psc;
94 struct glx_display *dpyPriv = psc->base.display;
95
96 __glxHashDelete(dpyPriv->dri2Hash, base->xDrawable);
97 driDestroyDrawable(base->dri_drawable);
98
99 /* If it's a GLX 1.3 drawables, we can destroy the DRI2 drawable
100 * now, as the application explicitly asked to destroy the GLX
101 * drawable. Otherwise, for legacy drawables, we let the DRI2
102 * drawable linger on the server, since there's no good way of
103 * knowing when the application is done with it. The server will
104 * destroy the DRI2 drawable when it destroys the X drawable or the
105 * client exits anyway. */
106 if (base->xDrawable != base->drawable)
107 DRI2DestroyDrawable(psc->base.dpy, base->xDrawable);
108
109 free(base);
110 }
111
112 static __GLXDRIdrawable *
dri2CreateDrawable(struct glx_screen * base,XID xDrawable,GLXDrawable drawable,int type,struct glx_config * config_base)113 dri2CreateDrawable(struct glx_screen *base, XID xDrawable,
114 GLXDrawable drawable, int type,
115 struct glx_config *config_base)
116 {
117 struct dri2_drawable *pdraw;
118 struct dri2_screen *psc = (struct dri2_screen *) base;
119 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
120 struct glx_display *dpyPriv;
121
122 dpyPriv = __glXInitialize(psc->base.dpy);
123 if (dpyPriv == NULL)
124 return NULL;
125
126 pdraw = calloc(1, sizeof(*pdraw));
127 if (!pdraw)
128 return NULL;
129
130 pdraw->base.destroyDrawable = dri2DestroyDrawable;
131 pdraw->base.xDrawable = xDrawable;
132 pdraw->base.drawable = drawable;
133 pdraw->base.psc = &psc->base;
134 pdraw->bufferCount = 0;
135 pdraw->swap_interval = dri_get_initial_swap_interval(psc->base.frontend_screen);
136 pdraw->have_back = 0;
137
138 DRI2CreateDrawable(psc->base.dpy, xDrawable);
139 /* Create a new drawable */
140 pdraw->base.dri_drawable =
141 dri_create_drawable(psc->base.frontend_screen, config->driConfig, false, pdraw);
142
143 if (!pdraw->base.dri_drawable) {
144 DRI2DestroyDrawable(psc->base.dpy, xDrawable);
145 free(pdraw);
146 return NULL;
147 }
148
149 if (__glxHashInsert(dpyPriv->dri2Hash, xDrawable, pdraw)) {
150 driDestroyDrawable(pdraw->base.dri_drawable);
151 DRI2DestroyDrawable(psc->base.dpy, xDrawable);
152 free(pdraw);
153 return None;
154 }
155
156 /*
157 * Make sure server has the same swap interval we do for the new
158 * drawable.
159 */
160 if (base->driScreen.setSwapInterval)
161 base->driScreen.setSwapInterval(&pdraw->base, pdraw->swap_interval);
162
163 return &pdraw->base;
164 }
165
166 static int
dri2DrawableGetMSC(struct glx_screen * psc,__GLXDRIdrawable * pdraw,int64_t * ust,int64_t * msc,int64_t * sbc)167 dri2DrawableGetMSC(struct glx_screen *psc, __GLXDRIdrawable *pdraw,
168 int64_t *ust, int64_t *msc, int64_t *sbc)
169 {
170 xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
171 xcb_dri2_get_msc_cookie_t get_msc_cookie;
172 xcb_dri2_get_msc_reply_t *get_msc_reply;
173
174 get_msc_cookie = xcb_dri2_get_msc_unchecked(c, pdraw->xDrawable);
175 get_msc_reply = xcb_dri2_get_msc_reply(c, get_msc_cookie, NULL);
176
177 if (!get_msc_reply)
178 return 0;
179
180 *ust = merge_counter(get_msc_reply->ust_hi, get_msc_reply->ust_lo);
181 *msc = merge_counter(get_msc_reply->msc_hi, get_msc_reply->msc_lo);
182 *sbc = merge_counter(get_msc_reply->sbc_hi, get_msc_reply->sbc_lo);
183 free(get_msc_reply);
184
185 return 1;
186 }
187
188 static int
dri2WaitForMSC(__GLXDRIdrawable * pdraw,int64_t target_msc,int64_t divisor,int64_t remainder,int64_t * ust,int64_t * msc,int64_t * sbc)189 dri2WaitForMSC(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
190 int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc)
191 {
192 xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
193 xcb_dri2_wait_msc_cookie_t wait_msc_cookie;
194 xcb_dri2_wait_msc_reply_t *wait_msc_reply;
195 uint32_t target_msc_hi, target_msc_lo;
196 uint32_t divisor_hi, divisor_lo;
197 uint32_t remainder_hi, remainder_lo;
198
199 split_counter(target_msc, &target_msc_hi, &target_msc_lo);
200 split_counter(divisor, &divisor_hi, &divisor_lo);
201 split_counter(remainder, &remainder_hi, &remainder_lo);
202
203 wait_msc_cookie = xcb_dri2_wait_msc_unchecked(c, pdraw->xDrawable,
204 target_msc_hi, target_msc_lo,
205 divisor_hi, divisor_lo,
206 remainder_hi, remainder_lo);
207 wait_msc_reply = xcb_dri2_wait_msc_reply(c, wait_msc_cookie, NULL);
208
209 if (!wait_msc_reply)
210 return 0;
211
212 *ust = merge_counter(wait_msc_reply->ust_hi, wait_msc_reply->ust_lo);
213 *msc = merge_counter(wait_msc_reply->msc_hi, wait_msc_reply->msc_lo);
214 *sbc = merge_counter(wait_msc_reply->sbc_hi, wait_msc_reply->sbc_lo);
215 free(wait_msc_reply);
216
217 return 1;
218 }
219
220 static int
dri2WaitForSBC(__GLXDRIdrawable * pdraw,int64_t target_sbc,int64_t * ust,int64_t * msc,int64_t * sbc)221 dri2WaitForSBC(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust,
222 int64_t *msc, int64_t *sbc)
223 {
224 xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
225 xcb_dri2_wait_sbc_cookie_t wait_sbc_cookie;
226 xcb_dri2_wait_sbc_reply_t *wait_sbc_reply;
227 uint32_t target_sbc_hi, target_sbc_lo;
228
229 split_counter(target_sbc, &target_sbc_hi, &target_sbc_lo);
230
231 wait_sbc_cookie = xcb_dri2_wait_sbc_unchecked(c, pdraw->xDrawable,
232 target_sbc_hi, target_sbc_lo);
233 wait_sbc_reply = xcb_dri2_wait_sbc_reply(c, wait_sbc_cookie, NULL);
234
235 if (!wait_sbc_reply)
236 return 0;
237
238 *ust = merge_counter(wait_sbc_reply->ust_hi, wait_sbc_reply->ust_lo);
239 *msc = merge_counter(wait_sbc_reply->msc_hi, wait_sbc_reply->msc_lo);
240 *sbc = merge_counter(wait_sbc_reply->sbc_hi, wait_sbc_reply->sbc_lo);
241 free(wait_sbc_reply);
242
243 return 1;
244 }
245
246 static __DRIcontext *
dri2GetCurrentContext()247 dri2GetCurrentContext()
248 {
249 struct glx_context *gc = __glXGetCurrentContext();
250
251 return (gc != &dummyContext) ? gc->driContext : NULL;
252 }
253
254 /**
255 * dri2Throttle - Request driver throttling
256 *
257 * This function uses the DRI2 throttle extension to give the
258 * driver the opportunity to throttle on flush front, copysubbuffer
259 * and swapbuffers.
260 */
261 static void
dri2Throttle(struct dri2_screen * psc,struct dri2_drawable * draw,enum __DRI2throttleReason reason)262 dri2Throttle(struct dri2_screen *psc,
263 struct dri2_drawable *draw,
264 enum __DRI2throttleReason reason)
265 {
266 __DRIcontext *ctx = dri2GetCurrentContext();
267
268 dri_throttle(ctx, draw->base.dri_drawable, reason);
269 }
270
271 /**
272 * Asks the driver to flush any queued work necessary for serializing with the
273 * X command stream, and optionally the slightly more strict requirement of
274 * glFlush() equivalence (which would require flushing even if nothing had
275 * been drawn to a window system framebuffer, for example).
276 */
277 static void
dri2Flush(struct dri2_screen * psc,__DRIcontext * ctx,struct dri2_drawable * draw,unsigned flags,enum __DRI2throttleReason throttle_reason)278 dri2Flush(struct dri2_screen *psc,
279 __DRIcontext *ctx,
280 struct dri2_drawable *draw,
281 unsigned flags,
282 enum __DRI2throttleReason throttle_reason)
283 {
284 if (ctx) {
285 dri_flush(ctx, draw->base.dri_drawable, flags, throttle_reason);
286 } else {
287 if (flags & __DRI2_FLUSH_CONTEXT)
288 glFlush();
289
290 dri_flush_drawable(draw->base.dri_drawable);
291
292 dri2Throttle(psc, draw, throttle_reason);
293 }
294 }
295
296 static void
__dri2CopySubBuffer(__GLXDRIdrawable * pdraw,int x,int y,int width,int height,enum __DRI2throttleReason reason,Bool flush)297 __dri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y,
298 int width, int height,
299 enum __DRI2throttleReason reason, Bool flush)
300 {
301 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
302 struct dri2_screen *psc = (struct dri2_screen *) pdraw->psc;
303 XRectangle xrect;
304 XserverRegion region;
305 __DRIcontext *ctx = dri2GetCurrentContext();
306 unsigned flags;
307
308 /* Check we have the right attachments */
309 if (!priv->have_back)
310 return;
311
312 xrect.x = x;
313 xrect.y = priv->height - y - height;
314 xrect.width = width;
315 xrect.height = height;
316
317 flags = __DRI2_FLUSH_DRAWABLE;
318 if (flush)
319 flags |= __DRI2_FLUSH_CONTEXT;
320 dri2Flush(psc, ctx, priv, flags, __DRI2_THROTTLE_COPYSUBBUFFER);
321
322 region = XFixesCreateRegion(psc->base.dpy, &xrect, 1);
323 DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region,
324 DRI2BufferFrontLeft, DRI2BufferBackLeft);
325
326 /* Refresh the fake front (if present) after we just damaged the real
327 * front.
328 */
329 if (priv->have_fake_front)
330 DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region,
331 DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
332
333 XFixesDestroyRegion(psc->base.dpy, region);
334 }
335
336 static void
dri2CopySubBuffer(__GLXDRIdrawable * pdraw,int x,int y,int width,int height,Bool flush)337 dri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y,
338 int width, int height, Bool flush)
339 {
340 __dri2CopySubBuffer(pdraw, x, y, width, height,
341 __DRI2_THROTTLE_COPYSUBBUFFER, flush);
342 }
343
344
345 static void
dri2_copy_drawable(struct dri2_drawable * priv,int dest,int src)346 dri2_copy_drawable(struct dri2_drawable *priv, int dest, int src)
347 {
348 XRectangle xrect;
349 XserverRegion region;
350 struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
351
352 xrect.x = 0;
353 xrect.y = 0;
354 xrect.width = priv->width;
355 xrect.height = priv->height;
356
357 dri_flush_drawable(priv->base.dri_drawable);
358
359 region = XFixesCreateRegion(psc->base.dpy, &xrect, 1);
360 DRI2CopyRegion(psc->base.dpy, priv->base.xDrawable, region, dest, src);
361 XFixesDestroyRegion(psc->base.dpy, region);
362
363 }
364
365 static void
dri2_wait_x(struct glx_context * gc)366 dri2_wait_x(struct glx_context *gc)
367 {
368 struct dri2_drawable *priv = (struct dri2_drawable *)
369 GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable);
370
371 if (priv == NULL || !priv->have_fake_front)
372 return;
373
374 dri2_copy_drawable(priv, DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
375 }
376
377 static void
dri2_wait_gl(struct glx_context * gc)378 dri2_wait_gl(struct glx_context *gc)
379 {
380 struct dri2_drawable *priv = (struct dri2_drawable *)
381 GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable);
382
383 if (priv == NULL || !priv->have_fake_front)
384 return;
385
386 dri2_copy_drawable(priv, DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
387 }
388
389 /**
390 * Called by the driver when it needs to update the real front buffer with the
391 * contents of its fake front buffer.
392 */
393 static void
dri2FlushFrontBuffer(__DRIdrawable * driDrawable,void * loaderPrivate)394 dri2FlushFrontBuffer(__DRIdrawable *driDrawable, void *loaderPrivate)
395 {
396 struct glx_display *priv;
397 struct glx_context *gc;
398 struct dri2_drawable *pdraw = loaderPrivate;
399 struct dri2_screen *psc;
400
401 if (!pdraw)
402 return;
403
404 if (!pdraw->base.psc)
405 return;
406
407 psc = (struct dri2_screen *) pdraw->base.psc;
408
409 priv = __glXInitialize(psc->base.dpy);
410
411 if (priv == NULL)
412 return;
413
414 gc = __glXGetCurrentContext();
415
416 dri2Throttle(psc, pdraw, __DRI2_THROTTLE_FLUSHFRONT);
417
418 dri2_wait_gl(gc);
419 }
420
421
422 static void
dri2DeinitScreen(struct glx_screen * base)423 dri2DeinitScreen(struct glx_screen *base)
424 {
425 struct dri2_screen *psc = (struct dri2_screen *) base;
426
427 close(psc->fd);
428 }
429
430 /**
431 * Process list of buffer received from the server
432 *
433 * Processes the list of buffers received in a reply from the server to either
434 * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat.
435 */
436 static void
process_buffers(struct dri2_drawable * pdraw,DRI2Buffer * buffers,unsigned count)437 process_buffers(struct dri2_drawable * pdraw, DRI2Buffer * buffers,
438 unsigned count)
439 {
440 int i;
441
442 pdraw->bufferCount = count;
443 pdraw->have_fake_front = 0;
444 pdraw->have_back = 0;
445
446 /* This assumes the DRI2 buffer attachment tokens matches the
447 * __DRIbuffer tokens. */
448 for (i = 0; i < count; i++) {
449 pdraw->buffers[i].attachment = buffers[i].attachment;
450 pdraw->buffers[i].name = buffers[i].name;
451 pdraw->buffers[i].pitch = buffers[i].pitch;
452 pdraw->buffers[i].cpp = buffers[i].cpp;
453 pdraw->buffers[i].flags = buffers[i].flags;
454 if (pdraw->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT)
455 pdraw->have_fake_front = 1;
456 if (pdraw->buffers[i].attachment == __DRI_BUFFER_BACK_LEFT)
457 pdraw->have_back = 1;
458 }
459
460 }
461
dri2GetSwapEventType(Display * dpy,XID drawable)462 unsigned dri2GetSwapEventType(Display* dpy, XID drawable)
463 {
464 struct glx_display *glx_dpy = __glXInitialize(dpy);
465 __GLXDRIdrawable *pdraw;
466 pdraw = dri2GetGlxDrawableFromXDrawableId(dpy, drawable);
467 if (!pdraw || !(pdraw->eventMask & GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK))
468 return 0;
469 return glx_dpy->codes.first_event + GLX_BufferSwapComplete;
470 }
471
472 static int64_t
dri2XcbSwapBuffers(Display * dpy,__GLXDRIdrawable * pdraw,int64_t target_msc,int64_t divisor,int64_t remainder)473 dri2XcbSwapBuffers(Display *dpy,
474 __GLXDRIdrawable *pdraw,
475 int64_t target_msc,
476 int64_t divisor,
477 int64_t remainder)
478 {
479 xcb_dri2_swap_buffers_cookie_t swap_buffers_cookie;
480 xcb_dri2_swap_buffers_reply_t *swap_buffers_reply;
481 uint32_t target_msc_hi, target_msc_lo;
482 uint32_t divisor_hi, divisor_lo;
483 uint32_t remainder_hi, remainder_lo;
484 int64_t ret = 0;
485 xcb_connection_t *c = XGetXCBConnection(dpy);
486
487 split_counter(target_msc, &target_msc_hi, &target_msc_lo);
488 split_counter(divisor, &divisor_hi, &divisor_lo);
489 split_counter(remainder, &remainder_hi, &remainder_lo);
490
491 swap_buffers_cookie =
492 xcb_dri2_swap_buffers_unchecked(c, pdraw->xDrawable,
493 target_msc_hi, target_msc_lo,
494 divisor_hi, divisor_lo,
495 remainder_hi, remainder_lo);
496
497 /* Immediately wait on the swapbuffers reply. If we didn't, we'd have
498 * to do so some time before reusing a (non-pageflipped) backbuffer.
499 * Otherwise, the new rendering could get ahead of the X Server's
500 * dispatch of the swapbuffer and you'd display garbage.
501 *
502 * We use XSync() first to reap the invalidate events through the event
503 * filter, to ensure that the next drawing doesn't use an invalidated
504 * buffer.
505 */
506 XSync(dpy, False);
507
508 swap_buffers_reply =
509 xcb_dri2_swap_buffers_reply(c, swap_buffers_cookie, NULL);
510 if (swap_buffers_reply) {
511 ret = merge_counter(swap_buffers_reply->swap_hi,
512 swap_buffers_reply->swap_lo);
513 free(swap_buffers_reply);
514 }
515 return ret;
516 }
517
518 static int64_t
dri2SwapBuffers(__GLXDRIdrawable * pdraw,int64_t target_msc,int64_t divisor,int64_t remainder,Bool flush)519 dri2SwapBuffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
520 int64_t remainder, Bool flush)
521 {
522 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
523 struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
524 int64_t ret = 0;
525
526 /* Check we have the right attachments */
527 if (!priv->have_back)
528 return ret;
529
530 __DRIcontext *ctx = dri2GetCurrentContext();
531 unsigned flags = __DRI2_FLUSH_DRAWABLE;
532 if (flush)
533 flags |= __DRI2_FLUSH_CONTEXT;
534 dri2Flush(psc, ctx, priv, flags, __DRI2_THROTTLE_SWAPBUFFER);
535
536 ret = dri2XcbSwapBuffers(pdraw->psc->dpy, pdraw,
537 target_msc, divisor, remainder);
538
539 return ret;
540 }
541
542 static __DRIbuffer *
dri2GetBuffers(__DRIdrawable * driDrawable,int * width,int * height,unsigned int * attachments,int count,int * out_count,void * loaderPrivate)543 dri2GetBuffers(__DRIdrawable * driDrawable,
544 int *width, int *height,
545 unsigned int *attachments, int count,
546 int *out_count, void *loaderPrivate)
547 {
548 struct dri2_drawable *pdraw = loaderPrivate;
549 DRI2Buffer *buffers;
550
551 buffers = DRI2GetBuffers(pdraw->base.psc->dpy, pdraw->base.xDrawable,
552 width, height, attachments, count, out_count);
553 if (buffers == NULL)
554 return NULL;
555
556 pdraw->width = *width;
557 pdraw->height = *height;
558 process_buffers(pdraw, buffers, *out_count);
559
560 free(buffers);
561
562 return pdraw->buffers;
563 }
564
565 static __DRIbuffer *
dri2GetBuffersWithFormat(__DRIdrawable * driDrawable,int * width,int * height,unsigned int * attachments,int count,int * out_count,void * loaderPrivate)566 dri2GetBuffersWithFormat(__DRIdrawable * driDrawable,
567 int *width, int *height,
568 unsigned int *attachments, int count,
569 int *out_count, void *loaderPrivate)
570 {
571 struct dri2_drawable *pdraw = loaderPrivate;
572 DRI2Buffer *buffers;
573
574 buffers = DRI2GetBuffersWithFormat(pdraw->base.psc->dpy,
575 pdraw->base.xDrawable,
576 width, height, attachments,
577 count, out_count);
578 if (buffers == NULL)
579 return NULL;
580
581 pdraw->width = *width;
582 pdraw->height = *height;
583 process_buffers(pdraw, buffers, *out_count);
584
585 free(buffers);
586
587 return pdraw->buffers;
588 }
589
590 static int
dri2SetSwapInterval(__GLXDRIdrawable * pdraw,int interval)591 dri2SetSwapInterval(__GLXDRIdrawable *pdraw, int interval)
592 {
593 xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
594 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
595 struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
596
597 if (!dri_valid_swap_interval(psc->base.frontend_screen, interval))
598 return GLX_BAD_VALUE;
599
600 xcb_dri2_swap_interval(c, priv->base.xDrawable, interval);
601 priv->swap_interval = interval;
602
603 return 0;
604 }
605
606 static int
dri2GetSwapInterval(__GLXDRIdrawable * pdraw)607 dri2GetSwapInterval(__GLXDRIdrawable *pdraw)
608 {
609 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
610
611 return priv->swap_interval;
612 }
613
614 static const __DRIdri2LoaderExtension dri2LoaderExtension = {
615 .base = { __DRI_DRI2_LOADER, 3 },
616
617 .getBuffers = dri2GetBuffers,
618 .flushFrontBuffer = dri2FlushFrontBuffer,
619 .getBuffersWithFormat = dri2GetBuffersWithFormat,
620 };
621
622 _X_HIDDEN void
dri2InvalidateBuffers(Display * dpy,XID drawable)623 dri2InvalidateBuffers(Display *dpy, XID drawable)
624 {
625 __GLXDRIdrawable *pdraw =
626 dri2GetGlxDrawableFromXDrawableId(dpy, drawable);
627
628 if (!pdraw)
629 return;
630
631 dri_invalidate_drawable(pdraw->dri_drawable);
632 }
633
634 static const struct glx_context_vtable dri2_context_vtable = {
635 .destroy = dri_destroy_context,
636 .bind = dri_bind_context,
637 .unbind = dri_unbind_context,
638 .wait_gl = dri2_wait_gl,
639 .wait_x = dri2_wait_x,
640 };
641
642 static const __DRIextension *loader_extensions[] = {
643 &dri2LoaderExtension.base,
644 &dri2UseInvalidate.base,
645 &driBackgroundCallable.base,
646 NULL
647 };
648
649 struct glx_screen *
dri2CreateScreen(int screen,struct glx_display * priv,bool driver_name_is_inferred)650 dri2CreateScreen(int screen, struct glx_display * priv, bool driver_name_is_inferred)
651 {
652 struct dri2_screen *psc;
653 __GLXDRIscreen *psp;
654 char *driverName = NULL, *loader_driverName, *deviceName, *tmp;
655 drm_magic_t magic;
656
657 psc = calloc(1, sizeof *psc);
658 if (psc == NULL)
659 return NULL;
660
661 psc->fd = -1;
662
663
664 if (!DRI2Connect(priv->dpy, RootWindow(priv->dpy, screen),
665 &driverName, &deviceName)) {
666 glx_screen_cleanup(&psc->base);
667 free(psc);
668 InfoMessageF("screen %d does not appear to be DRI2 capable\n", screen);
669 return NULL;
670 }
671
672 psc->fd = loader_open_device(deviceName);
673 if (psc->fd < 0) {
674 ErrorMessageF("failed to open %s: %s\n", deviceName, strerror(errno));
675 goto handle_error;
676 }
677
678 if (drmGetMagic(psc->fd, &magic)) {
679 ErrorMessageF("failed to get magic\n");
680 goto handle_error;
681 }
682
683 if (!DRI2Authenticate(priv->dpy, RootWindow(priv->dpy, screen), magic)) {
684 ErrorMessageF("failed to authenticate magic %d\n", magic);
685 goto handle_error;
686 }
687
688 /* If Mesa knows about the appropriate driver for this fd, then trust it.
689 * Otherwise, default to the server's value.
690 */
691 loader_driverName = loader_get_driver_for_fd(psc->fd);
692 if (loader_driverName) {
693 free(driverName);
694 driverName = loader_driverName;
695 }
696 psc->base.driverName = driverName;
697 priv->driver = GLX_DRIVER_DRI2;
698
699 if (!dri_screen_init(&psc->base, priv, screen, psc->fd, loader_extensions, driver_name_is_inferred)) {
700 ErrorMessageF("glx: failed to create dri2 screen\n");
701 goto handle_error;
702 }
703
704 psc->base.context_vtable = &dri2_context_vtable;
705 psp = &psc->base.driScreen;
706 psp->deinitScreen = dri2DeinitScreen;
707 psp->createDrawable = dri2CreateDrawable;
708 psp->swapBuffers = dri2SwapBuffers;
709 psp->getDrawableMSC = NULL;
710 psp->waitForMSC = NULL;
711 psp->waitForSBC = NULL;
712 psp->setSwapInterval = NULL;
713 psp->getSwapInterval = NULL;
714
715 psp->getDrawableMSC = dri2DrawableGetMSC;
716 psp->waitForMSC = dri2WaitForMSC;
717 psp->waitForSBC = dri2WaitForSBC;
718 psp->setSwapInterval = dri2SetSwapInterval;
719 psp->getSwapInterval = dri2GetSwapInterval;
720 psp->maxSwapInterval = INT_MAX;
721
722 psc->base.can_EXT_texture_from_pixmap = true;
723
724 /* DRI2 supports SubBuffer through DRI2CopyRegion, so it's always
725 * available.*/
726 psp->copySubBuffer = dri2CopySubBuffer;
727
728 free(deviceName);
729
730 tmp = getenv("LIBGL_SHOW_FPS");
731 psc->show_fps_interval = (tmp) ? atoi(tmp) : 0;
732 if (psc->show_fps_interval < 0)
733 psc->show_fps_interval = 0;
734
735
736 InfoMessageF("Using DRI2 for screen %d\n", screen);
737
738 return &psc->base;
739
740 handle_error:
741 CriticalErrorMessageF("failed to load driver: %s\n", driverName);
742
743 if (psc->fd >= 0)
744 close(psc->fd);
745
746 free(deviceName);
747 glx_screen_cleanup(&psc->base);
748 free(psc);
749
750 return NULL;
751 }
752
753 _X_HIDDEN __GLXDRIdrawable *
dri2GetGlxDrawableFromXDrawableId(Display * dpy,XID id)754 dri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id)
755 {
756 struct glx_display *d = __glXInitialize(dpy);
757 __GLXDRIdrawable *pdraw;
758
759 if (__glxHashLookup(d->dri2Hash, id, (void *) &pdraw) == 0)
760 return pdraw;
761
762 return NULL;
763 }
764
765 bool
dri2CheckSupport(Display * dpy)766 dri2CheckSupport(Display *dpy)
767 {
768 int eventBase, errorBase;
769 int driMajor, driMinor;
770
771 if (!DRI2QueryExtension(dpy, &eventBase, &errorBase))
772 return false;
773 if (!DRI2QueryVersion(dpy, &driMajor, &driMinor) ||
774 driMinor < 3) {
775 return false;
776 }
777 return true;
778 }
779
780 #endif /* GLX_DIRECT_RENDERING */
781