2 * Copyright © 2007 Red Hat, Inc
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.
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.
24 #ifdef HAVE_DIX_CONFIG_H
25 #include <dix-config.h>
36 #include <GL/internal/dri_interface.h>
37 #include <GL/glxtokens.h>
39 #include <windowstr.h>
42 #define _XF86DRI_SERVER_
47 #include "glxserver.h"
49 #include "glxdricommon.h"
51 #include "g_disptab.h"
52 #include "glapitable.h"
56 #include "extension_string.h"
58 typedef struct __GLXDRIscreen __GLXDRIscreen;
59 typedef struct __GLXDRIcontext __GLXDRIcontext;
60 typedef struct __GLXDRIdrawable __GLXDRIdrawable;
62 struct __GLXDRIscreen {
64 __DRIscreen *driScreen;
68 xf86EnterVTProc *enterVT;
69 xf86LeaveVTProc *leaveVT;
71 const __DRIcoreExtension *core;
72 const __DRIdri2Extension *dri2;
73 const __DRI2flushExtension *flush;
74 const __DRIcopySubBufferExtension *copySubBuffer;
75 const __DRIswapControlExtension *swapControl;
76 const __DRItexBufferExtension *texBuffer;
78 unsigned char glx_enable_bits[__GLX_EXT_BYTES];
81 struct __GLXDRIcontext {
83 __DRIcontext *driContext;
86 #define MAX_DRAWABLE_BUFFERS 5
88 struct __GLXDRIdrawable {
90 __DRIdrawable *driDrawable;
91 __GLXDRIscreen *screen;
93 /* Dimensions as last reported by DRI2GetBuffers. */
96 __DRIbuffer buffers[MAX_DRAWABLE_BUFFERS];
101 __glXDRIdrawableDestroy(__GLXdrawable *drawable)
103 __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable;
104 const __DRIcoreExtension *core = private->screen->core;
106 (*core->destroyDrawable)(private->driDrawable);
108 __glXDrawableRelease(drawable);
114 __glXDRIdrawableCopySubBuffer(__GLXdrawable *drawable,
115 int x, int y, int w, int h)
117 __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable;
122 box.y1 = private->height - y - h;
124 box.y2 = private->height - y;
125 RegionInit(®ion, &box, 0);
127 DRI2CopyRegion(drawable->pDraw, ®ion,
128 DRI2BufferFrontLeft, DRI2BufferBackLeft);
132 __glXDRIdrawableWaitX(__GLXdrawable *drawable)
134 __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable;
140 box.x2 = private->width;
141 box.y2 = private->height;
142 RegionInit(®ion, &box, 0);
144 DRI2CopyRegion(drawable->pDraw, ®ion,
145 DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
149 __glXDRIdrawableWaitGL(__GLXdrawable *drawable)
151 __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable;
157 box.x2 = private->width;
158 box.y2 = private->height;
159 RegionInit(®ion, &box, 0);
161 DRI2CopyRegion(drawable->pDraw, ®ion,
162 DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
166 __glXdriSwapEvent(ClientPtr client, void *data, int type, CARD64 ust,
167 CARD64 msc, CARD64 sbc)
169 __GLXdrawable *drawable = data;
170 xGLXBufferSwapComplete wire;
172 if (!(drawable->eventMask & GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK))
175 wire.type = __glXEventBase + GLX_BufferSwapComplete;
177 case DRI2_EXCHANGE_COMPLETE:
178 wire.event_type = GLX_EXCHANGE_COMPLETE_INTEL;
180 case DRI2_BLIT_COMPLETE:
181 wire.event_type = GLX_BLIT_COMPLETE_INTEL;
183 case DRI2_FLIP_COMPLETE:
184 wire.event_type = GLX_FLIP_COMPLETE_INTEL;
187 /* unknown swap completion type */
190 wire.drawable = drawable->drawId;
191 wire.ust_hi = ust >> 32;
192 wire.ust_lo = ust & 0xffffffff;
193 wire.msc_hi = msc >> 32;
194 wire.msc_lo = msc & 0xffffffff;
195 wire.sbc_hi = sbc >> 32;
196 wire.sbc_lo = sbc & 0xffffffff;
198 WriteEventsToClient(client, 1, (xEvent *) &wire);
202 * Copy or flip back to front, honoring the swap interval if possible.
204 * If the kernel supports it, we request an event for the frame when the
205 * swap should happen, then perform the copy when we receive it.
208 __glXDRIdrawableSwapBuffers(ClientPtr client, __GLXdrawable *drawable)
210 __GLXDRIdrawable *priv = (__GLXDRIdrawable *) drawable;
211 __GLXDRIscreen *screen = priv->screen;
214 #if __DRI2_FLUSH_VERSION >= 3
216 (*screen->flush->flush)(priv->driDrawable);
217 (*screen->flush->invalidate)(priv->driDrawable);
221 (*screen->flush->flushInvalidate)(priv->driDrawable);
224 if (DRI2SwapBuffers(client, drawable->pDraw, 0, 0, 0, &unused,
225 __glXdriSwapEvent, drawable->pDraw) != Success)
232 __glXDRIdrawableSwapInterval(__GLXdrawable *drawable, int interval)
234 if (interval <= 0) /* || interval > BIGNUM? */
235 return GLX_BAD_VALUE;
237 DRI2SwapInterval(drawable->pDraw, interval);
243 __glXDRIcontextDestroy(__GLXcontext *baseContext)
245 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
246 __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
248 (*screen->core->destroyContext)(context->driContext);
249 __glXContextDestroy(&context->base);
254 __glXDRIcontextMakeCurrent(__GLXcontext *baseContext)
256 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
257 __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseContext->drawPriv;
258 __GLXDRIdrawable *read = (__GLXDRIdrawable *) baseContext->readPriv;
259 __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
261 return (*screen->core->bindContext)(context->driContext,
267 __glXDRIcontextLoseCurrent(__GLXcontext *baseContext)
269 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
270 __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
272 return (*screen->core->unbindContext)(context->driContext);
276 __glXDRIcontextCopy(__GLXcontext *baseDst, __GLXcontext *baseSrc,
279 __GLXDRIcontext *dst = (__GLXDRIcontext *) baseDst;
280 __GLXDRIcontext *src = (__GLXDRIcontext *) baseSrc;
281 __GLXDRIscreen *screen = (__GLXDRIscreen *) dst->base.pGlxScreen;
283 return (*screen->core->copyContext)(dst->driContext,
284 src->driContext, mask);
288 __glXDRIcontextForceCurrent(__GLXcontext *baseContext)
290 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
291 __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseContext->drawPriv;
292 __GLXDRIdrawable *read = (__GLXDRIdrawable *) baseContext->readPriv;
293 __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
295 return (*screen->core->bindContext)(context->driContext,
301 __glXDRIcontextWait(__GLXcontext *baseContext,
302 __GLXclientState *cl, int *error)
304 if (DRI2WaitSwap(cl->client, baseContext->drawPriv->pDraw)) {
305 *error = cl->client->noClientException;
312 #ifdef __DRI_TEX_BUFFER
315 __glXDRIbindTexImage(__GLXcontext *baseContext,
317 __GLXdrawable *glxPixmap)
319 __GLXDRIdrawable *drawable = (__GLXDRIdrawable *) glxPixmap;
320 const __DRItexBufferExtension *texBuffer = drawable->screen->texBuffer;
321 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
323 if (texBuffer == NULL)
326 #if __DRI_TEX_BUFFER_VERSION >= 2
327 if (texBuffer->base.version >= 2 && texBuffer->setTexBuffer2 != NULL) {
328 (*texBuffer->setTexBuffer2)(context->driContext,
331 drawable->driDrawable);
335 texBuffer->setTexBuffer(context->driContext,
337 drawable->driDrawable);
344 __glXDRIreleaseTexImage(__GLXcontext *baseContext,
346 __GLXdrawable *pixmap)
348 /* FIXME: Just unbind the texture? */
355 __glXDRIbindTexImage(__GLXcontext *baseContext,
357 __GLXdrawable *glxPixmap)
363 __glXDRIreleaseTexImage(__GLXcontext *baseContext,
365 __GLXdrawable *pixmap)
372 static __GLXtextureFromPixmap __glXDRItextureFromPixmap = {
373 __glXDRIbindTexImage,
374 __glXDRIreleaseTexImage
378 __glXDRIscreenDestroy(__GLXscreen *baseScreen)
380 __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen;
382 (*screen->core->destroyScreen)(screen->driScreen);
384 dlclose(screen->driver);
386 __glXScreenDestroy(baseScreen);
391 static __GLXcontext *
392 __glXDRIscreenCreateContext(__GLXscreen *baseScreen,
393 __GLXconfig *glxConfig,
394 __GLXcontext *baseShareContext)
396 __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen;
397 __GLXDRIcontext *context, *shareContext;
398 __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig;
399 __DRIcontext *driShare;
401 shareContext = (__GLXDRIcontext *) baseShareContext;
403 driShare = shareContext->driContext;
407 context = calloc(1, sizeof *context);
411 context->base.destroy = __glXDRIcontextDestroy;
412 context->base.makeCurrent = __glXDRIcontextMakeCurrent;
413 context->base.loseCurrent = __glXDRIcontextLoseCurrent;
414 context->base.copy = __glXDRIcontextCopy;
415 context->base.forceCurrent = __glXDRIcontextForceCurrent;
416 context->base.textureFromPixmap = &__glXDRItextureFromPixmap;
417 context->base.wait = __glXDRIcontextWait;
419 context->driContext =
420 (*screen->dri2->createNewContext)(screen->driScreen,
423 if (context->driContext == NULL) {
428 return &context->base;
432 __glXDRIinvalidateBuffers(DrawablePtr pDraw, void *priv)
434 #if __DRI2_FLUSH_VERSION >= 3
435 __GLXDRIdrawable *private = priv;
436 __GLXDRIscreen *screen = private->screen;
439 (*screen->flush->invalidate)(private->driDrawable);
443 static __GLXdrawable *
444 __glXDRIscreenCreateDrawable(ClientPtr client,
450 __GLXconfig *glxConfig)
452 __GLXDRIscreen *driScreen = (__GLXDRIscreen *) screen;
453 __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig;
454 __GLXDRIdrawable *private;
456 private = calloc(1, sizeof *private);
460 private->screen = driScreen;
461 if (!__glXDrawableInit(&private->base, screen,
462 pDraw, type, glxDrawId, glxConfig)) {
467 private->base.destroy = __glXDRIdrawableDestroy;
468 private->base.swapBuffers = __glXDRIdrawableSwapBuffers;
469 private->base.copySubBuffer = __glXDRIdrawableCopySubBuffer;
470 private->base.waitGL = __glXDRIdrawableWaitGL;
471 private->base.waitX = __glXDRIdrawableWaitX;
473 if (DRI2CreateDrawable(client, pDraw, drawId,
474 __glXDRIinvalidateBuffers, private)) {
479 private->driDrawable =
480 (*driScreen->dri2->createNewDrawable)(driScreen->driScreen,
481 config->driConfig, private);
483 return &private->base;
487 dri2GetBuffers(__DRIdrawable *driDrawable,
488 int *width, int *height,
489 unsigned int *attachments, int count,
490 int *out_count, void *loaderPrivate)
492 __GLXDRIdrawable *private = loaderPrivate;
493 DRI2BufferPtr *buffers;
497 buffers = DRI2GetBuffers(private->base.pDraw,
498 width, height, attachments, count, out_count);
499 if (*out_count > MAX_DRAWABLE_BUFFERS) {
504 private->width = *width;
505 private->height = *height;
507 /* This assumes the DRI2 buffer attachment tokens matches the
508 * __DRIbuffer tokens. */
510 for (i = 0; i < *out_count; i++) {
511 /* Do not send the real front buffer of a window to the client.
513 if ((private->base.pDraw->type == DRAWABLE_WINDOW)
514 && (buffers[i]->attachment == DRI2BufferFrontLeft)) {
518 private->buffers[j].attachment = buffers[i]->attachment;
519 private->buffers[j].name = buffers[i]->name;
520 private->buffers[j].pitch = buffers[i]->pitch;
521 private->buffers[j].cpp = buffers[i]->cpp;
522 private->buffers[j].flags = buffers[i]->flags;
527 return private->buffers;
531 dri2GetBuffersWithFormat(__DRIdrawable *driDrawable,
532 int *width, int *height,
533 unsigned int *attachments, int count,
534 int *out_count, void *loaderPrivate)
536 __GLXDRIdrawable *private = loaderPrivate;
537 DRI2BufferPtr *buffers;
541 buffers = DRI2GetBuffersWithFormat(private->base.pDraw,
542 width, height, attachments, count,
544 if (*out_count > MAX_DRAWABLE_BUFFERS) {
549 private->width = *width;
550 private->height = *height;
552 /* This assumes the DRI2 buffer attachment tokens matches the
553 * __DRIbuffer tokens. */
554 for (i = 0; i < *out_count; i++) {
555 /* Do not send the real front buffer of a window to the client.
557 if ((private->base.pDraw->type == DRAWABLE_WINDOW)
558 && (buffers[i]->attachment == DRI2BufferFrontLeft)) {
562 private->buffers[j].attachment = buffers[i]->attachment;
563 private->buffers[j].name = buffers[i]->name;
564 private->buffers[j].pitch = buffers[i]->pitch;
565 private->buffers[j].cpp = buffers[i]->cpp;
566 private->buffers[j].flags = buffers[i]->flags;
571 return private->buffers;
575 dri2FlushFrontBuffer(__DRIdrawable *driDrawable, void *loaderPrivate)
578 __glXDRIdrawableWaitGL((__GLXdrawable *) loaderPrivate);
581 static const __DRIdri2LoaderExtension loaderExtension = {
582 { __DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION },
584 dri2FlushFrontBuffer,
585 dri2GetBuffersWithFormat,
588 #ifdef __DRI_USE_INVALIDATE
589 static const __DRIuseInvalidateExtension dri2UseInvalidate = {
590 { __DRI_USE_INVALIDATE, __DRI_USE_INVALIDATE_VERSION }
594 static const __DRIextension *loader_extensions[] = {
595 &systemTimeExtension.base,
596 &loaderExtension.base,
597 #ifdef __DRI_USE_INVALIDATE
603 static const char dri_driver_path[] = DRI_DRIVER_PATH;
606 glxDRIEnterVT (int index, int flags)
608 ScrnInfoPtr scrn = xf86Screens[index];
610 __GLXDRIscreen *screen = (__GLXDRIscreen *)
611 glxGetScreen(screenInfo.screens[index]);
613 LogMessage(X_INFO, "AIGLX: Resuming AIGLX clients after VT switch\n");
615 scrn->EnterVT = screen->enterVT;
617 ret = scrn->EnterVT (index, flags);
619 screen->enterVT = scrn->EnterVT;
620 scrn->EnterVT = glxDRIEnterVT;
631 glxDRILeaveVT (int index, int flags)
633 ScrnInfoPtr scrn = xf86Screens[index];
634 __GLXDRIscreen *screen = (__GLXDRIscreen *)
635 glxGetScreen(screenInfo.screens[index]);
637 LogMessage(X_INFO, "AIGLX: Suspending AIGLX clients for VT switch\n");
641 scrn->LeaveVT = screen->leaveVT;
642 (*screen->leaveVT) (index, flags);
643 screen->leaveVT = scrn->LeaveVT;
644 scrn->LeaveVT = glxDRILeaveVT;
648 initializeExtensions(__GLXDRIscreen *screen)
650 ScreenPtr pScreen = screen->base.pScreen;
651 const __DRIextension **extensions;
654 extensions = screen->core->getExtensions(screen->driScreen);
656 __glXEnableExtension(screen->glx_enable_bits,
657 "GLX_MESA_copy_sub_buffer");
658 LogMessage(X_INFO, "AIGLX: enabled GLX_MESA_copy_sub_buffer\n");
660 __glXEnableExtension(screen->glx_enable_bits, "GLX_INTEL_swap_event");
661 LogMessage(X_INFO, "AIGLX: enabled GLX_INTEL_swap_event\n");
663 if (DRI2HasSwapControl(pScreen)) {
664 __glXEnableExtension(screen->glx_enable_bits,
665 "GLX_SGI_swap_control");
666 __glXEnableExtension(screen->glx_enable_bits,
667 "GLX_MESA_swap_control");
668 LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_swap_control and GLX_MESA_swap_control\n");
671 for (i = 0; extensions[i]; i++) {
672 #ifdef __DRI_READ_DRAWABLE
673 if (strcmp(extensions[i]->name, __DRI_READ_DRAWABLE) == 0) {
674 __glXEnableExtension(screen->glx_enable_bits,
675 "GLX_SGI_make_current_read");
677 LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_make_current_read\n");
681 #ifdef __DRI_TEX_BUFFER
682 if (strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0) {
684 (const __DRItexBufferExtension *) extensions[i];
685 /* GLX_EXT_texture_from_pixmap is always enabled. */
686 LogMessage(X_INFO, "AIGLX: GLX_EXT_texture_from_pixmap backed by buffer objects\n");
691 if (strcmp(extensions[i]->name, __DRI2_FLUSH) == 0 &&
692 extensions[i]->version >= 3) {
693 screen->flush = (__DRI2flushExtension *) extensions[i];
697 /* Ignore unknown extensions */
702 __glXDRIscreenProbe(ScreenPtr pScreen)
704 const char *driverName, *deviceName;
705 __GLXDRIscreen *screen;
708 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
709 const __DRIextension **extensions;
710 const __DRIconfig **driConfigs;
713 screen = calloc(1, sizeof *screen);
717 if (!xf86LoaderCheckSymbol("DRI2Connect") ||
718 !DRI2Connect(pScreen, DRI2DriverDRI,
719 &screen->fd, &driverName, &deviceName)) {
721 "AIGLX: Screen %d is not DRI2 capable\n", pScreen->myNum);
725 screen->base.destroy = __glXDRIscreenDestroy;
726 screen->base.createContext = __glXDRIscreenCreateContext;
727 screen->base.createDrawable = __glXDRIscreenCreateDrawable;
728 screen->base.swapInterval = __glXDRIdrawableSwapInterval;
729 screen->base.pScreen = pScreen;
731 __glXInitExtensionEnableBits(screen->glx_enable_bits);
733 snprintf(filename, sizeof filename,
734 "%s/%s_dri.so", dri_driver_path, driverName);
736 screen->driver = dlopen(filename, RTLD_LAZY | RTLD_LOCAL);
737 if (screen->driver == NULL) {
738 LogMessage(X_ERROR, "AIGLX error: dlopen of %s failed (%s)\n",
739 filename, dlerror());
743 extensions = dlsym(screen->driver, __DRI_DRIVER_EXTENSIONS);
744 if (extensions == NULL) {
745 LogMessage(X_ERROR, "AIGLX error: %s exports no extensions (%s)\n",
746 driverName, dlerror());
750 for (i = 0; extensions[i]; i++) {
751 if (strcmp(extensions[i]->name, __DRI_CORE) == 0 &&
752 extensions[i]->version >= 1) {
753 screen->core = (const __DRIcoreExtension *) extensions[i];
755 if (strcmp(extensions[i]->name, __DRI_DRI2) == 0 &&
756 extensions[i]->version >= 1) {
757 screen->dri2 = (const __DRIdri2Extension *) extensions[i];
761 if (screen->core == NULL || screen->dri2 == NULL) {
762 LogMessage(X_ERROR, "AIGLX error: %s exports no DRI extension\n",
768 (*screen->dri2->createNewScreen)(pScreen->myNum,
774 if (screen->driScreen == NULL) {
776 "AIGLX error: Calling driver entry point failed\n");
780 initializeExtensions(screen);
782 screen->base.fbconfigs = glxConvertConfigs(screen->core, driConfigs,
787 __glXScreenInit(&screen->base, pScreen);
789 /* The first call simply determines the length of the extension string.
790 * This allows us to allocate some memory to hold the extension string,
791 * but it requires that we call __glXGetExtensionString a second time.
793 buffer_size = __glXGetExtensionString(screen->glx_enable_bits, NULL);
794 if (buffer_size > 0) {
795 if (screen->base.GLXextensions != NULL) {
796 free(screen->base.GLXextensions);
799 screen->base.GLXextensions = xnfalloc(buffer_size);
800 (void) __glXGetExtensionString(screen->glx_enable_bits,
801 screen->base.GLXextensions);
804 /* We're going to assume (perhaps incorrectly?) that all DRI2-enabled
805 * drivers support the required extensions for GLX 1.4. The extensions
806 * we're assuming are:
808 * - GLX_SGI_make_current_read (1.3)
809 * - GLX_SGIX_fbconfig (1.3)
810 * - GLX_SGIX_pbuffer (1.3)
811 * - GLX_ARB_multisample (1.4)
813 screen->base.GLXmajor = 1;
814 screen->base.GLXminor = 4;
816 screen->enterVT = pScrn->EnterVT;
817 pScrn->EnterVT = glxDRIEnterVT;
818 screen->leaveVT = pScrn->LeaveVT;
819 pScrn->LeaveVT = glxDRILeaveVT;
822 "AIGLX: Loaded and initialized %s\n", filename);
824 return &screen->base;
828 dlclose(screen->driver);
832 LogMessage(X_ERROR, "AIGLX: reverting to software rendering\n");
837 _X_EXPORT __GLXprovider __glXDRI2Provider = {