1 /*
2 * Copyright © 2007 Red Hat, Inc
3 *
4 * Permission to use, copy, modify, distribute, and sell this software
5 * and its documentation for any purpose is hereby granted without
6 * fee, provided that the above copyright notice appear in all copies
7 * and that both that copyright notice and this permission notice
8 * appear in supporting documentation, and that the name of Red Hat,
9 * Inc not be used in advertising or publicity pertaining to
10 * distribution of the software without specific, written prior
11 * permission. Red Hat, Inc makes no representations about the
12 * suitability of this software for any purpose. It is provided "as
13 * is" without express or implied warranty.
14 *
15 * RED HAT, INC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
17 * NO EVENT SHALL RED HAT, INC BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
19 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
20 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 */
23
24 #ifdef HAVE_DIX_CONFIG_H
25 #include <dix-config.h>
26 #endif
27
28 #include <stdint.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <dlfcn.h>
33
34 #include <GL/gl.h>
35 #include <GL/internal/dri_interface.h>
36 #include <GL/glxtokens.h>
37
38 #include <windowstr.h>
39 #include <os.h>
40
41 #define _XF86DRI_SERVER_
42 #include <xf86.h>
43 #include <dri2.h>
44
45 #include <GL/glxtokens.h>
46 #include "glxserver.h"
47 #include "glxutil.h"
48 #include "glxdricommon.h"
49
50 #include "extension_string.h"
51
52 typedef struct __GLXDRIscreen __GLXDRIscreen;
53 typedef struct __GLXDRIcontext __GLXDRIcontext;
54 typedef struct __GLXDRIdrawable __GLXDRIdrawable;
55
56 #define ALL_DRI_CTX_FLAGS (__DRI_CTX_FLAG_DEBUG \
57 | __DRI_CTX_FLAG_FORWARD_COMPATIBLE \
58 | __DRI_CTX_FLAG_ROBUST_BUFFER_ACCESS)
59
60 struct __GLXDRIscreen {
61 __GLXscreen base;
62 __DRIscreen *driScreen;
63 void *driver;
64 int fd;
65
66 xf86EnterVTProc *enterVT;
67 xf86LeaveVTProc *leaveVT;
68
69 const __DRIcoreExtension *core;
70 const __DRIdri2Extension *dri2;
71 const __DRI2flushExtension *flush;
72 const __DRIcopySubBufferExtension *copySubBuffer;
73 const __DRIswapControlExtension *swapControl;
74 const __DRItexBufferExtension *texBuffer;
75 const __DRIconfig **driConfigs;
76 };
77
78 struct __GLXDRIcontext {
79 __GLXcontext base;
80 __DRIcontext *driContext;
81 };
82
83 #define MAX_DRAWABLE_BUFFERS 5
84
85 struct __GLXDRIdrawable {
86 __GLXdrawable base;
87 __DRIdrawable *driDrawable;
88 __GLXDRIscreen *screen;
89
90 /* Dimensions as last reported by DRI2GetBuffers. */
91 int width;
92 int height;
93 __DRIbuffer buffers[MAX_DRAWABLE_BUFFERS];
94 int count;
95 XID dri2_id;
96 };
97
98 static void
copy_box(__GLXdrawable * drawable,int dst,int src,int x,int y,int w,int h)99 copy_box(__GLXdrawable * drawable,
100 int dst, int src,
101 int x, int y, int w, int h)
102 {
103 BoxRec box;
104 RegionRec region;
105 __GLXcontext *cx = lastGLContext;
106
107 box.x1 = x;
108 box.y1 = y;
109 box.x2 = x + w;
110 box.y2 = y + h;
111 RegionInit(®ion, &box, 0);
112
113 DRI2CopyRegion(drawable->pDraw, ®ion, dst, src);
114 if (cx != lastGLContext) {
115 lastGLContext = cx;
116 cx->makeCurrent(cx);
117 }
118 }
119
120 /* white lie */
121 extern glx_func_ptr glXGetProcAddressARB(const char *);
122
123 static void
__glXDRIdrawableDestroy(__GLXdrawable * drawable)124 __glXDRIdrawableDestroy(__GLXdrawable * drawable)
125 {
126 __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable;
127 const __DRIcoreExtension *core = private->screen->core;
128
129 FreeResource(private->dri2_id, FALSE);
130
131 (*core->destroyDrawable) (private->driDrawable);
132
133 __glXDrawableRelease(drawable);
134
135 free(private);
136 }
137
138 static void
__glXDRIdrawableCopySubBuffer(__GLXdrawable * drawable,int x,int y,int w,int h)139 __glXDRIdrawableCopySubBuffer(__GLXdrawable * drawable,
140 int x, int y, int w, int h)
141 {
142 __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable;
143
144 copy_box(drawable, x, private->height - y - h,
145 w, h,
146 DRI2BufferFrontLeft, DRI2BufferBackLeft);
147 }
148
149 static void
__glXDRIdrawableWaitX(__GLXdrawable * drawable)150 __glXDRIdrawableWaitX(__GLXdrawable * drawable)
151 {
152 __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable;
153
154 copy_box(drawable, DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft,
155 0, 0, private->width, private->height);
156 }
157
158 static void
__glXDRIdrawableWaitGL(__GLXdrawable * drawable)159 __glXDRIdrawableWaitGL(__GLXdrawable * drawable)
160 {
161 __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable;
162
163 copy_box(drawable, DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft,
164 0, 0, private->width, private->height);
165 }
166
167 static void
__glXdriSwapEvent(ClientPtr client,void * data,int type,CARD64 ust,CARD64 msc,CARD32 sbc)168 __glXdriSwapEvent(ClientPtr client, void *data, int type, CARD64 ust,
169 CARD64 msc, CARD32 sbc)
170 {
171 __GLXdrawable *drawable = data;
172 int glx_type;
173 switch (type) {
174 case DRI2_EXCHANGE_COMPLETE:
175 glx_type = GLX_EXCHANGE_COMPLETE_INTEL;
176 break;
177 default:
178 /* unknown swap completion type,
179 * BLIT is a reasonable default, so
180 * fall through ...
181 */
182 case DRI2_BLIT_COMPLETE:
183 glx_type = GLX_BLIT_COMPLETE_INTEL;
184 break;
185 case DRI2_FLIP_COMPLETE:
186 glx_type = GLX_FLIP_COMPLETE_INTEL;
187 break;
188 }
189
190 __glXsendSwapEvent(drawable, glx_type, ust, msc, sbc);
191 }
192
193 /*
194 * Copy or flip back to front, honoring the swap interval if possible.
195 *
196 * If the kernel supports it, we request an event for the frame when the
197 * swap should happen, then perform the copy when we receive it.
198 */
199 static GLboolean
__glXDRIdrawableSwapBuffers(ClientPtr client,__GLXdrawable * drawable)200 __glXDRIdrawableSwapBuffers(ClientPtr client, __GLXdrawable * drawable)
201 {
202 __GLXDRIdrawable *priv = (__GLXDRIdrawable *) drawable;
203 __GLXDRIscreen *screen = priv->screen;
204 CARD64 unused;
205 __GLXcontext *cx = lastGLContext;
206 int status;
207
208 if (screen->flush) {
209 (*screen->flush->flush) (priv->driDrawable);
210 (*screen->flush->invalidate) (priv->driDrawable);
211 }
212
213 status = DRI2SwapBuffers(client, drawable->pDraw, 0, 0, 0, &unused,
214 __glXdriSwapEvent, drawable);
215 if (cx != lastGLContext) {
216 lastGLContext = cx;
217 cx->makeCurrent(cx);
218 }
219
220 return status == Success;
221 }
222
223 static int
__glXDRIdrawableSwapInterval(__GLXdrawable * drawable,int interval)224 __glXDRIdrawableSwapInterval(__GLXdrawable * drawable, int interval)
225 {
226 __GLXcontext *cx = lastGLContext;
227
228 if (interval <= 0) /* || interval > BIGNUM? */
229 return GLX_BAD_VALUE;
230
231 DRI2SwapInterval(drawable->pDraw, interval);
232 if (cx != lastGLContext) {
233 lastGLContext = cx;
234 cx->makeCurrent(cx);
235 }
236
237 return 0;
238 }
239
240 static void
__glXDRIcontextDestroy(__GLXcontext * baseContext)241 __glXDRIcontextDestroy(__GLXcontext * baseContext)
242 {
243 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
244 __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
245
246 (*screen->core->destroyContext) (context->driContext);
247 __glXContextDestroy(&context->base);
248 free(context);
249 }
250
251 static int
__glXDRIcontextMakeCurrent(__GLXcontext * baseContext)252 __glXDRIcontextMakeCurrent(__GLXcontext * baseContext)
253 {
254 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
255 __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseContext->drawPriv;
256 __GLXDRIdrawable *read = (__GLXDRIdrawable *) baseContext->readPriv;
257 __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
258
259 return (*screen->core->bindContext) (context->driContext,
260 draw->driDrawable, read->driDrawable);
261 }
262
263 static int
__glXDRIcontextLoseCurrent(__GLXcontext * baseContext)264 __glXDRIcontextLoseCurrent(__GLXcontext * baseContext)
265 {
266 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
267 __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
268
269 return (*screen->core->unbindContext) (context->driContext);
270 }
271
272 static int
__glXDRIcontextCopy(__GLXcontext * baseDst,__GLXcontext * baseSrc,unsigned long mask)273 __glXDRIcontextCopy(__GLXcontext * baseDst, __GLXcontext * baseSrc,
274 unsigned long mask)
275 {
276 __GLXDRIcontext *dst = (__GLXDRIcontext *) baseDst;
277 __GLXDRIcontext *src = (__GLXDRIcontext *) baseSrc;
278 __GLXDRIscreen *screen = (__GLXDRIscreen *) dst->base.pGlxScreen;
279
280 return (*screen->core->copyContext) (dst->driContext,
281 src->driContext, mask);
282 }
283
284 static Bool
__glXDRIcontextWait(__GLXcontext * baseContext,__GLXclientState * cl,int * error)285 __glXDRIcontextWait(__GLXcontext * baseContext,
286 __GLXclientState * cl, int *error)
287 {
288 __GLXcontext *cx = lastGLContext;
289 Bool ret;
290
291 ret = DRI2WaitSwap(cl->client, baseContext->drawPriv->pDraw);
292 if (cx != lastGLContext) {
293 lastGLContext = cx;
294 cx->makeCurrent(cx);
295 }
296
297 if (ret) {
298 *error = cl->client->noClientException;
299 return TRUE;
300 }
301
302 return FALSE;
303 }
304
305 static int
__glXDRIbindTexImage(__GLXcontext * baseContext,int buffer,__GLXdrawable * glxPixmap)306 __glXDRIbindTexImage(__GLXcontext * baseContext,
307 int buffer, __GLXdrawable * glxPixmap)
308 {
309 __GLXDRIdrawable *drawable = (__GLXDRIdrawable *) glxPixmap;
310 const __DRItexBufferExtension *texBuffer = drawable->screen->texBuffer;
311 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
312
313 if (texBuffer == NULL)
314 return Success;
315
316 if (texBuffer->base.version >= 2 && texBuffer->setTexBuffer2 != NULL) {
317 (*texBuffer->setTexBuffer2) (context->driContext,
318 glxPixmap->target,
319 glxPixmap->format, drawable->driDrawable);
320 }
321 else
322 {
323 texBuffer->setTexBuffer(context->driContext,
324 glxPixmap->target, drawable->driDrawable);
325 }
326
327 return Success;
328 }
329
330 static int
__glXDRIreleaseTexImage(__GLXcontext * baseContext,int buffer,__GLXdrawable * pixmap)331 __glXDRIreleaseTexImage(__GLXcontext * baseContext,
332 int buffer, __GLXdrawable * pixmap)
333 {
334 /* FIXME: Just unbind the texture? */
335 return Success;
336 }
337
338 static Bool
dri2_convert_glx_attribs(__GLXDRIscreen * screen,unsigned num_attribs,const uint32_t * attribs,unsigned * major_ver,unsigned * minor_ver,uint32_t * flags,int * api,int * reset,unsigned * error)339 dri2_convert_glx_attribs(__GLXDRIscreen *screen, unsigned num_attribs,
340 const uint32_t *attribs,
341 unsigned *major_ver, unsigned *minor_ver,
342 uint32_t *flags, int *api, int *reset, unsigned *error)
343 {
344 unsigned i;
345
346 if (num_attribs == 0)
347 return TRUE;
348
349 if (attribs == NULL) {
350 *error = BadImplementation;
351 return FALSE;
352 }
353
354 *major_ver = 1;
355 *minor_ver = 0;
356 *reset = __DRI_CTX_RESET_NO_NOTIFICATION;
357
358 for (i = 0; i < num_attribs; i++) {
359 switch (attribs[i * 2]) {
360 case GLX_CONTEXT_MAJOR_VERSION_ARB:
361 *major_ver = attribs[i * 2 + 1];
362 break;
363 case GLX_CONTEXT_MINOR_VERSION_ARB:
364 *minor_ver = attribs[i * 2 + 1];
365 break;
366 case GLX_CONTEXT_FLAGS_ARB:
367 *flags = attribs[i * 2 + 1];
368 break;
369 case GLX_RENDER_TYPE:
370 break;
371 case GLX_CONTEXT_PROFILE_MASK_ARB:
372 switch (attribs[i * 2 + 1]) {
373 case GLX_CONTEXT_CORE_PROFILE_BIT_ARB:
374 *api = __DRI_API_OPENGL_CORE;
375 break;
376 case GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB:
377 *api = __DRI_API_OPENGL;
378 break;
379 case GLX_CONTEXT_ES2_PROFILE_BIT_EXT:
380 *api = __DRI_API_GLES2;
381 break;
382 default:
383 *error = __glXError(GLXBadProfileARB);
384 return FALSE;
385 }
386 break;
387 case GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB:
388 if (screen->dri2->base.version >= 4) {
389 *error = BadValue;
390 return FALSE;
391 }
392
393 switch (attribs[i * 2 + 1]) {
394 case GLX_NO_RESET_NOTIFICATION_ARB:
395 *reset = __DRI_CTX_RESET_NO_NOTIFICATION;
396 break;
397 case GLX_LOSE_CONTEXT_ON_RESET_ARB:
398 *reset = __DRI_CTX_RESET_LOSE_CONTEXT;
399 break;
400 default:
401 *error = BadValue;
402 return FALSE;
403 }
404 break;
405 case GLX_SCREEN:
406 /* already checked for us */
407 break;
408 case GLX_CONTEXT_OPENGL_NO_ERROR_ARB:
409 /* ignore */
410 break;
411 default:
412 /* If an unknown attribute is received, fail.
413 */
414 *error = BadValue;
415 return FALSE;
416 }
417 }
418
419 /* Unknown flag value.
420 */
421 if ((*flags & ~ALL_DRI_CTX_FLAGS) != 0) {
422 *error = BadValue;
423 return FALSE;
424 }
425
426 /* If the core profile is requested for a GL version is less than 3.2,
427 * request the non-core profile from the DRI driver. The core profile
428 * only makes sense for GL versions >= 3.2, and many DRI drivers that
429 * don't support OpenGL 3.2 may fail the request for a core profile.
430 */
431 if (*api == __DRI_API_OPENGL_CORE
432 && (*major_ver < 3 || (*major_ver == 3 && *minor_ver < 2))) {
433 *api = __DRI_API_OPENGL;
434 }
435
436 *error = Success;
437 return TRUE;
438 }
439
440 static void
create_driver_context(__GLXDRIcontext * context,__GLXDRIscreen * screen,__GLXDRIconfig * config,__DRIcontext * driShare,unsigned num_attribs,const uint32_t * attribs,int * error)441 create_driver_context(__GLXDRIcontext * context,
442 __GLXDRIscreen * screen,
443 __GLXDRIconfig * config,
444 __DRIcontext * driShare,
445 unsigned num_attribs,
446 const uint32_t *attribs,
447 int *error)
448 {
449 const __DRIconfig *driConfig = config ? config->driConfig : NULL;
450 context->driContext = NULL;
451
452 if (screen->dri2->base.version >= 3) {
453 uint32_t ctx_attribs[4 * 2];
454 unsigned num_ctx_attribs = 0;
455 unsigned dri_err = 0;
456 unsigned major_ver;
457 unsigned minor_ver;
458 uint32_t flags = 0;
459 int reset;
460 int api = __DRI_API_OPENGL;
461
462 if (num_attribs != 0) {
463 if (!dri2_convert_glx_attribs(screen, num_attribs, attribs,
464 &major_ver, &minor_ver,
465 &flags, &api, &reset,
466 (unsigned *) error))
467 return;
468
469 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MAJOR_VERSION;
470 ctx_attribs[num_ctx_attribs++] = major_ver;
471 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MINOR_VERSION;
472 ctx_attribs[num_ctx_attribs++] = minor_ver;
473
474 if (flags != 0) {
475 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_FLAGS;
476
477 /* The current __DRI_CTX_FLAG_* values are identical to the
478 * GLX_CONTEXT_*_BIT values.
479 */
480 ctx_attribs[num_ctx_attribs++] = flags;
481 }
482
483 if (reset != __DRI_CTX_RESET_NO_NOTIFICATION) {
484 ctx_attribs[num_ctx_attribs++] =
485 __DRI_CTX_ATTRIB_RESET_STRATEGY;
486 ctx_attribs[num_ctx_attribs++] = reset;
487 }
488
489 assert(num_ctx_attribs <= ARRAY_SIZE(ctx_attribs));
490 }
491
492 context->driContext =
493 (*screen->dri2->createContextAttribs)(screen->driScreen, api,
494 driConfig, driShare,
495 num_ctx_attribs / 2,
496 ctx_attribs,
497 &dri_err,
498 context);
499
500 switch (dri_err) {
501 case __DRI_CTX_ERROR_SUCCESS:
502 *error = Success;
503 break;
504 case __DRI_CTX_ERROR_NO_MEMORY:
505 *error = BadAlloc;
506 break;
507 case __DRI_CTX_ERROR_BAD_API:
508 *error = __glXError(GLXBadProfileARB);
509 break;
510 case __DRI_CTX_ERROR_BAD_VERSION:
511 case __DRI_CTX_ERROR_BAD_FLAG:
512 *error = __glXError(GLXBadFBConfig);
513 break;
514 case __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE:
515 case __DRI_CTX_ERROR_UNKNOWN_FLAG:
516 default:
517 *error = BadValue;
518 break;
519 }
520
521 return;
522 }
523
524 if (num_attribs != 0) {
525 *error = BadValue;
526 return;
527 }
528
529 context->driContext =
530 (*screen->dri2->createNewContext) (screen->driScreen, driConfig,
531 driShare, context);
532 }
533
534 static __GLXcontext *
__glXDRIscreenCreateContext(__GLXscreen * baseScreen,__GLXconfig * glxConfig,__GLXcontext * baseShareContext,unsigned num_attribs,const uint32_t * attribs,int * error)535 __glXDRIscreenCreateContext(__GLXscreen * baseScreen,
536 __GLXconfig * glxConfig,
537 __GLXcontext * baseShareContext,
538 unsigned num_attribs,
539 const uint32_t *attribs,
540 int *error)
541 {
542 __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen;
543 __GLXDRIcontext *context, *shareContext;
544 __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig;
545 __DRIcontext *driShare;
546
547 shareContext = (__GLXDRIcontext *) baseShareContext;
548 if (shareContext)
549 driShare = shareContext->driContext;
550 else
551 driShare = NULL;
552
553 context = calloc(1, sizeof *context);
554 if (context == NULL) {
555 *error = BadAlloc;
556 return NULL;
557 }
558
559 context->base.config = glxConfig;
560 context->base.destroy = __glXDRIcontextDestroy;
561 context->base.makeCurrent = __glXDRIcontextMakeCurrent;
562 context->base.loseCurrent = __glXDRIcontextLoseCurrent;
563 context->base.copy = __glXDRIcontextCopy;
564 context->base.bindTexImage = __glXDRIbindTexImage;
565 context->base.releaseTexImage = __glXDRIreleaseTexImage;
566 context->base.wait = __glXDRIcontextWait;
567
568 create_driver_context(context, screen, config, driShare, num_attribs,
569 attribs, error);
570 if (context->driContext == NULL) {
571 free(context);
572 return NULL;
573 }
574
575 return &context->base;
576 }
577
578 static void
__glXDRIinvalidateBuffers(DrawablePtr pDraw,void * priv,XID id)579 __glXDRIinvalidateBuffers(DrawablePtr pDraw, void *priv, XID id)
580 {
581 __GLXDRIdrawable *private = priv;
582 __GLXDRIscreen *screen = private->screen;
583
584 if (screen->flush)
585 (*screen->flush->invalidate) (private->driDrawable);
586 }
587
588 static __GLXdrawable *
__glXDRIscreenCreateDrawable(ClientPtr client,__GLXscreen * screen,DrawablePtr pDraw,XID drawId,int type,XID glxDrawId,__GLXconfig * glxConfig)589 __glXDRIscreenCreateDrawable(ClientPtr client,
590 __GLXscreen * screen,
591 DrawablePtr pDraw,
592 XID drawId,
593 int type, XID glxDrawId, __GLXconfig * glxConfig)
594 {
595 __GLXDRIscreen *driScreen = (__GLXDRIscreen *) screen;
596 __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig;
597 __GLXDRIdrawable *private;
598 __GLXcontext *cx = lastGLContext;
599 Bool ret;
600
601 private = calloc(1, sizeof *private);
602 if (private == NULL)
603 return NULL;
604
605 private->screen = driScreen;
606 if (!__glXDrawableInit(&private->base, screen,
607 pDraw, type, glxDrawId, glxConfig)) {
608 free(private);
609 return NULL;
610 }
611
612 private->base.destroy = __glXDRIdrawableDestroy;
613 private->base.swapBuffers = __glXDRIdrawableSwapBuffers;
614 private->base.copySubBuffer = __glXDRIdrawableCopySubBuffer;
615 private->base.waitGL = __glXDRIdrawableWaitGL;
616 private->base.waitX = __glXDRIdrawableWaitX;
617
618 ret = DRI2CreateDrawable2(client, pDraw, drawId,
619 __glXDRIinvalidateBuffers, private,
620 &private->dri2_id);
621 if (cx != lastGLContext) {
622 lastGLContext = cx;
623 cx->makeCurrent(cx);
624 }
625
626 if (ret) {
627 free(private);
628 return NULL;
629 }
630
631 private->driDrawable =
632 (*driScreen->dri2->createNewDrawable) (driScreen->driScreen,
633 config->driConfig, private);
634
635 return &private->base;
636 }
637
638 static __DRIbuffer *
dri2GetBuffers(__DRIdrawable * driDrawable,int * width,int * height,unsigned int * attachments,int count,int * out_count,void * loaderPrivate)639 dri2GetBuffers(__DRIdrawable * driDrawable,
640 int *width, int *height,
641 unsigned int *attachments, int count,
642 int *out_count, void *loaderPrivate)
643 {
644 __GLXDRIdrawable *private = loaderPrivate;
645 DRI2BufferPtr *buffers;
646 int i;
647 int j;
648 __GLXcontext *cx = lastGLContext;
649
650 buffers = DRI2GetBuffers(private->base.pDraw,
651 width, height, attachments, count, out_count);
652 if (cx != lastGLContext) {
653 lastGLContext = cx;
654 cx->makeCurrent(cx);
655
656 /* If DRI2GetBuffers() changed the GL context, it may also have
657 * invalidated the DRI2 buffers, so let's get them again
658 */
659 buffers = DRI2GetBuffers(private->base.pDraw,
660 width, height, attachments, count, out_count);
661 assert(lastGLContext == cx);
662 }
663
664 if (*out_count > MAX_DRAWABLE_BUFFERS) {
665 *out_count = 0;
666 return NULL;
667 }
668
669 private->width = *width;
670 private->height = *height;
671
672 /* This assumes the DRI2 buffer attachment tokens matches the
673 * __DRIbuffer tokens. */
674 j = 0;
675 for (i = 0; i < *out_count; i++) {
676 /* Do not send the real front buffer of a window to the client.
677 */
678 if ((private->base.pDraw->type == DRAWABLE_WINDOW)
679 && (buffers[i]->attachment == DRI2BufferFrontLeft)) {
680 continue;
681 }
682
683 private->buffers[j].attachment = buffers[i]->attachment;
684 private->buffers[j].name = buffers[i]->name;
685 private->buffers[j].pitch = buffers[i]->pitch;
686 private->buffers[j].cpp = buffers[i]->cpp;
687 private->buffers[j].flags = buffers[i]->flags;
688 j++;
689 }
690
691 *out_count = j;
692 return private->buffers;
693 }
694
695 static __DRIbuffer *
dri2GetBuffersWithFormat(__DRIdrawable * driDrawable,int * width,int * height,unsigned int * attachments,int count,int * out_count,void * loaderPrivate)696 dri2GetBuffersWithFormat(__DRIdrawable * driDrawable,
697 int *width, int *height,
698 unsigned int *attachments, int count,
699 int *out_count, void *loaderPrivate)
700 {
701 __GLXDRIdrawable *private = loaderPrivate;
702 DRI2BufferPtr *buffers;
703 int i;
704 int j = 0;
705 __GLXcontext *cx = lastGLContext;
706
707 buffers = DRI2GetBuffersWithFormat(private->base.pDraw,
708 width, height, attachments, count,
709 out_count);
710 if (cx != lastGLContext) {
711 lastGLContext = cx;
712 cx->makeCurrent(cx);
713
714 /* If DRI2GetBuffersWithFormat() changed the GL context, it may also have
715 * invalidated the DRI2 buffers, so let's get them again
716 */
717 buffers = DRI2GetBuffersWithFormat(private->base.pDraw,
718 width, height, attachments, count,
719 out_count);
720 assert(lastGLContext == cx);
721 }
722
723 if (*out_count > MAX_DRAWABLE_BUFFERS) {
724 *out_count = 0;
725 return NULL;
726 }
727
728 private->width = *width;
729 private->height = *height;
730
731 /* This assumes the DRI2 buffer attachment tokens matches the
732 * __DRIbuffer tokens. */
733 for (i = 0; i < *out_count; i++) {
734 /* Do not send the real front buffer of a window to the client.
735 */
736 if ((private->base.pDraw->type == DRAWABLE_WINDOW)
737 && (buffers[i]->attachment == DRI2BufferFrontLeft)) {
738 continue;
739 }
740
741 private->buffers[j].attachment = buffers[i]->attachment;
742 private->buffers[j].name = buffers[i]->name;
743 private->buffers[j].pitch = buffers[i]->pitch;
744 private->buffers[j].cpp = buffers[i]->cpp;
745 private->buffers[j].flags = buffers[i]->flags;
746 j++;
747 }
748
749 *out_count = j;
750 return private->buffers;
751 }
752
753 static void
dri2FlushFrontBuffer(__DRIdrawable * driDrawable,void * loaderPrivate)754 dri2FlushFrontBuffer(__DRIdrawable * driDrawable, void *loaderPrivate)
755 {
756 __GLXDRIdrawable *private = (__GLXDRIdrawable *) loaderPrivate;
757 (void) driDrawable;
758
759 copy_box(loaderPrivate, DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft,
760 0, 0, private->width, private->height);
761 }
762
763 static const __DRIdri2LoaderExtension loaderExtension = {
764 {__DRI_DRI2_LOADER, 3},
765 dri2GetBuffers,
766 dri2FlushFrontBuffer,
767 dri2GetBuffersWithFormat,
768 };
769
770 static const __DRIuseInvalidateExtension dri2UseInvalidate = {
771 {__DRI_USE_INVALIDATE, 1}
772 };
773
774 static const __DRIextension *loader_extensions[] = {
775 &loaderExtension.base,
776 &dri2UseInvalidate.base,
777 NULL
778 };
779
780 static Bool
glxDRIEnterVT(ScrnInfoPtr scrn)781 glxDRIEnterVT(ScrnInfoPtr scrn)
782 {
783 Bool ret;
784 __GLXDRIscreen *screen = (__GLXDRIscreen *)
785 glxGetScreen(xf86ScrnToScreen(scrn));
786
787 LogMessage(X_INFO, "AIGLX: Resuming AIGLX clients after VT switch\n");
788
789 scrn->EnterVT = screen->enterVT;
790
791 ret = scrn->EnterVT(scrn);
792
793 screen->enterVT = scrn->EnterVT;
794 scrn->EnterVT = glxDRIEnterVT;
795
796 if (!ret)
797 return FALSE;
798
799 glxResumeClients();
800
801 return TRUE;
802 }
803
804 static void
glxDRILeaveVT(ScrnInfoPtr scrn)805 glxDRILeaveVT(ScrnInfoPtr scrn)
806 {
807 __GLXDRIscreen *screen = (__GLXDRIscreen *)
808 glxGetScreen(xf86ScrnToScreen(scrn));
809
810 LogMessageVerbSigSafe(X_INFO, -1, "AIGLX: Suspending AIGLX clients for VT switch\n");
811
812 glxSuspendClients();
813
814 scrn->LeaveVT = screen->leaveVT;
815 (*screen->leaveVT) (scrn);
816 screen->leaveVT = scrn->LeaveVT;
817 scrn->LeaveVT = glxDRILeaveVT;
818 }
819
820 /**
821 * Initialize extension flags in glx_enable_bits when a new screen is created
822 *
823 * @param screen The screen where glx_enable_bits are to be set.
824 */
825 static void
initializeExtensions(__GLXscreen * screen)826 initializeExtensions(__GLXscreen * screen)
827 {
828 ScreenPtr pScreen = screen->pScreen;
829 __GLXDRIscreen *dri = (__GLXDRIscreen *)screen;
830 const __DRIextension **extensions;
831 int i;
832
833 extensions = dri->core->getExtensions(dri->driScreen);
834
835 __glXEnableExtension(screen->glx_enable_bits, "GLX_MESA_copy_sub_buffer");
836 __glXEnableExtension(screen->glx_enable_bits, "GLX_EXT_no_config_context");
837
838 if (dri->dri2->base.version >= 3) {
839 __glXEnableExtension(screen->glx_enable_bits,
840 "GLX_ARB_create_context");
841 __glXEnableExtension(screen->glx_enable_bits,
842 "GLX_ARB_create_context_no_error");
843 __glXEnableExtension(screen->glx_enable_bits,
844 "GLX_ARB_create_context_profile");
845 __glXEnableExtension(screen->glx_enable_bits,
846 "GLX_EXT_create_context_es_profile");
847 __glXEnableExtension(screen->glx_enable_bits,
848 "GLX_EXT_create_context_es2_profile");
849 }
850
851 if (DRI2HasSwapControl(pScreen)) {
852 __glXEnableExtension(screen->glx_enable_bits, "GLX_INTEL_swap_event");
853 __glXEnableExtension(screen->glx_enable_bits, "GLX_SGI_swap_control");
854 }
855
856 /* enable EXT_framebuffer_sRGB extension (even if there are no sRGB capable fbconfigs) */
857 __glXEnableExtension(screen->glx_enable_bits, "GLX_EXT_framebuffer_sRGB");
858
859 /* enable ARB_fbconfig_float extension (even if there are no float fbconfigs) */
860 __glXEnableExtension(screen->glx_enable_bits, "GLX_ARB_fbconfig_float");
861
862 /* enable EXT_fbconfig_packed_float (even if there are no packed float fbconfigs) */
863 __glXEnableExtension(screen->glx_enable_bits, "GLX_EXT_fbconfig_packed_float");
864
865 for (i = 0; extensions[i]; i++) {
866 if (strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0) {
867 dri->texBuffer = (const __DRItexBufferExtension *) extensions[i];
868 __glXEnableExtension(screen->glx_enable_bits,
869 "GLX_EXT_texture_from_pixmap");
870 }
871
872 if (strcmp(extensions[i]->name, __DRI2_FLUSH) == 0 &&
873 extensions[i]->version >= 3) {
874 dri->flush = (__DRI2flushExtension *) extensions[i];
875 }
876
877 if (strcmp(extensions[i]->name, __DRI2_ROBUSTNESS) == 0 &&
878 dri->dri2->base.version >= 3) {
879 __glXEnableExtension(screen->glx_enable_bits,
880 "GLX_ARB_create_context_robustness");
881 }
882
883 #ifdef __DRI2_FLUSH_CONTROL
884 if (strcmp(extensions[i]->name, __DRI2_FLUSH_CONTROL) == 0) {
885 __glXEnableExtension(screen->glx_enable_bits,
886 "GLX_ARB_context_flush_control");
887 }
888 #endif
889
890 /* Ignore unknown extensions */
891 }
892 }
893
894 static void
__glXDRIscreenDestroy(__GLXscreen * baseScreen)895 __glXDRIscreenDestroy(__GLXscreen * baseScreen)
896 {
897 int i;
898
899 ScrnInfoPtr pScrn = xf86ScreenToScrn(baseScreen->pScreen);
900 __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen;
901
902 (*screen->core->destroyScreen) (screen->driScreen);
903
904 dlclose(screen->driver);
905
906 __glXScreenDestroy(baseScreen);
907
908 if (screen->driConfigs) {
909 for (i = 0; screen->driConfigs[i] != NULL; i++)
910 free((__DRIconfig **) screen->driConfigs[i]);
911 free(screen->driConfigs);
912 }
913
914 pScrn->EnterVT = screen->enterVT;
915 pScrn->LeaveVT = screen->leaveVT;
916
917 free(screen);
918 }
919
920 enum {
921 GLXOPT_VENDOR_LIBRARY,
922 };
923
924 static const OptionInfoRec GLXOptions[] = {
925 { GLXOPT_VENDOR_LIBRARY, "GlxVendorLibrary", OPTV_STRING, {0}, FALSE },
926 { -1, NULL, OPTV_NONE, {0}, FALSE },
927 };
928
929 static __GLXscreen *
__glXDRIscreenProbe(ScreenPtr pScreen)930 __glXDRIscreenProbe(ScreenPtr pScreen)
931 {
932 const char *driverName, *deviceName;
933 __GLXDRIscreen *screen;
934 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
935 const char *glvnd = NULL;
936 OptionInfoPtr options;
937
938 screen = calloc(1, sizeof *screen);
939 if (screen == NULL)
940 return NULL;
941
942 if (!DRI2Connect(serverClient, pScreen, DRI2DriverDRI,
943 &screen->fd, &driverName, &deviceName)) {
944 LogMessage(X_INFO,
945 "AIGLX: Screen %d is not DRI2 capable\n", pScreen->myNum);
946 goto handle_error;
947 }
948
949 screen->base.destroy = __glXDRIscreenDestroy;
950 screen->base.createContext = __glXDRIscreenCreateContext;
951 screen->base.createDrawable = __glXDRIscreenCreateDrawable;
952 screen->base.swapInterval = __glXDRIdrawableSwapInterval;
953 screen->base.pScreen = pScreen;
954
955 __glXInitExtensionEnableBits(screen->base.glx_enable_bits);
956
957 screen->driver =
958 glxProbeDriver(driverName, (void **) &screen->core, __DRI_CORE, 1,
959 (void **) &screen->dri2, __DRI_DRI2, 1);
960 if (screen->driver == NULL) {
961 goto handle_error;
962 }
963
964 screen->driScreen =
965 (*screen->dri2->createNewScreen) (pScreen->myNum,
966 screen->fd,
967 loader_extensions,
968 &screen->driConfigs, screen);
969
970 if (screen->driScreen == NULL) {
971 LogMessage(X_ERROR, "AIGLX error: Calling driver entry point failed\n");
972 goto handle_error;
973 }
974
975 initializeExtensions(&screen->base);
976
977 screen->base.fbconfigs = glxConvertConfigs(screen->core,
978 screen->driConfigs);
979
980 options = xnfalloc(sizeof(GLXOptions));
981 memcpy(options, GLXOptions, sizeof(GLXOptions));
982 xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, options);
983 glvnd = xf86GetOptValString(options, GLXOPT_VENDOR_LIBRARY);
984 if (glvnd)
985 screen->base.glvnd = xnfstrdup(glvnd);
986 free(options);
987
988 if (!screen->base.glvnd)
989 screen->base.glvnd = strdup("mesa");
990
991 __glXScreenInit(&screen->base, pScreen);
992
993 screen->enterVT = pScrn->EnterVT;
994 pScrn->EnterVT = glxDRIEnterVT;
995 screen->leaveVT = pScrn->LeaveVT;
996 pScrn->LeaveVT = glxDRILeaveVT;
997
998 __glXsetGetProcAddress(glXGetProcAddressARB);
999
1000 LogMessage(X_INFO, "AIGLX: Loaded and initialized %s\n", driverName);
1001
1002 return &screen->base;
1003
1004 handle_error:
1005 if (screen->driver)
1006 dlclose(screen->driver);
1007
1008 free(screen);
1009
1010 return NULL;
1011 }
1012
1013 _X_EXPORT __GLXprovider __glXDRI2Provider = {
1014 __glXDRIscreenProbe,
1015 "DRI2",
1016 NULL
1017 };
1018