1fda9279dSmrg#include <sys/types.h> 2fda9279dSmrg#include <sys/stat.h> 3fda9279dSmrg#include <fcntl.h> 4fda9279dSmrg#include <errno.h> 5fda9279dSmrg 6fda9279dSmrg#include "xorg-server.h" 7fda9279dSmrg#include "nv_include.h" 8fda9279dSmrg#ifdef DRI2 9fda9279dSmrg#include "dri2.h" 10fda9279dSmrg#else 11fda9279dSmrg#error "This driver requires a DRI2-enabled X server" 12fda9279dSmrg#endif 1316ee1e9aSmrg#ifdef DRI3 1416ee1e9aSmrg#include "dri3.h" 1516ee1e9aSmrg#endif 16fda9279dSmrg#include "xf86drmMode.h" 17fda9279dSmrg 18fda9279dSmrgstruct nouveau_dri2_buffer { 19fda9279dSmrg DRI2BufferRec base; 20fda9279dSmrg PixmapPtr ppix; 21fda9279dSmrg}; 22fda9279dSmrg 23fda9279dSmrgstatic inline struct nouveau_dri2_buffer * 24fda9279dSmrgnouveau_dri2_buffer(DRI2BufferPtr buf) 25fda9279dSmrg{ 26fda9279dSmrg return (struct nouveau_dri2_buffer *)buf; 27fda9279dSmrg} 28fda9279dSmrg 29fda9279dSmrgstatic PixmapPtr get_drawable_pixmap(DrawablePtr drawable) 30fda9279dSmrg{ 31fda9279dSmrg if (drawable->type == DRAWABLE_PIXMAP) 32fda9279dSmrg return (PixmapPtr)drawable; 33fda9279dSmrg else 34fda9279dSmrg return (*drawable->pScreen->GetWindowPixmap)((WindowPtr)drawable); 35fda9279dSmrg} 36fda9279dSmrg 37dd52494dSmrgstatic DRI2BufferPtr 38fda9279dSmrgnouveau_dri2_create_buffer2(ScreenPtr pScreen, DrawablePtr pDraw, unsigned int attachment, 39fda9279dSmrg unsigned int format) 40fda9279dSmrg{ 41fda9279dSmrg NVPtr pNv = NVPTR(xf86ScreenToScrn(pScreen)); 42fda9279dSmrg struct nouveau_dri2_buffer *nvbuf; 43fda9279dSmrg struct nouveau_pixmap *nvpix; 44fda9279dSmrg PixmapPtr ppix = NULL; 45fda9279dSmrg 46fda9279dSmrg nvbuf = calloc(1, sizeof(*nvbuf)); 47fda9279dSmrg if (!nvbuf) 48fda9279dSmrg return NULL; 49fda9279dSmrg 50fda9279dSmrg if (attachment == DRI2BufferFrontLeft) { 51fda9279dSmrg ppix = get_drawable_pixmap(pDraw); 52fda9279dSmrg if (pScreen != ppix->drawable.pScreen) 53fda9279dSmrg ppix = NULL; 54fda9279dSmrg 55fda9279dSmrg if (pDraw->type == DRAWABLE_WINDOW) { 56fda9279dSmrg#if DRI2INFOREC_VERSION >= 6 57fda9279dSmrg /* Set initial swap limit on drawable. */ 58fda9279dSmrg DRI2SwapLimit(pDraw, pNv->swap_limit); 59fda9279dSmrg#endif 60fda9279dSmrg } 61fda9279dSmrg if (ppix) 62fda9279dSmrg ppix->refcnt++; 63fda9279dSmrg } else { 64fda9279dSmrg int bpp; 6592405695Smrg unsigned int usage_hint = 0; 6692405695Smrg 6792405695Smrg if (pNv->Architecture >= NV_ARCH_10) 6892405695Smrg usage_hint |= NOUVEAU_CREATE_PIXMAP_TILED; 69fda9279dSmrg 70fda9279dSmrg /* 'format' is just depth (or 0, or maybe it depends on the caller) */ 71fda9279dSmrg bpp = round_up_pow2(format ? format : pDraw->depth); 72fda9279dSmrg 73fda9279dSmrg if (attachment == DRI2BufferDepth || 74fda9279dSmrg attachment == DRI2BufferDepthStencil) 75fda9279dSmrg usage_hint |= NOUVEAU_CREATE_PIXMAP_ZETA; 76fda9279dSmrg else 77fda9279dSmrg usage_hint |= NOUVEAU_CREATE_PIXMAP_SCANOUT; 78fda9279dSmrg 79fda9279dSmrg ppix = pScreen->CreatePixmap(pScreen, pDraw->width, 80fda9279dSmrg pDraw->height, bpp, 81fda9279dSmrg usage_hint); 82fda9279dSmrg } 83fda9279dSmrg 84fda9279dSmrg if (ppix) { 85fda9279dSmrg pNv->exa_force_cp = TRUE; 86fda9279dSmrg exaMoveInPixmap(ppix); 87fda9279dSmrg pNv->exa_force_cp = FALSE; 88fda9279dSmrg 89fda9279dSmrg nvbuf->base.pitch = ppix->devKind; 90fda9279dSmrg nvbuf->base.cpp = ppix->drawable.bitsPerPixel / 8; 91fda9279dSmrg } 92fda9279dSmrg 93fda9279dSmrg nvbuf->base.attachment = attachment; 94fda9279dSmrg nvbuf->base.driverPrivate = nvbuf; 95fda9279dSmrg nvbuf->base.format = format; 96fda9279dSmrg nvbuf->base.flags = 0; 97fda9279dSmrg nvbuf->ppix = ppix; 98fda9279dSmrg 99fda9279dSmrg if (ppix) { 100fda9279dSmrg nvpix = nouveau_pixmap(ppix); 101fda9279dSmrg if (!nvpix || !nvpix->bo || 102fda9279dSmrg nouveau_bo_name_get(nvpix->bo, &nvbuf->base.name)) { 10333adc6acSmrg dixDestroyPixmap(nvbuf->ppix, 0); 104fda9279dSmrg free(nvbuf); 105fda9279dSmrg return NULL; 106fda9279dSmrg } 107fda9279dSmrg } 108fda9279dSmrg return &nvbuf->base; 109fda9279dSmrg} 110fda9279dSmrg 111dd52494dSmrgstatic DRI2BufferPtr 112fda9279dSmrgnouveau_dri2_create_buffer(DrawablePtr pDraw, unsigned int attachment, 113fda9279dSmrg unsigned int format) 114fda9279dSmrg{ 115fda9279dSmrg return nouveau_dri2_create_buffer2(pDraw->pScreen, pDraw, 116fda9279dSmrg attachment, format); 117fda9279dSmrg} 118fda9279dSmrg 119dd52494dSmrgstatic void 120fda9279dSmrgnouveau_dri2_destroy_buffer2(ScreenPtr pScreen, DrawablePtr pDraw, DRI2BufferPtr buf) 121fda9279dSmrg{ 122fda9279dSmrg struct nouveau_dri2_buffer *nvbuf; 123fda9279dSmrg 124fda9279dSmrg nvbuf = nouveau_dri2_buffer(buf); 125fda9279dSmrg if (!nvbuf) 126fda9279dSmrg return; 127fda9279dSmrg 128fda9279dSmrg if (nvbuf->ppix) 12933adc6acSmrg dixDestroyPixmap(nvbuf->ppix, 0); 130fda9279dSmrg free(nvbuf); 131fda9279dSmrg} 132fda9279dSmrg 133dd52494dSmrgstatic void 134fda9279dSmrgnouveau_dri2_destroy_buffer(DrawablePtr pDraw, DRI2BufferPtr buf) 135fda9279dSmrg{ 136fda9279dSmrg nouveau_dri2_destroy_buffer2(pDraw->pScreen, pDraw, buf); 137fda9279dSmrg} 138fda9279dSmrg 139dd52494dSmrgstatic void 140fda9279dSmrgnouveau_dri2_copy_region2(ScreenPtr pScreen, DrawablePtr pDraw, RegionPtr pRegion, 141fda9279dSmrg DRI2BufferPtr pDstBuffer, DRI2BufferPtr pSrcBuffer) 142fda9279dSmrg{ 143fda9279dSmrg struct nouveau_dri2_buffer *src = nouveau_dri2_buffer(pSrcBuffer); 144fda9279dSmrg struct nouveau_dri2_buffer *dst = nouveau_dri2_buffer(pDstBuffer); 145fda9279dSmrg NVPtr pNv = NVPTR(xf86ScreenToScrn(pScreen)); 146fda9279dSmrg RegionPtr pCopyClip; 147fda9279dSmrg GCPtr pGC; 148fda9279dSmrg DrawablePtr src_draw, dst_draw; 149fda9279dSmrg Bool translate = FALSE; 150fda9279dSmrg int off_x = 0, off_y = 0; 151fda9279dSmrg 152fda9279dSmrg src_draw = &src->ppix->drawable; 153fda9279dSmrg dst_draw = &dst->ppix->drawable; 154fda9279dSmrg#if 0 155fda9279dSmrg ErrorF("attachments src %d, dst %d, drawable %p %p pDraw %p\n", 156fda9279dSmrg src->base.attachment, dst->base.attachment, 157fda9279dSmrg src_draw, dst_draw, pDraw); 158fda9279dSmrg#endif 159fda9279dSmrg if (src->base.attachment == DRI2BufferFrontLeft) 160fda9279dSmrg src_draw = pDraw; 161fda9279dSmrg if (dst->base.attachment == DRI2BufferFrontLeft) { 162fda9279dSmrg#ifdef NOUVEAU_PIXMAP_SHARING 163fda9279dSmrg if (pDraw->pScreen != pScreen) { 164fda9279dSmrg dst_draw = DRI2UpdatePrime(pDraw, pDstBuffer); 165fda9279dSmrg if (!dst_draw) 166fda9279dSmrg return; 167fda9279dSmrg } 168fda9279dSmrg else 169fda9279dSmrg#endif 170fda9279dSmrg dst_draw = pDraw; 171fda9279dSmrg if (dst_draw != pDraw) 172fda9279dSmrg translate = TRUE; 173fda9279dSmrg } 174fda9279dSmrg 175fda9279dSmrg if (translate && pDraw->type == DRAWABLE_WINDOW) { 17616ee1e9aSmrg#ifdef COMPOSITE 177fda9279dSmrg PixmapPtr pPix = get_drawable_pixmap(pDraw); 17816ee1e9aSmrg off_x = -pPix->screen_x; 17916ee1e9aSmrg off_y = -pPix->screen_y; 18016ee1e9aSmrg#endif 18116ee1e9aSmrg off_x += pDraw->x; 18216ee1e9aSmrg off_y += pDraw->y; 183fda9279dSmrg } 184fda9279dSmrg 185fda9279dSmrg pGC = GetScratchGC(pDraw->depth, pScreen); 186fda9279dSmrg pCopyClip = REGION_CREATE(pScreen, NULL, 0); 187fda9279dSmrg REGION_COPY(pScreen, pCopyClip, pRegion); 188fda9279dSmrg 189fda9279dSmrg if (translate) { 190fda9279dSmrg REGION_TRANSLATE(pScreen, pCopyClip, off_x, off_y); 191fda9279dSmrg } 192fda9279dSmrg pGC->funcs->ChangeClip(pGC, CT_REGION, pCopyClip, 0); 193fda9279dSmrg ValidateGC(dst_draw, pGC); 194fda9279dSmrg 195fda9279dSmrg /* If this is a full buffer swap or frontbuffer flush, throttle on 196fda9279dSmrg * the previous one. 197fda9279dSmrg */ 198fda9279dSmrg if (dst->base.attachment == DRI2BufferFrontLeft && 199fda9279dSmrg REGION_NUM_RECTS(pRegion) == 1) { 200fda9279dSmrg BoxPtr extents = REGION_EXTENTS(pScreen, pRegion); 201fda9279dSmrg if (extents->x1 == 0 && extents->y1 == 0 && 202fda9279dSmrg extents->x2 == pDraw->width && 203fda9279dSmrg extents->y2 == pDraw->height) { 204fda9279dSmrg PixmapPtr fpix = get_drawable_pixmap(dst_draw); 205fda9279dSmrg struct nouveau_bo *bo = nouveau_pixmap_bo(fpix); 206fda9279dSmrg if (bo) 207fda9279dSmrg nouveau_bo_wait(bo, NOUVEAU_BO_RD, pNv->client); 208fda9279dSmrg } 209fda9279dSmrg } 210fda9279dSmrg 211fda9279dSmrg pGC->ops->CopyArea(src_draw, dst_draw, pGC, 0, 0, 212fda9279dSmrg pDraw->width, pDraw->height, off_x, off_y); 213fda9279dSmrg 214fda9279dSmrg FreeScratchGC(pGC); 215fda9279dSmrg} 216fda9279dSmrg 217dd52494dSmrgstatic void 218fda9279dSmrgnouveau_dri2_copy_region(DrawablePtr pDraw, RegionPtr pRegion, 219fda9279dSmrg DRI2BufferPtr pDstBuffer, DRI2BufferPtr pSrcBuffer) 220fda9279dSmrg{ 221fda9279dSmrg return nouveau_dri2_copy_region2(pDraw->pScreen, pDraw, pRegion, 222fda9279dSmrg pDstBuffer, pSrcBuffer); 223fda9279dSmrg} 224fda9279dSmrg 225fda9279dSmrgstruct nouveau_dri2_vblank_state { 226fda9279dSmrg enum { 227fda9279dSmrg SWAP, 228fda9279dSmrg BLIT, 229fda9279dSmrg WAIT 230fda9279dSmrg } action; 231fda9279dSmrg 232fda9279dSmrg ClientPtr client; 233fda9279dSmrg XID draw; 234fda9279dSmrg 235fda9279dSmrg DRI2BufferPtr dst; 236fda9279dSmrg DRI2BufferPtr src; 237fda9279dSmrg DRI2SwapEventPtr func; 238fda9279dSmrg void *data; 239fda9279dSmrg unsigned int frame; 240fda9279dSmrg}; 241fda9279dSmrg 242fda9279dSmrgstruct dri2_vblank { 243fda9279dSmrg struct nouveau_dri2_vblank_state *s; 244fda9279dSmrg}; 245fda9279dSmrg 246fda9279dSmrgstatic uint64_t dri2_sequence; 247fda9279dSmrg 248fda9279dSmrgstatic Bool 249fda9279dSmrgupdate_front(DrawablePtr draw, DRI2BufferPtr front) 250fda9279dSmrg{ 25192405695Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen); 25292405695Smrg NVPtr pNv = NVPTR(scrn); 253fda9279dSmrg struct nouveau_dri2_buffer *nvbuf = nouveau_dri2_buffer(front); 25492405695Smrg struct nouveau_bo *pixmap_bo; 25592405695Smrg 25692405695Smrg PixmapPtr pixmap; 25792405695Smrg int r; 258fda9279dSmrg 259fda9279dSmrg if (draw->type == DRAWABLE_PIXMAP) 260fda9279dSmrg pixmap = (PixmapPtr)draw; 261fda9279dSmrg else 262fda9279dSmrg pixmap = (*draw->pScreen->GetWindowPixmap)((WindowPtr)draw); 263fda9279dSmrg 264fda9279dSmrg pixmap->refcnt++; 265fda9279dSmrg 26692405695Smrg pNv->exa_force_cp = TRUE; 267fda9279dSmrg exaMoveInPixmap(pixmap); 26892405695Smrg pNv->exa_force_cp = FALSE; 26992405695Smrg pixmap_bo = nouveau_pixmap_bo(pixmap); 27092405695Smrg 27192405695Smrg if (!pixmap_bo) 27292405695Smrg r = -1; 27392405695Smrg else 27492405695Smrg r = nouveau_bo_name_get(pixmap_bo, &front->name); 27592405695Smrg 276fda9279dSmrg if (r) { 27733adc6acSmrg dixDestroyPixmap(pixmap, 0); 278fda9279dSmrg return FALSE; 279fda9279dSmrg } 280fda9279dSmrg 281fda9279dSmrg if (nvbuf->ppix) 28233adc6acSmrg dixDestroyPixmap(nvbuf->ppix, 0); 283fda9279dSmrg 284fda9279dSmrg front->pitch = pixmap->devKind; 285fda9279dSmrg front->cpp = pixmap->drawable.bitsPerPixel / 8; 286fda9279dSmrg nvbuf->ppix = pixmap; 287fda9279dSmrg 288fda9279dSmrg return TRUE; 289fda9279dSmrg} 290fda9279dSmrg 291fda9279dSmrgstatic Bool 292fda9279dSmrgcan_exchange(DrawablePtr draw, PixmapPtr dst_pix, PixmapPtr src_pix) 293fda9279dSmrg{ 294fda9279dSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen); 295fda9279dSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 296fda9279dSmrg NVPtr pNv = NVPTR(scrn); 297cd34e0e1Smrg int i, active_crtc_count = 0; 298fda9279dSmrg 299fda9279dSmrg if (!xf86_config->num_crtc) 300fda9279dSmrg return FALSE; 301fda9279dSmrg 302fda9279dSmrg for (i = 0; i < xf86_config->num_crtc; i++) { 303fda9279dSmrg xf86CrtcPtr crtc = xf86_config->crtc[i]; 30433adc6acSmrg if (xf86_crtc_on(crtc)) { 305cd34e0e1Smrg if (crtc->rotatedData) 306cd34e0e1Smrg return FALSE; 307fda9279dSmrg 308cd34e0e1Smrg active_crtc_count++; 309cd34e0e1Smrg } 310fda9279dSmrg } 311fda9279dSmrg 312fda9279dSmrg return ((DRI2CanFlip(draw) && pNv->has_pageflip)) && 313fda9279dSmrg dst_pix->drawable.width == src_pix->drawable.width && 314fda9279dSmrg dst_pix->drawable.height == src_pix->drawable.height && 315fda9279dSmrg dst_pix->drawable.bitsPerPixel == src_pix->drawable.bitsPerPixel && 316cd34e0e1Smrg dst_pix->devKind == src_pix->devKind && 317cd34e0e1Smrg active_crtc_count; 318fda9279dSmrg} 319fda9279dSmrg 320fda9279dSmrgstatic Bool 321fda9279dSmrgcan_sync_to_vblank(DrawablePtr draw) 322fda9279dSmrg{ 323fda9279dSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen); 324fda9279dSmrg NVPtr pNv = NVPTR(scrn); 325fda9279dSmrg 326fda9279dSmrg return pNv->glx_vblank && 327fda9279dSmrg nv_window_belongs_to_crtc(scrn, draw->x, draw->y, 328fda9279dSmrg draw->width, draw->height); 329fda9279dSmrg} 330fda9279dSmrg 331fda9279dSmrg#if DRI2INFOREC_VERSION >= 6 332fda9279dSmrgstatic Bool 333fda9279dSmrgnouveau_dri2_swap_limit_validate(DrawablePtr draw, int swap_limit) 334fda9279dSmrg{ 335fda9279dSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen); 336fda9279dSmrg NVPtr pNv = NVPTR(scrn); 337fda9279dSmrg 338fda9279dSmrg if ((swap_limit < 1 ) || (swap_limit > pNv->max_swap_limit)) 339fda9279dSmrg return FALSE; 340fda9279dSmrg 341fda9279dSmrg return TRUE; 342fda9279dSmrg} 343fda9279dSmrg#endif 344fda9279dSmrg 345fda9279dSmrg/* Shall we intentionally violate the OML_sync_control spec to 346fda9279dSmrg * get some sort of triple-buffering behaviour on a pre 1.12.0 347fda9279dSmrg * x-server? 348fda9279dSmrg */ 349fda9279dSmrgstatic Bool violate_oml(DrawablePtr draw) 350fda9279dSmrg{ 351fda9279dSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen); 352fda9279dSmrg NVPtr pNv = NVPTR(scrn); 353fda9279dSmrg 354fda9279dSmrg return (DRI2INFOREC_VERSION < 6) && (pNv->swap_limit > 1); 355fda9279dSmrg} 356fda9279dSmrg 357fda9279dSmrgtypedef struct { 358fda9279dSmrg int fd; 359fda9279dSmrg unsigned old_fb_id; 360fda9279dSmrg int flip_count; 361fda9279dSmrg void *event_data; 362fda9279dSmrg unsigned int fe_msc; 363fda9279dSmrg uint64_t fe_ust; 364fda9279dSmrg} dri2_flipdata_rec, *dri2_flipdata_ptr; 365fda9279dSmrg 366fda9279dSmrgtypedef struct { 367fda9279dSmrg dri2_flipdata_ptr flipdata; 368fda9279dSmrg Bool dispatch_me; 369fda9279dSmrg} dri2_flipevtcarrier_rec, *dri2_flipevtcarrier_ptr; 370fda9279dSmrg 371fda9279dSmrgstatic void 372fda9279dSmrgnouveau_dri2_flip_event_handler(unsigned int frame, unsigned int tv_sec, 373fda9279dSmrg unsigned int tv_usec, void *event_data) 374fda9279dSmrg{ 375fda9279dSmrg struct nouveau_dri2_vblank_state *flip = event_data; 376fda9279dSmrg DrawablePtr draw; 377fda9279dSmrg ScreenPtr screen; 378fda9279dSmrg ScrnInfoPtr scrn; 379fda9279dSmrg int status; 380fda9279dSmrg 381fda9279dSmrg status = dixLookupDrawable(&draw, flip->draw, serverClient, 382fda9279dSmrg M_ANY, DixWriteAccess); 383fda9279dSmrg if (status != Success) { 384fda9279dSmrg free(flip); 385fda9279dSmrg return; 386fda9279dSmrg } 387fda9279dSmrg 388fda9279dSmrg screen = draw->pScreen; 389fda9279dSmrg scrn = xf86ScreenToScrn(screen); 390fda9279dSmrg 391fda9279dSmrg /* We assume our flips arrive in order, so we don't check the frame */ 392fda9279dSmrg switch (flip->action) { 393fda9279dSmrg case SWAP: 394fda9279dSmrg /* Check for too small vblank count of pageflip completion, 395fda9279dSmrg * taking wraparound into account. This usually means some 396fda9279dSmrg * defective kms pageflip completion, causing wrong (msc, ust) 397fda9279dSmrg * return values and possible visual corruption. 398fda9279dSmrg * Skip test for frame == 0, as this is a valid constant value 399fda9279dSmrg * reported by all Linux kernels at least up to Linux 3.0. 400fda9279dSmrg */ 401fda9279dSmrg if ((frame != 0) && 402fda9279dSmrg (frame < flip->frame) && (flip->frame - frame < 5)) { 403fda9279dSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 404fda9279dSmrg "%s: Pageflip has impossible msc %d < target_msc %d\n", 405fda9279dSmrg __func__, frame, flip->frame); 406fda9279dSmrg /* All-Zero values signal failure of (msc, ust) 407fda9279dSmrg * timestamping to client. 408fda9279dSmrg */ 409fda9279dSmrg frame = tv_sec = tv_usec = 0; 410fda9279dSmrg } 411fda9279dSmrg 412fda9279dSmrg DRI2SwapComplete(flip->client, draw, frame, tv_sec, tv_usec, 413fda9279dSmrg DRI2_FLIP_COMPLETE, flip->func, 414fda9279dSmrg flip->data); 415fda9279dSmrg break; 416fda9279dSmrg default: 417fda9279dSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 418fda9279dSmrg "%s: unknown vblank event received\n", __func__); 419fda9279dSmrg /* Unknown type */ 420fda9279dSmrg break; 421fda9279dSmrg } 422fda9279dSmrg 423fda9279dSmrg free(flip); 424fda9279dSmrg} 425fda9279dSmrg 426fda9279dSmrgstatic void 427fda9279dSmrgnouveau_dri2_flip_handler(void *priv, uint64_t name, uint64_t ust, uint32_t msc) 428fda9279dSmrg{ 429fda9279dSmrg dri2_flipevtcarrier_ptr flipcarrier = priv; 430fda9279dSmrg dri2_flipdata_ptr flipdata = flipcarrier->flipdata; 431fda9279dSmrg 432fda9279dSmrg /* Is this the event whose info shall be delivered to higher level? */ 433fda9279dSmrg if (flipcarrier->dispatch_me) { 434fda9279dSmrg /* Yes: Cache msc, ust for later delivery. */ 435fda9279dSmrg flipdata->fe_msc = msc; 436fda9279dSmrg flipdata->fe_ust = ust; 437fda9279dSmrg } 438fda9279dSmrg 439fda9279dSmrg /* Last crtc completed flip? */ 440fda9279dSmrg flipdata->flip_count--; 441fda9279dSmrg if (flipdata->flip_count > 0) 442fda9279dSmrg return; 443fda9279dSmrg 444fda9279dSmrg /* Release framebuffer */ 445fda9279dSmrg drmModeRmFB(flipdata->fd, flipdata->old_fb_id); 446fda9279dSmrg 447fda9279dSmrg if (flipdata->event_data == NULL) { 448fda9279dSmrg free(flipdata); 449fda9279dSmrg return; 450fda9279dSmrg } 451fda9279dSmrg 452fda9279dSmrg /* Deliver cached msc, ust from reference crtc to flip event handler */ 453fda9279dSmrg nouveau_dri2_flip_event_handler(flipdata->fe_msc, 454fda9279dSmrg flipdata->fe_ust / 1000000, 455fda9279dSmrg flipdata->fe_ust % 1000000, 456fda9279dSmrg flipdata->event_data); 457fda9279dSmrg free(flipdata); 458fda9279dSmrg} 459fda9279dSmrg 460fda9279dSmrgstatic Bool 461fda9279dSmrgdri2_page_flip(DrawablePtr draw, PixmapPtr back, void *priv, 462fda9279dSmrg xf86CrtcPtr ref_crtc) 463fda9279dSmrg{ 464fda9279dSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen); 465fda9279dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 466fda9279dSmrg NVPtr pNv = NVPTR(scrn); 467fda9279dSmrg uint32_t next_fb; 468fda9279dSmrg int emitted = 0; 469fda9279dSmrg int ret, i; 470fda9279dSmrg dri2_flipdata_ptr flipdata; 471fda9279dSmrg dri2_flipevtcarrier_ptr flipcarrier; 472fda9279dSmrg 473fda9279dSmrg ret = drmModeAddFB(pNv->dev->fd, scrn->virtualX, scrn->virtualY, 474fda9279dSmrg scrn->depth, scrn->bitsPerPixel, 475fda9279dSmrg scrn->displayWidth * scrn->bitsPerPixel / 8, 476fda9279dSmrg nouveau_pixmap(back)->bo->handle, &next_fb); 477fda9279dSmrg if (ret) { 478fda9279dSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 479fda9279dSmrg "add fb failed: %s\n", strerror(errno)); 480fda9279dSmrg return FALSE; 481fda9279dSmrg } 482fda9279dSmrg 483fda9279dSmrg flipdata = calloc(1, sizeof(dri2_flipdata_rec)); 484fda9279dSmrg if (!flipdata) { 485fda9279dSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 486fda9279dSmrg "flip queue: data alloc failed.\n"); 487fda9279dSmrg goto error_undo; 488fda9279dSmrg } 489fda9279dSmrg 490fda9279dSmrg flipdata->event_data = priv; 491fda9279dSmrg flipdata->fd = pNv->dev->fd; 492fda9279dSmrg 493fda9279dSmrg for (i = 0; i < config->num_crtc; i++) { 494fda9279dSmrg int head = drmmode_crtc(config->crtc[i]); 495fda9279dSmrg void *token; 496fda9279dSmrg 49733adc6acSmrg if (!xf86_crtc_on(config->crtc[i])) 498fda9279dSmrg continue; 499fda9279dSmrg 500fda9279dSmrg flipdata->flip_count++; 501fda9279dSmrg 502fda9279dSmrg flipcarrier = drmmode_event_queue(scrn, ++dri2_sequence, 503fda9279dSmrg sizeof(*flipcarrier), 504fda9279dSmrg nouveau_dri2_flip_handler, 505fda9279dSmrg &token); 506fda9279dSmrg if (!flipcarrier) { 507fda9279dSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 508fda9279dSmrg "flip queue: carrier alloc failed.\n"); 509fda9279dSmrg if (emitted == 0) 510fda9279dSmrg free(flipdata); 511fda9279dSmrg goto error_undo; 512fda9279dSmrg } 513fda9279dSmrg 514fda9279dSmrg /* Only the reference crtc will finally deliver its page flip 515fda9279dSmrg * completion event. All other crtc's events will be discarded. 516fda9279dSmrg */ 517fda9279dSmrg flipcarrier->dispatch_me = (config->crtc[i] == ref_crtc); 518fda9279dSmrg flipcarrier->flipdata = flipdata; 519fda9279dSmrg 520fda9279dSmrg ret = drmModePageFlip(pNv->dev->fd, head, next_fb, 521fda9279dSmrg DRM_MODE_PAGE_FLIP_EVENT, token); 522fda9279dSmrg if (ret) { 523fda9279dSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 524fda9279dSmrg "flip queue failed: %s\n", strerror(errno)); 525fda9279dSmrg drmmode_event_abort(scrn, dri2_sequence--, false); 526fda9279dSmrg if (emitted == 0) 527fda9279dSmrg free(flipdata); 528fda9279dSmrg goto error_undo; 529fda9279dSmrg } 530fda9279dSmrg 531fda9279dSmrg emitted++; 532fda9279dSmrg } 533fda9279dSmrg 534fda9279dSmrg /* Will release old fb after all crtc's completed flip. */ 535fda9279dSmrg drmmode_swap(scrn, next_fb, &flipdata->old_fb_id); 536fda9279dSmrg return TRUE; 537fda9279dSmrg 538fda9279dSmrgerror_undo: 539fda9279dSmrg drmModeRmFB(pNv->dev->fd, next_fb); 540fda9279dSmrg return FALSE; 541fda9279dSmrg} 542fda9279dSmrg 543fda9279dSmrgstatic void 544fda9279dSmrgnouveau_dri2_finish_swap(DrawablePtr draw, unsigned int frame, 545fda9279dSmrg unsigned int tv_sec, unsigned int tv_usec, 546fda9279dSmrg struct nouveau_dri2_vblank_state *s); 547fda9279dSmrg 548fda9279dSmrgstatic void 549fda9279dSmrgnouveau_dri2_vblank_handler(void *priv, uint64_t name, uint64_t ust, uint32_t frame) 550fda9279dSmrg{ 551fda9279dSmrg struct dri2_vblank *event = priv; 552fda9279dSmrg struct nouveau_dri2_vblank_state *s = event->s; 553fda9279dSmrg uint32_t tv_sec = ust / 1000000; 554fda9279dSmrg uint32_t tv_usec = ust % 1000000; 555fda9279dSmrg DrawablePtr draw; 556fda9279dSmrg int ret; 557fda9279dSmrg 558fda9279dSmrg ret = dixLookupDrawable(&draw, s->draw, serverClient, 559fda9279dSmrg M_ANY, DixWriteAccess); 560fda9279dSmrg if (ret) { 561fda9279dSmrg free(s); 562fda9279dSmrg return; 563fda9279dSmrg } 564fda9279dSmrg 565fda9279dSmrg switch (s->action) { 566fda9279dSmrg case SWAP: 567fda9279dSmrg nouveau_dri2_finish_swap(draw, frame, tv_sec, tv_usec, s); 568fda9279dSmrg#if DRI2INFOREC_VERSION >= 6 569fda9279dSmrg /* Restore real swap limit on drawable, now that it is safe. */ 570fda9279dSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen); 571fda9279dSmrg DRI2SwapLimit(draw, NVPTR(scrn)->swap_limit); 572fda9279dSmrg#endif 573fda9279dSmrg break; 574fda9279dSmrg 575fda9279dSmrg case WAIT: 576fda9279dSmrg DRI2WaitMSCComplete(s->client, draw, frame, tv_sec, tv_usec); 577fda9279dSmrg free(s); 578fda9279dSmrg break; 579fda9279dSmrg 580fda9279dSmrg case BLIT: 581fda9279dSmrg DRI2SwapComplete(s->client, draw, frame, tv_sec, tv_usec, 582fda9279dSmrg DRI2_BLIT_COMPLETE, s->func, s->data); 583fda9279dSmrg free(s); 584fda9279dSmrg break; 585fda9279dSmrg } 586fda9279dSmrg} 587fda9279dSmrg 588fda9279dSmrgstatic int 589fda9279dSmrgnouveau_wait_vblank(DrawablePtr draw, int type, CARD64 msc, 590fda9279dSmrg CARD64 *pmsc, CARD64 *pust, void *data) 591fda9279dSmrg{ 592fda9279dSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen); 593fda9279dSmrg NVPtr pNv = NVPTR(scrn); 594fda9279dSmrg xf86CrtcPtr crtc; 595fda9279dSmrg drmVBlank vbl; 596fda9279dSmrg struct dri2_vblank *event = NULL; 597fda9279dSmrg void *token = NULL; 598fda9279dSmrg int ret; 599fda9279dSmrg int head; 600fda9279dSmrg 601fda9279dSmrg /* Select crtc which shows the largest part of the drawable */ 60233adc6acSmrg crtc = nouveau_pick_best_crtc(scrn, 60333adc6acSmrg draw->x, draw->y, draw->width, draw->height); 604fda9279dSmrg 605fda9279dSmrg if (!crtc) { 606fda9279dSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 607fda9279dSmrg "Wait for VBlank failed: No valid crtc for drawable.\n"); 608fda9279dSmrg return -EINVAL; 609fda9279dSmrg } 610fda9279dSmrg 611fda9279dSmrg if (type & DRM_VBLANK_EVENT) { 612fda9279dSmrg event = drmmode_event_queue(scrn, ++dri2_sequence, 613fda9279dSmrg sizeof(*event), 614fda9279dSmrg nouveau_dri2_vblank_handler, 615fda9279dSmrg &token); 616fda9279dSmrg if (!event) 617fda9279dSmrg return -ENOMEM; 618fda9279dSmrg 619fda9279dSmrg event->s = data; 620fda9279dSmrg } 621fda9279dSmrg 622fda9279dSmrg /* Map xf86CrtcPtr to drmWaitVBlank compatible display head index. */ 623fda9279dSmrg head = drmmode_head(crtc); 624fda9279dSmrg 625fda9279dSmrg if (head == 1) 626fda9279dSmrg type |= DRM_VBLANK_SECONDARY; 627fda9279dSmrg else if (head > 1) 628fda9279dSmrg#ifdef DRM_VBLANK_HIGH_CRTC_SHIFT 629fda9279dSmrg type |= (head << DRM_VBLANK_HIGH_CRTC_SHIFT) & 630fda9279dSmrg DRM_VBLANK_HIGH_CRTC_MASK; 631fda9279dSmrg#else 632fda9279dSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 633fda9279dSmrg "Wait for VBlank failed: Called for CRTC %d > 1, but " 634fda9279dSmrg "DRM_VBLANK_HIGH_CRTC_SHIFT not defined at build time.\n", 635fda9279dSmrg head); 636fda9279dSmrg#endif 637fda9279dSmrg 638fda9279dSmrg vbl.request.type = type; 639fda9279dSmrg vbl.request.sequence = msc; 640fda9279dSmrg vbl.request.signal = (unsigned long)token; 641fda9279dSmrg 642fda9279dSmrg ret = drmWaitVBlank(pNv->dev->fd, &vbl); 643fda9279dSmrg if (ret) { 644fda9279dSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 645fda9279dSmrg "Wait for VBlank failed: %s\n", strerror(errno)); 646fda9279dSmrg if (event) 647fda9279dSmrg drmmode_event_abort(scrn, dri2_sequence--, false); 648fda9279dSmrg return ret; 649fda9279dSmrg } 650fda9279dSmrg 651fda9279dSmrg if (pmsc) 652fda9279dSmrg *pmsc = vbl.reply.sequence; 653fda9279dSmrg if (pust) 654fda9279dSmrg *pust = (CARD64)vbl.reply.tval_sec * 1000000 + 655fda9279dSmrg vbl.reply.tval_usec; 656fda9279dSmrg return 0; 657fda9279dSmrg} 658fda9279dSmrg 659fda9279dSmrgstatic void 660fda9279dSmrgnouveau_dri2_finish_swap(DrawablePtr draw, unsigned int frame, 661fda9279dSmrg unsigned int tv_sec, unsigned int tv_usec, 662fda9279dSmrg struct nouveau_dri2_vblank_state *s) 663fda9279dSmrg{ 664fda9279dSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen); 665fda9279dSmrg NVPtr pNv = NVPTR(scrn); 666fda9279dSmrg PixmapPtr dst_pix; 667fda9279dSmrg PixmapPtr src_pix = nouveau_dri2_buffer(s->src)->ppix; 668fda9279dSmrg struct nouveau_bo *dst_bo; 669fda9279dSmrg struct nouveau_bo *src_bo = nouveau_pixmap_bo(src_pix); 670fda9279dSmrg struct nouveau_pushbuf *push = pNv->pushbuf; 671fda9279dSmrg RegionRec reg; 672fda9279dSmrg int type, ret; 673fda9279dSmrg Bool front_updated, will_exchange; 674fda9279dSmrg xf86CrtcPtr ref_crtc; 675fda9279dSmrg 676fda9279dSmrg REGION_INIT(0, ®, (&(BoxRec){ 0, 0, draw->width, draw->height }), 0); 677fda9279dSmrg REGION_TRANSLATE(0, ®, draw->x, draw->y); 678fda9279dSmrg 679fda9279dSmrg /* Main crtc for this drawable shall finally deliver pageflip event. */ 68033adc6acSmrg ref_crtc = nouveau_pick_best_crtc(scrn, draw->x, draw->y, 68133adc6acSmrg draw->width, draw->height); 682fda9279dSmrg 683fda9279dSmrg /* Update frontbuffer pixmap and name: Could have changed due to 684fda9279dSmrg * window (un)redirection as part of compositing. 685fda9279dSmrg */ 686fda9279dSmrg front_updated = update_front(draw, s->dst); 687fda9279dSmrg 688fda9279dSmrg /* Assign frontbuffer pixmap, after update in update_front() */ 689fda9279dSmrg dst_pix = nouveau_dri2_buffer(s->dst)->ppix; 690fda9279dSmrg dst_bo = nouveau_pixmap_bo(dst_pix); 691fda9279dSmrg 692fda9279dSmrg /* Throttle on the previous frame before swapping */ 693fda9279dSmrg nouveau_bo_wait(dst_bo, NOUVEAU_BO_RD, push->client); 694fda9279dSmrg 695fda9279dSmrg /* Swap by buffer exchange possible? */ 696fda9279dSmrg will_exchange = front_updated && can_exchange(draw, dst_pix, src_pix); 697fda9279dSmrg 698fda9279dSmrg /* Only emit a wait for vblank pushbuf here if this is a copy-swap, or 699fda9279dSmrg * if it is a kms pageflip-swap on an old kernel. Pure exchange swaps 700fda9279dSmrg * don't need sync to vblank. kms pageflip-swaps on Linux 3.13+ are 701fda9279dSmrg * synced to vblank in the kms driver, so we must not sync here, or 702fda9279dSmrg * framerate will be cut in half! 703fda9279dSmrg */ 704fda9279dSmrg if (can_sync_to_vblank(draw) && 705fda9279dSmrg (!will_exchange || 706fda9279dSmrg (!pNv->has_async_pageflip && nouveau_exa_pixmap_is_onscreen(dst_pix)))) { 707fda9279dSmrg /* Reference the back buffer to sync it to vblank */ 708fda9279dSmrg nouveau_pushbuf_refn(push, &(struct nouveau_pushbuf_refn) { 709fda9279dSmrg src_bo, 710fda9279dSmrg NOUVEAU_BO_VRAM | NOUVEAU_BO_RD 711fda9279dSmrg }, 1); 712fda9279dSmrg 713fda9279dSmrg if (pNv->Architecture >= NV_FERMI) 714fda9279dSmrg NVC0SyncToVBlank(dst_pix, REGION_EXTENTS(0, ®)); 715fda9279dSmrg else 716fda9279dSmrg if (pNv->Architecture >= NV_TESLA) 717fda9279dSmrg NV50SyncToVBlank(dst_pix, REGION_EXTENTS(0, ®)); 718fda9279dSmrg else 719fda9279dSmrg NV11SyncToVBlank(dst_pix, REGION_EXTENTS(0, ®)); 720fda9279dSmrg 721fda9279dSmrg nouveau_pushbuf_kick(push, push->channel); 722fda9279dSmrg } 723fda9279dSmrg 724fda9279dSmrg if (will_exchange) { 725fda9279dSmrg type = DRI2_EXCHANGE_COMPLETE; 726fda9279dSmrg DamageRegionAppend(draw, ®); 727fda9279dSmrg 728fda9279dSmrg if (nouveau_exa_pixmap_is_onscreen(dst_pix)) { 729fda9279dSmrg type = DRI2_FLIP_COMPLETE; 730fda9279dSmrg ret = dri2_page_flip(draw, src_pix, violate_oml(draw) ? 731fda9279dSmrg NULL : s, ref_crtc); 732fda9279dSmrg if (!ret) 733fda9279dSmrg goto out; 734fda9279dSmrg } 735fda9279dSmrg 736fda9279dSmrg SWAP(s->dst->name, s->src->name); 737fda9279dSmrg SWAP(nouveau_pixmap(dst_pix)->bo, nouveau_pixmap(src_pix)->bo); 738fda9279dSmrg 739fda9279dSmrg DamageRegionProcessPending(draw); 740fda9279dSmrg 741fda9279dSmrg /* If it is a page flip, finish it in the flip event handler. */ 742fda9279dSmrg if ((type == DRI2_FLIP_COMPLETE) && !violate_oml(draw)) 743fda9279dSmrg return; 744fda9279dSmrg } else { 745fda9279dSmrg type = DRI2_BLIT_COMPLETE; 746fda9279dSmrg 747fda9279dSmrg /* Reference the front buffer to let throttling work 748fda9279dSmrg * on occluded drawables. */ 749fda9279dSmrg nouveau_pushbuf_refn(push, &(struct nouveau_pushbuf_refn) { 750fda9279dSmrg dst_bo, 751fda9279dSmrg NOUVEAU_BO_VRAM | NOUVEAU_BO_RD 752fda9279dSmrg }, 1); 753fda9279dSmrg 754fda9279dSmrg REGION_TRANSLATE(0, ®, -draw->x, -draw->y); 755fda9279dSmrg nouveau_dri2_copy_region(draw, ®, s->dst, s->src); 756fda9279dSmrg 757fda9279dSmrg if (can_sync_to_vblank(draw) && !violate_oml(draw)) { 758fda9279dSmrg /* Request a vblank event one vblank from now, the most 759fda9279dSmrg * likely (optimistic?) time a direct framebuffer blit 760fda9279dSmrg * will complete or a desktop compositor will update its 761fda9279dSmrg * screen. This defers DRI2SwapComplete() to the earliest 762fda9279dSmrg * likely time of real swap completion. 763fda9279dSmrg */ 764fda9279dSmrg s->action = BLIT; 765fda9279dSmrg ret = nouveau_wait_vblank(draw, DRM_VBLANK_EVENT | 766fda9279dSmrg DRM_VBLANK_RELATIVE, 1, 767fda9279dSmrg NULL, NULL, s); 768fda9279dSmrg /* Done, if success. Otherwise use fallback below. */ 769fda9279dSmrg if (!ret) 770fda9279dSmrg return; 771fda9279dSmrg } 772fda9279dSmrg } 773fda9279dSmrg 774fda9279dSmrg /* Special triple-buffering hack for old pre 1.12.0 x-servers used? */ 775fda9279dSmrg if (violate_oml(draw)) { 776fda9279dSmrg /* Signal to client that swap completion timestamps and counts 777fda9279dSmrg * are invalid - they violate the specification. 778fda9279dSmrg */ 779fda9279dSmrg frame = tv_sec = tv_usec = 0; 780fda9279dSmrg } 781fda9279dSmrg 782fda9279dSmrg /* 783fda9279dSmrg * Tell the X server buffers are already swapped even if they're 784fda9279dSmrg * not, to prevent it from blocking the client on the next 785fda9279dSmrg * GetBuffers request (and let the client do triple-buffering). 786fda9279dSmrg * 787fda9279dSmrg * XXX - The DRI2SwapLimit() API allowed us to move this to 788fda9279dSmrg * the flip handler with no FPS hit for page flipped swaps. 789fda9279dSmrg * It is still needed as a fallback for some copy swaps as 790fda9279dSmrg * we lack a method to detect true swap completion for 791fda9279dSmrg * DRI2_BLIT_COMPLETE. 792fda9279dSmrg * 793fda9279dSmrg * It is also used if triple-buffering is requested on 794fda9279dSmrg * old x-servers which don't support the DRI2SwapLimit() 795fda9279dSmrg * function. 796fda9279dSmrg */ 797fda9279dSmrg DRI2SwapComplete(s->client, draw, frame, tv_sec, tv_usec, 798fda9279dSmrg type, s->func, s->data); 799fda9279dSmrgout: 800fda9279dSmrg free(s); 801fda9279dSmrg} 802fda9279dSmrg 803fda9279dSmrgstatic Bool 804fda9279dSmrgnouveau_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, 805fda9279dSmrg DRI2BufferPtr dst, DRI2BufferPtr src, 806fda9279dSmrg CARD64 *target_msc, CARD64 divisor, CARD64 remainder, 807fda9279dSmrg DRI2SwapEventPtr func, void *data) 808fda9279dSmrg{ 809fda9279dSmrg struct nouveau_dri2_vblank_state *s; 810fda9279dSmrg CARD64 current_msc, expect_msc; 811fda9279dSmrg CARD64 current_ust; 812fda9279dSmrg int ret; 813fda9279dSmrg 814fda9279dSmrg /* Initialize a swap structure */ 815fda9279dSmrg s = malloc(sizeof(*s)); 816fda9279dSmrg if (!s) 817fda9279dSmrg return FALSE; 818fda9279dSmrg 819fda9279dSmrg *s = (struct nouveau_dri2_vblank_state) 820fda9279dSmrg { SWAP, client, draw->id, dst, src, func, data, 0 }; 821fda9279dSmrg 822fda9279dSmrg if (can_sync_to_vblank(draw)) { 823fda9279dSmrg /* Get current sequence and vblank time*/ 824fda9279dSmrg ret = nouveau_wait_vblank(draw, DRM_VBLANK_RELATIVE, 0, 825fda9279dSmrg ¤t_msc, ¤t_ust, NULL); 826fda9279dSmrg if (ret) 827fda9279dSmrg goto fail; 828fda9279dSmrg 829fda9279dSmrg /* Truncate to match kernel interfaces; means occasional overflow 830fda9279dSmrg * misses, but that's generally not a big deal. 831fda9279dSmrg */ 832fda9279dSmrg *target_msc &= 0xffffffff; 833fda9279dSmrg divisor &= 0xffffffff; 834fda9279dSmrg remainder &= 0xffffffff; 835fda9279dSmrg 836fda9279dSmrg /* Calculate a swap target if we don't have one */ 837fda9279dSmrg if (current_msc >= *target_msc && divisor) 838fda9279dSmrg *target_msc = current_msc + divisor 839fda9279dSmrg - (current_msc - remainder) % divisor; 840fda9279dSmrg 841fda9279dSmrg /* Avoid underflow of unsigned value below */ 842fda9279dSmrg if (*target_msc == 0) 843fda9279dSmrg *target_msc = 1; 844fda9279dSmrg 845fda9279dSmrg /* Swap at next possible vblank requested? */ 846fda9279dSmrg if (current_msc >= *target_msc - 1) { 847fda9279dSmrg /* Special case: Need to swap at next vblank. 848fda9279dSmrg * Schedule swap immediately, bypassing the kernel 849fda9279dSmrg * vblank event mechanism to avoid a dangerous race 850fda9279dSmrg * between the client and the x-server vblank event 851fda9279dSmrg * dispatch in the main x-server dispatch loop when 852fda9279dSmrg * the swap_limit is set to 2 for triple-buffering. 853fda9279dSmrg * 854fda9279dSmrg * This also optimizes for the common case of swap 855fda9279dSmrg * at next vblank, avoiding vblank dispatch delay. 856fda9279dSmrg */ 857fda9279dSmrg s->frame = 1 + ((unsigned int) current_msc & 0xffffffff); 858fda9279dSmrg *target_msc = 1 + current_msc; 859fda9279dSmrg nouveau_dri2_finish_swap(draw, current_msc, 860fda9279dSmrg (unsigned int) (current_ust / 1000000), 861fda9279dSmrg (unsigned int) (current_ust % 1000000), 862fda9279dSmrg s); 863fda9279dSmrg return TRUE; 864fda9279dSmrg } 865fda9279dSmrg 866fda9279dSmrg /* This is a swap in the future, ie. the vblank event will 867fda9279dSmrg * only get dispatched at least 2 vblanks into the future. 868fda9279dSmrg */ 869fda9279dSmrg 870fda9279dSmrg#if DRI2INFOREC_VERSION >= 6 871fda9279dSmrg /* On XOrg 1.12+ we need to temporarily lower the swaplimit to 1, 872fda9279dSmrg * so that DRI2GetBuffersWithFormat() requests from the client get 873fda9279dSmrg * deferred in the x-server until the vblank event has been 874fda9279dSmrg * dispatched to us and nouveau_dri2_finish_swap() is done. If 875fda9279dSmrg * we wouldn't do this, DRI2GetBuffersWithFormat() would operate 876fda9279dSmrg * on wrong (pre-swap) buffers, and cause a segfault later on in 877fda9279dSmrg * nouveau_dri2_finish_swap(). Our vblank event handler will restore 878fda9279dSmrg * the old swaplimit immediately after nouveau_dri2_finish_swap() 879fda9279dSmrg * is done, so we still get 1 video refresh cycle worth of triple- 880fda9279dSmrg * buffering, because the client can start rendering again 1 cycle 881fda9279dSmrg * before the pending swap is completed. 882fda9279dSmrg * 883fda9279dSmrg * The same race would happen for the "swap at next vblank" case, 884fda9279dSmrg * but the special case "swap immediately" code above prevents this. 885fda9279dSmrg */ 886fda9279dSmrg DRI2SwapLimit(draw, 1); 887fda9279dSmrg#endif 888fda9279dSmrg 889fda9279dSmrg /* Request a vblank event one frame before the target */ 890fda9279dSmrg ret = nouveau_wait_vblank(draw, DRM_VBLANK_ABSOLUTE | 891fda9279dSmrg DRM_VBLANK_EVENT, 892fda9279dSmrg max(current_msc, *target_msc - 1), 893fda9279dSmrg &expect_msc, NULL, s); 894fda9279dSmrg if (ret) 895fda9279dSmrg goto fail; 896fda9279dSmrg s->frame = 1 + ((unsigned int) expect_msc & 0xffffffff); 897fda9279dSmrg *target_msc = 1 + expect_msc; 898fda9279dSmrg } else { 899fda9279dSmrg /* We can't/don't want to sync to vblank, just swap. */ 900fda9279dSmrg nouveau_dri2_finish_swap(draw, 0, 0, 0, s); 901fda9279dSmrg } 902fda9279dSmrg 903fda9279dSmrg return TRUE; 904fda9279dSmrg 905fda9279dSmrgfail: 906fda9279dSmrg free(s); 907fda9279dSmrg return FALSE; 908fda9279dSmrg} 909fda9279dSmrg 910fda9279dSmrgstatic Bool 911fda9279dSmrgnouveau_dri2_schedule_wait(ClientPtr client, DrawablePtr draw, 912fda9279dSmrg CARD64 target_msc, CARD64 divisor, CARD64 remainder) 913fda9279dSmrg{ 914fda9279dSmrg struct nouveau_dri2_vblank_state *s; 915fda9279dSmrg CARD64 current_msc; 916fda9279dSmrg int ret; 917fda9279dSmrg 918fda9279dSmrg /* Truncate to match kernel interfaces; means occasional overflow 919fda9279dSmrg * misses, but that's generally not a big deal. 920fda9279dSmrg */ 921fda9279dSmrg target_msc &= 0xffffffff; 922fda9279dSmrg divisor &= 0xffffffff; 923fda9279dSmrg remainder &= 0xffffffff; 924fda9279dSmrg 925fda9279dSmrg if (!can_sync_to_vblank(draw)) { 926fda9279dSmrg DRI2WaitMSCComplete(client, draw, target_msc, 0, 0); 927fda9279dSmrg return TRUE; 928fda9279dSmrg } 929fda9279dSmrg 930fda9279dSmrg /* Initialize a vblank structure */ 931fda9279dSmrg s = malloc(sizeof(*s)); 932fda9279dSmrg if (!s) 933fda9279dSmrg return FALSE; 934fda9279dSmrg 935fda9279dSmrg *s = (struct nouveau_dri2_vblank_state) { WAIT, client, draw->id }; 936fda9279dSmrg 937fda9279dSmrg /* Get current sequence */ 938fda9279dSmrg ret = nouveau_wait_vblank(draw, DRM_VBLANK_RELATIVE, 0, 939fda9279dSmrg ¤t_msc, NULL, NULL); 940fda9279dSmrg if (ret) 941fda9279dSmrg goto fail; 942fda9279dSmrg 943fda9279dSmrg /* Calculate a wait target if we don't have one */ 944fda9279dSmrg if (current_msc >= target_msc && divisor) 945fda9279dSmrg target_msc = current_msc + divisor 946fda9279dSmrg - (current_msc - remainder) % divisor; 947fda9279dSmrg 948fda9279dSmrg /* Request a vblank event */ 949fda9279dSmrg ret = nouveau_wait_vblank(draw, DRM_VBLANK_ABSOLUTE | 950fda9279dSmrg DRM_VBLANK_EVENT, 951fda9279dSmrg max(current_msc, target_msc), 952fda9279dSmrg NULL, NULL, s); 953fda9279dSmrg if (ret) 954fda9279dSmrg goto fail; 955fda9279dSmrg 956fda9279dSmrg DRI2BlockClient(client, draw); 957fda9279dSmrg return TRUE; 958fda9279dSmrgfail: 959fda9279dSmrg free(s); 960fda9279dSmrg return FALSE; 961fda9279dSmrg} 962fda9279dSmrg 963fda9279dSmrgstatic Bool 964fda9279dSmrgnouveau_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc) 965fda9279dSmrg{ 966fda9279dSmrg int ret; 967fda9279dSmrg 968fda9279dSmrg if (!can_sync_to_vblank(draw)) { 969fda9279dSmrg *ust = 0; 970fda9279dSmrg *msc = 0; 971fda9279dSmrg return TRUE; 972fda9279dSmrg } 973fda9279dSmrg 974fda9279dSmrg /* Get current sequence */ 975fda9279dSmrg ret = nouveau_wait_vblank(draw, DRM_VBLANK_RELATIVE, 0, msc, ust, NULL); 976fda9279dSmrg if (ret) 977fda9279dSmrg return FALSE; 978fda9279dSmrg 979fda9279dSmrg return TRUE; 980fda9279dSmrg} 981fda9279dSmrg 982fda9279dSmrgBool 983fda9279dSmrgnouveau_dri2_init(ScreenPtr pScreen) 984fda9279dSmrg{ 985fda9279dSmrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 986fda9279dSmrg NVPtr pNv = NVPTR(pScrn); 987fda9279dSmrg DRI2InfoRec dri2 = { 0 }; 988fda9279dSmrg const char *drivernames[2][2] = { 989fda9279dSmrg { "nouveau", "nouveau" }, 990fda9279dSmrg { "nouveau_vieux", "nouveau_vieux" } 991fda9279dSmrg }; 992fda9279dSmrg 993fda9279dSmrg if (pNv->AccelMethod != EXA) 994fda9279dSmrg return FALSE; 995fda9279dSmrg 996fda9279dSmrg if (pNv->Architecture >= NV_ARCH_30) 997fda9279dSmrg dri2.driverNames = drivernames[0]; 998fda9279dSmrg else 999fda9279dSmrg dri2.driverNames = drivernames[1]; 1000fda9279dSmrg dri2.numDrivers = 2; 1001fda9279dSmrg dri2.driverName = dri2.driverNames[0]; 1002fda9279dSmrg 1003fda9279dSmrg dri2.fd = pNv->dev->fd; 1004fda9279dSmrg dri2.deviceName = pNv->drm_device_name; 1005fda9279dSmrg 1006fda9279dSmrg dri2.version = DRI2INFOREC_VERSION; 1007fda9279dSmrg dri2.CreateBuffer = nouveau_dri2_create_buffer; 1008fda9279dSmrg dri2.DestroyBuffer = nouveau_dri2_destroy_buffer; 1009fda9279dSmrg dri2.CopyRegion = nouveau_dri2_copy_region; 1010fda9279dSmrg dri2.ScheduleSwap = nouveau_dri2_schedule_swap; 1011fda9279dSmrg dri2.ScheduleWaitMSC = nouveau_dri2_schedule_wait; 1012fda9279dSmrg dri2.GetMSC = nouveau_dri2_get_msc; 1013fda9279dSmrg 1014fda9279dSmrg#if DRI2INFOREC_VERSION >= 6 1015fda9279dSmrg dri2.SwapLimitValidate = nouveau_dri2_swap_limit_validate; 1016fda9279dSmrg#endif 1017fda9279dSmrg 1018fda9279dSmrg#if DRI2INFOREC_VERSION >= 7 1019fda9279dSmrg dri2.version = 7; 1020fda9279dSmrg dri2.GetParam = NULL; 1021fda9279dSmrg#endif 1022fda9279dSmrg 1023fda9279dSmrg#if DRI2INFOREC_VERSION >= 9 1024fda9279dSmrg dri2.version = 9; 1025fda9279dSmrg dri2.CreateBuffer2 = nouveau_dri2_create_buffer2; 1026fda9279dSmrg dri2.DestroyBuffer2 = nouveau_dri2_destroy_buffer2; 1027fda9279dSmrg dri2.CopyRegion2 = nouveau_dri2_copy_region2; 1028fda9279dSmrg#endif 1029fda9279dSmrg return DRI2ScreenInit(pScreen, &dri2); 1030fda9279dSmrg} 1031fda9279dSmrg 1032fda9279dSmrgvoid 1033fda9279dSmrgnouveau_dri2_fini(ScreenPtr pScreen) 1034fda9279dSmrg{ 1035fda9279dSmrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1036fda9279dSmrg NVPtr pNv = NVPTR(pScrn); 1037fda9279dSmrg if (pNv->AccelMethod == EXA) 1038fda9279dSmrg DRI2CloseScreen(pScreen); 1039fda9279dSmrg} 104016ee1e9aSmrg 104116ee1e9aSmrg#ifdef DRI3 1042dd52494dSmrgstatic int is_render_node(int fd) 104316ee1e9aSmrg{ 1044dd52494dSmrg struct stat st; 1045dd52494dSmrg if (fstat(fd, &st)) 104616ee1e9aSmrg return 0; 104716ee1e9aSmrg 1048dd52494dSmrg if (!S_ISCHR(st.st_mode)) 104916ee1e9aSmrg return 0; 105016ee1e9aSmrg 1051dd52494dSmrg return st.st_rdev & 0x80; 105216ee1e9aSmrg } 105316ee1e9aSmrg 105416ee1e9aSmrgstatic int 105516ee1e9aSmrgnouveau_dri3_open(ScreenPtr screen, RRProviderPtr provider, int *out) 105616ee1e9aSmrg{ 105716ee1e9aSmrg ScrnInfoPtr pScrn = xf86ScreenToScrn(screen); 105816ee1e9aSmrg NVPtr pNv = NVPTR(pScrn); 105916ee1e9aSmrg int fd = -1; 106016ee1e9aSmrg 106116ee1e9aSmrg#ifdef O_CLOEXEC 106216ee1e9aSmrg fd = open(pNv->render_node, O_RDWR | O_CLOEXEC); 106316ee1e9aSmrg#endif 106416ee1e9aSmrg if (fd < 0) 106516ee1e9aSmrg fd = open(pNv->render_node, O_RDWR); 106616ee1e9aSmrg if (fd < 0) 106716ee1e9aSmrg return -BadAlloc; 106816ee1e9aSmrg 1069dd52494dSmrg if (!is_render_node(fd)) { 107016ee1e9aSmrg drm_magic_t magic; 107116ee1e9aSmrg 107216ee1e9aSmrg if (drmGetMagic(fd, &magic) || drmAuthMagic(pNv->dev->fd, magic)) { 107316ee1e9aSmrg close(fd); 107416ee1e9aSmrg return -BadMatch; 107516ee1e9aSmrg } 107616ee1e9aSmrg } 107716ee1e9aSmrg 107816ee1e9aSmrg *out = fd; 107916ee1e9aSmrg return Success; 108016ee1e9aSmrg} 108116ee1e9aSmrg 108216ee1e9aSmrgstatic PixmapPtr nouveau_dri3_pixmap_from_fd(ScreenPtr screen, int fd, CARD16 width, CARD16 height, CARD16 stride, CARD8 depth, CARD8 bpp) 108316ee1e9aSmrg{ 108416ee1e9aSmrg ScrnInfoPtr pScrn = xf86ScreenToScrn(screen); 108516ee1e9aSmrg NVPtr pNv = NVPTR(pScrn); 108616ee1e9aSmrg PixmapPtr pixmap; 108716ee1e9aSmrg struct nouveau_bo *bo = NULL; 108816ee1e9aSmrg struct nouveau_pixmap *nvpix; 108916ee1e9aSmrg 1090dd52494dSmrg if (depth < 8 || depth > 32) 109116ee1e9aSmrg return NULL; 109216ee1e9aSmrg 109316ee1e9aSmrg pixmap = screen->CreatePixmap(screen, 0, 0, depth, 0); 109416ee1e9aSmrg if (!pixmap) 109516ee1e9aSmrg return NULL; 109616ee1e9aSmrg 1097dd52494dSmrg if (pixmap->drawable.bitsPerPixel % 8) 1098dd52494dSmrg goto free_pixmap; 1099dd52494dSmrg 110016ee1e9aSmrg if (!screen->ModifyPixmapHeader(pixmap, width, height, 0, 0, stride, NULL)) 110116ee1e9aSmrg goto free_pixmap; 110216ee1e9aSmrg 110316ee1e9aSmrg if (nouveau_bo_prime_handle_ref(pNv->dev, fd, &bo)) 110416ee1e9aSmrg goto free_pixmap; 110516ee1e9aSmrg 110616ee1e9aSmrg nvpix = nouveau_pixmap(pixmap); 110716ee1e9aSmrg nouveau_bo_ref(NULL, &nvpix->bo); 110816ee1e9aSmrg nvpix->bo = bo; 110916ee1e9aSmrg nvpix->shared = (bo->flags & NOUVEAU_BO_APER) == NOUVEAU_BO_GART; 111016ee1e9aSmrg return pixmap; 111116ee1e9aSmrg 111216ee1e9aSmrgfree_pixmap: 111333adc6acSmrg dixDestroyPixmap(pixmap, 0); 111416ee1e9aSmrg return NULL; 111516ee1e9aSmrg} 111616ee1e9aSmrg 111716ee1e9aSmrgstatic int nouveau_dri3_fd_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, CARD16 *stride, CARD32 *size) 111816ee1e9aSmrg{ 111916ee1e9aSmrg struct nouveau_bo *bo = nouveau_pixmap_bo(pixmap); 112016ee1e9aSmrg int fd; 112116ee1e9aSmrg 112216ee1e9aSmrg if (!bo || nouveau_bo_set_prime(bo, &fd) < 0) 112316ee1e9aSmrg return -EINVAL; 112416ee1e9aSmrg 112516ee1e9aSmrg *stride = pixmap->devKind; 112616ee1e9aSmrg *size = bo->size; 112716ee1e9aSmrg return fd; 112816ee1e9aSmrg} 112916ee1e9aSmrg 113016ee1e9aSmrgstatic dri3_screen_info_rec nouveau_dri3_screen_info = { 113116ee1e9aSmrg .version = DRI3_SCREEN_INFO_VERSION, 113216ee1e9aSmrg 113316ee1e9aSmrg .open = nouveau_dri3_open, 113416ee1e9aSmrg .pixmap_from_fd = nouveau_dri3_pixmap_from_fd, 113516ee1e9aSmrg .fd_from_pixmap = nouveau_dri3_fd_from_pixmap 113616ee1e9aSmrg}; 113716ee1e9aSmrg#endif 113816ee1e9aSmrg 113916ee1e9aSmrgBool 114016ee1e9aSmrgnouveau_dri3_screen_init(ScreenPtr screen) 114116ee1e9aSmrg{ 114216ee1e9aSmrg#ifdef DRI3 114316ee1e9aSmrg ScrnInfoPtr pScrn = xf86ScreenToScrn(screen); 114416ee1e9aSmrg NVPtr pNv = NVPTR(pScrn); 114516ee1e9aSmrg char *buf; 114616ee1e9aSmrg 1147dd52494dSmrg if (is_render_node(pNv->dev->fd)) 114816ee1e9aSmrg return TRUE; 114916ee1e9aSmrg 115016ee1e9aSmrg buf = drmGetRenderDeviceNameFromFd(pNv->dev->fd); 1151dd52494dSmrg if (buf) { 115216ee1e9aSmrg pNv->render_node = buf; 115316ee1e9aSmrg if (dri3_screen_init(screen, &nouveau_dri3_screen_info)) { 115416ee1e9aSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 115516ee1e9aSmrg "DRI3 on EXA enabled\n"); 115616ee1e9aSmrg return TRUE; 115716ee1e9aSmrg } 115816ee1e9aSmrg else { 115916ee1e9aSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 116016ee1e9aSmrg "DRI3 on EXA initialization failed\n"); 116116ee1e9aSmrg return FALSE; 116216ee1e9aSmrg } 116316ee1e9aSmrg } else 116416ee1e9aSmrg free(buf); 116516ee1e9aSmrg#endif 116616ee1e9aSmrg 116716ee1e9aSmrg return TRUE; 116816ee1e9aSmrg} 1169