1706f2543Smrg/* 2706f2543Smrg * Copyright © 2007 Red Hat, Inc 3706f2543Smrg * 4706f2543Smrg * Permission to use, copy, modify, distribute, and sell this software 5706f2543Smrg * and its documentation for any purpose is hereby granted without 6706f2543Smrg * fee, provided that the above copyright notice appear in all copies 7706f2543Smrg * and that both that copyright notice and this permission notice 8706f2543Smrg * appear in supporting documentation, and that the name of Red Hat, 9706f2543Smrg * Inc not be used in advertising or publicity pertaining to 10706f2543Smrg * distribution of the software without specific, written prior 11706f2543Smrg * permission. Red Hat, Inc makes no representations about the 12706f2543Smrg * suitability of this software for any purpose. It is provided "as 13706f2543Smrg * is" without express or implied warranty. 14706f2543Smrg * 15706f2543Smrg * RED HAT, INC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 16706f2543Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN 17706f2543Smrg * NO EVENT SHALL RED HAT, INC BE LIABLE FOR ANY SPECIAL, INDIRECT OR 18706f2543Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 19706f2543Smrg * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 20706f2543Smrg * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 21706f2543Smrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 22706f2543Smrg */ 23706f2543Smrg 24706f2543Smrg#ifdef HAVE_DIX_CONFIG_H 25706f2543Smrg#include <dix-config.h> 26706f2543Smrg#endif 27706f2543Smrg 28706f2543Smrg#include <stdint.h> 29706f2543Smrg#include <stdio.h> 30706f2543Smrg#include <string.h> 31706f2543Smrg#include <errno.h> 32706f2543Smrg#include <dlfcn.h> 33706f2543Smrg 34706f2543Smrg#include <drm.h> 35706f2543Smrg#include <GL/gl.h> 36706f2543Smrg#include <GL/internal/dri_interface.h> 37706f2543Smrg#include <GL/glxtokens.h> 38706f2543Smrg 39706f2543Smrg#include <windowstr.h> 40706f2543Smrg#include <os.h> 41706f2543Smrg 42706f2543Smrg#define _XF86DRI_SERVER_ 43706f2543Smrg#include <xf86drm.h> 44706f2543Smrg#include <xf86.h> 45706f2543Smrg#include <dri2.h> 46706f2543Smrg 47706f2543Smrg#include "glxserver.h" 48706f2543Smrg#include "glxutil.h" 49706f2543Smrg#include "glxdricommon.h" 50706f2543Smrg 51706f2543Smrg#include "glapitable.h" 52706f2543Smrg#include "glapi.h" 53706f2543Smrg#include "glthread.h" 54706f2543Smrg#include "dispatch.h" 55706f2543Smrg#include "extension_string.h" 56706f2543Smrg 57706f2543Smrgtypedef struct __GLXDRIscreen __GLXDRIscreen; 58706f2543Smrgtypedef struct __GLXDRIcontext __GLXDRIcontext; 59706f2543Smrgtypedef struct __GLXDRIdrawable __GLXDRIdrawable; 60706f2543Smrg 61706f2543Smrgstruct __GLXDRIscreen { 62706f2543Smrg __GLXscreen base; 63706f2543Smrg __DRIscreen *driScreen; 64706f2543Smrg void *driver; 65706f2543Smrg int fd; 66706f2543Smrg 67706f2543Smrg xf86EnterVTProc *enterVT; 68706f2543Smrg xf86LeaveVTProc *leaveVT; 69706f2543Smrg 70706f2543Smrg const __DRIcoreExtension *core; 71706f2543Smrg const __DRIdri2Extension *dri2; 72706f2543Smrg const __DRI2flushExtension *flush; 73706f2543Smrg const __DRIcopySubBufferExtension *copySubBuffer; 74706f2543Smrg const __DRIswapControlExtension *swapControl; 75706f2543Smrg const __DRItexBufferExtension *texBuffer; 76706f2543Smrg 77706f2543Smrg unsigned char glx_enable_bits[__GLX_EXT_BYTES]; 78706f2543Smrg}; 79706f2543Smrg 80706f2543Smrgstruct __GLXDRIcontext { 81706f2543Smrg __GLXcontext base; 82706f2543Smrg __DRIcontext *driContext; 83706f2543Smrg}; 84706f2543Smrg 85706f2543Smrg#define MAX_DRAWABLE_BUFFERS 5 86706f2543Smrg 87706f2543Smrgstruct __GLXDRIdrawable { 88706f2543Smrg __GLXdrawable base; 89706f2543Smrg __DRIdrawable *driDrawable; 90706f2543Smrg __GLXDRIscreen *screen; 91706f2543Smrg 92706f2543Smrg /* Dimensions as last reported by DRI2GetBuffers. */ 93706f2543Smrg int width; 94706f2543Smrg int height; 95706f2543Smrg __DRIbuffer buffers[MAX_DRAWABLE_BUFFERS]; 96706f2543Smrg int count; 97706f2543Smrg}; 98706f2543Smrg 99706f2543Smrgstatic void 100706f2543Smrg__glXDRIdrawableDestroy(__GLXdrawable *drawable) 101706f2543Smrg{ 102706f2543Smrg __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; 103706f2543Smrg const __DRIcoreExtension *core = private->screen->core; 104706f2543Smrg 105706f2543Smrg (*core->destroyDrawable)(private->driDrawable); 106706f2543Smrg 107706f2543Smrg __glXDrawableRelease(drawable); 108706f2543Smrg 109706f2543Smrg free(private); 110706f2543Smrg} 111706f2543Smrg 112706f2543Smrgstatic void 113706f2543Smrg__glXDRIdrawableCopySubBuffer(__GLXdrawable *drawable, 114706f2543Smrg int x, int y, int w, int h) 115706f2543Smrg{ 116706f2543Smrg __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; 117706f2543Smrg BoxRec box; 118706f2543Smrg RegionRec region; 119706f2543Smrg 120706f2543Smrg box.x1 = x; 121706f2543Smrg box.y1 = private->height - y - h; 122706f2543Smrg box.x2 = x + w; 123706f2543Smrg box.y2 = private->height - y; 124706f2543Smrg RegionInit(®ion, &box, 0); 125706f2543Smrg 126706f2543Smrg DRI2CopyRegion(drawable->pDraw, ®ion, 127706f2543Smrg DRI2BufferFrontLeft, DRI2BufferBackLeft); 128706f2543Smrg} 129706f2543Smrg 130706f2543Smrgstatic void 131706f2543Smrg__glXDRIdrawableWaitX(__GLXdrawable *drawable) 132706f2543Smrg{ 133706f2543Smrg __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; 134706f2543Smrg BoxRec box; 135706f2543Smrg RegionRec region; 136706f2543Smrg 137706f2543Smrg box.x1 = 0; 138706f2543Smrg box.y1 = 0; 139706f2543Smrg box.x2 = private->width; 140706f2543Smrg box.y2 = private->height; 141706f2543Smrg RegionInit(®ion, &box, 0); 142706f2543Smrg 143706f2543Smrg DRI2CopyRegion(drawable->pDraw, ®ion, 144706f2543Smrg DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft); 145706f2543Smrg} 146706f2543Smrg 147706f2543Smrgstatic void 148706f2543Smrg__glXDRIdrawableWaitGL(__GLXdrawable *drawable) 149706f2543Smrg{ 150706f2543Smrg __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; 151706f2543Smrg BoxRec box; 152706f2543Smrg RegionRec region; 153706f2543Smrg 154706f2543Smrg box.x1 = 0; 155706f2543Smrg box.y1 = 0; 156706f2543Smrg box.x2 = private->width; 157706f2543Smrg box.y2 = private->height; 158706f2543Smrg RegionInit(®ion, &box, 0); 159706f2543Smrg 160706f2543Smrg DRI2CopyRegion(drawable->pDraw, ®ion, 161706f2543Smrg DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft); 162706f2543Smrg} 163706f2543Smrg 164706f2543Smrgstatic void 165706f2543Smrg__glXdriSwapEvent(ClientPtr client, void *data, int type, CARD64 ust, 166706f2543Smrg CARD64 msc, CARD64 sbc) 167706f2543Smrg{ 168706f2543Smrg __GLXdrawable *drawable = data; 169706f2543Smrg xGLXBufferSwapComplete wire; 170706f2543Smrg 171706f2543Smrg if (!(drawable->eventMask & GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK)) 172706f2543Smrg return; 173706f2543Smrg 174706f2543Smrg wire.type = __glXEventBase + GLX_BufferSwapComplete; 175706f2543Smrg switch (type) { 176706f2543Smrg case DRI2_EXCHANGE_COMPLETE: 177706f2543Smrg wire.event_type = GLX_EXCHANGE_COMPLETE_INTEL; 178706f2543Smrg break; 179706f2543Smrg case DRI2_BLIT_COMPLETE: 180706f2543Smrg wire.event_type = GLX_BLIT_COMPLETE_INTEL; 181706f2543Smrg break; 182706f2543Smrg case DRI2_FLIP_COMPLETE: 183706f2543Smrg wire.event_type = GLX_FLIP_COMPLETE_INTEL; 184706f2543Smrg break; 185706f2543Smrg default: 186706f2543Smrg /* unknown swap completion type */ 187706f2543Smrg wire.event_type = 0; 188706f2543Smrg break; 189706f2543Smrg } 190706f2543Smrg wire.drawable = drawable->drawId; 191706f2543Smrg wire.ust_hi = ust >> 32; 192706f2543Smrg wire.ust_lo = ust & 0xffffffff; 193706f2543Smrg wire.msc_hi = msc >> 32; 194706f2543Smrg wire.msc_lo = msc & 0xffffffff; 195706f2543Smrg wire.sbc_hi = sbc >> 32; 196706f2543Smrg wire.sbc_lo = sbc & 0xffffffff; 197706f2543Smrg 198706f2543Smrg WriteEventsToClient(client, 1, (xEvent *) &wire); 199706f2543Smrg} 200706f2543Smrg 201706f2543Smrg/* 202706f2543Smrg * Copy or flip back to front, honoring the swap interval if possible. 203706f2543Smrg * 204706f2543Smrg * If the kernel supports it, we request an event for the frame when the 205706f2543Smrg * swap should happen, then perform the copy when we receive it. 206706f2543Smrg */ 207706f2543Smrgstatic GLboolean 208706f2543Smrg__glXDRIdrawableSwapBuffers(ClientPtr client, __GLXdrawable *drawable) 209706f2543Smrg{ 210706f2543Smrg __GLXDRIdrawable *priv = (__GLXDRIdrawable *) drawable; 211706f2543Smrg __GLXDRIscreen *screen = priv->screen; 212706f2543Smrg CARD64 unused; 213706f2543Smrg 214706f2543Smrg#if __DRI2_FLUSH_VERSION >= 3 215706f2543Smrg if (screen->flush) { 216706f2543Smrg (*screen->flush->flush)(priv->driDrawable); 217706f2543Smrg (*screen->flush->invalidate)(priv->driDrawable); 218706f2543Smrg } 219706f2543Smrg#else 220706f2543Smrg if (screen->flush) 221706f2543Smrg (*screen->flush->flushInvalidate)(priv->driDrawable); 222706f2543Smrg#endif 223706f2543Smrg 224706f2543Smrg if (DRI2SwapBuffers(client, drawable->pDraw, 0, 0, 0, &unused, 225706f2543Smrg __glXdriSwapEvent, drawable->pDraw) != Success) 226706f2543Smrg return FALSE; 227706f2543Smrg 228706f2543Smrg return TRUE; 229706f2543Smrg} 230706f2543Smrg 231706f2543Smrgstatic int 232706f2543Smrg__glXDRIdrawableSwapInterval(__GLXdrawable *drawable, int interval) 233706f2543Smrg{ 234706f2543Smrg if (interval <= 0) /* || interval > BIGNUM? */ 235706f2543Smrg return GLX_BAD_VALUE; 236706f2543Smrg 237706f2543Smrg DRI2SwapInterval(drawable->pDraw, interval); 238706f2543Smrg 239706f2543Smrg return 0; 240706f2543Smrg} 241706f2543Smrg 242706f2543Smrgstatic void 243706f2543Smrg__glXDRIcontextDestroy(__GLXcontext *baseContext) 244706f2543Smrg{ 245706f2543Smrg __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; 246706f2543Smrg __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; 247706f2543Smrg 248706f2543Smrg (*screen->core->destroyContext)(context->driContext); 249706f2543Smrg __glXContextDestroy(&context->base); 250706f2543Smrg free(context); 251706f2543Smrg} 252706f2543Smrg 253706f2543Smrgstatic int 254706f2543Smrg__glXDRIcontextMakeCurrent(__GLXcontext *baseContext) 255706f2543Smrg{ 256706f2543Smrg __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; 257706f2543Smrg __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseContext->drawPriv; 258706f2543Smrg __GLXDRIdrawable *read = (__GLXDRIdrawable *) baseContext->readPriv; 259706f2543Smrg __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; 260706f2543Smrg 261706f2543Smrg return (*screen->core->bindContext)(context->driContext, 262706f2543Smrg draw->driDrawable, 263706f2543Smrg read->driDrawable); 264706f2543Smrg} 265706f2543Smrg 266706f2543Smrgstatic int 267706f2543Smrg__glXDRIcontextLoseCurrent(__GLXcontext *baseContext) 268706f2543Smrg{ 269706f2543Smrg __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; 270706f2543Smrg __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; 271706f2543Smrg 272706f2543Smrg return (*screen->core->unbindContext)(context->driContext); 273706f2543Smrg} 274706f2543Smrg 275706f2543Smrgstatic int 276706f2543Smrg__glXDRIcontextCopy(__GLXcontext *baseDst, __GLXcontext *baseSrc, 277706f2543Smrg unsigned long mask) 278706f2543Smrg{ 279706f2543Smrg __GLXDRIcontext *dst = (__GLXDRIcontext *) baseDst; 280706f2543Smrg __GLXDRIcontext *src = (__GLXDRIcontext *) baseSrc; 281706f2543Smrg __GLXDRIscreen *screen = (__GLXDRIscreen *) dst->base.pGlxScreen; 282706f2543Smrg 283706f2543Smrg return (*screen->core->copyContext)(dst->driContext, 284706f2543Smrg src->driContext, mask); 285706f2543Smrg} 286706f2543Smrg 287706f2543Smrgstatic int 288706f2543Smrg__glXDRIcontextForceCurrent(__GLXcontext *baseContext) 289706f2543Smrg{ 290706f2543Smrg __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; 291706f2543Smrg __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseContext->drawPriv; 292706f2543Smrg __GLXDRIdrawable *read = (__GLXDRIdrawable *) baseContext->readPriv; 293706f2543Smrg __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; 294706f2543Smrg 295706f2543Smrg return (*screen->core->bindContext)(context->driContext, 296706f2543Smrg draw->driDrawable, 297706f2543Smrg read->driDrawable); 298706f2543Smrg} 299706f2543Smrg 300706f2543Smrgstatic Bool 301706f2543Smrg__glXDRIcontextWait(__GLXcontext *baseContext, 302706f2543Smrg __GLXclientState *cl, int *error) 303706f2543Smrg{ 304706f2543Smrg if (DRI2WaitSwap(cl->client, baseContext->drawPriv->pDraw)) { 305706f2543Smrg *error = cl->client->noClientException; 306706f2543Smrg return TRUE; 307706f2543Smrg } 308706f2543Smrg 309706f2543Smrg return FALSE; 310706f2543Smrg} 311706f2543Smrg 312706f2543Smrg#ifdef __DRI_TEX_BUFFER 313706f2543Smrg 314706f2543Smrgstatic int 315706f2543Smrg__glXDRIbindTexImage(__GLXcontext *baseContext, 316706f2543Smrg int buffer, 317706f2543Smrg __GLXdrawable *glxPixmap) 318706f2543Smrg{ 319706f2543Smrg __GLXDRIdrawable *drawable = (__GLXDRIdrawable *) glxPixmap; 320706f2543Smrg const __DRItexBufferExtension *texBuffer = drawable->screen->texBuffer; 321706f2543Smrg __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; 322706f2543Smrg 323706f2543Smrg if (texBuffer == NULL) 324706f2543Smrg return Success; 325706f2543Smrg 326706f2543Smrg#if __DRI_TEX_BUFFER_VERSION >= 2 327706f2543Smrg if (texBuffer->base.version >= 2 && texBuffer->setTexBuffer2 != NULL) { 328706f2543Smrg (*texBuffer->setTexBuffer2)(context->driContext, 329706f2543Smrg glxPixmap->target, 330706f2543Smrg glxPixmap->format, 331706f2543Smrg drawable->driDrawable); 332706f2543Smrg } else 333706f2543Smrg#endif 334706f2543Smrg { 335706f2543Smrg texBuffer->setTexBuffer(context->driContext, 336706f2543Smrg glxPixmap->target, 337706f2543Smrg drawable->driDrawable); 338706f2543Smrg } 339706f2543Smrg 340706f2543Smrg return Success; 341706f2543Smrg} 342706f2543Smrg 343706f2543Smrgstatic int 344706f2543Smrg__glXDRIreleaseTexImage(__GLXcontext *baseContext, 345706f2543Smrg int buffer, 346706f2543Smrg __GLXdrawable *pixmap) 347706f2543Smrg{ 348706f2543Smrg /* FIXME: Just unbind the texture? */ 349706f2543Smrg return Success; 350706f2543Smrg} 351706f2543Smrg 352706f2543Smrg#else 353706f2543Smrg 354706f2543Smrgstatic int 355706f2543Smrg__glXDRIbindTexImage(__GLXcontext *baseContext, 356706f2543Smrg int buffer, 357706f2543Smrg __GLXdrawable *glxPixmap) 358706f2543Smrg{ 359706f2543Smrg return Success; 360706f2543Smrg} 361706f2543Smrg 362706f2543Smrgstatic int 363706f2543Smrg__glXDRIreleaseTexImage(__GLXcontext *baseContext, 364706f2543Smrg int buffer, 365706f2543Smrg __GLXdrawable *pixmap) 366706f2543Smrg{ 367706f2543Smrg return Success; 368706f2543Smrg} 369706f2543Smrg 370706f2543Smrg#endif 371706f2543Smrg 372706f2543Smrgstatic __GLXtextureFromPixmap __glXDRItextureFromPixmap = { 373706f2543Smrg __glXDRIbindTexImage, 374706f2543Smrg __glXDRIreleaseTexImage 375706f2543Smrg}; 376706f2543Smrg 377706f2543Smrgstatic void 378706f2543Smrg__glXDRIscreenDestroy(__GLXscreen *baseScreen) 379706f2543Smrg{ 380706f2543Smrg __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen; 381706f2543Smrg 382706f2543Smrg (*screen->core->destroyScreen)(screen->driScreen); 383706f2543Smrg 384706f2543Smrg dlclose(screen->driver); 385706f2543Smrg 386706f2543Smrg __glXScreenDestroy(baseScreen); 387706f2543Smrg 388706f2543Smrg free(screen); 389706f2543Smrg} 390706f2543Smrg 391706f2543Smrgstatic __GLXcontext * 392706f2543Smrg__glXDRIscreenCreateContext(__GLXscreen *baseScreen, 393706f2543Smrg __GLXconfig *glxConfig, 394706f2543Smrg __GLXcontext *baseShareContext) 395706f2543Smrg{ 396706f2543Smrg __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen; 397706f2543Smrg __GLXDRIcontext *context, *shareContext; 398706f2543Smrg __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig; 399706f2543Smrg __DRIcontext *driShare; 400706f2543Smrg 401706f2543Smrg shareContext = (__GLXDRIcontext *) baseShareContext; 402706f2543Smrg if (shareContext) 403706f2543Smrg driShare = shareContext->driContext; 404706f2543Smrg else 405706f2543Smrg driShare = NULL; 406706f2543Smrg 407706f2543Smrg context = calloc(1, sizeof *context); 408706f2543Smrg if (context == NULL) 409706f2543Smrg return NULL; 410706f2543Smrg 411706f2543Smrg context->base.destroy = __glXDRIcontextDestroy; 412706f2543Smrg context->base.makeCurrent = __glXDRIcontextMakeCurrent; 413706f2543Smrg context->base.loseCurrent = __glXDRIcontextLoseCurrent; 414706f2543Smrg context->base.copy = __glXDRIcontextCopy; 415706f2543Smrg context->base.forceCurrent = __glXDRIcontextForceCurrent; 416706f2543Smrg context->base.textureFromPixmap = &__glXDRItextureFromPixmap; 417706f2543Smrg context->base.wait = __glXDRIcontextWait; 418706f2543Smrg 419706f2543Smrg context->driContext = 420706f2543Smrg (*screen->dri2->createNewContext)(screen->driScreen, 421706f2543Smrg config->driConfig, 422706f2543Smrg driShare, context); 423706f2543Smrg if (context->driContext == NULL) { 424706f2543Smrg free(context); 425706f2543Smrg return NULL; 426706f2543Smrg } 427706f2543Smrg 428706f2543Smrg return &context->base; 429706f2543Smrg} 430706f2543Smrg 431706f2543Smrgstatic void 432706f2543Smrg__glXDRIinvalidateBuffers(DrawablePtr pDraw, void *priv) 433706f2543Smrg{ 434706f2543Smrg#if __DRI2_FLUSH_VERSION >= 3 435706f2543Smrg __GLXDRIdrawable *private = priv; 436706f2543Smrg __GLXDRIscreen *screen = private->screen; 437706f2543Smrg 438706f2543Smrg if (screen->flush) 439706f2543Smrg (*screen->flush->invalidate)(private->driDrawable); 440706f2543Smrg#endif 441706f2543Smrg} 442706f2543Smrg 443706f2543Smrgstatic __GLXdrawable * 444706f2543Smrg__glXDRIscreenCreateDrawable(ClientPtr client, 445706f2543Smrg __GLXscreen *screen, 446706f2543Smrg DrawablePtr pDraw, 447706f2543Smrg XID drawId, 448706f2543Smrg int type, 449706f2543Smrg XID glxDrawId, 450706f2543Smrg __GLXconfig *glxConfig) 451706f2543Smrg{ 452706f2543Smrg __GLXDRIscreen *driScreen = (__GLXDRIscreen *) screen; 453706f2543Smrg __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig; 454706f2543Smrg __GLXDRIdrawable *private; 455706f2543Smrg 456706f2543Smrg private = calloc(1, sizeof *private); 457706f2543Smrg if (private == NULL) 458706f2543Smrg return NULL; 459706f2543Smrg 460706f2543Smrg private->screen = driScreen; 461706f2543Smrg if (!__glXDrawableInit(&private->base, screen, 462706f2543Smrg pDraw, type, glxDrawId, glxConfig)) { 463706f2543Smrg free(private); 464706f2543Smrg return NULL; 465706f2543Smrg } 466706f2543Smrg 467706f2543Smrg private->base.destroy = __glXDRIdrawableDestroy; 468706f2543Smrg private->base.swapBuffers = __glXDRIdrawableSwapBuffers; 469706f2543Smrg private->base.copySubBuffer = __glXDRIdrawableCopySubBuffer; 470706f2543Smrg private->base.waitGL = __glXDRIdrawableWaitGL; 471706f2543Smrg private->base.waitX = __glXDRIdrawableWaitX; 472706f2543Smrg 473706f2543Smrg if (DRI2CreateDrawable(client, pDraw, drawId, 474706f2543Smrg __glXDRIinvalidateBuffers, private)) { 475706f2543Smrg free(private); 476706f2543Smrg return NULL; 477706f2543Smrg } 478706f2543Smrg 479706f2543Smrg private->driDrawable = 480706f2543Smrg (*driScreen->dri2->createNewDrawable)(driScreen->driScreen, 481706f2543Smrg config->driConfig, private); 482706f2543Smrg 483706f2543Smrg return &private->base; 484706f2543Smrg} 485706f2543Smrg 486706f2543Smrgstatic __DRIbuffer * 487706f2543Smrgdri2GetBuffers(__DRIdrawable *driDrawable, 488706f2543Smrg int *width, int *height, 489706f2543Smrg unsigned int *attachments, int count, 490706f2543Smrg int *out_count, void *loaderPrivate) 491706f2543Smrg{ 492706f2543Smrg __GLXDRIdrawable *private = loaderPrivate; 493706f2543Smrg DRI2BufferPtr *buffers; 494706f2543Smrg int i; 495706f2543Smrg int j; 496706f2543Smrg 497706f2543Smrg buffers = DRI2GetBuffers(private->base.pDraw, 498706f2543Smrg width, height, attachments, count, out_count); 499706f2543Smrg if (*out_count > MAX_DRAWABLE_BUFFERS) { 500706f2543Smrg *out_count = 0; 501706f2543Smrg return NULL; 502706f2543Smrg } 503706f2543Smrg 504706f2543Smrg private->width = *width; 505706f2543Smrg private->height = *height; 506706f2543Smrg 507706f2543Smrg /* This assumes the DRI2 buffer attachment tokens matches the 508706f2543Smrg * __DRIbuffer tokens. */ 509706f2543Smrg j = 0; 510706f2543Smrg for (i = 0; i < *out_count; i++) { 511706f2543Smrg /* Do not send the real front buffer of a window to the client. 512706f2543Smrg */ 513706f2543Smrg if ((private->base.pDraw->type == DRAWABLE_WINDOW) 514706f2543Smrg && (buffers[i]->attachment == DRI2BufferFrontLeft)) { 515706f2543Smrg continue; 516706f2543Smrg } 517706f2543Smrg 518706f2543Smrg private->buffers[j].attachment = buffers[i]->attachment; 519706f2543Smrg private->buffers[j].name = buffers[i]->name; 520706f2543Smrg private->buffers[j].pitch = buffers[i]->pitch; 521706f2543Smrg private->buffers[j].cpp = buffers[i]->cpp; 522706f2543Smrg private->buffers[j].flags = buffers[i]->flags; 523706f2543Smrg j++; 524706f2543Smrg } 525706f2543Smrg 526706f2543Smrg *out_count = j; 527706f2543Smrg return private->buffers; 528706f2543Smrg} 529706f2543Smrg 530706f2543Smrgstatic __DRIbuffer * 531706f2543Smrgdri2GetBuffersWithFormat(__DRIdrawable *driDrawable, 532706f2543Smrg int *width, int *height, 533706f2543Smrg unsigned int *attachments, int count, 534706f2543Smrg int *out_count, void *loaderPrivate) 535706f2543Smrg{ 536706f2543Smrg __GLXDRIdrawable *private = loaderPrivate; 537706f2543Smrg DRI2BufferPtr *buffers; 538706f2543Smrg int i; 539706f2543Smrg int j = 0; 540706f2543Smrg 541706f2543Smrg buffers = DRI2GetBuffersWithFormat(private->base.pDraw, 542706f2543Smrg width, height, attachments, count, 543706f2543Smrg out_count); 544706f2543Smrg if (*out_count > MAX_DRAWABLE_BUFFERS) { 545706f2543Smrg *out_count = 0; 546706f2543Smrg return NULL; 547706f2543Smrg } 548706f2543Smrg 549706f2543Smrg private->width = *width; 550706f2543Smrg private->height = *height; 551706f2543Smrg 552706f2543Smrg /* This assumes the DRI2 buffer attachment tokens matches the 553706f2543Smrg * __DRIbuffer tokens. */ 554706f2543Smrg for (i = 0; i < *out_count; i++) { 555706f2543Smrg /* Do not send the real front buffer of a window to the client. 556706f2543Smrg */ 557706f2543Smrg if ((private->base.pDraw->type == DRAWABLE_WINDOW) 558706f2543Smrg && (buffers[i]->attachment == DRI2BufferFrontLeft)) { 559706f2543Smrg continue; 560706f2543Smrg } 561706f2543Smrg 562706f2543Smrg private->buffers[j].attachment = buffers[i]->attachment; 563706f2543Smrg private->buffers[j].name = buffers[i]->name; 564706f2543Smrg private->buffers[j].pitch = buffers[i]->pitch; 565706f2543Smrg private->buffers[j].cpp = buffers[i]->cpp; 566706f2543Smrg private->buffers[j].flags = buffers[i]->flags; 567706f2543Smrg j++; 568706f2543Smrg } 569706f2543Smrg 570706f2543Smrg *out_count = j; 571706f2543Smrg return private->buffers; 572706f2543Smrg} 573706f2543Smrg 574706f2543Smrgstatic void 575706f2543Smrgdri2FlushFrontBuffer(__DRIdrawable *driDrawable, void *loaderPrivate) 576706f2543Smrg{ 577706f2543Smrg (void) driDrawable; 578706f2543Smrg __glXDRIdrawableWaitGL((__GLXdrawable *) loaderPrivate); 579706f2543Smrg} 580706f2543Smrg 581706f2543Smrgstatic const __DRIdri2LoaderExtension loaderExtension = { 582706f2543Smrg { __DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION }, 583706f2543Smrg dri2GetBuffers, 584706f2543Smrg dri2FlushFrontBuffer, 585706f2543Smrg dri2GetBuffersWithFormat, 586706f2543Smrg}; 587706f2543Smrg 588706f2543Smrg#ifdef __DRI_USE_INVALIDATE 589706f2543Smrgstatic const __DRIuseInvalidateExtension dri2UseInvalidate = { 590706f2543Smrg { __DRI_USE_INVALIDATE, __DRI_USE_INVALIDATE_VERSION } 591706f2543Smrg}; 592706f2543Smrg#endif 593706f2543Smrg 594706f2543Smrgstatic const __DRIextension *loader_extensions[] = { 595706f2543Smrg &systemTimeExtension.base, 596706f2543Smrg &loaderExtension.base, 597706f2543Smrg#ifdef __DRI_USE_INVALIDATE 598706f2543Smrg &dri2UseInvalidate.base, 599706f2543Smrg#endif 600706f2543Smrg NULL 601706f2543Smrg}; 602706f2543Smrg 603706f2543Smrgstatic const char dri_driver_path[] = DRI_DRIVER_PATH; 604706f2543Smrg 605706f2543Smrgstatic Bool 606706f2543SmrgglxDRIEnterVT (int index, int flags) 607706f2543Smrg{ 608706f2543Smrg ScrnInfoPtr scrn = xf86Screens[index]; 609706f2543Smrg Bool ret; 610706f2543Smrg __GLXDRIscreen *screen = (__GLXDRIscreen *) 611706f2543Smrg glxGetScreen(screenInfo.screens[index]); 612706f2543Smrg 613706f2543Smrg LogMessage(X_INFO, "AIGLX: Resuming AIGLX clients after VT switch\n"); 614706f2543Smrg 615706f2543Smrg scrn->EnterVT = screen->enterVT; 616706f2543Smrg 617706f2543Smrg ret = scrn->EnterVT (index, flags); 618706f2543Smrg 619706f2543Smrg screen->enterVT = scrn->EnterVT; 620706f2543Smrg scrn->EnterVT = glxDRIEnterVT; 621706f2543Smrg 622706f2543Smrg if (!ret) 623706f2543Smrg return FALSE; 624706f2543Smrg 625706f2543Smrg glxResumeClients(); 626706f2543Smrg 627706f2543Smrg return TRUE; 628706f2543Smrg} 629706f2543Smrg 630706f2543Smrgstatic void 631706f2543SmrgglxDRILeaveVT (int index, int flags) 632706f2543Smrg{ 633706f2543Smrg ScrnInfoPtr scrn = xf86Screens[index]; 634706f2543Smrg __GLXDRIscreen *screen = (__GLXDRIscreen *) 635706f2543Smrg glxGetScreen(screenInfo.screens[index]); 636706f2543Smrg 637706f2543Smrg LogMessage(X_INFO, "AIGLX: Suspending AIGLX clients for VT switch\n"); 638706f2543Smrg 639706f2543Smrg glxSuspendClients(); 640706f2543Smrg 641706f2543Smrg scrn->LeaveVT = screen->leaveVT; 642706f2543Smrg (*screen->leaveVT) (index, flags); 643706f2543Smrg screen->leaveVT = scrn->LeaveVT; 644706f2543Smrg scrn->LeaveVT = glxDRILeaveVT; 645706f2543Smrg} 646706f2543Smrg 647706f2543Smrgstatic void 648706f2543SmrginitializeExtensions(__GLXDRIscreen *screen) 649706f2543Smrg{ 650706f2543Smrg ScreenPtr pScreen = screen->base.pScreen; 651706f2543Smrg const __DRIextension **extensions; 652706f2543Smrg int i; 653706f2543Smrg 654706f2543Smrg extensions = screen->core->getExtensions(screen->driScreen); 655706f2543Smrg 656706f2543Smrg __glXEnableExtension(screen->glx_enable_bits, 657706f2543Smrg "GLX_MESA_copy_sub_buffer"); 658706f2543Smrg LogMessage(X_INFO, "AIGLX: enabled GLX_MESA_copy_sub_buffer\n"); 659706f2543Smrg 660706f2543Smrg __glXEnableExtension(screen->glx_enable_bits, "GLX_INTEL_swap_event"); 661706f2543Smrg LogMessage(X_INFO, "AIGLX: enabled GLX_INTEL_swap_event\n"); 662706f2543Smrg 663706f2543Smrg if (DRI2HasSwapControl(pScreen)) { 664706f2543Smrg __glXEnableExtension(screen->glx_enable_bits, 665706f2543Smrg "GLX_SGI_swap_control"); 666706f2543Smrg __glXEnableExtension(screen->glx_enable_bits, 667706f2543Smrg "GLX_MESA_swap_control"); 668706f2543Smrg LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_swap_control and GLX_MESA_swap_control\n"); 669706f2543Smrg } 670706f2543Smrg 671706f2543Smrg for (i = 0; extensions[i]; i++) { 672706f2543Smrg#ifdef __DRI_READ_DRAWABLE 673706f2543Smrg if (strcmp(extensions[i]->name, __DRI_READ_DRAWABLE) == 0) { 674706f2543Smrg __glXEnableExtension(screen->glx_enable_bits, 675706f2543Smrg "GLX_SGI_make_current_read"); 676706f2543Smrg 677706f2543Smrg LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_make_current_read\n"); 678706f2543Smrg } 679706f2543Smrg#endif 680706f2543Smrg 681706f2543Smrg#ifdef __DRI_TEX_BUFFER 682706f2543Smrg if (strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0) { 683706f2543Smrg screen->texBuffer = 684706f2543Smrg (const __DRItexBufferExtension *) extensions[i]; 685706f2543Smrg /* GLX_EXT_texture_from_pixmap is always enabled. */ 686706f2543Smrg LogMessage(X_INFO, "AIGLX: GLX_EXT_texture_from_pixmap backed by buffer objects\n"); 687706f2543Smrg } 688706f2543Smrg#endif 689706f2543Smrg 690706f2543Smrg#ifdef __DRI2_FLUSH 691706f2543Smrg if (strcmp(extensions[i]->name, __DRI2_FLUSH) == 0 && 692706f2543Smrg extensions[i]->version >= 3) { 693706f2543Smrg screen->flush = (__DRI2flushExtension *) extensions[i]; 694706f2543Smrg } 695706f2543Smrg#endif 696706f2543Smrg 697706f2543Smrg /* Ignore unknown extensions */ 698706f2543Smrg } 699706f2543Smrg} 700706f2543Smrg 701706f2543Smrgstatic __GLXscreen * 702706f2543Smrg__glXDRIscreenProbe(ScreenPtr pScreen) 703706f2543Smrg{ 704706f2543Smrg const char *driverName, *deviceName; 705706f2543Smrg __GLXDRIscreen *screen; 706706f2543Smrg char filename[128]; 707706f2543Smrg size_t buffer_size; 708706f2543Smrg ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 709706f2543Smrg const __DRIextension **extensions; 710706f2543Smrg const __DRIconfig **driConfigs; 711706f2543Smrg int i; 712706f2543Smrg 713706f2543Smrg screen = calloc(1, sizeof *screen); 714706f2543Smrg if (screen == NULL) 715706f2543Smrg return NULL; 716706f2543Smrg 717706f2543Smrg if (!xf86LoaderCheckSymbol("DRI2Connect") || 718706f2543Smrg !DRI2Connect(pScreen, DRI2DriverDRI, 719706f2543Smrg &screen->fd, &driverName, &deviceName)) { 720706f2543Smrg LogMessage(X_INFO, 721706f2543Smrg "AIGLX: Screen %d is not DRI2 capable\n", pScreen->myNum); 722706f2543Smrg return NULL; 723706f2543Smrg } 724706f2543Smrg 725706f2543Smrg screen->base.destroy = __glXDRIscreenDestroy; 726706f2543Smrg screen->base.createContext = __glXDRIscreenCreateContext; 727706f2543Smrg screen->base.createDrawable = __glXDRIscreenCreateDrawable; 728706f2543Smrg screen->base.swapInterval = __glXDRIdrawableSwapInterval; 729706f2543Smrg screen->base.pScreen = pScreen; 730706f2543Smrg 731706f2543Smrg __glXInitExtensionEnableBits(screen->glx_enable_bits); 732706f2543Smrg 733706f2543Smrg snprintf(filename, sizeof filename, 734706f2543Smrg "%s/%s_dri.so", dri_driver_path, driverName); 735706f2543Smrg 736706f2543Smrg screen->driver = dlopen(filename, RTLD_LAZY | RTLD_LOCAL); 737706f2543Smrg if (screen->driver == NULL) { 738706f2543Smrg LogMessage(X_ERROR, "AIGLX error: dlopen of %s failed (%s)\n", 739706f2543Smrg filename, dlerror()); 740706f2543Smrg goto handle_error; 741706f2543Smrg } 742706f2543Smrg 743706f2543Smrg extensions = dlsym(screen->driver, __DRI_DRIVER_EXTENSIONS); 744706f2543Smrg if (extensions == NULL) { 745706f2543Smrg LogMessage(X_ERROR, "AIGLX error: %s exports no extensions (%s)\n", 746706f2543Smrg driverName, dlerror()); 747706f2543Smrg goto handle_error; 748706f2543Smrg } 749706f2543Smrg 750706f2543Smrg for (i = 0; extensions[i]; i++) { 751706f2543Smrg if (strcmp(extensions[i]->name, __DRI_CORE) == 0 && 752706f2543Smrg extensions[i]->version >= 1) { 753706f2543Smrg screen->core = (const __DRIcoreExtension *) extensions[i]; 754706f2543Smrg } 755706f2543Smrg if (strcmp(extensions[i]->name, __DRI_DRI2) == 0 && 756706f2543Smrg extensions[i]->version >= 1) { 757706f2543Smrg screen->dri2 = (const __DRIdri2Extension *) extensions[i]; 758706f2543Smrg } 759706f2543Smrg } 760706f2543Smrg 761706f2543Smrg if (screen->core == NULL || screen->dri2 == NULL) { 762706f2543Smrg LogMessage(X_ERROR, "AIGLX error: %s exports no DRI extension\n", 763706f2543Smrg driverName); 764706f2543Smrg goto handle_error; 765706f2543Smrg } 766706f2543Smrg 767706f2543Smrg screen->driScreen = 768706f2543Smrg (*screen->dri2->createNewScreen)(pScreen->myNum, 769706f2543Smrg screen->fd, 770706f2543Smrg loader_extensions, 771706f2543Smrg &driConfigs, 772706f2543Smrg screen); 773706f2543Smrg 774706f2543Smrg if (screen->driScreen == NULL) { 775706f2543Smrg LogMessage(X_ERROR, 776706f2543Smrg "AIGLX error: Calling driver entry point failed\n"); 777706f2543Smrg goto handle_error; 778706f2543Smrg } 779706f2543Smrg 780706f2543Smrg initializeExtensions(screen); 781706f2543Smrg 782706f2543Smrg screen->base.fbconfigs = glxConvertConfigs(screen->core, driConfigs, 783706f2543Smrg GLX_WINDOW_BIT | 784706f2543Smrg GLX_PIXMAP_BIT | 785706f2543Smrg GLX_PBUFFER_BIT); 786706f2543Smrg 787706f2543Smrg __glXScreenInit(&screen->base, pScreen); 788706f2543Smrg 789706f2543Smrg /* The first call simply determines the length of the extension string. 790706f2543Smrg * This allows us to allocate some memory to hold the extension string, 791706f2543Smrg * but it requires that we call __glXGetExtensionString a second time. 792706f2543Smrg */ 793706f2543Smrg buffer_size = __glXGetExtensionString(screen->glx_enable_bits, NULL); 794706f2543Smrg if (buffer_size > 0) { 795706f2543Smrg free(screen->base.GLXextensions); 796706f2543Smrg 797706f2543Smrg screen->base.GLXextensions = xnfalloc(buffer_size); 798706f2543Smrg (void) __glXGetExtensionString(screen->glx_enable_bits, 799706f2543Smrg screen->base.GLXextensions); 800706f2543Smrg } 801706f2543Smrg 802706f2543Smrg /* We're going to assume (perhaps incorrectly?) that all DRI2-enabled 803706f2543Smrg * drivers support the required extensions for GLX 1.4. The extensions 804706f2543Smrg * we're assuming are: 805706f2543Smrg * 806706f2543Smrg * - GLX_SGI_make_current_read (1.3) 807706f2543Smrg * - GLX_SGIX_fbconfig (1.3) 808706f2543Smrg * - GLX_SGIX_pbuffer (1.3) 809706f2543Smrg * - GLX_ARB_multisample (1.4) 810706f2543Smrg */ 811706f2543Smrg screen->base.GLXmajor = 1; 812706f2543Smrg screen->base.GLXminor = 4; 813706f2543Smrg 814706f2543Smrg screen->enterVT = pScrn->EnterVT; 815706f2543Smrg pScrn->EnterVT = glxDRIEnterVT; 816706f2543Smrg screen->leaveVT = pScrn->LeaveVT; 817706f2543Smrg pScrn->LeaveVT = glxDRILeaveVT; 818706f2543Smrg 819706f2543Smrg LogMessage(X_INFO, 820706f2543Smrg "AIGLX: Loaded and initialized %s\n", filename); 821706f2543Smrg 822706f2543Smrg return &screen->base; 823706f2543Smrg 824706f2543Smrg handle_error: 825706f2543Smrg if (screen->driver) 826706f2543Smrg dlclose(screen->driver); 827706f2543Smrg 828706f2543Smrg free(screen); 829706f2543Smrg 830706f2543Smrg LogMessage(X_ERROR, "AIGLX: reverting to software rendering\n"); 831706f2543Smrg 832706f2543Smrg return NULL; 833706f2543Smrg} 834706f2543Smrg 835706f2543Smrg_X_EXPORT __GLXprovider __glXDRI2Provider = { 836706f2543Smrg __glXDRIscreenProbe, 837706f2543Smrg "DRI2", 838706f2543Smrg NULL 839706f2543Smrg}; 840