glx: Add screen privates for dri drivers and moved some fields there
[mesa.git] / src / glx / dri2_glx.c
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 (krh@redhat.com)
31 */
32
33 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
34
35 #include <X11/Xlib.h>
36 #include <X11/extensions/Xfixes.h>
37 #include <X11/extensions/Xdamage.h>
38 #include "glapi.h"
39 #include "glxclient.h"
40 #include <X11/extensions/dri2proto.h>
41 #include "xf86dri.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 "xf86drm.h"
48 #include "dri2.h"
49 #include "dri_common.h"
50
51 /* From xmlpool/options.h, user exposed so should be stable */
52 #define DRI_CONF_VBLANK_NEVER 0
53 #define DRI_CONF_VBLANK_DEF_INTERVAL_0 1
54 #define DRI_CONF_VBLANK_DEF_INTERVAL_1 2
55 #define DRI_CONF_VBLANK_ALWAYS_SYNC 3
56
57 #undef DRI2_MINOR
58 #define DRI2_MINOR 1
59
60 struct dri2_display
61 {
62 __GLXDRIdisplay base;
63
64 /*
65 ** XFree86-DRI version information
66 */
67 int driMajor;
68 int driMinor;
69 int driPatch;
70 int swapAvailable;
71 int invalidateAvailable;
72
73 __glxHashTable *dri2Hash;
74
75 const __DRIextension *loader_extensions[4];
76 };
77
78 struct dri2_screen {
79 __GLXscreenConfigs base;
80
81 __GLXDRIscreen driScreen;
82 const __DRIdri2Extension *dri2;
83 const __DRIcoreExtension *core;
84 void *driver;
85 int fd;
86 };
87
88 struct dri2_context
89 {
90 __GLXDRIcontext base;
91 __DRIcontext *driContext;
92 __GLXscreenConfigs *psc;
93 };
94
95 struct dri2_drawable
96 {
97 __GLXDRIdrawable base;
98 __DRIbuffer buffers[5];
99 int bufferCount;
100 int width, height;
101 int have_back;
102 int have_fake_front;
103 int swap_interval;
104 };
105
106 static void
107 dri2DestroyContext(__GLXDRIcontext *context,
108 __GLXscreenConfigs *base, Display *dpy)
109 {
110 struct dri2_context *pcp = (struct dri2_context *) context;
111 struct dri2_screen *psc = (struct dri2_screen *) base;
112
113 (*psc->core->destroyContext) (pcp->driContext);
114
115 Xfree(pcp);
116 }
117
118 static Bool
119 dri2BindContext(__GLXDRIcontext *context,
120 __GLXDRIdrawable *draw, __GLXDRIdrawable *read)
121 {
122 struct dri2_context *pcp = (struct dri2_context *) context;
123 struct dri2_screen *psc = (struct dri2_screen *) pcp->psc;
124
125 return (*psc->core->bindContext) (pcp->driContext,
126 draw->driDrawable, read->driDrawable);
127 }
128
129 static void
130 dri2UnbindContext(__GLXDRIcontext *context)
131 {
132 struct dri2_context *pcp = (struct dri2_context *) context;
133 struct dri2_screen *psc = (struct dri2_screen *) pcp->psc;
134
135 (*psc->core->unbindContext) (pcp->driContext);
136 }
137
138 static __GLXDRIcontext *
139 dri2CreateContext(__GLXscreenConfigs *base,
140 const __GLcontextModes * mode,
141 GLXContext gc, GLXContext shareList, int renderType)
142 {
143 struct dri2_context *pcp, *pcp_shared;
144 struct dri2_screen *psc = (struct dri2_screen *) base;
145 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) mode;
146 __DRIcontext *shared = NULL;
147
148 if (shareList) {
149 pcp_shared = (struct dri2_context *) shareList->driContext;
150 shared = pcp_shared->driContext;
151 }
152
153 pcp = Xmalloc(sizeof *pcp);
154 if (pcp == NULL)
155 return NULL;
156
157 pcp->psc = &psc->base;
158 pcp->driContext =
159 (*psc->dri2->createNewContext) (psc->base.__driScreen,
160 config->driConfig, shared, pcp);
161 gc->__driContext = pcp->driContext;
162
163 if (pcp->driContext == NULL) {
164 Xfree(pcp);
165 return NULL;
166 }
167
168 pcp->base.destroyContext = dri2DestroyContext;
169 pcp->base.bindContext = dri2BindContext;
170 pcp->base.unbindContext = dri2UnbindContext;
171
172 return &pcp->base;
173 }
174
175 static void
176 dri2DestroyDrawable(__GLXDRIdrawable *pdraw)
177 {
178 struct dri2_screen *psc = (struct dri2_screen *) pdraw->psc;
179 __GLXdisplayPrivate *dpyPriv;
180 struct dri2_display *pdp;
181
182 dpyPriv = __glXInitialize(pdraw->psc->dpy);
183 pdp = (struct dri2_display *)dpyPriv->dri2Display;
184
185 __glxHashDelete(pdp->dri2Hash, pdraw->xDrawable);
186 (*psc->core->destroyDrawable) (pdraw->driDrawable);
187 DRI2DestroyDrawable(psc->base.dpy, pdraw->xDrawable);
188 Xfree(pdraw);
189 }
190
191 static __GLXDRIdrawable *
192 dri2CreateDrawable(__GLXscreenConfigs *base, XID xDrawable,
193 GLXDrawable drawable, const __GLcontextModes * modes)
194 {
195 struct dri2_drawable *pdraw;
196 struct dri2_screen *psc = (struct dri2_screen *) base;
197 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes;
198 __GLXdisplayPrivate *dpyPriv;
199 struct dri2_display *pdp;
200 GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
201
202 pdraw = Xmalloc(sizeof(*pdraw));
203 if (!pdraw)
204 return NULL;
205
206 pdraw->base.destroyDrawable = dri2DestroyDrawable;
207 pdraw->base.xDrawable = xDrawable;
208 pdraw->base.drawable = drawable;
209 pdraw->base.psc = &psc->base;
210 pdraw->bufferCount = 0;
211 pdraw->swap_interval = 1; /* default may be overridden below */
212 pdraw->have_back = 0;
213
214 if (psc->base.config)
215 psc->base.config->configQueryi(psc->base.__driScreen,
216 "vblank_mode", &vblank_mode);
217
218 switch (vblank_mode) {
219 case DRI_CONF_VBLANK_NEVER:
220 case DRI_CONF_VBLANK_DEF_INTERVAL_0:
221 pdraw->swap_interval = 0;
222 break;
223 case DRI_CONF_VBLANK_DEF_INTERVAL_1:
224 case DRI_CONF_VBLANK_ALWAYS_SYNC:
225 default:
226 pdraw->swap_interval = 1;
227 break;
228 }
229
230 DRI2CreateDrawable(psc->base.dpy, xDrawable);
231
232 dpyPriv = __glXInitialize(psc->base.dpy);
233 pdp = (struct dri2_display *)dpyPriv->dri2Display;;
234 /* Create a new drawable */
235 pdraw->base.driDrawable =
236 (*psc->dri2->createNewDrawable) (psc->base.__driScreen,
237 config->driConfig, pdraw);
238
239 if (!pdraw->base.driDrawable) {
240 DRI2DestroyDrawable(psc->base.dpy, xDrawable);
241 Xfree(pdraw);
242 return NULL;
243 }
244
245 if (__glxHashInsert(pdp->dri2Hash, xDrawable, pdraw)) {
246 (*psc->core->destroyDrawable) (pdraw->base.driDrawable);
247 DRI2DestroyDrawable(psc->base.dpy, xDrawable);
248 Xfree(pdraw);
249 return None;
250 }
251
252
253 #ifdef X_DRI2SwapInterval
254 /*
255 * Make sure server has the same swap interval we do for the new
256 * drawable.
257 */
258 if (pdp->swapAvailable)
259 DRI2SwapInterval(psc->base.dpy, xDrawable, pdraw->swap_interval);
260 #endif
261
262 return &pdraw->base;
263 }
264
265 #ifdef X_DRI2GetMSC
266
267 static int
268 dri2DrawableGetMSC(__GLXscreenConfigs *psc, __GLXDRIdrawable *pdraw,
269 int64_t *ust, int64_t *msc, int64_t *sbc)
270 {
271 return DRI2GetMSC(psc->dpy, pdraw->xDrawable, ust, msc, sbc);
272 }
273
274 #endif
275
276
277 #ifdef X_DRI2WaitMSC
278
279 static int
280 dri2WaitForMSC(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
281 int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc)
282 {
283 return DRI2WaitMSC(pdraw->psc->dpy, pdraw->xDrawable, target_msc, divisor,
284 remainder, ust, msc, sbc);
285 }
286
287 static int
288 dri2WaitForSBC(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust,
289 int64_t *msc, int64_t *sbc)
290 {
291 return DRI2WaitSBC(pdraw->psc->dpy, pdraw->xDrawable, target_sbc, ust, msc,
292 sbc);
293 }
294
295 #endif /* X_DRI2WaitMSC */
296
297 static void
298 dri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y, int width, int height)
299 {
300 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
301 XRectangle xrect;
302 XserverRegion region;
303
304 /* Check we have the right attachments */
305 if (!priv->have_back)
306 return;
307
308 xrect.x = x;
309 xrect.y = priv->height - y - height;
310 xrect.width = width;
311 xrect.height = height;
312
313 #ifdef __DRI2_FLUSH
314 if (pdraw->psc->f)
315 (*pdraw->psc->f->flush) (pdraw->driDrawable);
316 #endif
317
318 region = XFixesCreateRegion(pdraw->psc->dpy, &xrect, 1);
319 DRI2CopyRegion(pdraw->psc->dpy, pdraw->xDrawable, region,
320 DRI2BufferFrontLeft, DRI2BufferBackLeft);
321 XFixesDestroyRegion(pdraw->psc->dpy, region);
322
323 /* Refresh the fake front (if present) after we just damaged the real
324 * front.
325 */
326 DRI2CopyRegion(pdraw->psc->dpy, pdraw->xDrawable, region,
327 DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
328 XFixesDestroyRegion(pdraw->psc->dpy, region);
329 }
330
331 static void
332 dri2_copy_drawable(struct dri2_drawable *priv, int dest, int src)
333 {
334 XRectangle xrect;
335 XserverRegion region;
336 __GLXscreenConfigs *const psc = priv->base.psc;
337
338 xrect.x = 0;
339 xrect.y = 0;
340 xrect.width = priv->width;
341 xrect.height = priv->height;
342
343 #ifdef __DRI2_FLUSH
344 if (psc->f)
345 (*psc->f->flush) (priv->base.driDrawable);
346 #endif
347
348 region = XFixesCreateRegion(psc->dpy, &xrect, 1);
349 DRI2CopyRegion(psc->dpy, priv->base.xDrawable, region, dest, src);
350 XFixesDestroyRegion(psc->dpy, region);
351
352 }
353
354 static void
355 dri2WaitX(__GLXDRIdrawable *pdraw)
356 {
357 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
358
359 if (!priv->have_fake_front)
360 return;
361
362 dri2_copy_drawable(priv, DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
363 }
364
365 static void
366 dri2WaitGL(__GLXDRIdrawable * pdraw)
367 {
368 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
369
370 if (!priv->have_fake_front)
371 return;
372
373 dri2_copy_drawable(priv, DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
374 }
375
376 static void
377 dri2FlushFrontBuffer(__DRIdrawable *driDrawable, void *loaderPrivate)
378 {
379 struct dri2_drawable *pdraw = loaderPrivate;
380 __GLXdisplayPrivate *priv = __glXInitialize(pdraw->base.psc->dpy);
381 struct dri2_display *pdp = (struct dri2_display *)priv->dri2Display;
382
383 /* Old servers don't send invalidate events */
384 if (!pdp->invalidateAvailable)
385 dri2InvalidateBuffers(priv->dpy, pdraw->base.drawable);
386
387 dri2WaitGL(loaderPrivate);
388 }
389
390
391 static void
392 dri2DestroyScreen(__GLXscreenConfigs *base)
393 {
394 struct dri2_screen *psc = (struct dri2_screen *) base;
395
396 /* Free the direct rendering per screen data */
397 (*psc->core->destroyScreen) (psc->base.__driScreen);
398 close(psc->fd);
399 base->__driScreen = NULL;
400 Xfree(psc);
401 }
402
403 /**
404 * Process list of buffer received from the server
405 *
406 * Processes the list of buffers received in a reply from the server to either
407 * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat.
408 */
409 static void
410 process_buffers(struct dri2_drawable * pdraw, DRI2Buffer * buffers,
411 unsigned count)
412 {
413 int i;
414
415 pdraw->bufferCount = count;
416 pdraw->have_fake_front = 0;
417 pdraw->have_back = 0;
418
419 /* This assumes the DRI2 buffer attachment tokens matches the
420 * __DRIbuffer tokens. */
421 for (i = 0; i < count; i++) {
422 pdraw->buffers[i].attachment = buffers[i].attachment;
423 pdraw->buffers[i].name = buffers[i].name;
424 pdraw->buffers[i].pitch = buffers[i].pitch;
425 pdraw->buffers[i].cpp = buffers[i].cpp;
426 pdraw->buffers[i].flags = buffers[i].flags;
427 if (pdraw->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT)
428 pdraw->have_fake_front = 1;
429 if (pdraw->buffers[i].attachment == __DRI_BUFFER_BACK_LEFT)
430 pdraw->have_back = 1;
431 }
432
433 }
434
435 static int64_t
436 dri2SwapBuffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
437 int64_t remainder)
438 {
439 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
440 __GLXdisplayPrivate *dpyPriv = __glXInitialize(priv->base.psc->dpy);
441 struct dri2_display *pdp =
442 (struct dri2_display *)dpyPriv->dri2Display;
443 int64_t ret;
444
445 #ifdef __DRI2_FLUSH
446 if (pdraw->psc->f)
447 (*pdraw->psc->f->flush)(pdraw->driDrawable);
448 #endif
449
450 /* Old servers don't send invalidate events */
451 if (!pdp->invalidateAvailable)
452 dri2InvalidateBuffers(dpyPriv->dpy, pdraw->drawable);
453
454 /* Old servers can't handle swapbuffers */
455 if (!pdp->swapAvailable) {
456 dri2CopySubBuffer(pdraw, 0, 0, priv->width, priv->height);
457 return 0;
458 }
459
460 #ifdef X_DRI2SwapBuffers
461 DRI2SwapBuffers(pdraw->psc->dpy, pdraw->xDrawable, target_msc, divisor,
462 remainder, &ret);
463 #endif
464
465 return ret;
466 }
467
468 static __DRIbuffer *
469 dri2GetBuffers(__DRIdrawable * driDrawable,
470 int *width, int *height,
471 unsigned int *attachments, int count,
472 int *out_count, void *loaderPrivate)
473 {
474 struct dri2_drawable *pdraw = loaderPrivate;
475 DRI2Buffer *buffers;
476
477 buffers = DRI2GetBuffers(pdraw->base.psc->dpy, pdraw->base.xDrawable,
478 width, height, attachments, count, out_count);
479 if (buffers == NULL)
480 return NULL;
481
482 pdraw->width = *width;
483 pdraw->height = *height;
484 process_buffers(pdraw, buffers, *out_count);
485
486 Xfree(buffers);
487
488 return pdraw->buffers;
489 }
490
491 static __DRIbuffer *
492 dri2GetBuffersWithFormat(__DRIdrawable * driDrawable,
493 int *width, int *height,
494 unsigned int *attachments, int count,
495 int *out_count, void *loaderPrivate)
496 {
497 struct dri2_drawable *pdraw = loaderPrivate;
498 DRI2Buffer *buffers;
499
500 buffers = DRI2GetBuffersWithFormat(pdraw->base.psc->dpy,
501 pdraw->base.xDrawable,
502 width, height, attachments,
503 count, out_count);
504 if (buffers == NULL)
505 return NULL;
506
507 pdraw->width = *width;
508 pdraw->height = *height;
509 process_buffers(pdraw, buffers, *out_count);
510
511 Xfree(buffers);
512
513 return pdraw->buffers;
514 }
515
516 #ifdef X_DRI2SwapInterval
517
518 static void
519 dri2SetSwapInterval(__GLXDRIdrawable *pdraw, int interval)
520 {
521 __GLXscreenConfigs *psc = pdraw->psc;
522 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
523 GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
524
525 if (psc->config)
526 psc->config->configQueryi(psc->__driScreen, "vblank_mode", &vblank_mode);
527
528 switch (vblank_mode) {
529 case DRI_CONF_VBLANK_NEVER:
530 return;
531 case DRI_CONF_VBLANK_ALWAYS_SYNC:
532 if (interval <= 0)
533 return;
534 break;
535 default:
536 break;
537 }
538
539 DRI2SwapInterval(priv->base.psc->dpy, pdraw->xDrawable, interval);
540 priv->swap_interval = interval;
541 }
542
543 static unsigned int
544 dri2GetSwapInterval(__GLXDRIdrawable *pdraw)
545 {
546 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
547
548 return priv->swap_interval;
549 }
550
551 #endif /* X_DRI2SwapInterval */
552
553 static const __DRIdri2LoaderExtension dri2LoaderExtension = {
554 {__DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION},
555 dri2GetBuffers,
556 dri2FlushFrontBuffer,
557 dri2GetBuffersWithFormat,
558 };
559
560 static const __DRIdri2LoaderExtension dri2LoaderExtension_old = {
561 {__DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION},
562 dri2GetBuffers,
563 dri2FlushFrontBuffer,
564 NULL,
565 };
566
567 #ifdef __DRI_USE_INVALIDATE
568 static const __DRIuseInvalidateExtension dri2UseInvalidate = {
569 { __DRI_USE_INVALIDATE, __DRI_USE_INVALIDATE_VERSION }
570 };
571 #endif
572
573 _X_HIDDEN void
574 dri2InvalidateBuffers(Display *dpy, XID drawable)
575 {
576 __GLXDRIdrawable *pdraw =
577 dri2GetGlxDrawableFromXDrawableId(dpy, drawable);
578
579 #if __DRI2_FLUSH_VERSION >= 3
580 if (pdraw && pdraw->psc->f)
581 pdraw->psc->f->invalidate(pdraw->driDrawable);
582 #endif
583 }
584
585 static void
586 dri2_bind_tex_image(Display * dpy,
587 GLXDrawable drawable,
588 int buffer, const int *attrib_list)
589 {
590 GLXContext gc = __glXGetCurrentContext();
591 __GLXDRIdrawable *pdraw = GetGLXDRIDrawable(dpy, drawable, NULL);
592 __GLXdisplayPrivate *dpyPriv = __glXInitialize(dpy);
593 struct dri2_display *pdp =
594 (struct dri2_display *) dpyPriv->dri2Display;
595
596 if (pdraw != NULL) {
597
598 #if __DRI2_FLUSH_VERSION >= 3
599 if (!pdp->invalidateAvailable && pdraw->psc->f)
600 pdraw->psc->f->invalidate(pdraw->driDrawable);
601 #endif
602
603 if (pdraw->psc->texBuffer->base.version >= 2 &&
604 pdraw->psc->texBuffer->setTexBuffer2 != NULL) {
605 (*pdraw->psc->texBuffer->setTexBuffer2) (gc->__driContext,
606 pdraw->textureTarget,
607 pdraw->textureFormat,
608 pdraw->driDrawable);
609 }
610 else {
611 (*pdraw->psc->texBuffer->setTexBuffer) (gc->__driContext,
612 pdraw->textureTarget,
613 pdraw->driDrawable);
614 }
615 }
616 }
617
618 static void
619 dri2_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer)
620 {
621 }
622
623 static const struct glx_context_vtable dri2_context_vtable = {
624 dri2_bind_tex_image,
625 dri2_release_tex_image,
626 };
627
628 static __GLXscreenConfigs *
629 dri2CreateScreen(int screen, __GLXdisplayPrivate * priv)
630 {
631 const __DRIconfig **driver_configs;
632 const __DRIextension **extensions;
633 const struct dri2_display *const pdp = (struct dri2_display *)
634 priv->dri2Display;
635 struct dri2_screen *psc;
636 __GLXDRIscreen *psp;
637 char *driverName, *deviceName;
638 drm_magic_t magic;
639 int i;
640
641 psc = Xmalloc(sizeof *psc);
642 if (psc == NULL)
643 return NULL;
644
645 memset(psc, 0, sizeof *psc);
646 if (!glx_screen_init(&psc->base, screen, priv))
647 return NULL;
648
649 if (!DRI2Connect(priv->dpy, RootWindow(priv->dpy, screen),
650 &driverName, &deviceName)) {
651 XFree(psc);
652 return NULL;
653 }
654
655 psc->driver = driOpenDriver(driverName);
656 if (psc->driver == NULL) {
657 ErrorMessageF("driver pointer missing\n");
658 goto handle_error;
659 }
660
661 extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
662 if (extensions == NULL) {
663 ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
664 goto handle_error;
665 }
666
667 for (i = 0; extensions[i]; i++) {
668 if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
669 psc->core = (__DRIcoreExtension *) extensions[i];
670 if (strcmp(extensions[i]->name, __DRI_DRI2) == 0)
671 psc->dri2 = (__DRIdri2Extension *) extensions[i];
672 }
673
674 if (psc->core == NULL || psc->dri2 == NULL) {
675 ErrorMessageF("core dri or dri2 extension not found\n");
676 goto handle_error;
677 }
678
679 psc->fd = open(deviceName, O_RDWR);
680 if (psc->fd < 0) {
681 ErrorMessageF("failed to open drm device: %s\n", strerror(errno));
682 goto handle_error;
683 }
684
685 if (drmGetMagic(psc->fd, &magic)) {
686 ErrorMessageF("failed to get magic\n");
687 goto handle_error;
688 }
689
690 if (!DRI2Authenticate(priv->dpy, RootWindow(priv->dpy, screen), magic)) {
691 ErrorMessageF("failed to authenticate magic %d\n", magic);
692 goto handle_error;
693 }
694
695
696 /* If the server does not support the protocol for
697 * DRI2GetBuffersWithFormat, don't supply that interface to the driver.
698 */
699 psc->base.__driScreen =
700 psc->dri2->createNewScreen(screen, psc->fd,
701 (const __DRIextension **)
702 &pdp->loader_extensions[0],
703 &driver_configs, psc);
704
705 if (psc->base.__driScreen == NULL) {
706 ErrorMessageF("failed to create dri screen\n");
707 goto handle_error;
708 }
709
710 extensions = psc->core->getExtensions(psc->base.__driScreen);
711 driBindCommonExtensions(&psc->base, extensions);
712 dri2BindExtensions(&psc->base, extensions);
713
714 psc->base.configs =
715 driConvertConfigs(psc->core, psc->base.configs, driver_configs);
716 psc->base.visuals =
717 driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
718
719 psc->base.driver_configs = driver_configs;
720
721 psp = &psc->driScreen;
722 psc->base.driScreen = psp;
723 psp->destroyScreen = dri2DestroyScreen;
724 psp->createContext = dri2CreateContext;
725 psp->createDrawable = dri2CreateDrawable;
726 psp->swapBuffers = dri2SwapBuffers;
727 psp->waitGL = dri2WaitGL;
728 psp->waitX = dri2WaitX;
729 psp->getDrawableMSC = NULL;
730 psp->waitForMSC = NULL;
731 psp->waitForSBC = NULL;
732 psp->setSwapInterval = NULL;
733 psp->getSwapInterval = NULL;
734
735 if (pdp->driMinor >= 2) {
736 #ifdef X_DRI2GetMSC
737 psp->getDrawableMSC = dri2DrawableGetMSC;
738 #endif
739 #ifdef X_DRI2WaitMSC
740 psp->waitForMSC = dri2WaitForMSC;
741 psp->waitForSBC = dri2WaitForSBC;
742 #endif
743 #ifdef X_DRI2SwapInterval
744 psp->setSwapInterval = dri2SetSwapInterval;
745 psp->getSwapInterval = dri2GetSwapInterval;
746 #endif
747 #if defined(X_DRI2GetMSC) && defined(X_DRI2WaitMSC) && defined(X_DRI2SwapInterval)
748 __glXEnableDirectExtension(&psc->base, "GLX_OML_sync_control");
749 #endif
750 }
751
752 /* DRI2 suports SubBuffer through DRI2CopyRegion, so it's always
753 * available.*/
754 psp->copySubBuffer = dri2CopySubBuffer;
755 __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
756
757 psc->base.direct_context_vtable = &dri2_context_vtable;
758
759 Xfree(driverName);
760 Xfree(deviceName);
761
762 return &psc->base;
763
764 handle_error:
765 Xfree(driverName);
766 Xfree(deviceName);
767 XFree(psc);
768
769 /* FIXME: clean up here */
770
771 return NULL;
772 }
773
774 /* Called from __glXFreeDisplayPrivate.
775 */
776 static void
777 dri2DestroyDisplay(__GLXDRIdisplay * dpy)
778 {
779 Xfree(dpy);
780 }
781
782 _X_HIDDEN __GLXDRIdrawable *
783 dri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id)
784 {
785 __GLXdisplayPrivate *d = __glXInitialize(dpy);
786 struct dri2_display *pdp = (struct dri2_display *) d->dri2Display;
787 __GLXDRIdrawable *pdraw;
788
789 if (__glxHashLookup(pdp->dri2Hash, id, (void *) &pdraw) == 0)
790 return pdraw;
791
792 return NULL;
793 }
794
795 /*
796 * Allocate, initialize and return a __DRIdisplayPrivate object.
797 * This is called from __glXInitialize() when we are given a new
798 * display pointer.
799 */
800 _X_HIDDEN __GLXDRIdisplay *
801 dri2CreateDisplay(Display * dpy)
802 {
803 struct dri2_display *pdp;
804 int eventBase, errorBase, i;
805
806 if (!DRI2QueryExtension(dpy, &eventBase, &errorBase))
807 return NULL;
808
809 pdp = Xmalloc(sizeof *pdp);
810 if (pdp == NULL)
811 return NULL;
812
813 if (!DRI2QueryVersion(dpy, &pdp->driMajor, &pdp->driMinor)) {
814 Xfree(pdp);
815 return NULL;
816 }
817
818 pdp->driPatch = 0;
819 pdp->swapAvailable = (pdp->driMinor >= 2);
820 pdp->invalidateAvailable = (pdp->driMinor >= 3);
821
822 pdp->base.destroyDisplay = dri2DestroyDisplay;
823 pdp->base.createScreen = dri2CreateScreen;
824
825 i = 0;
826 if (pdp->driMinor < 1)
827 pdp->loader_extensions[i++] = &dri2LoaderExtension_old.base;
828 else
829 pdp->loader_extensions[i++] = &dri2LoaderExtension.base;
830
831 pdp->loader_extensions[i++] = &systemTimeExtension.base;
832
833 #ifdef __DRI_USE_INVALIDATE
834 pdp->loader_extensions[i++] = &dri2UseInvalidate.base;
835 #endif
836 pdp->loader_extensions[i++] = NULL;
837
838 pdp->dri2Hash = __glxHashCreate();
839 if (pdp->dri2Hash == NULL) {
840 Xfree(pdp);
841 return NULL;
842 }
843
844 return &pdp->base;
845 }
846
847 #endif /* GLX_DIRECT_RENDERING */