1706f2543Smrg/* 2706f2543Smrg * Copyright © 2007, 2008 Red Hat, Inc. 3706f2543Smrg * 4706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining a 5706f2543Smrg * copy of this software and associated documentation files (the "Soft- 6706f2543Smrg * ware"), to deal in the Software without restriction, including without 7706f2543Smrg * limitation the rights to use, copy, modify, merge, publish, distribute, 8706f2543Smrg * and/or sell copies of the Software, and to permit persons to whom the 9706f2543Smrg * Software is furnished to do so, provided that the above copyright 10706f2543Smrg * notice(s) and this permission notice appear in all copies of the Soft- 11706f2543Smrg * ware and that both the above copyright notice(s) and this permission 12706f2543Smrg * notice appear in supporting documentation. 13706f2543Smrg * 14706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15706f2543Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- 16706f2543Smrg * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY 17706f2543Smrg * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN 18706f2543Smrg * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE- 19706f2543Smrg * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 20706f2543Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 21706f2543Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR- 22706f2543Smrg * MANCE OF THIS SOFTWARE. 23706f2543Smrg * 24706f2543Smrg * Except as contained in this notice, the name of a copyright holder shall 25706f2543Smrg * not be used in advertising or otherwise to promote the sale, use or 26706f2543Smrg * other dealings in this Software without prior written authorization of 27706f2543Smrg * the copyright holder. 28706f2543Smrg * 29706f2543Smrg * Authors: 30706f2543Smrg * Kristian Høgsberg (krh@redhat.com) 31706f2543Smrg */ 32706f2543Smrg 33706f2543Smrg#ifdef HAVE_XORG_CONFIG_H 34706f2543Smrg#include <xorg-config.h> 35706f2543Smrg#endif 36706f2543Smrg 37706f2543Smrg#include <errno.h> 38706f2543Smrg#ifdef WITH_LIBDRM 39706f2543Smrg#include <xf86drm.h> 40706f2543Smrg#endif 41706f2543Smrg#include "xf86Module.h" 42706f2543Smrg#include "list.h" 43706f2543Smrg#include "scrnintstr.h" 44706f2543Smrg#include "windowstr.h" 45706f2543Smrg#include "dixstruct.h" 46706f2543Smrg#include "dri2.h" 47706f2543Smrg#include "xf86VGAarbiter.h" 48706f2543Smrg 49706f2543Smrg#include "xf86.h" 50706f2543Smrg 51706f2543SmrgCARD8 dri2_major; /* version of DRI2 supported by DDX */ 52706f2543SmrgCARD8 dri2_minor; 53706f2543Smrg 54706f2543Smrgstatic DevPrivateKeyRec dri2ScreenPrivateKeyRec; 55706f2543Smrg#define dri2ScreenPrivateKey (&dri2ScreenPrivateKeyRec) 56706f2543Smrg 57706f2543Smrgstatic DevPrivateKeyRec dri2WindowPrivateKeyRec; 58706f2543Smrg#define dri2WindowPrivateKey (&dri2WindowPrivateKeyRec) 59706f2543Smrg 60706f2543Smrgstatic DevPrivateKeyRec dri2PixmapPrivateKeyRec; 61706f2543Smrg#define dri2PixmapPrivateKey (&dri2PixmapPrivateKeyRec) 62706f2543Smrg 63706f2543Smrgstatic RESTYPE dri2DrawableRes; 64706f2543Smrg 65706f2543Smrgtypedef struct _DRI2Screen *DRI2ScreenPtr; 66706f2543Smrg 67706f2543Smrgtypedef struct _DRI2Drawable { 68706f2543Smrg DRI2ScreenPtr dri2_screen; 69706f2543Smrg DrawablePtr drawable; 70706f2543Smrg struct list reference_list; 71706f2543Smrg int width; 72706f2543Smrg int height; 73706f2543Smrg DRI2BufferPtr *buffers; 74706f2543Smrg int bufferCount; 75706f2543Smrg unsigned int swapsPending; 76706f2543Smrg ClientPtr blockedClient; 77706f2543Smrg Bool blockedOnMsc; 78706f2543Smrg int swap_interval; 79706f2543Smrg CARD64 swap_count; 80706f2543Smrg int64_t target_sbc; /* -1 means no SBC wait outstanding */ 81706f2543Smrg CARD64 last_swap_target; /* most recently queued swap target */ 82706f2543Smrg CARD64 last_swap_msc; /* msc at completion of most recent swap */ 83706f2543Smrg CARD64 last_swap_ust; /* ust at completion of most recent swap */ 84706f2543Smrg int swap_limit; /* for N-buffering */ 85706f2543Smrg unsigned long serialNumber; 86706f2543Smrg} DRI2DrawableRec, *DRI2DrawablePtr; 87706f2543Smrg 88706f2543Smrgtypedef struct _DRI2Screen { 89706f2543Smrg ScreenPtr screen; 90706f2543Smrg int refcnt; 91706f2543Smrg unsigned int numDrivers; 92706f2543Smrg const char **driverNames; 93706f2543Smrg const char *deviceName; 94706f2543Smrg int fd; 95706f2543Smrg unsigned int lastSequence; 96706f2543Smrg 97706f2543Smrg DRI2CreateBufferProcPtr CreateBuffer; 98706f2543Smrg DRI2DestroyBufferProcPtr DestroyBuffer; 99706f2543Smrg DRI2CopyRegionProcPtr CopyRegion; 100706f2543Smrg DRI2ScheduleSwapProcPtr ScheduleSwap; 101706f2543Smrg DRI2GetMSCProcPtr GetMSC; 102706f2543Smrg DRI2ScheduleWaitMSCProcPtr ScheduleWaitMSC; 103706f2543Smrg DRI2AuthMagicProcPtr AuthMagic; 104706f2543Smrg 105706f2543Smrg HandleExposuresProcPtr HandleExposures; 106706f2543Smrg 107706f2543Smrg ConfigNotifyProcPtr ConfigNotify; 108706f2543Smrg} DRI2ScreenRec; 109706f2543Smrg 110706f2543Smrgstatic DRI2ScreenPtr 111706f2543SmrgDRI2GetScreen(ScreenPtr pScreen) 112706f2543Smrg{ 113706f2543Smrg return dixLookupPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey); 114706f2543Smrg} 115706f2543Smrg 116706f2543Smrgstatic DRI2DrawablePtr 117706f2543SmrgDRI2GetDrawable(DrawablePtr pDraw) 118706f2543Smrg{ 119706f2543Smrg WindowPtr pWin; 120706f2543Smrg PixmapPtr pPixmap; 121706f2543Smrg 122706f2543Smrg switch (pDraw->type) { 123706f2543Smrg case DRAWABLE_WINDOW: 124706f2543Smrg pWin = (WindowPtr) pDraw; 125706f2543Smrg return dixLookupPrivate(&pWin->devPrivates, dri2WindowPrivateKey); 126706f2543Smrg case DRAWABLE_PIXMAP: 127706f2543Smrg pPixmap = (PixmapPtr) pDraw; 128706f2543Smrg return dixLookupPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey); 129706f2543Smrg default: 130706f2543Smrg return NULL; 131706f2543Smrg } 132706f2543Smrg} 133706f2543Smrg 134706f2543Smrgstatic unsigned long 135706f2543SmrgDRI2DrawableSerial(DrawablePtr pDraw) 136706f2543Smrg{ 137706f2543Smrg ScreenPtr pScreen = pDraw->pScreen; 138706f2543Smrg PixmapPtr pPix; 139706f2543Smrg 140706f2543Smrg if (pDraw->type != DRAWABLE_WINDOW) 141706f2543Smrg return pDraw->serialNumber; 142706f2543Smrg 143706f2543Smrg pPix = pScreen->GetWindowPixmap((WindowPtr)pDraw); 144706f2543Smrg return pPix->drawable.serialNumber; 145706f2543Smrg} 146706f2543Smrg 147706f2543Smrgstatic DRI2DrawablePtr 148706f2543SmrgDRI2AllocateDrawable(DrawablePtr pDraw) 149706f2543Smrg{ 150706f2543Smrg DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); 151706f2543Smrg DRI2DrawablePtr pPriv; 152706f2543Smrg CARD64 ust; 153706f2543Smrg WindowPtr pWin; 154706f2543Smrg PixmapPtr pPixmap; 155706f2543Smrg 156706f2543Smrg pPriv = malloc(sizeof *pPriv); 157706f2543Smrg if (pPriv == NULL) 158706f2543Smrg return NULL; 159706f2543Smrg 160706f2543Smrg pPriv->dri2_screen = ds; 161706f2543Smrg pPriv->drawable = pDraw; 162706f2543Smrg pPriv->width = pDraw->width; 163706f2543Smrg pPriv->height = pDraw->height; 164706f2543Smrg pPriv->buffers = NULL; 165706f2543Smrg pPriv->bufferCount = 0; 166706f2543Smrg pPriv->swapsPending = 0; 167706f2543Smrg pPriv->blockedClient = NULL; 168706f2543Smrg pPriv->blockedOnMsc = FALSE; 169706f2543Smrg pPriv->swap_count = 0; 170706f2543Smrg pPriv->target_sbc = -1; 171706f2543Smrg pPriv->swap_interval = 1; 172706f2543Smrg /* Initialize last swap target from DDX if possible */ 173706f2543Smrg if (!ds->GetMSC || !(*ds->GetMSC)(pDraw, &ust, &pPriv->last_swap_target)) 174706f2543Smrg pPriv->last_swap_target = 0; 175706f2543Smrg 176706f2543Smrg pPriv->swap_limit = 1; /* default to double buffering */ 177706f2543Smrg pPriv->last_swap_msc = 0; 178706f2543Smrg pPriv->last_swap_ust = 0; 179706f2543Smrg list_init(&pPriv->reference_list); 180706f2543Smrg pPriv->serialNumber = DRI2DrawableSerial(pDraw); 181706f2543Smrg 182706f2543Smrg if (pDraw->type == DRAWABLE_WINDOW) { 183706f2543Smrg pWin = (WindowPtr) pDraw; 184706f2543Smrg dixSetPrivate(&pWin->devPrivates, dri2WindowPrivateKey, pPriv); 185706f2543Smrg } else { 186706f2543Smrg pPixmap = (PixmapPtr) pDraw; 187706f2543Smrg dixSetPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey, pPriv); 188706f2543Smrg } 189706f2543Smrg 190706f2543Smrg return pPriv; 191706f2543Smrg} 192706f2543Smrg 193706f2543Smrgtypedef struct DRI2DrawableRefRec { 194706f2543Smrg XID id; 195706f2543Smrg XID dri2_id; 196706f2543Smrg DRI2InvalidateProcPtr invalidate; 197706f2543Smrg void *priv; 198706f2543Smrg struct list link; 199706f2543Smrg} DRI2DrawableRefRec, *DRI2DrawableRefPtr; 200706f2543Smrg 201706f2543Smrgstatic DRI2DrawableRefPtr 202706f2543SmrgDRI2LookupDrawableRef(DRI2DrawablePtr pPriv, XID id) 203706f2543Smrg{ 204706f2543Smrg DRI2DrawableRefPtr ref = NULL; 205706f2543Smrg 206706f2543Smrg list_for_each_entry(ref, &pPriv->reference_list, link) { 207706f2543Smrg if (ref->id == id) 208706f2543Smrg return ref; 209706f2543Smrg } 210706f2543Smrg 211706f2543Smrg return NULL; 212706f2543Smrg} 213706f2543Smrg 214706f2543Smrgstatic int 215706f2543SmrgDRI2AddDrawableRef(DRI2DrawablePtr pPriv, XID id, XID dri2_id, 216706f2543Smrg DRI2InvalidateProcPtr invalidate, void *priv) 217706f2543Smrg{ 218706f2543Smrg DRI2DrawableRefPtr ref; 219706f2543Smrg 220706f2543Smrg ref = malloc(sizeof *ref); 221706f2543Smrg if (ref == NULL) 222706f2543Smrg return BadAlloc; 223706f2543Smrg 224706f2543Smrg if (!AddResource(dri2_id, dri2DrawableRes, pPriv)) { 225706f2543Smrg free(ref); 226706f2543Smrg return BadAlloc; 227706f2543Smrg } 228706f2543Smrg if (!DRI2LookupDrawableRef(pPriv, id)) 229706f2543Smrg if (!AddResource(id, dri2DrawableRes, pPriv)) { 230706f2543Smrg FreeResourceByType(dri2_id, dri2DrawableRes, TRUE); 231706f2543Smrg free(ref); 232706f2543Smrg return BadAlloc; 233706f2543Smrg } 234706f2543Smrg 235706f2543Smrg ref->id = id; 236706f2543Smrg ref->dri2_id = dri2_id; 237706f2543Smrg ref->invalidate = invalidate; 238706f2543Smrg ref->priv = priv; 239706f2543Smrg list_add(&ref->link, &pPriv->reference_list); 240706f2543Smrg 241706f2543Smrg return Success; 242706f2543Smrg} 243706f2543Smrg 244706f2543Smrgint 245706f2543SmrgDRI2CreateDrawable(ClientPtr client, DrawablePtr pDraw, XID id, 246706f2543Smrg DRI2InvalidateProcPtr invalidate, void *priv) 247706f2543Smrg{ 248706f2543Smrg DRI2DrawablePtr pPriv; 249706f2543Smrg XID dri2_id; 250706f2543Smrg int rc; 251706f2543Smrg 252706f2543Smrg pPriv = DRI2GetDrawable(pDraw); 253706f2543Smrg if (pPriv == NULL) 254706f2543Smrg pPriv = DRI2AllocateDrawable(pDraw); 255706f2543Smrg if (pPriv == NULL) 256706f2543Smrg return BadAlloc; 257706f2543Smrg 258706f2543Smrg dri2_id = FakeClientID(client->index); 259706f2543Smrg rc = DRI2AddDrawableRef(pPriv, id, dri2_id, invalidate, priv); 260706f2543Smrg if (rc != Success) 261706f2543Smrg return rc; 262706f2543Smrg 263706f2543Smrg return Success; 264706f2543Smrg} 265706f2543Smrg 266706f2543Smrgstatic int DRI2DrawableGone(pointer p, XID id) 267706f2543Smrg{ 268706f2543Smrg DRI2DrawablePtr pPriv = p; 269706f2543Smrg DRI2ScreenPtr ds = pPriv->dri2_screen; 270706f2543Smrg DRI2DrawableRefPtr ref = NULL, next; 271706f2543Smrg WindowPtr pWin; 272706f2543Smrg PixmapPtr pPixmap; 273706f2543Smrg DrawablePtr pDraw; 274706f2543Smrg int i; 275706f2543Smrg 276706f2543Smrg list_for_each_entry_safe(ref, next, &pPriv->reference_list, link) { 277706f2543Smrg if (ref->dri2_id == id) { 278706f2543Smrg list_del(&ref->link); 279706f2543Smrg /* If this was the last ref under this X drawable XID, 280706f2543Smrg * unregister the X drawable resource. */ 281706f2543Smrg if (!DRI2LookupDrawableRef(pPriv, ref->id)) 282706f2543Smrg FreeResourceByType(ref->id, dri2DrawableRes, TRUE); 283706f2543Smrg free(ref); 284706f2543Smrg break; 285706f2543Smrg } 286706f2543Smrg 287706f2543Smrg if (ref->id == id) { 288706f2543Smrg list_del(&ref->link); 289706f2543Smrg FreeResourceByType(ref->dri2_id, dri2DrawableRes, TRUE); 290706f2543Smrg free(ref); 291706f2543Smrg } 292706f2543Smrg } 293706f2543Smrg 294706f2543Smrg if (!list_is_empty(&pPriv->reference_list)) 295706f2543Smrg return Success; 296706f2543Smrg 297706f2543Smrg pDraw = pPriv->drawable; 298706f2543Smrg if (pDraw->type == DRAWABLE_WINDOW) { 299706f2543Smrg pWin = (WindowPtr) pDraw; 300706f2543Smrg dixSetPrivate(&pWin->devPrivates, dri2WindowPrivateKey, NULL); 301706f2543Smrg } else { 302706f2543Smrg pPixmap = (PixmapPtr) pDraw; 303706f2543Smrg dixSetPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey, NULL); 304706f2543Smrg } 305706f2543Smrg 306706f2543Smrg if (pPriv->buffers != NULL) { 307706f2543Smrg for (i = 0; i < pPriv->bufferCount; i++) 308706f2543Smrg (*ds->DestroyBuffer)(pDraw, pPriv->buffers[i]); 309706f2543Smrg 310706f2543Smrg free(pPriv->buffers); 311706f2543Smrg } 312706f2543Smrg 313706f2543Smrg free(pPriv); 314706f2543Smrg 315706f2543Smrg return Success; 316706f2543Smrg} 317706f2543Smrg 318706f2543Smrgstatic int 319706f2543Smrgfind_attachment(DRI2DrawablePtr pPriv, unsigned attachment) 320706f2543Smrg{ 321706f2543Smrg int i; 322706f2543Smrg 323706f2543Smrg if (pPriv->buffers == NULL) { 324706f2543Smrg return -1; 325706f2543Smrg } 326706f2543Smrg 327706f2543Smrg for (i = 0; i < pPriv->bufferCount; i++) { 328706f2543Smrg if ((pPriv->buffers[i] != NULL) 329706f2543Smrg && (pPriv->buffers[i]->attachment == attachment)) { 330706f2543Smrg return i; 331706f2543Smrg } 332706f2543Smrg } 333706f2543Smrg 334706f2543Smrg return -1; 335706f2543Smrg} 336706f2543Smrg 337706f2543Smrgstatic Bool 338706f2543Smrgallocate_or_reuse_buffer(DrawablePtr pDraw, DRI2ScreenPtr ds, 339706f2543Smrg DRI2DrawablePtr pPriv, 340706f2543Smrg unsigned int attachment, unsigned int format, 341706f2543Smrg int dimensions_match, DRI2BufferPtr *buffer) 342706f2543Smrg{ 343706f2543Smrg int old_buf = find_attachment(pPriv, attachment); 344706f2543Smrg 345706f2543Smrg if ((old_buf < 0) 346706f2543Smrg || !dimensions_match 347706f2543Smrg || (pPriv->buffers[old_buf]->format != format)) { 348706f2543Smrg *buffer = (*ds->CreateBuffer)(pDraw, attachment, format); 349706f2543Smrg pPriv->serialNumber = DRI2DrawableSerial(pDraw); 350706f2543Smrg return TRUE; 351706f2543Smrg 352706f2543Smrg } else { 353706f2543Smrg *buffer = pPriv->buffers[old_buf]; 354706f2543Smrg pPriv->buffers[old_buf] = NULL; 355706f2543Smrg return FALSE; 356706f2543Smrg } 357706f2543Smrg} 358706f2543Smrg 359706f2543Smrgstatic void 360706f2543Smrgupdate_dri2_drawable_buffers(DRI2DrawablePtr pPriv, DrawablePtr pDraw, 361706f2543Smrg DRI2BufferPtr *buffers, int *out_count, int *width, int *height) 362706f2543Smrg{ 363706f2543Smrg DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); 364706f2543Smrg int i; 365706f2543Smrg 366706f2543Smrg if (pPriv->buffers != NULL) { 367706f2543Smrg for (i = 0; i < pPriv->bufferCount; i++) { 368706f2543Smrg if (pPriv->buffers[i] != NULL) { 369706f2543Smrg (*ds->DestroyBuffer)(pDraw, pPriv->buffers[i]); 370706f2543Smrg } 371706f2543Smrg } 372706f2543Smrg 373706f2543Smrg free(pPriv->buffers); 374706f2543Smrg } 375706f2543Smrg 376706f2543Smrg pPriv->buffers = buffers; 377706f2543Smrg pPriv->bufferCount = *out_count; 378706f2543Smrg pPriv->width = pDraw->width; 379706f2543Smrg pPriv->height = pDraw->height; 380706f2543Smrg *width = pPriv->width; 381706f2543Smrg *height = pPriv->height; 382706f2543Smrg} 383706f2543Smrg 384706f2543Smrgstatic DRI2BufferPtr * 385706f2543Smrgdo_get_buffers(DrawablePtr pDraw, int *width, int *height, 386706f2543Smrg unsigned int *attachments, int count, int *out_count, 387706f2543Smrg int has_format) 388706f2543Smrg{ 389706f2543Smrg DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); 390706f2543Smrg DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw); 391706f2543Smrg DRI2BufferPtr *buffers; 392706f2543Smrg int need_real_front = 0; 393706f2543Smrg int need_fake_front = 0; 394706f2543Smrg int have_fake_front = 0; 395706f2543Smrg int front_format = 0; 396706f2543Smrg int dimensions_match; 397706f2543Smrg int buffers_changed = 0; 398706f2543Smrg int i; 399706f2543Smrg 400706f2543Smrg if (!pPriv) { 401706f2543Smrg *width = pDraw->width; 402706f2543Smrg *height = pDraw->height; 403706f2543Smrg *out_count = 0; 404706f2543Smrg return NULL; 405706f2543Smrg } 406706f2543Smrg 407706f2543Smrg dimensions_match = (pDraw->width == pPriv->width) 408706f2543Smrg && (pDraw->height == pPriv->height) 409706f2543Smrg && (pPriv->serialNumber == DRI2DrawableSerial(pDraw)); 410706f2543Smrg 411706f2543Smrg buffers = calloc((count + 1), sizeof(buffers[0])); 412706f2543Smrg 413706f2543Smrg for (i = 0; i < count; i++) { 414706f2543Smrg const unsigned attachment = *(attachments++); 415706f2543Smrg const unsigned format = (has_format) ? *(attachments++) : 0; 416706f2543Smrg 417706f2543Smrg if (allocate_or_reuse_buffer(pDraw, ds, pPriv, attachment, 418706f2543Smrg format, dimensions_match, 419706f2543Smrg &buffers[i])) 420706f2543Smrg buffers_changed = 1; 421706f2543Smrg 422706f2543Smrg if (buffers[i] == NULL) 423706f2543Smrg goto err_out; 424706f2543Smrg 425706f2543Smrg /* If the drawable is a window and the front-buffer is requested, 426706f2543Smrg * silently add the fake front-buffer to the list of requested 427706f2543Smrg * attachments. The counting logic in the loop accounts for the case 428706f2543Smrg * where the client requests both the fake and real front-buffer. 429706f2543Smrg */ 430706f2543Smrg if (attachment == DRI2BufferBackLeft) { 431706f2543Smrg need_real_front++; 432706f2543Smrg front_format = format; 433706f2543Smrg } 434706f2543Smrg 435706f2543Smrg if (attachment == DRI2BufferFrontLeft) { 436706f2543Smrg need_real_front--; 437706f2543Smrg front_format = format; 438706f2543Smrg 439706f2543Smrg if (pDraw->type == DRAWABLE_WINDOW) { 440706f2543Smrg need_fake_front++; 441706f2543Smrg } 442706f2543Smrg } 443706f2543Smrg 444706f2543Smrg if (pDraw->type == DRAWABLE_WINDOW) { 445706f2543Smrg if (attachment == DRI2BufferFakeFrontLeft) { 446706f2543Smrg need_fake_front--; 447706f2543Smrg have_fake_front = 1; 448706f2543Smrg } 449706f2543Smrg } 450706f2543Smrg } 451706f2543Smrg 452706f2543Smrg if (need_real_front > 0) { 453706f2543Smrg if (allocate_or_reuse_buffer(pDraw, ds, pPriv, DRI2BufferFrontLeft, 454706f2543Smrg front_format, dimensions_match, 455706f2543Smrg &buffers[i])) 456706f2543Smrg buffers_changed = 1; 457706f2543Smrg 458706f2543Smrg if (buffers[i] == NULL) 459706f2543Smrg goto err_out; 460706f2543Smrg i++; 461706f2543Smrg } 462706f2543Smrg 463706f2543Smrg if (need_fake_front > 0) { 464706f2543Smrg if (allocate_or_reuse_buffer(pDraw, ds, pPriv, DRI2BufferFakeFrontLeft, 465706f2543Smrg front_format, dimensions_match, 466706f2543Smrg &buffers[i])) 467706f2543Smrg buffers_changed = 1; 468706f2543Smrg 469706f2543Smrg if (buffers[i] == NULL) 470706f2543Smrg goto err_out; 471706f2543Smrg 472706f2543Smrg i++; 473706f2543Smrg have_fake_front = 1; 474706f2543Smrg } 475706f2543Smrg 476706f2543Smrg *out_count = i; 477706f2543Smrg 478706f2543Smrg update_dri2_drawable_buffers(pPriv, pDraw, buffers, out_count, width, height); 479706f2543Smrg 480706f2543Smrg /* If the client is getting a fake front-buffer, pre-fill it with the 481706f2543Smrg * contents of the real front-buffer. This ensures correct operation of 482706f2543Smrg * applications that call glXWaitX before calling glDrawBuffer. 483706f2543Smrg */ 484706f2543Smrg if (have_fake_front && buffers_changed) { 485706f2543Smrg BoxRec box; 486706f2543Smrg RegionRec region; 487706f2543Smrg 488706f2543Smrg box.x1 = 0; 489706f2543Smrg box.y1 = 0; 490706f2543Smrg box.x2 = pPriv->width; 491706f2543Smrg box.y2 = pPriv->height; 492706f2543Smrg RegionInit(®ion, &box, 0); 493706f2543Smrg 494706f2543Smrg DRI2CopyRegion(pDraw, ®ion, DRI2BufferFakeFrontLeft, 495706f2543Smrg DRI2BufferFrontLeft); 496706f2543Smrg } 497706f2543Smrg 498706f2543Smrg return pPriv->buffers; 499706f2543Smrg 500706f2543Smrgerr_out: 501706f2543Smrg 502706f2543Smrg *out_count = 0; 503706f2543Smrg 504706f2543Smrg for (i = 0; i < count; i++) { 505706f2543Smrg if (buffers[i] != NULL) 506706f2543Smrg (*ds->DestroyBuffer)(pDraw, buffers[i]); 507706f2543Smrg } 508706f2543Smrg 509706f2543Smrg free(buffers); 510706f2543Smrg buffers = NULL; 511706f2543Smrg 512706f2543Smrg update_dri2_drawable_buffers(pPriv, pDraw, buffers, out_count, width, height); 513706f2543Smrg 514706f2543Smrg return buffers; 515706f2543Smrg} 516706f2543Smrg 517706f2543SmrgDRI2BufferPtr * 518706f2543SmrgDRI2GetBuffers(DrawablePtr pDraw, int *width, int *height, 519706f2543Smrg unsigned int *attachments, int count, int *out_count) 520706f2543Smrg{ 521706f2543Smrg return do_get_buffers(pDraw, width, height, attachments, count, 522706f2543Smrg out_count, FALSE); 523706f2543Smrg} 524706f2543Smrg 525706f2543SmrgDRI2BufferPtr * 526706f2543SmrgDRI2GetBuffersWithFormat(DrawablePtr pDraw, int *width, int *height, 527706f2543Smrg unsigned int *attachments, int count, int *out_count) 528706f2543Smrg{ 529706f2543Smrg return do_get_buffers(pDraw, width, height, attachments, count, 530706f2543Smrg out_count, TRUE); 531706f2543Smrg} 532706f2543Smrg 533706f2543Smrgstatic void 534706f2543SmrgDRI2InvalidateDrawable(DrawablePtr pDraw) 535706f2543Smrg{ 536706f2543Smrg DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw); 537706f2543Smrg DRI2DrawableRefPtr ref = NULL; 538706f2543Smrg 539706f2543Smrg if (!pPriv) 540706f2543Smrg return; 541706f2543Smrg 542706f2543Smrg list_for_each_entry(ref, &pPriv->reference_list, link) 543706f2543Smrg ref->invalidate(pDraw, ref->priv); 544706f2543Smrg} 545706f2543Smrg 546706f2543Smrg/* 547706f2543Smrg * In the direct rendered case, we throttle the clients that have more 548706f2543Smrg * than their share of outstanding swaps (and thus busy buffers) when a 549706f2543Smrg * new GetBuffers request is received. In the AIGLX case, we allow the 550706f2543Smrg * client to get the new buffers, but throttle when the next GLX request 551706f2543Smrg * comes in (see __glXDRIcontextWait()). 552706f2543Smrg */ 553706f2543SmrgBool 554706f2543SmrgDRI2ThrottleClient(ClientPtr client, DrawablePtr pDraw) 555706f2543Smrg{ 556706f2543Smrg DRI2DrawablePtr pPriv; 557706f2543Smrg 558706f2543Smrg pPriv = DRI2GetDrawable(pDraw); 559706f2543Smrg if (pPriv == NULL) 560706f2543Smrg return FALSE; 561706f2543Smrg 562706f2543Smrg /* Throttle to swap limit */ 563706f2543Smrg if ((pPriv->swapsPending >= pPriv->swap_limit) && 564706f2543Smrg !pPriv->blockedClient) { 565706f2543Smrg ResetCurrentRequest(client); 566706f2543Smrg client->sequence--; 567706f2543Smrg IgnoreClient(client); 568706f2543Smrg pPriv->blockedClient = client; 569706f2543Smrg return TRUE; 570706f2543Smrg } 571706f2543Smrg 572706f2543Smrg return FALSE; 573706f2543Smrg} 574706f2543Smrg 575706f2543Smrgstatic void 576706f2543Smrg__DRI2BlockClient(ClientPtr client, DRI2DrawablePtr pPriv) 577706f2543Smrg{ 578706f2543Smrg if (pPriv->blockedClient == NULL) { 579706f2543Smrg IgnoreClient(client); 580706f2543Smrg pPriv->blockedClient = client; 581706f2543Smrg } 582706f2543Smrg} 583706f2543Smrg 584706f2543Smrgvoid 585706f2543SmrgDRI2BlockClient(ClientPtr client, DrawablePtr pDraw) 586706f2543Smrg{ 587706f2543Smrg DRI2DrawablePtr pPriv; 588706f2543Smrg 589706f2543Smrg pPriv = DRI2GetDrawable(pDraw); 590706f2543Smrg if (pPriv == NULL) 591706f2543Smrg return; 592706f2543Smrg 593706f2543Smrg __DRI2BlockClient(client, pPriv); 594706f2543Smrg pPriv->blockedOnMsc = TRUE; 595706f2543Smrg} 596706f2543Smrg 597706f2543Smrgint 598706f2543SmrgDRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion, 599706f2543Smrg unsigned int dest, unsigned int src) 600706f2543Smrg{ 601706f2543Smrg DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); 602706f2543Smrg DRI2DrawablePtr pPriv; 603706f2543Smrg DRI2BufferPtr pDestBuffer, pSrcBuffer; 604706f2543Smrg int i; 605706f2543Smrg 606706f2543Smrg pPriv = DRI2GetDrawable(pDraw); 607706f2543Smrg if (pPriv == NULL) 608706f2543Smrg return BadDrawable; 609706f2543Smrg 610706f2543Smrg pDestBuffer = NULL; 611706f2543Smrg pSrcBuffer = NULL; 612706f2543Smrg for (i = 0; i < pPriv->bufferCount; i++) 613706f2543Smrg { 614706f2543Smrg if (pPriv->buffers[i]->attachment == dest) 615706f2543Smrg pDestBuffer = (DRI2BufferPtr) pPriv->buffers[i]; 616706f2543Smrg if (pPriv->buffers[i]->attachment == src) 617706f2543Smrg pSrcBuffer = (DRI2BufferPtr) pPriv->buffers[i]; 618706f2543Smrg } 619706f2543Smrg if (pSrcBuffer == NULL || pDestBuffer == NULL) 620706f2543Smrg return BadValue; 621706f2543Smrg 622706f2543Smrg (*ds->CopyRegion)(pDraw, pRegion, pDestBuffer, pSrcBuffer); 623706f2543Smrg 624706f2543Smrg return Success; 625706f2543Smrg} 626706f2543Smrg 627706f2543Smrg/* Can this drawable be page flipped? */ 628706f2543SmrgBool 629706f2543SmrgDRI2CanFlip(DrawablePtr pDraw) 630706f2543Smrg{ 631706f2543Smrg ScreenPtr pScreen = pDraw->pScreen; 632706f2543Smrg WindowPtr pWin, pRoot; 633706f2543Smrg PixmapPtr pWinPixmap, pRootPixmap; 634706f2543Smrg 635706f2543Smrg if (pDraw->type == DRAWABLE_PIXMAP) 636706f2543Smrg return TRUE; 637706f2543Smrg 638706f2543Smrg pRoot = pScreen->root; 639706f2543Smrg pRootPixmap = pScreen->GetWindowPixmap(pRoot); 640706f2543Smrg 641706f2543Smrg pWin = (WindowPtr) pDraw; 642706f2543Smrg pWinPixmap = pScreen->GetWindowPixmap(pWin); 643706f2543Smrg if (pRootPixmap != pWinPixmap) 644706f2543Smrg return FALSE; 645706f2543Smrg if (!RegionEqual(&pWin->clipList, &pRoot->winSize)) 646706f2543Smrg return FALSE; 647706f2543Smrg 648706f2543Smrg /* Does the window match the pixmap exactly? */ 649706f2543Smrg if (pDraw->x != 0 || 650706f2543Smrg pDraw->y != 0 || 651706f2543Smrg#ifdef COMPOSITE 652706f2543Smrg pDraw->x != pWinPixmap->screen_x || 653706f2543Smrg pDraw->y != pWinPixmap->screen_y || 654706f2543Smrg#endif 655706f2543Smrg pDraw->width != pWinPixmap->drawable.width || 656706f2543Smrg pDraw->height != pWinPixmap->drawable.height) 657706f2543Smrg return FALSE; 658706f2543Smrg 659706f2543Smrg return TRUE; 660706f2543Smrg} 661706f2543Smrg 662706f2543Smrg/* Can we do a pixmap exchange instead of a blit? */ 663706f2543SmrgBool 664706f2543SmrgDRI2CanExchange(DrawablePtr pDraw) 665706f2543Smrg{ 666706f2543Smrg return FALSE; 667706f2543Smrg} 668706f2543Smrg 669706f2543Smrgvoid 670706f2543SmrgDRI2WaitMSCComplete(ClientPtr client, DrawablePtr pDraw, int frame, 671706f2543Smrg unsigned int tv_sec, unsigned int tv_usec) 672706f2543Smrg{ 673706f2543Smrg DRI2DrawablePtr pPriv; 674706f2543Smrg 675706f2543Smrg pPriv = DRI2GetDrawable(pDraw); 676706f2543Smrg if (pPriv == NULL) 677706f2543Smrg return; 678706f2543Smrg 679706f2543Smrg ProcDRI2WaitMSCReply(client, ((CARD64)tv_sec * 1000000) + tv_usec, 680706f2543Smrg frame, pPriv->swap_count); 681706f2543Smrg 682706f2543Smrg if (pPriv->blockedClient) 683706f2543Smrg AttendClient(pPriv->blockedClient); 684706f2543Smrg 685706f2543Smrg pPriv->blockedClient = NULL; 686706f2543Smrg pPriv->blockedOnMsc = FALSE; 687706f2543Smrg} 688706f2543Smrg 689706f2543Smrgstatic void 690706f2543SmrgDRI2WakeClient(ClientPtr client, DrawablePtr pDraw, int frame, 691706f2543Smrg unsigned int tv_sec, unsigned int tv_usec) 692706f2543Smrg{ 693706f2543Smrg ScreenPtr pScreen = pDraw->pScreen; 694706f2543Smrg DRI2DrawablePtr pPriv; 695706f2543Smrg 696706f2543Smrg pPriv = DRI2GetDrawable(pDraw); 697706f2543Smrg if (pPriv == NULL) { 698706f2543Smrg xf86DrvMsg(pScreen->myNum, X_ERROR, 699706f2543Smrg "[DRI2] %s: bad drawable\n", __func__); 700706f2543Smrg return; 701706f2543Smrg } 702706f2543Smrg 703706f2543Smrg /* 704706f2543Smrg * Swap completed. 705706f2543Smrg * Wake the client iff: 706706f2543Smrg * - it was waiting on SBC 707706f2543Smrg * - was blocked due to GLX make current 708706f2543Smrg * - was blocked due to swap throttling 709706f2543Smrg * - is not blocked due to an MSC wait 710706f2543Smrg */ 711706f2543Smrg if (pPriv->target_sbc != -1 && 712706f2543Smrg pPriv->target_sbc <= pPriv->swap_count) { 713706f2543Smrg ProcDRI2WaitMSCReply(client, ((CARD64)tv_sec * 1000000) + tv_usec, 714706f2543Smrg frame, pPriv->swap_count); 715706f2543Smrg pPriv->target_sbc = -1; 716706f2543Smrg 717706f2543Smrg AttendClient(pPriv->blockedClient); 718706f2543Smrg pPriv->blockedClient = NULL; 719706f2543Smrg } else if (pPriv->target_sbc == -1 && !pPriv->blockedOnMsc) { 720706f2543Smrg if (pPriv->blockedClient) { 721706f2543Smrg AttendClient(pPriv->blockedClient); 722706f2543Smrg pPriv->blockedClient = NULL; 723706f2543Smrg } 724706f2543Smrg } 725706f2543Smrg} 726706f2543Smrg 727706f2543Smrgvoid 728706f2543SmrgDRI2SwapComplete(ClientPtr client, DrawablePtr pDraw, int frame, 729706f2543Smrg unsigned int tv_sec, unsigned int tv_usec, int type, 730706f2543Smrg DRI2SwapEventPtr swap_complete, void *swap_data) 731706f2543Smrg{ 732706f2543Smrg ScreenPtr pScreen = pDraw->pScreen; 733706f2543Smrg DRI2DrawablePtr pPriv; 734706f2543Smrg CARD64 ust = 0; 735706f2543Smrg BoxRec box; 736706f2543Smrg RegionRec region; 737706f2543Smrg 738706f2543Smrg pPriv = DRI2GetDrawable(pDraw); 739706f2543Smrg if (pPriv == NULL) { 740706f2543Smrg xf86DrvMsg(pScreen->myNum, X_ERROR, 741706f2543Smrg "[DRI2] %s: bad drawable\n", __func__); 742706f2543Smrg return; 743706f2543Smrg } 744706f2543Smrg 745706f2543Smrg pPriv->swapsPending--; 746706f2543Smrg pPriv->swap_count++; 747706f2543Smrg 748706f2543Smrg box.x1 = 0; 749706f2543Smrg box.y1 = 0; 750706f2543Smrg box.x2 = pDraw->width; 751706f2543Smrg box.y2 = pDraw->height; 752706f2543Smrg RegionInit(®ion, &box, 0); 753706f2543Smrg DRI2CopyRegion(pDraw, ®ion, DRI2BufferFakeFrontLeft, 754706f2543Smrg DRI2BufferFrontLeft); 755706f2543Smrg 756706f2543Smrg ust = ((CARD64)tv_sec * 1000000) + tv_usec; 757706f2543Smrg if (swap_complete) 758706f2543Smrg swap_complete(client, swap_data, type, ust, frame, pPriv->swap_count); 759706f2543Smrg 760706f2543Smrg pPriv->last_swap_msc = frame; 761706f2543Smrg pPriv->last_swap_ust = ust; 762706f2543Smrg 763706f2543Smrg DRI2WakeClient(client, pDraw, frame, tv_sec, tv_usec); 764706f2543Smrg} 765706f2543Smrg 766706f2543SmrgBool 767706f2543SmrgDRI2WaitSwap(ClientPtr client, DrawablePtr pDrawable) 768706f2543Smrg{ 769706f2543Smrg DRI2DrawablePtr pPriv = DRI2GetDrawable(pDrawable); 770706f2543Smrg 771706f2543Smrg /* If we're currently waiting for a swap on this drawable, reset 772706f2543Smrg * the request and suspend the client. We only support one 773706f2543Smrg * blocked client per drawable. */ 774706f2543Smrg if (pPriv && 775706f2543Smrg pPriv->swapsPending && 776706f2543Smrg pPriv->blockedClient == NULL) { 777706f2543Smrg ResetCurrentRequest(client); 778706f2543Smrg client->sequence--; 779706f2543Smrg __DRI2BlockClient(client, pPriv); 780706f2543Smrg return TRUE; 781706f2543Smrg } 782706f2543Smrg 783706f2543Smrg return FALSE; 784706f2543Smrg} 785706f2543Smrg 786706f2543Smrgint 787706f2543SmrgDRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc, 788706f2543Smrg CARD64 divisor, CARD64 remainder, CARD64 *swap_target, 789706f2543Smrg DRI2SwapEventPtr func, void *data) 790706f2543Smrg{ 791706f2543Smrg ScreenPtr pScreen = pDraw->pScreen; 792706f2543Smrg DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); 793706f2543Smrg DRI2DrawablePtr pPriv; 794706f2543Smrg DRI2BufferPtr pDestBuffer = NULL, pSrcBuffer = NULL; 795706f2543Smrg int ret, i; 796706f2543Smrg CARD64 ust, current_msc; 797706f2543Smrg 798706f2543Smrg pPriv = DRI2GetDrawable(pDraw); 799706f2543Smrg if (pPriv == NULL) { 800706f2543Smrg xf86DrvMsg(pScreen->myNum, X_ERROR, 801706f2543Smrg "[DRI2] %s: bad drawable\n", __func__); 802706f2543Smrg return BadDrawable; 803706f2543Smrg } 804706f2543Smrg 805706f2543Smrg for (i = 0; i < pPriv->bufferCount; i++) { 806706f2543Smrg if (pPriv->buffers[i]->attachment == DRI2BufferFrontLeft) 807706f2543Smrg pDestBuffer = (DRI2BufferPtr) pPriv->buffers[i]; 808706f2543Smrg if (pPriv->buffers[i]->attachment == DRI2BufferBackLeft) 809706f2543Smrg pSrcBuffer = (DRI2BufferPtr) pPriv->buffers[i]; 810706f2543Smrg } 811706f2543Smrg if (pSrcBuffer == NULL || pDestBuffer == NULL) { 812706f2543Smrg xf86DrvMsg(pScreen->myNum, X_ERROR, 813706f2543Smrg "[DRI2] %s: drawable has no back or front?\n", __func__); 814706f2543Smrg return BadDrawable; 815706f2543Smrg } 816706f2543Smrg 817706f2543Smrg /* Old DDX or no swap interval, just blit */ 818706f2543Smrg if (!ds->ScheduleSwap || !pPriv->swap_interval) { 819706f2543Smrg BoxRec box; 820706f2543Smrg RegionRec region; 821706f2543Smrg 822706f2543Smrg box.x1 = 0; 823706f2543Smrg box.y1 = 0; 824706f2543Smrg box.x2 = pDraw->width; 825706f2543Smrg box.y2 = pDraw->height; 826706f2543Smrg RegionInit(®ion, &box, 0); 827706f2543Smrg 828706f2543Smrg pPriv->swapsPending++; 829706f2543Smrg 830706f2543Smrg (*ds->CopyRegion)(pDraw, ®ion, pDestBuffer, pSrcBuffer); 831706f2543Smrg DRI2SwapComplete(client, pDraw, target_msc, 0, 0, DRI2_BLIT_COMPLETE, 832706f2543Smrg func, data); 833706f2543Smrg return Success; 834706f2543Smrg } 835706f2543Smrg 836706f2543Smrg /* 837706f2543Smrg * In the simple glXSwapBuffers case, all params will be 0, and we just 838706f2543Smrg * need to schedule a swap for the last swap target + the swap interval. 839706f2543Smrg */ 840706f2543Smrg if (target_msc == 0 && divisor == 0 && remainder == 0) { 841706f2543Smrg /* If the current vblank count of the drawable's crtc is lower 842706f2543Smrg * than the count stored in last_swap_target from a previous swap 843706f2543Smrg * then reinitialize last_swap_target to the current crtc's msc, 844706f2543Smrg * otherwise the swap will hang. This will happen if the drawable 845706f2543Smrg * is moved to a crtc with a lower refresh rate, or a crtc that just 846706f2543Smrg * got enabled. 847706f2543Smrg */ 848706f2543Smrg if (ds->GetMSC) { 849706f2543Smrg if (!(*ds->GetMSC)(pDraw, &ust, ¤t_msc)) 850706f2543Smrg pPriv->last_swap_target = 0; 851706f2543Smrg 852706f2543Smrg if (current_msc < pPriv->last_swap_target) 853706f2543Smrg pPriv->last_swap_target = current_msc; 854706f2543Smrg 855706f2543Smrg } 856706f2543Smrg 857706f2543Smrg /* 858706f2543Smrg * Swap target for this swap is last swap target + swap interval since 859706f2543Smrg * we have to account for the current swap count, interval, and the 860706f2543Smrg * number of pending swaps. 861706f2543Smrg */ 862706f2543Smrg *swap_target = pPriv->last_swap_target + pPriv->swap_interval; 863706f2543Smrg 864706f2543Smrg } else { 865706f2543Smrg /* glXSwapBuffersMscOML could have a 0 target_msc, honor it */ 866706f2543Smrg *swap_target = target_msc; 867706f2543Smrg } 868706f2543Smrg 869706f2543Smrg pPriv->swapsPending++; 870706f2543Smrg ret = (*ds->ScheduleSwap)(client, pDraw, pDestBuffer, pSrcBuffer, 871706f2543Smrg swap_target, divisor, remainder, func, data); 872706f2543Smrg if (!ret) { 873706f2543Smrg pPriv->swapsPending--; /* didn't schedule */ 874706f2543Smrg xf86DrvMsg(pScreen->myNum, X_ERROR, 875706f2543Smrg "[DRI2] %s: driver failed to schedule swap\n", __func__); 876706f2543Smrg return BadDrawable; 877706f2543Smrg } 878706f2543Smrg 879706f2543Smrg pPriv->last_swap_target = *swap_target; 880706f2543Smrg 881706f2543Smrg /* According to spec, return expected swapbuffers count SBC after this swap 882706f2543Smrg * will complete. 883706f2543Smrg */ 884706f2543Smrg *swap_target = pPriv->swap_count + pPriv->swapsPending; 885706f2543Smrg 886706f2543Smrg DRI2InvalidateDrawable(pDraw); 887706f2543Smrg 888706f2543Smrg return Success; 889706f2543Smrg} 890706f2543Smrg 891706f2543Smrgvoid 892706f2543SmrgDRI2SwapInterval(DrawablePtr pDrawable, int interval) 893706f2543Smrg{ 894706f2543Smrg ScreenPtr pScreen = pDrawable->pScreen; 895706f2543Smrg DRI2DrawablePtr pPriv = DRI2GetDrawable(pDrawable); 896706f2543Smrg 897706f2543Smrg if (pPriv == NULL) { 898706f2543Smrg xf86DrvMsg(pScreen->myNum, X_ERROR, 899706f2543Smrg "[DRI2] %s: bad drawable\n", __func__); 900706f2543Smrg return; 901706f2543Smrg } 902706f2543Smrg 903706f2543Smrg /* fixme: check against arbitrary max? */ 904706f2543Smrg pPriv->swap_interval = interval; 905706f2543Smrg} 906706f2543Smrg 907706f2543Smrgint 908706f2543SmrgDRI2GetMSC(DrawablePtr pDraw, CARD64 *ust, CARD64 *msc, CARD64 *sbc) 909706f2543Smrg{ 910706f2543Smrg ScreenPtr pScreen = pDraw->pScreen; 911706f2543Smrg DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); 912706f2543Smrg DRI2DrawablePtr pPriv; 913706f2543Smrg Bool ret; 914706f2543Smrg 915706f2543Smrg pPriv = DRI2GetDrawable(pDraw); 916706f2543Smrg if (pPriv == NULL) { 917706f2543Smrg xf86DrvMsg(pScreen->myNum, X_ERROR, 918706f2543Smrg "[DRI2] %s: bad drawable\n", __func__); 919706f2543Smrg return BadDrawable; 920706f2543Smrg } 921706f2543Smrg 922706f2543Smrg if (!ds->GetMSC) { 923706f2543Smrg *ust = 0; 924706f2543Smrg *msc = 0; 925706f2543Smrg *sbc = pPriv->swap_count; 926706f2543Smrg return Success; 927706f2543Smrg } 928706f2543Smrg 929706f2543Smrg /* 930706f2543Smrg * Spec needs to be updated to include unmapped or redirected 931706f2543Smrg * drawables 932706f2543Smrg */ 933706f2543Smrg 934706f2543Smrg ret = (*ds->GetMSC)(pDraw, ust, msc); 935706f2543Smrg if (!ret) 936706f2543Smrg return BadDrawable; 937706f2543Smrg 938706f2543Smrg *sbc = pPriv->swap_count; 939706f2543Smrg 940706f2543Smrg return Success; 941706f2543Smrg} 942706f2543Smrg 943706f2543Smrgint 944706f2543SmrgDRI2WaitMSC(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc, 945706f2543Smrg CARD64 divisor, CARD64 remainder) 946706f2543Smrg{ 947706f2543Smrg DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); 948706f2543Smrg DRI2DrawablePtr pPriv; 949706f2543Smrg Bool ret; 950706f2543Smrg 951706f2543Smrg pPriv = DRI2GetDrawable(pDraw); 952706f2543Smrg if (pPriv == NULL) 953706f2543Smrg return BadDrawable; 954706f2543Smrg 955706f2543Smrg /* Old DDX just completes immediately */ 956706f2543Smrg if (!ds->ScheduleWaitMSC) { 957706f2543Smrg DRI2WaitMSCComplete(client, pDraw, target_msc, 0, 0); 958706f2543Smrg 959706f2543Smrg return Success; 960706f2543Smrg } 961706f2543Smrg 962706f2543Smrg ret = (*ds->ScheduleWaitMSC)(client, pDraw, target_msc, divisor, remainder); 963706f2543Smrg if (!ret) 964706f2543Smrg return BadDrawable; 965706f2543Smrg 966706f2543Smrg return Success; 967706f2543Smrg} 968706f2543Smrg 969706f2543Smrgint 970706f2543SmrgDRI2WaitSBC(ClientPtr client, DrawablePtr pDraw, CARD64 target_sbc) 971706f2543Smrg{ 972706f2543Smrg DRI2DrawablePtr pPriv; 973706f2543Smrg 974706f2543Smrg pPriv = DRI2GetDrawable(pDraw); 975706f2543Smrg if (pPriv == NULL) 976706f2543Smrg return BadDrawable; 977706f2543Smrg 978706f2543Smrg /* target_sbc == 0 means to block until all pending swaps are 979706f2543Smrg * finished. Recalculate target_sbc to get that behaviour. 980706f2543Smrg */ 981706f2543Smrg if (target_sbc == 0) 982706f2543Smrg target_sbc = pPriv->swap_count + pPriv->swapsPending; 983706f2543Smrg 984706f2543Smrg /* If current swap count already >= target_sbc, reply and 985706f2543Smrg * return immediately with (ust, msc, sbc) triplet of 986706f2543Smrg * most recent completed swap. 987706f2543Smrg */ 988706f2543Smrg if (pPriv->swap_count >= target_sbc) { 989706f2543Smrg ProcDRI2WaitMSCReply(client, pPriv->last_swap_ust, 990706f2543Smrg pPriv->last_swap_msc, pPriv->swap_count); 991706f2543Smrg return Success; 992706f2543Smrg } 993706f2543Smrg 994706f2543Smrg pPriv->target_sbc = target_sbc; 995706f2543Smrg __DRI2BlockClient(client, pPriv); 996706f2543Smrg 997706f2543Smrg return Success; 998706f2543Smrg} 999706f2543Smrg 1000706f2543SmrgBool 1001706f2543SmrgDRI2HasSwapControl(ScreenPtr pScreen) 1002706f2543Smrg{ 1003706f2543Smrg DRI2ScreenPtr ds = DRI2GetScreen(pScreen); 1004706f2543Smrg 1005706f2543Smrg return ds->ScheduleSwap && ds->GetMSC; 1006706f2543Smrg} 1007706f2543Smrg 1008706f2543SmrgBool 1009706f2543SmrgDRI2Connect(ScreenPtr pScreen, unsigned int driverType, int *fd, 1010706f2543Smrg const char **driverName, const char **deviceName) 1011706f2543Smrg{ 1012706f2543Smrg DRI2ScreenPtr ds; 1013706f2543Smrg 1014706f2543Smrg if (!dixPrivateKeyRegistered(dri2ScreenPrivateKey)) 1015706f2543Smrg return FALSE; 1016706f2543Smrg 1017706f2543Smrg ds = DRI2GetScreen(pScreen); 1018706f2543Smrg if (ds == NULL || driverType >= ds->numDrivers || 1019706f2543Smrg !ds->driverNames[driverType]) 1020706f2543Smrg return FALSE; 1021706f2543Smrg 1022706f2543Smrg *fd = ds->fd; 1023706f2543Smrg *driverName = ds->driverNames[driverType]; 1024706f2543Smrg *deviceName = ds->deviceName; 1025706f2543Smrg 1026706f2543Smrg return TRUE; 1027706f2543Smrg} 1028706f2543Smrg 1029706f2543SmrgBool 1030706f2543SmrgDRI2Authenticate(ScreenPtr pScreen, uint32_t magic) 1031706f2543Smrg{ 1032706f2543Smrg DRI2ScreenPtr ds = DRI2GetScreen(pScreen); 1033706f2543Smrg 1034706f2543Smrg if (ds == NULL || (*ds->AuthMagic)(ds->fd, magic)) 1035706f2543Smrg return FALSE; 1036706f2543Smrg 1037706f2543Smrg return TRUE; 1038706f2543Smrg} 1039706f2543Smrg 1040706f2543Smrgstatic int 1041706f2543SmrgDRI2ConfigNotify(WindowPtr pWin, int x, int y, int w, int h, int bw, 1042706f2543Smrg WindowPtr pSib) 1043706f2543Smrg{ 1044706f2543Smrg DrawablePtr pDraw = (DrawablePtr)pWin; 1045706f2543Smrg ScreenPtr pScreen = pDraw->pScreen; 1046706f2543Smrg DRI2ScreenPtr ds = DRI2GetScreen(pScreen); 1047706f2543Smrg DRI2DrawablePtr dd = DRI2GetDrawable(pDraw); 1048706f2543Smrg int ret; 1049706f2543Smrg 1050706f2543Smrg if (ds->ConfigNotify) { 1051706f2543Smrg pScreen->ConfigNotify = ds->ConfigNotify; 1052706f2543Smrg 1053706f2543Smrg ret = (*pScreen->ConfigNotify)(pWin, x, y, w, h, bw, pSib); 1054706f2543Smrg 1055706f2543Smrg ds->ConfigNotify = pScreen->ConfigNotify; 1056706f2543Smrg pScreen->ConfigNotify = DRI2ConfigNotify; 1057706f2543Smrg if (ret) 1058706f2543Smrg return ret; 1059706f2543Smrg } 1060706f2543Smrg 1061706f2543Smrg if (!dd || (dd->width == w && dd->height == h)) 1062706f2543Smrg return Success; 1063706f2543Smrg 1064706f2543Smrg DRI2InvalidateDrawable(pDraw); 1065706f2543Smrg return Success; 1066706f2543Smrg} 1067706f2543Smrg 1068706f2543SmrgBool 1069706f2543SmrgDRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info) 1070706f2543Smrg{ 1071706f2543Smrg DRI2ScreenPtr ds; 1072706f2543Smrg const char* driverTypeNames[] = { 1073706f2543Smrg "DRI", /* DRI2DriverDRI */ 1074706f2543Smrg "VDPAU", /* DRI2DriverVDPAU */ 1075706f2543Smrg }; 1076706f2543Smrg unsigned int i; 1077706f2543Smrg CARD8 cur_minor; 1078706f2543Smrg 1079706f2543Smrg if (info->version < 3) 1080706f2543Smrg return FALSE; 1081706f2543Smrg 1082706f2543Smrg if (!xf86VGAarbiterAllowDRI(pScreen)) { 1083706f2543Smrg xf86DrvMsg(pScreen->myNum, X_WARNING, 1084706f2543Smrg "[DRI2] Direct rendering is not supported when VGA arb is necessary for the device\n"); 1085706f2543Smrg return FALSE; 1086706f2543Smrg } 1087706f2543Smrg 1088706f2543Smrg if (!dixRegisterPrivateKey(&dri2ScreenPrivateKeyRec, PRIVATE_SCREEN, 0)) 1089706f2543Smrg return FALSE; 1090706f2543Smrg 1091706f2543Smrg if (!dixRegisterPrivateKey(&dri2WindowPrivateKeyRec, PRIVATE_WINDOW, 0)) 1092706f2543Smrg return FALSE; 1093706f2543Smrg 1094706f2543Smrg if (!dixRegisterPrivateKey(&dri2PixmapPrivateKeyRec, PRIVATE_PIXMAP, 0)) 1095706f2543Smrg return FALSE; 1096706f2543Smrg 1097706f2543Smrg ds = calloc(1, sizeof *ds); 1098706f2543Smrg if (!ds) 1099706f2543Smrg return FALSE; 1100706f2543Smrg 1101706f2543Smrg ds->screen = pScreen; 1102706f2543Smrg ds->fd = info->fd; 1103706f2543Smrg ds->deviceName = info->deviceName; 1104706f2543Smrg dri2_major = 1; 1105706f2543Smrg 1106706f2543Smrg ds->CreateBuffer = info->CreateBuffer; 1107706f2543Smrg ds->DestroyBuffer = info->DestroyBuffer; 1108706f2543Smrg ds->CopyRegion = info->CopyRegion; 1109706f2543Smrg 1110706f2543Smrg if (info->version >= 4) { 1111706f2543Smrg ds->ScheduleSwap = info->ScheduleSwap; 1112706f2543Smrg ds->ScheduleWaitMSC = info->ScheduleWaitMSC; 1113706f2543Smrg ds->GetMSC = info->GetMSC; 1114706f2543Smrg cur_minor = 3; 1115706f2543Smrg } else { 1116706f2543Smrg cur_minor = 1; 1117706f2543Smrg } 1118706f2543Smrg 1119706f2543Smrg if (info->version >= 5) { 1120706f2543Smrg ds->AuthMagic = info->AuthMagic; 1121706f2543Smrg } 1122706f2543Smrg 1123706f2543Smrg /* 1124706f2543Smrg * if the driver doesn't provide an AuthMagic function or the info struct 1125706f2543Smrg * version is too low, it relies on the old method (using libdrm) or fail 1126706f2543Smrg */ 1127706f2543Smrg if (!ds->AuthMagic) 1128706f2543Smrg#ifdef WITH_LIBDRM 1129706f2543Smrg ds->AuthMagic = drmAuthMagic; 1130706f2543Smrg#else 1131706f2543Smrg goto err_out; 1132706f2543Smrg#endif 1133706f2543Smrg 1134706f2543Smrg /* Initialize minor if needed and set to minimum provied by DDX */ 1135706f2543Smrg if (!dri2_minor || dri2_minor > cur_minor) 1136706f2543Smrg dri2_minor = cur_minor; 1137706f2543Smrg 1138706f2543Smrg if (info->version == 3 || info->numDrivers == 0) { 1139706f2543Smrg /* Driver too old: use the old-style driverName field */ 1140706f2543Smrg ds->numDrivers = 1; 1141706f2543Smrg ds->driverNames = malloc(sizeof(*ds->driverNames)); 1142706f2543Smrg if (!ds->driverNames) 1143706f2543Smrg goto err_out; 1144706f2543Smrg ds->driverNames[0] = info->driverName; 1145706f2543Smrg } else { 1146706f2543Smrg ds->numDrivers = info->numDrivers; 1147706f2543Smrg ds->driverNames = malloc(info->numDrivers * sizeof(*ds->driverNames)); 1148706f2543Smrg if (!ds->driverNames) 1149706f2543Smrg goto err_out; 1150706f2543Smrg memcpy(ds->driverNames, info->driverNames, 1151706f2543Smrg info->numDrivers * sizeof(*ds->driverNames)); 1152706f2543Smrg } 1153706f2543Smrg 1154706f2543Smrg dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, ds); 1155706f2543Smrg 1156706f2543Smrg ds->ConfigNotify = pScreen->ConfigNotify; 1157706f2543Smrg pScreen->ConfigNotify = DRI2ConfigNotify; 1158706f2543Smrg 1159706f2543Smrg xf86DrvMsg(pScreen->myNum, X_INFO, "[DRI2] Setup complete\n"); 1160706f2543Smrg for (i = 0; i < sizeof(driverTypeNames) / sizeof(driverTypeNames[0]); i++) { 1161706f2543Smrg if (i < ds->numDrivers && ds->driverNames[i]) { 1162706f2543Smrg xf86DrvMsg(pScreen->myNum, X_INFO, "[DRI2] %s driver: %s\n", 1163706f2543Smrg driverTypeNames[i], ds->driverNames[i]); 1164706f2543Smrg } 1165706f2543Smrg } 1166706f2543Smrg 1167706f2543Smrg return TRUE; 1168706f2543Smrg 1169706f2543Smrgerr_out: 1170706f2543Smrg xf86DrvMsg(pScreen->myNum, X_WARNING, 1171706f2543Smrg "[DRI2] Initialization failed for info version %d.\n", info->version); 1172706f2543Smrg free(ds); 1173706f2543Smrg return FALSE; 1174706f2543Smrg} 1175706f2543Smrg 1176706f2543Smrgvoid 1177706f2543SmrgDRI2CloseScreen(ScreenPtr pScreen) 1178706f2543Smrg{ 1179706f2543Smrg DRI2ScreenPtr ds = DRI2GetScreen(pScreen); 1180706f2543Smrg 1181706f2543Smrg free(ds->driverNames); 1182706f2543Smrg free(ds); 1183706f2543Smrg dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, NULL); 1184706f2543Smrg} 1185706f2543Smrg 1186706f2543Smrgextern ExtensionModule dri2ExtensionModule; 1187706f2543Smrgextern Bool DRI2ModuleSetup(void); 1188706f2543Smrg 1189706f2543Smrg/* Called by InitExtensions() */ 1190706f2543SmrgBool 1191706f2543SmrgDRI2ModuleSetup(void) 1192706f2543Smrg{ 1193706f2543Smrg dri2DrawableRes = CreateNewResourceType(DRI2DrawableGone, "DRI2Drawable"); 1194706f2543Smrg if (!dri2DrawableRes) 1195706f2543Smrg return FALSE; 1196706f2543Smrg 1197706f2543Smrg return TRUE; 1198706f2543Smrg} 1199706f2543Smrg 1200706f2543Smrgstatic pointer 1201706f2543SmrgDRI2Setup(pointer module, pointer opts, int *errmaj, int *errmin) 1202706f2543Smrg{ 1203706f2543Smrg static Bool setupDone = FALSE; 1204706f2543Smrg 1205706f2543Smrg if (!setupDone) 1206706f2543Smrg { 1207706f2543Smrg setupDone = TRUE; 1208706f2543Smrg LoadExtension(&dri2ExtensionModule, FALSE); 1209706f2543Smrg } 1210706f2543Smrg else 1211706f2543Smrg { 1212706f2543Smrg if (errmaj) 1213706f2543Smrg *errmaj = LDR_ONCEONLY; 1214706f2543Smrg } 1215706f2543Smrg 1216706f2543Smrg return (pointer) 1; 1217706f2543Smrg} 1218706f2543Smrg 1219706f2543Smrgstatic XF86ModuleVersionInfo DRI2VersRec = 1220706f2543Smrg{ 1221706f2543Smrg "dri2", 1222706f2543Smrg MODULEVENDORSTRING, 1223706f2543Smrg MODINFOSTRING1, 1224706f2543Smrg MODINFOSTRING2, 1225706f2543Smrg XORG_VERSION_CURRENT, 1226706f2543Smrg 1, 2, 0, 1227706f2543Smrg ABI_CLASS_EXTENSION, 1228706f2543Smrg ABI_EXTENSION_VERSION, 1229706f2543Smrg MOD_CLASS_NONE, 1230706f2543Smrg { 0, 0, 0, 0 } 1231706f2543Smrg}; 1232706f2543Smrg 1233706f2543Smrg_X_EXPORT XF86ModuleData dri2ModuleData = { &DRI2VersRec, DRI2Setup, NULL }; 1234706f2543Smrg 1235706f2543Smrgvoid 1236706f2543SmrgDRI2Version(int *major, int *minor) 1237706f2543Smrg{ 1238706f2543Smrg if (major != NULL) 1239706f2543Smrg *major = DRI2VersRec.majorversion; 1240706f2543Smrg 1241706f2543Smrg if (minor != NULL) 1242706f2543Smrg *minor = DRI2VersRec.minorversion; 1243706f2543Smrg} 1244