radeon_dri2.c revision 39413783
1de2362d3Smrg/* 2de2362d3Smrg * Copyright 2008 Kristian Høgsberg 3de2362d3Smrg * Copyright 2008 Jérôme Glisse 4de2362d3Smrg * 5de2362d3Smrg * All Rights Reserved. 6de2362d3Smrg * 7de2362d3Smrg * Permission is hereby granted, free of charge, to any person obtaining 8de2362d3Smrg * a copy of this software and associated documentation files (the 9de2362d3Smrg * "Software"), to deal in the Software without restriction, including 10de2362d3Smrg * without limitation on the rights to use, copy, modify, merge, 11de2362d3Smrg * publish, distribute, sublicense, and/or sell copies of the Software, 12de2362d3Smrg * and to permit persons to whom the Software is furnished to do so, 13de2362d3Smrg * subject to the following conditions: 14de2362d3Smrg * 15de2362d3Smrg * The above copyright notice and this permission notice (including the 16de2362d3Smrg * next paragraph) shall be included in all copies or substantial 17de2362d3Smrg * portions of the Software. 18de2362d3Smrg * 19de2362d3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20de2362d3Smrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21de2362d3Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22de2362d3Smrg * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR 23de2362d3Smrg * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 24de2362d3Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25de2362d3Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26de2362d3Smrg * DEALINGS IN THE SOFTWARE. 27de2362d3Smrg */ 28de2362d3Smrg#ifdef HAVE_CONFIG_H 29de2362d3Smrg#include "config.h" 30de2362d3Smrg#endif 31de2362d3Smrg 3218781e08Smrg#include "radeon.h" 3318781e08Smrg#include "radeon_dri2.h" 3418781e08Smrg#include "radeon_video.h" 3518781e08Smrg 3618781e08Smrg#ifdef DRI2 3718781e08Smrg 38de2362d3Smrg#include <sys/types.h> 39de2362d3Smrg#include <sys/stat.h> 40de2362d3Smrg#include <fcntl.h> 41de2362d3Smrg#include <errno.h> 42de2362d3Smrg 4318781e08Smrg#include "radeon_bo_helper.h" 44de2362d3Smrg#include "radeon_version.h" 45de2362d3Smrg 467821949aSmrg#include "radeon_bo_gem.h" 47de2362d3Smrg 488bf5c682Smrg#include <list.h> 4918781e08Smrg#include <xf86Priv.h> 503ed65abbSmrg#include <X11/extensions/dpmsconst.h> 51de2362d3Smrg 5218781e08Smrg#define FALLBACK_SWAP_DELAY 16 5318781e08Smrg 5418781e08Smrg#include "radeon_glamor.h" 5518781e08Smrg 56de2362d3Smrgtypedef DRI2BufferPtr BufferPtr; 57de2362d3Smrg 58de2362d3Smrgstruct dri2_buffer_priv { 59de2362d3Smrg PixmapPtr pixmap; 60de2362d3Smrg unsigned int attachment; 61de2362d3Smrg unsigned int refcnt; 62de2362d3Smrg}; 63de2362d3Smrg 64de2362d3Smrg 6518781e08Smrgstruct dri2_window_priv { 6618781e08Smrg xf86CrtcPtr crtc; 6718781e08Smrg int vblank_delta; 6818781e08Smrg}; 690d16fef4Smrg 7018781e08Smrgstatic DevPrivateKeyRec dri2_window_private_key_rec; 7118781e08Smrg#define dri2_window_private_key (&dri2_window_private_key_rec) 720d16fef4Smrg 7318781e08Smrg#define get_dri2_window_priv(window) \ 7418781e08Smrg ((struct dri2_window_priv*) \ 7518781e08Smrg dixLookupPrivate(&(window)->devPrivates, dri2_window_private_key)) 760d16fef4Smrg 770d16fef4Smrg 7818781e08Smrg/* Get GEM flink name for a pixmap */ 7918781e08Smrgstatic Bool 808bf5c682Smrgradeon_get_flink_name(RADEONEntPtr pRADEONEnt, PixmapPtr pixmap, uint32_t *name) 8118781e08Smrg{ 8239413783Smrg struct radeon_buffer *bo = radeon_get_pixmap_bo(pixmap); 8318781e08Smrg struct drm_gem_flink flink; 840d16fef4Smrg 8539413783Smrg if (bo && !(bo->flags & RADEON_BO_FLAGS_GBM) && 8639413783Smrg radeon_gem_get_kernel_name(bo->bo.radeon, name) == 0) 8739413783Smrg return TRUE; 8818781e08Smrg 8918781e08Smrg if (radeon_get_pixmap_handle(pixmap, &flink.handle)) { 908bf5c682Smrg if (drmIoctl(pRADEONEnt->fd, DRM_IOCTL_GEM_FLINK, &flink) != 0) 9118781e08Smrg return FALSE; 920d16fef4Smrg 9318781e08Smrg *name = flink.name; 9418781e08Smrg return TRUE; 950d16fef4Smrg } 9618781e08Smrg 9718781e08Smrg return FALSE; 980d16fef4Smrg} 9918781e08Smrg 100de2362d3Smrgstatic BufferPtr 10118781e08Smrgradeon_dri2_create_buffer2(ScreenPtr pScreen, 10218781e08Smrg DrawablePtr drawable, 10318781e08Smrg unsigned int attachment, 10418781e08Smrg unsigned int format) 105de2362d3Smrg{ 106de2362d3Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1078bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 108de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 109de2362d3Smrg BufferPtr buffers; 110de2362d3Smrg struct dri2_buffer_priv *privates; 11118781e08Smrg PixmapPtr pixmap; 112de2362d3Smrg int flags; 113de2362d3Smrg unsigned front_width; 114de2362d3Smrg uint32_t tiling = 0; 115de2362d3Smrg unsigned aligned_width = drawable->width; 11618781e08Smrg unsigned height = drawable->height; 11718781e08Smrg Bool is_glamor_pixmap = FALSE; 11818781e08Smrg int depth; 11918781e08Smrg int cpp; 12018781e08Smrg 12118781e08Smrg if (format) { 12218781e08Smrg depth = format; 12318781e08Smrg 12418781e08Smrg switch (depth) { 12518781e08Smrg case 15: 12618781e08Smrg cpp = 2; 12718781e08Smrg break; 12818781e08Smrg case 24: 1298bf5c682Smrg case 30: 13018781e08Smrg cpp = 4; 13118781e08Smrg break; 13218781e08Smrg default: 13318781e08Smrg cpp = depth / 8; 13418781e08Smrg } 13518781e08Smrg } else { 13618781e08Smrg depth = drawable->depth; 13718781e08Smrg cpp = drawable->bitsPerPixel / 8; 13818781e08Smrg } 139de2362d3Smrg 14018781e08Smrg front_width = pScreen->GetScreenPixmap(pScreen)->drawable.width; 141de2362d3Smrg 14218781e08Smrg pixmap = NULL; 143de2362d3Smrg 144de2362d3Smrg if (attachment == DRI2BufferFrontLeft) { 14518781e08Smrg uint32_t handle; 14618781e08Smrg 14718781e08Smrg pixmap = get_drawable_pixmap(drawable); 14818781e08Smrg if (pScreen != pixmap->drawable.pScreen) 14918781e08Smrg pixmap = NULL; 15018781e08Smrg else if (info->use_glamor && !radeon_get_pixmap_handle(pixmap, &handle)) { 15118781e08Smrg is_glamor_pixmap = TRUE; 15218781e08Smrg aligned_width = pixmap->drawable.width; 15318781e08Smrg height = pixmap->drawable.height; 15418781e08Smrg pixmap = NULL; 15518781e08Smrg } else 15618781e08Smrg pixmap->refcnt++; 15718781e08Smrg } 15818781e08Smrg 15918781e08Smrg if (!pixmap && (is_glamor_pixmap || attachment != DRI2BufferFrontLeft)) { 160de2362d3Smrg /* tile the back buffer */ 161de2362d3Smrg switch(attachment) { 162de2362d3Smrg case DRI2BufferDepth: 163de2362d3Smrg /* macro is the preferred setting, but the 2D detiling for software 164de2362d3Smrg * fallbacks in mesa still has issues on some configurations 165de2362d3Smrg */ 166de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 167de2362d3Smrg if (info->allowColorTiling2D) { 168de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO; 169de2362d3Smrg } else { 170de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MICRO; 171de2362d3Smrg } 172de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_CEDAR) 173de2362d3Smrg flags |= RADEON_CREATE_PIXMAP_SZBUFFER; 17418781e08Smrg } else if (cpp == 2 && info->ChipFamily >= CHIP_FAMILY_R300) 17518781e08Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO | RADEON_CREATE_PIXMAP_TILING_MICRO_SQUARE; 17618781e08Smrg else 177de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO | RADEON_CREATE_PIXMAP_TILING_MICRO; 178de2362d3Smrg if (IS_R200_3D || info->ChipFamily == CHIP_FAMILY_RV200 || info->ChipFamily == CHIP_FAMILY_RADEON) 179de2362d3Smrg flags |= RADEON_CREATE_PIXMAP_DEPTH; 180de2362d3Smrg break; 181de2362d3Smrg case DRI2BufferDepthStencil: 182de2362d3Smrg /* macro is the preferred setting, but the 2D detiling for software 183de2362d3Smrg * fallbacks in mesa still has issues on some configurations 184de2362d3Smrg */ 185de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 186de2362d3Smrg if (info->allowColorTiling2D) { 187de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO; 188de2362d3Smrg } else { 189de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MICRO; 190de2362d3Smrg } 191de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_CEDAR) 192de2362d3Smrg flags |= RADEON_CREATE_PIXMAP_SZBUFFER; 19318781e08Smrg } else if (cpp == 2 && info->ChipFamily >= CHIP_FAMILY_R300) 19418781e08Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO | RADEON_CREATE_PIXMAP_TILING_MICRO_SQUARE; 19518781e08Smrg else 196de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO | RADEON_CREATE_PIXMAP_TILING_MICRO; 197de2362d3Smrg if (IS_R200_3D || info->ChipFamily == CHIP_FAMILY_RV200 || info->ChipFamily == CHIP_FAMILY_RADEON) 198de2362d3Smrg flags |= RADEON_CREATE_PIXMAP_DEPTH; 199de2362d3Smrg 200de2362d3Smrg break; 201de2362d3Smrg case DRI2BufferBackLeft: 202de2362d3Smrg case DRI2BufferBackRight: 20318781e08Smrg case DRI2BufferFrontLeft: 20418781e08Smrg case DRI2BufferFrontRight: 205de2362d3Smrg case DRI2BufferFakeFrontLeft: 206de2362d3Smrg case DRI2BufferFakeFrontRight: 207de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 208de2362d3Smrg if (info->allowColorTiling2D) { 209de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO; 210de2362d3Smrg } else { 211de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MICRO; 212de2362d3Smrg } 213de2362d3Smrg } else 214de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO; 215de2362d3Smrg break; 216de2362d3Smrg default: 217de2362d3Smrg flags = 0; 218de2362d3Smrg } 219de2362d3Smrg 220de2362d3Smrg if (flags & RADEON_CREATE_PIXMAP_TILING_MICRO) 221de2362d3Smrg tiling |= RADEON_TILING_MICRO; 22218781e08Smrg if (flags & RADEON_CREATE_PIXMAP_TILING_MICRO_SQUARE) 22318781e08Smrg tiling |= RADEON_TILING_MICRO_SQUARE; 224de2362d3Smrg if (flags & RADEON_CREATE_PIXMAP_TILING_MACRO) 225de2362d3Smrg tiling |= RADEON_TILING_MACRO; 226de2362d3Smrg 22718781e08Smrg if (aligned_width == front_width) 22818781e08Smrg aligned_width = pScrn->virtualX; 229de2362d3Smrg 23018781e08Smrg pixmap = (*pScreen->CreatePixmap)(pScreen, 23118781e08Smrg aligned_width, 23218781e08Smrg height, 23318781e08Smrg depth, 23418781e08Smrg flags | RADEON_CREATE_PIXMAP_DRI2); 235de2362d3Smrg } 236de2362d3Smrg 23739413783Smrg if (!pixmap) 23839413783Smrg return NULL; 23939413783Smrg 240de2362d3Smrg buffers = calloc(1, sizeof *buffers); 24139413783Smrg if (!buffers) 242de2362d3Smrg goto error; 243de2362d3Smrg 24439413783Smrg if (!info->use_glamor) { 24539413783Smrg info->exa_force_create = TRUE; 24639413783Smrg exaMoveInPixmap(pixmap); 24739413783Smrg info->exa_force_create = FALSE; 24839413783Smrg if (!exaGetPixmapDriverPrivate(pixmap)) { 24939413783Smrg /* this happen if pixmap is non accelerable */ 25018781e08Smrg goto error; 25139413783Smrg } 25239413783Smrg } else if (is_glamor_pixmap) { 25339413783Smrg pixmap = radeon_glamor_set_pixmap_bo(drawable, pixmap); 25439413783Smrg pixmap->refcnt++; 255de2362d3Smrg } 256de2362d3Smrg 25739413783Smrg if (!radeon_get_flink_name(pRADEONEnt, pixmap, &buffers->name)) 25839413783Smrg goto error; 25939413783Smrg 260de2362d3Smrg privates = calloc(1, sizeof(struct dri2_buffer_priv)); 26139413783Smrg if (!privates) 262de2362d3Smrg goto error; 263de2362d3Smrg 264de2362d3Smrg buffers->attachment = attachment; 26539413783Smrg buffers->pitch = pixmap->devKind; 26639413783Smrg buffers->cpp = cpp; 267de2362d3Smrg buffers->driverPrivate = privates; 268de2362d3Smrg buffers->format = format; 269de2362d3Smrg buffers->flags = 0; /* not tiled */ 270de2362d3Smrg privates->pixmap = pixmap; 271de2362d3Smrg privates->attachment = attachment; 272de2362d3Smrg privates->refcnt = 1; 273de2362d3Smrg 274de2362d3Smrg return buffers; 275de2362d3Smrg 276de2362d3Smrgerror: 277de2362d3Smrg free(buffers); 27839413783Smrg (*pScreen->DestroyPixmap)(pixmap); 279de2362d3Smrg return NULL; 280de2362d3Smrg} 281de2362d3Smrg 282de2362d3Smrgstatic void 28318781e08Smrgradeon_dri2_destroy_buffer2(ScreenPtr pScreen, 28418781e08Smrg DrawablePtr drawable, BufferPtr buffers) 285de2362d3Smrg{ 286de2362d3Smrg if(buffers) 287de2362d3Smrg { 288de2362d3Smrg struct dri2_buffer_priv *private = buffers->driverPrivate; 289de2362d3Smrg 290de2362d3Smrg /* Trying to free an already freed buffer is unlikely to end well */ 291de2362d3Smrg if (private->refcnt == 0) { 292de2362d3Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 293de2362d3Smrg 294de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 295de2362d3Smrg "Attempted to destroy previously destroyed buffer.\ 296de2362d3Smrg This is a programming error\n"); 297de2362d3Smrg return; 298de2362d3Smrg } 299de2362d3Smrg 300de2362d3Smrg private->refcnt--; 301de2362d3Smrg if (private->refcnt == 0) 302de2362d3Smrg { 30318781e08Smrg if (private->pixmap) 30418781e08Smrg (*pScreen->DestroyPixmap)(private->pixmap); 305de2362d3Smrg 306de2362d3Smrg free(buffers->driverPrivate); 307de2362d3Smrg free(buffers); 308de2362d3Smrg } 309de2362d3Smrg } 310de2362d3Smrg} 311de2362d3Smrg 31218781e08Smrg 31318781e08Smrgstatic inline PixmapPtr GetDrawablePixmap(DrawablePtr drawable) 31418781e08Smrg{ 31518781e08Smrg if (drawable->type == DRAWABLE_PIXMAP) 31618781e08Smrg return (PixmapPtr)drawable; 31718781e08Smrg else { 31818781e08Smrg struct _Window *pWin = (struct _Window *)drawable; 31918781e08Smrg return drawable->pScreen->GetWindowPixmap(pWin); 32018781e08Smrg } 32118781e08Smrg} 322de2362d3Smrgstatic void 32318781e08Smrgradeon_dri2_copy_region2(ScreenPtr pScreen, 32418781e08Smrg DrawablePtr drawable, 32518781e08Smrg RegionPtr region, 32618781e08Smrg BufferPtr dest_buffer, 32718781e08Smrg BufferPtr src_buffer) 328de2362d3Smrg{ 329de2362d3Smrg struct dri2_buffer_priv *src_private = src_buffer->driverPrivate; 330de2362d3Smrg struct dri2_buffer_priv *dst_private = dest_buffer->driverPrivate; 331de2362d3Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 332de2362d3Smrg DrawablePtr src_drawable; 333de2362d3Smrg DrawablePtr dst_drawable; 334de2362d3Smrg RegionPtr copy_clip; 335de2362d3Smrg GCPtr gc; 336de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 337de2362d3Smrg Bool vsync; 33818781e08Smrg Bool translate = FALSE; 33918781e08Smrg int off_x = 0, off_y = 0; 34018781e08Smrg 34118781e08Smrg src_drawable = &src_private->pixmap->drawable; 34218781e08Smrg dst_drawable = &dst_private->pixmap->drawable; 343de2362d3Smrg 344de2362d3Smrg if (src_private->attachment == DRI2BufferFrontLeft) { 34518781e08Smrg if (drawable->pScreen != pScreen) { 34618781e08Smrg src_drawable = DRI2UpdatePrime(drawable, src_buffer); 34718781e08Smrg if (!src_drawable) 34818781e08Smrg return; 34918781e08Smrg } else 35018781e08Smrg src_drawable = drawable; 351de2362d3Smrg } 352de2362d3Smrg if (dst_private->attachment == DRI2BufferFrontLeft) { 35318781e08Smrg if (drawable->pScreen != pScreen) { 35418781e08Smrg dst_drawable = DRI2UpdatePrime(drawable, dest_buffer); 35518781e08Smrg if (!dst_drawable) 35618781e08Smrg return; 35718781e08Smrg if (dst_drawable != drawable) 35818781e08Smrg translate = TRUE; 35918781e08Smrg } else 36018781e08Smrg dst_drawable = drawable; 36118781e08Smrg } 36218781e08Smrg 36318781e08Smrg if (translate && drawable->type == DRAWABLE_WINDOW) { 36418781e08Smrg PixmapPtr pPix = GetDrawablePixmap(drawable); 36518781e08Smrg 36618781e08Smrg off_x = drawable->x - pPix->screen_x; 36718781e08Smrg off_y = drawable->y - pPix->screen_y; 368de2362d3Smrg } 369de2362d3Smrg gc = GetScratchGC(dst_drawable->depth, pScreen); 370de2362d3Smrg copy_clip = REGION_CREATE(pScreen, NULL, 0); 371de2362d3Smrg REGION_COPY(pScreen, copy_clip, region); 37218781e08Smrg 37318781e08Smrg if (translate) { 37418781e08Smrg REGION_TRANSLATE(pScreen, copy_clip, off_x, off_y); 37518781e08Smrg } 37618781e08Smrg 377de2362d3Smrg (*gc->funcs->ChangeClip) (gc, CT_REGION, copy_clip, 0); 378de2362d3Smrg ValidateGC(dst_drawable, gc); 379de2362d3Smrg 380de2362d3Smrg vsync = info->accel_state->vsync; 381de2362d3Smrg /* Driver option "SwapbuffersWait" defines if we vsync DRI2 copy-swaps. */ 382de2362d3Smrg info->accel_state->vsync = info->swapBuffersWait; 38318781e08Smrg info->accel_state->force = TRUE; 384de2362d3Smrg 385de2362d3Smrg (*gc->ops->CopyArea)(src_drawable, dst_drawable, gc, 38618781e08Smrg 0, 0, drawable->width, drawable->height, off_x, off_y); 387de2362d3Smrg 38818781e08Smrg info->accel_state->force = FALSE; 389de2362d3Smrg info->accel_state->vsync = vsync; 390de2362d3Smrg 391de2362d3Smrg FreeScratchGC(gc); 392de2362d3Smrg} 393de2362d3Smrg 394de2362d3Smrgenum DRI2FrameEventType { 395de2362d3Smrg DRI2_SWAP, 396de2362d3Smrg DRI2_FLIP, 397de2362d3Smrg DRI2_WAITMSC, 398de2362d3Smrg}; 399de2362d3Smrg 400de2362d3Smrgtypedef struct _DRI2FrameEvent { 401de2362d3Smrg XID drawable_id; 402de2362d3Smrg ClientPtr client; 403de2362d3Smrg enum DRI2FrameEventType type; 40418781e08Smrg unsigned frame; 40518781e08Smrg xf86CrtcPtr crtc; 40618781e08Smrg OsTimerPtr timer; 40718781e08Smrg uintptr_t drm_queue_seq; 408de2362d3Smrg 409de2362d3Smrg /* for swaps & flips only */ 410de2362d3Smrg DRI2SwapEventPtr event_complete; 411de2362d3Smrg void *event_data; 412de2362d3Smrg DRI2BufferPtr front; 413de2362d3Smrg DRI2BufferPtr back; 414de2362d3Smrg} DRI2FrameEventRec, *DRI2FrameEventPtr; 415de2362d3Smrg 41618781e08Smrgstatic int DRI2InfoCnt; 417de2362d3Smrg 418de2362d3Smrgstatic void 419de2362d3Smrgradeon_dri2_ref_buffer(BufferPtr buffer) 420de2362d3Smrg{ 421de2362d3Smrg struct dri2_buffer_priv *private = buffer->driverPrivate; 422de2362d3Smrg private->refcnt++; 423de2362d3Smrg} 424de2362d3Smrg 425de2362d3Smrgstatic void 426de2362d3Smrgradeon_dri2_unref_buffer(BufferPtr buffer) 427de2362d3Smrg{ 428de2362d3Smrg if (buffer) { 429de2362d3Smrg struct dri2_buffer_priv *private = buffer->driverPrivate; 4308bf5c682Smrg DrawablePtr draw = &private->pixmap->drawable; 4318bf5c682Smrg 4328bf5c682Smrg radeon_dri2_destroy_buffer2(draw->pScreen, draw, buffer); 433de2362d3Smrg } 434de2362d3Smrg} 435de2362d3Smrg 436de2362d3Smrgstatic void 437de2362d3Smrgradeon_dri2_client_state_changed(CallbackListPtr *ClientStateCallback, pointer data, pointer calldata) 438de2362d3Smrg{ 439de2362d3Smrg NewClientInfoRec *clientinfo = calldata; 440de2362d3Smrg ClientPtr pClient = clientinfo->client; 441de2362d3Smrg 442de2362d3Smrg switch (pClient->clientState) { 443de2362d3Smrg case ClientStateRetained: 444de2362d3Smrg case ClientStateGone: 44518781e08Smrg radeon_drm_abort_client(pClient); 446de2362d3Smrg break; 447de2362d3Smrg default: 448de2362d3Smrg break; 449de2362d3Smrg } 450de2362d3Smrg} 451de2362d3Smrg 45218781e08Smrg/* 45318781e08Smrg * Get current frame count delta for the specified drawable and CRTC 45418781e08Smrg */ 45518781e08Smrgstatic uint32_t radeon_get_msc_delta(DrawablePtr pDraw, xf86CrtcPtr crtc) 45618781e08Smrg{ 45718781e08Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 45818781e08Smrg 45918781e08Smrg if (pDraw && pDraw->type == DRAWABLE_WINDOW) 46018781e08Smrg return drmmode_crtc->interpolated_vblanks + 46118781e08Smrg get_dri2_window_priv((WindowPtr)pDraw)->vblank_delta; 46218781e08Smrg 46318781e08Smrg return drmmode_crtc->interpolated_vblanks; 46418781e08Smrg} 46518781e08Smrg 46618781e08Smrg/* 46718781e08Smrg * Get current frame count and timestamp of the specified CRTC 46818781e08Smrg */ 46918781e08Smrgstatic Bool radeon_dri2_get_crtc_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc) 47018781e08Smrg{ 47118781e08Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 47218781e08Smrg 47318781e08Smrg if (!radeon_crtc_is_enabled(crtc) || 47418781e08Smrg drmmode_crtc_get_ust_msc(crtc, ust, msc) != Success) { 47518781e08Smrg /* CRTC is not running, extrapolate MSC and timestamp */ 47618781e08Smrg ScrnInfoPtr scrn = crtc->scrn; 4778bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 47818781e08Smrg CARD64 now, delta_t, delta_seq; 47918781e08Smrg 48018781e08Smrg if (!drmmode_crtc->dpms_last_ust) 48118781e08Smrg return FALSE; 48218781e08Smrg 4838bf5c682Smrg if (drmmode_get_current_ust(pRADEONEnt->fd, &now) != 0) { 48418781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 48518781e08Smrg "%s cannot get current time\n", __func__); 48618781e08Smrg return FALSE; 48718781e08Smrg } 48818781e08Smrg 48918781e08Smrg delta_t = now - drmmode_crtc->dpms_last_ust; 49018781e08Smrg delta_seq = delta_t * drmmode_crtc->dpms_last_fps; 49118781e08Smrg delta_seq /= 1000000; 49218781e08Smrg *ust = drmmode_crtc->dpms_last_ust; 49318781e08Smrg delta_t = delta_seq * 1000000; 49418781e08Smrg delta_t /= drmmode_crtc->dpms_last_fps; 49518781e08Smrg *ust += delta_t; 49618781e08Smrg *msc = drmmode_crtc->dpms_last_seq; 49718781e08Smrg *msc += delta_seq; 49818781e08Smrg } 49918781e08Smrg 50018781e08Smrg *msc += drmmode_crtc->interpolated_vblanks; 50118781e08Smrg 50218781e08Smrg return TRUE; 50318781e08Smrg} 50418781e08Smrg 50518781e08Smrgstatic 50618781e08Smrgxf86CrtcPtr radeon_dri2_drawable_crtc(DrawablePtr pDraw, Bool consider_disabled) 507de2362d3Smrg{ 508de2362d3Smrg ScreenPtr pScreen = pDraw->pScreen; 509de2362d3Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 51018781e08Smrg xf86CrtcPtr crtc = radeon_pick_best_crtc(pScrn, consider_disabled, 51118781e08Smrg pDraw->x, pDraw->x + pDraw->width, 51218781e08Smrg pDraw->y, pDraw->y + pDraw->height); 51318781e08Smrg 51418781e08Smrg if (crtc && pDraw->type == DRAWABLE_WINDOW) { 51518781e08Smrg struct dri2_window_priv *priv = get_dri2_window_priv((WindowPtr)pDraw); 51618781e08Smrg 51718781e08Smrg if (priv->crtc && priv->crtc != crtc) { 51818781e08Smrg CARD64 ust, mscold, mscnew; 51918781e08Smrg 52018781e08Smrg if (radeon_dri2_get_crtc_msc(priv->crtc, &ust, &mscold) && 52118781e08Smrg radeon_dri2_get_crtc_msc(crtc, &ust, &mscnew)) 52218781e08Smrg priv->vblank_delta += mscold - mscnew; 52318781e08Smrg } 52418781e08Smrg 52518781e08Smrg priv->crtc = crtc; 52618781e08Smrg } 52718781e08Smrg 52818781e08Smrg return crtc; 52918781e08Smrg} 53018781e08Smrg 53118781e08Smrgstatic void 53218781e08Smrgradeon_dri2_flip_event_abort(xf86CrtcPtr crtc, void *event_data) 53318781e08Smrg{ 5343ed65abbSmrg if (crtc) 5353ed65abbSmrg RADEONPTR(crtc->scrn)->drmmode.dri2_flipping = FALSE; 53618781e08Smrg 53718781e08Smrg free(event_data); 53818781e08Smrg} 53918781e08Smrg 54018781e08Smrgstatic void 54118781e08Smrgradeon_dri2_flip_event_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, 54218781e08Smrg void *event_data) 54318781e08Smrg{ 54418781e08Smrg DRI2FrameEventPtr flip = event_data; 54518781e08Smrg ScrnInfoPtr scrn = crtc->scrn; 54618781e08Smrg unsigned tv_sec, tv_usec; 54718781e08Smrg DrawablePtr drawable; 54818781e08Smrg ScreenPtr screen; 54918781e08Smrg int status; 55018781e08Smrg PixmapPtr pixmap; 55118781e08Smrg 55218781e08Smrg status = dixLookupDrawable(&drawable, flip->drawable_id, serverClient, 55318781e08Smrg M_ANY, DixWriteAccess); 55418781e08Smrg if (status != Success) 55518781e08Smrg goto abort; 55618781e08Smrg 55718781e08Smrg frame += radeon_get_msc_delta(drawable, crtc); 5580d16fef4Smrg 55918781e08Smrg screen = scrn->pScreen; 56018781e08Smrg pixmap = screen->GetScreenPixmap(screen); 56118781e08Smrg xf86DrvMsgVerb(scrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 56218781e08Smrg "%s:%d fevent[%p] width %d pitch %d (/4 %d)\n", 56318781e08Smrg __func__, __LINE__, flip, pixmap->drawable.width, pixmap->devKind, pixmap->devKind/4); 56418781e08Smrg 56518781e08Smrg tv_sec = usec / 1000000; 56618781e08Smrg tv_usec = usec % 1000000; 56718781e08Smrg 56818781e08Smrg /* We assume our flips arrive in order, so we don't check the frame */ 56918781e08Smrg switch (flip->type) { 57018781e08Smrg case DRI2_SWAP: 57118781e08Smrg /* Check for too small vblank count of pageflip completion, taking wraparound 57218781e08Smrg * into account. This usually means some defective kms pageflip completion, 57318781e08Smrg * causing wrong (msc, ust) return values and possible visual corruption. 57418781e08Smrg */ 57518781e08Smrg if ((frame < flip->frame) && (flip->frame - frame < 5)) { 57618781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 57718781e08Smrg "%s: Pageflip completion event has impossible msc %u < target_msc %u\n", 57818781e08Smrg __func__, frame, flip->frame); 57918781e08Smrg /* All-Zero values signal failure of (msc, ust) timestamping to client. */ 58018781e08Smrg frame = tv_sec = tv_usec = 0; 58118781e08Smrg } 5820d16fef4Smrg 58318781e08Smrg DRI2SwapComplete(flip->client, drawable, frame, tv_sec, tv_usec, 58418781e08Smrg DRI2_FLIP_COMPLETE, flip->event_complete, 58518781e08Smrg flip->event_data); 58618781e08Smrg break; 58718781e08Smrg default: 58818781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, "%s: unknown vblank event received\n", __func__); 58918781e08Smrg /* Unknown type */ 59018781e08Smrg break; 5910d16fef4Smrg } 59218781e08Smrg 59318781e08Smrgabort: 59418781e08Smrg radeon_dri2_flip_event_abort(crtc, event_data); 595de2362d3Smrg} 596de2362d3Smrg 597de2362d3Smrgstatic Bool 59818781e08Smrgradeon_dri2_schedule_flip(xf86CrtcPtr crtc, ClientPtr client, 599de2362d3Smrg DrawablePtr draw, DRI2BufferPtr front, 600de2362d3Smrg DRI2BufferPtr back, DRI2SwapEventPtr func, 601de2362d3Smrg void *data, unsigned int target_msc) 602de2362d3Smrg{ 60318781e08Smrg ScrnInfoPtr scrn = crtc->scrn; 60418781e08Smrg RADEONInfoPtr info = RADEONPTR(scrn); 605de2362d3Smrg struct dri2_buffer_priv *back_priv; 606de2362d3Smrg DRI2FrameEventPtr flip_info; 607de2362d3Smrg 608de2362d3Smrg flip_info = calloc(1, sizeof(DRI2FrameEventRec)); 609de2362d3Smrg if (!flip_info) 610de2362d3Smrg return FALSE; 611de2362d3Smrg 612de2362d3Smrg flip_info->drawable_id = draw->id; 613de2362d3Smrg flip_info->client = client; 614de2362d3Smrg flip_info->type = DRI2_SWAP; 615de2362d3Smrg flip_info->event_complete = func; 616de2362d3Smrg flip_info->event_data = data; 617de2362d3Smrg flip_info->frame = target_msc; 61818781e08Smrg flip_info->crtc = crtc; 619de2362d3Smrg 620de2362d3Smrg xf86DrvMsgVerb(scrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 621de2362d3Smrg "%s:%d fevent[%p]\n", __func__, __LINE__, flip_info); 622de2362d3Smrg 623de2362d3Smrg /* Page flip the full screen buffer */ 624de2362d3Smrg back_priv = back->driverPrivate; 6258bf5c682Smrg if (radeon_do_pageflip(scrn, client, back_priv->pixmap, 6268bf5c682Smrg RADEON_DRM_QUEUE_ID_DEFAULT, flip_info, crtc, 62718781e08Smrg radeon_dri2_flip_event_handler, 6283ed65abbSmrg radeon_dri2_flip_event_abort, FLIP_VSYNC, 6293ed65abbSmrg target_msc - radeon_get_msc_delta(draw, crtc))) { 63018781e08Smrg info->drmmode.dri2_flipping = TRUE; 63118781e08Smrg return TRUE; 63218781e08Smrg } 6330d16fef4Smrg 63418781e08Smrg return FALSE; 635de2362d3Smrg} 636de2362d3Smrg 637de2362d3Smrgstatic Bool 638de2362d3Smrgupdate_front(DrawablePtr draw, DRI2BufferPtr front) 639de2362d3Smrg{ 640de2362d3Smrg PixmapPtr pixmap; 6418bf5c682Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen); 6428bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 6438bf5c682Smrg RADEONInfoPtr info = RADEONPTR(scrn); 644de2362d3Smrg struct dri2_buffer_priv *priv = front->driverPrivate; 645de2362d3Smrg 64618781e08Smrg pixmap = get_drawable_pixmap(draw); 647de2362d3Smrg pixmap->refcnt++; 648de2362d3Smrg 64918781e08Smrg if (!info->use_glamor) 65018781e08Smrg exaMoveInPixmap(pixmap); 6518bf5c682Smrg if (!radeon_get_flink_name(pRADEONEnt, pixmap, &front->name)) { 652de2362d3Smrg (*draw->pScreen->DestroyPixmap)(pixmap); 653de2362d3Smrg return FALSE; 654de2362d3Smrg } 655de2362d3Smrg (*draw->pScreen->DestroyPixmap)(priv->pixmap); 656de2362d3Smrg front->pitch = pixmap->devKind; 657de2362d3Smrg front->cpp = pixmap->drawable.bitsPerPixel / 8; 658de2362d3Smrg priv->pixmap = pixmap; 659de2362d3Smrg 660de2362d3Smrg return TRUE; 661de2362d3Smrg} 662de2362d3Smrg 663de2362d3Smrgstatic Bool 664de2362d3Smrgcan_exchange(ScrnInfoPtr pScrn, DrawablePtr draw, 665de2362d3Smrg DRI2BufferPtr front, DRI2BufferPtr back) 666de2362d3Smrg{ 667de2362d3Smrg struct dri2_buffer_priv *front_priv = front->driverPrivate; 668de2362d3Smrg struct dri2_buffer_priv *back_priv = back->driverPrivate; 669de2362d3Smrg PixmapPtr front_pixmap; 670de2362d3Smrg PixmapPtr back_pixmap = back_priv->pixmap; 671de2362d3Smrg 672de2362d3Smrg if (!update_front(draw, front)) 673de2362d3Smrg return FALSE; 674de2362d3Smrg 675de2362d3Smrg front_pixmap = front_priv->pixmap; 676de2362d3Smrg 677de2362d3Smrg if (front_pixmap->drawable.width != back_pixmap->drawable.width) 678de2362d3Smrg return FALSE; 679de2362d3Smrg 680de2362d3Smrg if (front_pixmap->drawable.height != back_pixmap->drawable.height) 681de2362d3Smrg return FALSE; 682de2362d3Smrg 683de2362d3Smrg if (front_pixmap->drawable.bitsPerPixel != back_pixmap->drawable.bitsPerPixel) 684de2362d3Smrg return FALSE; 685de2362d3Smrg 686de2362d3Smrg if (front_pixmap->devKind != back_pixmap->devKind) 687de2362d3Smrg return FALSE; 688de2362d3Smrg 689de2362d3Smrg return TRUE; 690de2362d3Smrg} 691de2362d3Smrg 692de2362d3Smrgstatic Bool 6938bf5c682Smrgcan_flip(xf86CrtcPtr crtc, DrawablePtr draw, 694de2362d3Smrg DRI2BufferPtr front, DRI2BufferPtr back) 695de2362d3Smrg{ 6968bf5c682Smrg ScrnInfoPtr pScrn = crtc->scrn; 69718781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 6983ed65abbSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 6993ed65abbSmrg int num_crtcs_on; 7003ed65abbSmrg int i; 7013ed65abbSmrg 7023ed65abbSmrg if (draw->type != DRAWABLE_WINDOW || 7033ed65abbSmrg !info->allowPageFlip || 7048bf5c682Smrg info->sprites_visible > 0 || 7053ed65abbSmrg info->drmmode.present_flipping || 7063ed65abbSmrg !pScrn->vtSema || 7073ed65abbSmrg !DRI2CanFlip(draw)) 7083ed65abbSmrg return FALSE; 7093ed65abbSmrg 7103ed65abbSmrg for (i = 0, num_crtcs_on = 0; i < config->num_crtc; i++) { 7118bf5c682Smrg if (drmmode_crtc_can_flip(config->crtc[i])) 7123ed65abbSmrg num_crtcs_on++; 7133ed65abbSmrg } 71418781e08Smrg 7153ed65abbSmrg return num_crtcs_on > 0 && can_exchange(pScrn, draw, front, back); 716de2362d3Smrg} 717de2362d3Smrg 718de2362d3Smrgstatic void 719de2362d3Smrgradeon_dri2_exchange_buffers(DrawablePtr draw, DRI2BufferPtr front, DRI2BufferPtr back) 720de2362d3Smrg{ 721de2362d3Smrg struct dri2_buffer_priv *front_priv = front->driverPrivate; 722de2362d3Smrg struct dri2_buffer_priv *back_priv = back->driverPrivate; 72339413783Smrg ScreenPtr screen = draw->pScreen; 72439413783Smrg RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(screen)); 72518781e08Smrg RegionRec region; 726de2362d3Smrg int tmp; 727de2362d3Smrg 72818781e08Smrg region.extents.x1 = region.extents.y1 = 0; 72918781e08Smrg region.extents.x2 = front_priv->pixmap->drawable.width; 73018781e08Smrg region.extents.y2 = front_priv->pixmap->drawable.height; 73118781e08Smrg region.data = NULL; 73218781e08Smrg DamageRegionAppend(&front_priv->pixmap->drawable, ®ion); 73318781e08Smrg 734de2362d3Smrg /* Swap BO names so DRI works */ 735de2362d3Smrg tmp = front->name; 736de2362d3Smrg front->name = back->name; 737de2362d3Smrg back->name = tmp; 738de2362d3Smrg 73939413783Smrg /* Swap pixmap privates */ 74039413783Smrg#ifdef USE_GLAMOR 74139413783Smrg if (info->use_glamor) { 74239413783Smrg struct radeon_pixmap *front_pix, *back_pix; 74318781e08Smrg 74439413783Smrg front_pix = radeon_get_pixmap_private(front_priv->pixmap); 74539413783Smrg back_pix = radeon_get_pixmap_private(back_priv->pixmap); 74639413783Smrg radeon_set_pixmap_private(front_priv->pixmap, back_pix); 74739413783Smrg radeon_set_pixmap_private(back_priv->pixmap, front_pix); 74839413783Smrg 74939413783Smrg radeon_glamor_exchange_buffers(front_priv->pixmap, back_priv->pixmap); 75039413783Smrg } else 75139413783Smrg#endif 75239413783Smrg { 75339413783Smrg struct radeon_exa_pixmap_priv driver_priv = *(struct radeon_exa_pixmap_priv*) 75439413783Smrg exaGetPixmapDriverPrivate(front_priv->pixmap); 75539413783Smrg 75639413783Smrg *(struct radeon_exa_pixmap_priv*)exaGetPixmapDriverPrivate(front_priv->pixmap) = 75739413783Smrg *(struct radeon_exa_pixmap_priv*)exaGetPixmapDriverPrivate(back_priv->pixmap); 75839413783Smrg *(struct radeon_exa_pixmap_priv*)exaGetPixmapDriverPrivate(back_priv->pixmap) = 75939413783Smrg driver_priv; 76039413783Smrg } 76118781e08Smrg 76218781e08Smrg DamageRegionProcessPending(&front_priv->pixmap->drawable); 763de2362d3Smrg} 764de2362d3Smrg 76518781e08Smrgstatic void radeon_dri2_frame_event_abort(xf86CrtcPtr crtc, void *event_data) 766de2362d3Smrg{ 767de2362d3Smrg DRI2FrameEventPtr event = event_data; 76818781e08Smrg 76918781e08Smrg TimerCancel(event->timer); 77018781e08Smrg TimerFree(event->timer); 77118781e08Smrg radeon_dri2_unref_buffer(event->front); 77218781e08Smrg radeon_dri2_unref_buffer(event->back); 77318781e08Smrg free(event); 77418781e08Smrg} 77518781e08Smrg 77618781e08Smrgstatic void radeon_dri2_frame_event_handler(xf86CrtcPtr crtc, uint32_t seq, 77718781e08Smrg uint64_t usec, void *event_data) 77818781e08Smrg{ 77918781e08Smrg DRI2FrameEventPtr event = event_data; 78018781e08Smrg ScrnInfoPtr scrn = crtc->scrn; 781de2362d3Smrg DrawablePtr drawable; 782de2362d3Smrg int status; 783de2362d3Smrg int swap_type; 784de2362d3Smrg BoxRec box; 785de2362d3Smrg RegionRec region; 786de2362d3Smrg 787de2362d3Smrg status = dixLookupDrawable(&drawable, event->drawable_id, serverClient, 788de2362d3Smrg M_ANY, DixWriteAccess); 789de2362d3Smrg if (status != Success) 790de2362d3Smrg goto cleanup; 791de2362d3Smrg 79218781e08Smrg seq += radeon_get_msc_delta(drawable, crtc); 793de2362d3Smrg 794de2362d3Smrg switch (event->type) { 795de2362d3Smrg case DRI2_FLIP: 7968bf5c682Smrg if (can_flip(crtc, drawable, event->front, event->back) && 79718781e08Smrg radeon_dri2_schedule_flip(crtc, 798de2362d3Smrg event->client, 799de2362d3Smrg drawable, 800de2362d3Smrg event->front, 801de2362d3Smrg event->back, 802de2362d3Smrg event->event_complete, 803de2362d3Smrg event->event_data, 804de2362d3Smrg event->frame)) { 805de2362d3Smrg radeon_dri2_exchange_buffers(drawable, event->front, event->back); 806de2362d3Smrg break; 807de2362d3Smrg } 808de2362d3Smrg /* else fall through to exchange/blit */ 809de2362d3Smrg case DRI2_SWAP: 810de2362d3Smrg if (DRI2CanExchange(drawable) && 811de2362d3Smrg can_exchange(scrn, drawable, event->front, event->back)) { 812de2362d3Smrg radeon_dri2_exchange_buffers(drawable, event->front, event->back); 813de2362d3Smrg swap_type = DRI2_EXCHANGE_COMPLETE; 814de2362d3Smrg } else { 815de2362d3Smrg box.x1 = 0; 816de2362d3Smrg box.y1 = 0; 817de2362d3Smrg box.x2 = drawable->width; 818de2362d3Smrg box.y2 = drawable->height; 819de2362d3Smrg REGION_INIT(pScreen, ®ion, &box, 0); 8208bf5c682Smrg radeon_dri2_copy_region2(drawable->pScreen, drawable, ®ion, 8218bf5c682Smrg event->front, event->back); 822de2362d3Smrg swap_type = DRI2_BLIT_COMPLETE; 823de2362d3Smrg } 824de2362d3Smrg 82518781e08Smrg DRI2SwapComplete(event->client, drawable, seq, usec / 1000000, 82618781e08Smrg usec % 1000000, swap_type, event->event_complete, 82718781e08Smrg event->event_data); 828de2362d3Smrg 829de2362d3Smrg break; 830de2362d3Smrg case DRI2_WAITMSC: 83118781e08Smrg DRI2WaitMSCComplete(event->client, drawable, seq, usec / 1000000, 83218781e08Smrg usec % 1000000); 833de2362d3Smrg break; 834de2362d3Smrg default: 835de2362d3Smrg /* Unknown type */ 836de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 837de2362d3Smrg "%s: unknown vblank event received\n", __func__); 838de2362d3Smrg break; 839de2362d3Smrg } 840de2362d3Smrg 841de2362d3Smrgcleanup: 84218781e08Smrg radeon_dri2_frame_event_abort(crtc, event_data); 843de2362d3Smrg} 844de2362d3Smrg 845de2362d3Smrg/* 84618781e08Smrg * This function should be called on a disabled CRTC only (i.e., CRTC 84718781e08Smrg * in DPMS-off state). It will calculate the delay necessary to reach 84818781e08Smrg * target_msc from present time if the CRTC were running. 849de2362d3Smrg */ 85018781e08Smrgstatic 85118781e08SmrgCARD32 radeon_dri2_extrapolate_msc_delay(xf86CrtcPtr crtc, CARD64 *target_msc, 85218781e08Smrg CARD64 divisor, CARD64 remainder) 853de2362d3Smrg{ 85418781e08Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 85518781e08Smrg ScrnInfoPtr pScrn = crtc->scrn; 8568bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 85718781e08Smrg int nominal_frame_rate = drmmode_crtc->dpms_last_fps; 85818781e08Smrg CARD64 last_vblank_ust = drmmode_crtc->dpms_last_ust; 85918781e08Smrg uint32_t last_vblank_seq = drmmode_crtc->dpms_last_seq; 86018781e08Smrg CARD64 now, target_time, delta_t; 86118781e08Smrg int64_t d, delta_seq; 8627821949aSmrg int ret; 86318781e08Smrg CARD32 d_ms; 86418781e08Smrg 86518781e08Smrg if (!last_vblank_ust) { 86618781e08Smrg *target_msc = 0; 86718781e08Smrg return FALLBACK_SWAP_DELAY; 86818781e08Smrg } 8698bf5c682Smrg ret = drmmode_get_current_ust(pRADEONEnt->fd, &now); 87018781e08Smrg if (ret) { 87118781e08Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 87218781e08Smrg "%s cannot get current time\n", __func__); 87318781e08Smrg *target_msc = 0; 87418781e08Smrg return FALLBACK_SWAP_DELAY; 87518781e08Smrg } 87618781e08Smrg delta_seq = *target_msc - last_vblank_seq; 87718781e08Smrg delta_seq *= 1000000; 87818781e08Smrg target_time = last_vblank_ust; 87918781e08Smrg target_time += delta_seq / nominal_frame_rate; 88018781e08Smrg d = target_time - now; 88118781e08Smrg if (d < 0) { 88218781e08Smrg /* we missed the event, adjust target_msc, do the divisor magic */ 88318781e08Smrg CARD64 current_msc = last_vblank_seq; 88418781e08Smrg 88518781e08Smrg delta_t = now - last_vblank_ust; 88618781e08Smrg delta_seq = delta_t * nominal_frame_rate; 88718781e08Smrg current_msc += delta_seq / 1000000; 88818781e08Smrg current_msc &= 0xffffffff; 88918781e08Smrg if (divisor == 0) { 89018781e08Smrg *target_msc = current_msc; 89118781e08Smrg d = 0; 89218781e08Smrg } else { 89318781e08Smrg *target_msc = current_msc - (current_msc % divisor) + remainder; 89418781e08Smrg if ((current_msc % divisor) >= remainder) 89518781e08Smrg *target_msc += divisor; 89618781e08Smrg *target_msc &= 0xffffffff; 89718781e08Smrg delta_seq = *target_msc - last_vblank_seq; 89818781e08Smrg delta_seq *= 1000000; 89918781e08Smrg target_time = last_vblank_ust; 90018781e08Smrg target_time += delta_seq / nominal_frame_rate; 90118781e08Smrg d = target_time - now; 90218781e08Smrg } 90318781e08Smrg } 90418781e08Smrg /* 90518781e08Smrg * convert delay to milliseconds and add margin to prevent the client 90618781e08Smrg * from coming back early (due to timer granularity and rounding 90718781e08Smrg * errors) and getting the same MSC it just got 90818781e08Smrg */ 90918781e08Smrg d_ms = (CARD32)d / 1000; 91018781e08Smrg if ((CARD32)d - d_ms * 1000 > 0) 91118781e08Smrg d_ms += 2; 91218781e08Smrg else 91318781e08Smrg d_ms++; 91418781e08Smrg return d_ms; 91518781e08Smrg} 91618781e08Smrg 91718781e08Smrg/* 91818781e08Smrg * Get current interpolated frame count and frame count timestamp, based on 91918781e08Smrg * drawable's crtc. 92018781e08Smrg */ 92118781e08Smrgstatic int radeon_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc) 92218781e08Smrg{ 92318781e08Smrg xf86CrtcPtr crtc = radeon_dri2_drawable_crtc(draw, TRUE); 924de2362d3Smrg 925de2362d3Smrg /* Drawable not displayed, make up a value */ 92639413783Smrg if (!crtc) { 927de2362d3Smrg *ust = 0; 928de2362d3Smrg *msc = 0; 929de2362d3Smrg return TRUE; 930de2362d3Smrg } 931de2362d3Smrg 93218781e08Smrg if (!radeon_dri2_get_crtc_msc(crtc, ust, msc)) 93318781e08Smrg return FALSE; 93418781e08Smrg 93518781e08Smrg if (draw && draw->type == DRAWABLE_WINDOW) 93618781e08Smrg *msc += get_dri2_window_priv((WindowPtr)draw)->vblank_delta; 93718781e08Smrg *msc &= 0xffffffff; 93818781e08Smrg return TRUE; 93918781e08Smrg} 94018781e08Smrg 94118781e08Smrgstatic 94218781e08SmrgCARD32 radeon_dri2_deferred_event(OsTimerPtr timer, CARD32 now, pointer data) 94318781e08Smrg{ 94418781e08Smrg DRI2FrameEventPtr event_info = (DRI2FrameEventPtr)data; 94518781e08Smrg xf86CrtcPtr crtc = event_info->crtc; 94618781e08Smrg ScrnInfoPtr scrn; 9478bf5c682Smrg RADEONEntPtr pRADEONEnt; 94818781e08Smrg CARD64 drm_now; 94918781e08Smrg int ret; 95018781e08Smrg CARD64 delta_t, delta_seq, frame; 95118781e08Smrg drmmode_crtc_private_ptr drmmode_crtc; 95218781e08Smrg 95318781e08Smrg /* 95418781e08Smrg * This is emulated event, so its time is current time, which we 95518781e08Smrg * have to get in DRM-compatible form (which is a bit messy given 95618781e08Smrg * the information that we have at this point). Can't use now argument 95718781e08Smrg * because DRM event time may come from monotonic clock, while 95818781e08Smrg * DIX timer facility uses real-time clock. 95918781e08Smrg */ 96018781e08Smrg if (!event_info->crtc) { 96118781e08Smrg ErrorF("%s no crtc\n", __func__); 96218781e08Smrg if (event_info->drm_queue_seq) 96318781e08Smrg radeon_drm_abort_entry(event_info->drm_queue_seq); 96418781e08Smrg else 96518781e08Smrg radeon_dri2_frame_event_abort(NULL, data); 96618781e08Smrg return 0; 967de2362d3Smrg } 968de2362d3Smrg 96918781e08Smrg scrn = crtc->scrn; 9708bf5c682Smrg pRADEONEnt = RADEONEntPriv(scrn); 97139413783Smrg drmmode_crtc = event_info->crtc->driver_private; 9728bf5c682Smrg ret = drmmode_get_current_ust(pRADEONEnt->fd, &drm_now); 97318781e08Smrg if (ret) { 97418781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 97518781e08Smrg "%s cannot get current time\n", __func__); 97618781e08Smrg if (event_info->drm_queue_seq) 97739413783Smrg drmmode_crtc->drmmode->event_context. 97839413783Smrg vblank_handler(pRADEONEnt->fd, 0, 0, 0, 97939413783Smrg (void*)event_info->drm_queue_seq); 98018781e08Smrg else 98118781e08Smrg radeon_dri2_frame_event_handler(crtc, 0, 0, data); 98218781e08Smrg return 0; 98318781e08Smrg } 98418781e08Smrg /* 98518781e08Smrg * calculate the frame number from current time 98618781e08Smrg * that would come from CRTC if it were running 98718781e08Smrg */ 98818781e08Smrg delta_t = drm_now - (CARD64)drmmode_crtc->dpms_last_ust; 98918781e08Smrg delta_seq = delta_t * drmmode_crtc->dpms_last_fps; 99018781e08Smrg delta_seq /= 1000000; 99118781e08Smrg frame = (CARD64)drmmode_crtc->dpms_last_seq + delta_seq; 99218781e08Smrg if (event_info->drm_queue_seq) 99339413783Smrg drmmode_crtc->drmmode->event_context. 99439413783Smrg vblank_handler(pRADEONEnt->fd, frame, drm_now / 1000000, 99539413783Smrg drm_now % 1000000, 99639413783Smrg (void*)event_info->drm_queue_seq); 99718781e08Smrg else 99818781e08Smrg radeon_dri2_frame_event_handler(crtc, frame, drm_now, data); 99918781e08Smrg return 0; 100018781e08Smrg} 10017821949aSmrg 100218781e08Smrgstatic 100318781e08Smrgvoid radeon_dri2_schedule_event(CARD32 delay, DRI2FrameEventPtr event_info) 100418781e08Smrg{ 100518781e08Smrg event_info->timer = TimerSet(NULL, 0, delay, radeon_dri2_deferred_event, 100618781e08Smrg event_info); 100718781e08Smrg if (delay == 0) { 100818781e08Smrg CARD32 now = GetTimeInMillis(); 100918781e08Smrg radeon_dri2_deferred_event(event_info->timer, now, event_info); 101018781e08Smrg } 1011de2362d3Smrg} 1012de2362d3Smrg 1013de2362d3Smrg/* 1014de2362d3Smrg * Request a DRM event when the requested conditions will be satisfied. 1015de2362d3Smrg * 1016de2362d3Smrg * We need to handle the event and ask the server to wake up the client when 1017de2362d3Smrg * we receive it. 1018de2362d3Smrg */ 1019de2362d3Smrgstatic int radeon_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, 1020de2362d3Smrg CARD64 target_msc, CARD64 divisor, 1021de2362d3Smrg CARD64 remainder) 1022de2362d3Smrg{ 1023de2362d3Smrg ScreenPtr screen = draw->pScreen; 1024de2362d3Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 1025de2362d3Smrg DRI2FrameEventPtr wait_info = NULL; 102618781e08Smrg uintptr_t drm_queue_seq = 0; 102718781e08Smrg xf86CrtcPtr crtc = radeon_dri2_drawable_crtc(draw, TRUE); 102818781e08Smrg uint32_t msc_delta; 10298bf5c682Smrg uint32_t seq; 1030de2362d3Smrg CARD64 current_msc; 1031de2362d3Smrg 1032de2362d3Smrg /* Truncate to match kernel interfaces; means occasional overflow 1033de2362d3Smrg * misses, but that's generally not a big deal */ 1034de2362d3Smrg target_msc &= 0xffffffff; 1035de2362d3Smrg divisor &= 0xffffffff; 1036de2362d3Smrg remainder &= 0xffffffff; 1037de2362d3Smrg 1038de2362d3Smrg /* Drawable not visible, return immediately */ 103939413783Smrg if (!crtc) 1040de2362d3Smrg goto out_complete; 1041de2362d3Smrg 104218781e08Smrg msc_delta = radeon_get_msc_delta(draw, crtc); 104318781e08Smrg 1044de2362d3Smrg wait_info = calloc(1, sizeof(DRI2FrameEventRec)); 1045de2362d3Smrg if (!wait_info) 1046de2362d3Smrg goto out_complete; 1047de2362d3Smrg 1048de2362d3Smrg wait_info->drawable_id = draw->id; 1049de2362d3Smrg wait_info->client = client; 1050de2362d3Smrg wait_info->type = DRI2_WAITMSC; 105118781e08Smrg wait_info->crtc = crtc; 1052de2362d3Smrg 105318781e08Smrg /* 105418781e08Smrg * CRTC is in DPMS off state, calculate wait time from current time, 105518781e08Smrg * target_msc and last vblank time/sequence when CRTC was turned off 105618781e08Smrg */ 105718781e08Smrg if (!radeon_crtc_is_enabled(crtc)) { 105818781e08Smrg CARD32 delay; 105918781e08Smrg target_msc -= msc_delta; 106018781e08Smrg delay = radeon_dri2_extrapolate_msc_delay(crtc, &target_msc, 106118781e08Smrg divisor, remainder); 106218781e08Smrg radeon_dri2_schedule_event(delay, wait_info); 106318781e08Smrg DRI2BlockClient(client, draw); 106418781e08Smrg return TRUE; 1065de2362d3Smrg } 1066de2362d3Smrg 1067de2362d3Smrg /* Get current count */ 10688bf5c682Smrg if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, NULL, &seq)) { 1069de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1070de2362d3Smrg "get vblank counter failed: %s\n", strerror(errno)); 1071de2362d3Smrg goto out_complete; 1072de2362d3Smrg } 1073de2362d3Smrg 10748bf5c682Smrg current_msc = seq + msc_delta; 107518781e08Smrg current_msc &= 0xffffffff; 107618781e08Smrg 107718781e08Smrg drm_queue_seq = radeon_drm_queue_alloc(crtc, client, RADEON_DRM_QUEUE_ID_DEFAULT, 107818781e08Smrg wait_info, radeon_dri2_frame_event_handler, 107918781e08Smrg radeon_dri2_frame_event_abort); 108018781e08Smrg if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) { 108118781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 108218781e08Smrg "Allocating DRM queue event entry failed.\n"); 108318781e08Smrg goto out_complete; 108418781e08Smrg } 108518781e08Smrg wait_info->drm_queue_seq = drm_queue_seq; 10860d16fef4Smrg 1087de2362d3Smrg /* 1088de2362d3Smrg * If divisor is zero, or current_msc is smaller than target_msc, 1089de2362d3Smrg * we just need to make sure target_msc passes before waking up the 1090de2362d3Smrg * client. 1091de2362d3Smrg */ 1092de2362d3Smrg if (divisor == 0 || current_msc < target_msc) { 1093de2362d3Smrg /* If target_msc already reached or passed, set it to 1094de2362d3Smrg * current_msc to ensure we return a reasonable value back 1095de2362d3Smrg * to the caller. This keeps the client from continually 1096de2362d3Smrg * sending us MSC targets from the past by forcibly updating 1097de2362d3Smrg * their count on this call. 1098de2362d3Smrg */ 1099de2362d3Smrg if (current_msc >= target_msc) 1100de2362d3Smrg target_msc = current_msc; 11018bf5c682Smrg if (!drmmode_wait_vblank(crtc, DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT, 11028bf5c682Smrg target_msc - msc_delta, drm_queue_seq, NULL, 11038bf5c682Smrg NULL)) { 1104de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1105de2362d3Smrg "get vblank counter failed: %s\n", strerror(errno)); 1106de2362d3Smrg goto out_complete; 1107de2362d3Smrg } 1108de2362d3Smrg 1109de2362d3Smrg DRI2BlockClient(client, draw); 1110de2362d3Smrg return TRUE; 1111de2362d3Smrg } 1112de2362d3Smrg 1113de2362d3Smrg /* 1114de2362d3Smrg * If we get here, target_msc has already passed or we don't have one, 1115de2362d3Smrg * so we queue an event that will satisfy the divisor/remainder equation. 1116de2362d3Smrg */ 11178bf5c682Smrg target_msc = current_msc - (current_msc % divisor) + remainder - msc_delta; 1118de2362d3Smrg 1119de2362d3Smrg /* 1120de2362d3Smrg * If calculated remainder is larger than requested remainder, 1121de2362d3Smrg * it means we've passed the last point where 1122de2362d3Smrg * seq % divisor == remainder, so we need to wait for the next time 1123de2362d3Smrg * that will happen. 1124de2362d3Smrg */ 1125de2362d3Smrg if ((current_msc % divisor) >= remainder) 11268bf5c682Smrg target_msc += divisor; 1127de2362d3Smrg 11288bf5c682Smrg if (!drmmode_wait_vblank(crtc, DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT, 11298bf5c682Smrg target_msc, drm_queue_seq, NULL, NULL)) { 1130de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1131de2362d3Smrg "get vblank counter failed: %s\n", strerror(errno)); 1132de2362d3Smrg goto out_complete; 1133de2362d3Smrg } 1134de2362d3Smrg 1135de2362d3Smrg DRI2BlockClient(client, draw); 1136de2362d3Smrg 1137de2362d3Smrg return TRUE; 1138de2362d3Smrg 1139de2362d3Smrgout_complete: 114018781e08Smrg if (wait_info) 114118781e08Smrg radeon_dri2_deferred_event(NULL, 0, wait_info); 1142de2362d3Smrg return TRUE; 1143de2362d3Smrg} 1144de2362d3Smrg 1145de2362d3Smrg/* 1146de2362d3Smrg * ScheduleSwap is responsible for requesting a DRM vblank event for the 1147de2362d3Smrg * appropriate frame. 1148de2362d3Smrg * 1149de2362d3Smrg * In the case of a blit (e.g. for a windowed swap) or buffer exchange, 1150de2362d3Smrg * the vblank requested can simply be the last queued swap frame + the swap 1151de2362d3Smrg * interval for the drawable. 1152de2362d3Smrg * 1153de2362d3Smrg * In the case of a page flip, we request an event for the last queued swap 1154de2362d3Smrg * frame + swap interval - 1, since we'll need to queue the flip for the frame 1155de2362d3Smrg * immediately following the received event. 1156de2362d3Smrg * 1157de2362d3Smrg * The client will be blocked if it tries to perform further GL commands 1158de2362d3Smrg * after queueing a swap, though in the Intel case after queueing a flip, the 1159de2362d3Smrg * client is free to queue more commands; they'll block in the kernel if 1160de2362d3Smrg * they access buffers busy with the flip. 1161de2362d3Smrg * 1162de2362d3Smrg * When the swap is complete, the driver should call into the server so it 1163de2362d3Smrg * can send any swap complete events that have been requested. 1164de2362d3Smrg */ 1165de2362d3Smrgstatic int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, 1166de2362d3Smrg DRI2BufferPtr front, DRI2BufferPtr back, 1167de2362d3Smrg CARD64 *target_msc, CARD64 divisor, 1168de2362d3Smrg CARD64 remainder, DRI2SwapEventPtr func, 1169de2362d3Smrg void *data) 1170de2362d3Smrg{ 1171de2362d3Smrg ScreenPtr screen = draw->pScreen; 1172de2362d3Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 117318781e08Smrg xf86CrtcPtr crtc = radeon_dri2_drawable_crtc(draw, TRUE); 117418781e08Smrg uint32_t msc_delta; 11758bf5c682Smrg drmVBlankSeqType type; 11768bf5c682Smrg uint32_t seq; 11778bf5c682Smrg int flip = 0; 1178de2362d3Smrg DRI2FrameEventPtr swap_info = NULL; 117918781e08Smrg uintptr_t drm_queue_seq; 11808bf5c682Smrg CARD64 current_msc, event_msc; 1181de2362d3Smrg BoxRec box; 1182de2362d3Smrg RegionRec region; 1183de2362d3Smrg 1184de2362d3Smrg /* Truncate to match kernel interfaces; means occasional overflow 1185de2362d3Smrg * misses, but that's generally not a big deal */ 1186de2362d3Smrg *target_msc &= 0xffffffff; 1187de2362d3Smrg divisor &= 0xffffffff; 1188de2362d3Smrg remainder &= 0xffffffff; 1189de2362d3Smrg 1190de2362d3Smrg /* radeon_dri2_frame_event_handler will get called some unknown time in the 1191de2362d3Smrg * future with these buffers. Take a reference to ensure that they won't 1192de2362d3Smrg * get destroyed before then. 1193de2362d3Smrg */ 1194de2362d3Smrg radeon_dri2_ref_buffer(front); 1195de2362d3Smrg radeon_dri2_ref_buffer(back); 1196de2362d3Smrg 119718781e08Smrg /* either off-screen or CRTC not usable... just complete the swap */ 119839413783Smrg if (!crtc) 1199de2362d3Smrg goto blit_fallback; 1200de2362d3Smrg 120118781e08Smrg msc_delta = radeon_get_msc_delta(draw, crtc); 120218781e08Smrg 1203de2362d3Smrg swap_info = calloc(1, sizeof(DRI2FrameEventRec)); 1204de2362d3Smrg if (!swap_info) 1205de2362d3Smrg goto blit_fallback; 1206de2362d3Smrg 120718781e08Smrg swap_info->type = DRI2_SWAP; 1208de2362d3Smrg swap_info->drawable_id = draw->id; 1209de2362d3Smrg swap_info->client = client; 1210de2362d3Smrg swap_info->event_complete = func; 1211de2362d3Smrg swap_info->event_data = data; 1212de2362d3Smrg swap_info->front = front; 1213de2362d3Smrg swap_info->back = back; 121418781e08Smrg swap_info->crtc = crtc; 121518781e08Smrg 121618781e08Smrg drm_queue_seq = radeon_drm_queue_alloc(crtc, client, RADEON_DRM_QUEUE_ID_DEFAULT, 121718781e08Smrg swap_info, radeon_dri2_frame_event_handler, 121818781e08Smrg radeon_dri2_frame_event_abort); 121918781e08Smrg if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) { 1220de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 122118781e08Smrg "Allocating DRM queue entry failed.\n"); 1222de2362d3Smrg goto blit_fallback; 1223de2362d3Smrg } 122418781e08Smrg swap_info->drm_queue_seq = drm_queue_seq; 122518781e08Smrg 122618781e08Smrg /* 122718781e08Smrg * CRTC is in DPMS off state, fallback to blit, but calculate 122818781e08Smrg * wait time from current time, target_msc and last vblank 122918781e08Smrg * time/sequence when CRTC was turned off 123018781e08Smrg */ 123118781e08Smrg if (!radeon_crtc_is_enabled(crtc)) { 123218781e08Smrg CARD32 delay; 123318781e08Smrg *target_msc -= msc_delta; 123418781e08Smrg delay = radeon_dri2_extrapolate_msc_delay(crtc, target_msc, 123518781e08Smrg divisor, remainder); 123618781e08Smrg *target_msc += msc_delta; 123718781e08Smrg *target_msc &= 0xffffffff; 123818781e08Smrg radeon_dri2_schedule_event(delay, swap_info); 123918781e08Smrg return TRUE; 124018781e08Smrg } 1241de2362d3Smrg 1242de2362d3Smrg /* Get current count */ 12438bf5c682Smrg if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, NULL, &seq)) { 1244de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1245de2362d3Smrg "first get vblank counter failed: %s\n", 1246de2362d3Smrg strerror(errno)); 124718781e08Smrg goto blit_fallback; 1248de2362d3Smrg } 1249de2362d3Smrg 12508bf5c682Smrg current_msc = seq + msc_delta; 125118781e08Smrg current_msc &= 0xffffffff; 1252de2362d3Smrg 1253de2362d3Smrg /* Flips need to be submitted one frame before */ 12548bf5c682Smrg if (can_flip(crtc, draw, front, back)) { 125518781e08Smrg swap_info->type = DRI2_FLIP; 1256de2362d3Smrg flip = 1; 1257de2362d3Smrg } 1258de2362d3Smrg 125918781e08Smrg /* Correct target_msc by 'flip' if swap_info->type == DRI2_FLIP. 1260de2362d3Smrg * Do it early, so handling of different timing constraints 1261de2362d3Smrg * for divisor, remainder and msc vs. target_msc works. 1262de2362d3Smrg */ 1263de2362d3Smrg if (*target_msc > 0) 1264de2362d3Smrg *target_msc -= flip; 1265de2362d3Smrg 1266de2362d3Smrg /* 1267de2362d3Smrg * If divisor is zero, or current_msc is smaller than target_msc 1268de2362d3Smrg * we just need to make sure target_msc passes before initiating 1269de2362d3Smrg * the swap. 1270de2362d3Smrg */ 1271de2362d3Smrg if (divisor == 0 || current_msc < *target_msc) { 12728bf5c682Smrg type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; 1273de2362d3Smrg /* If non-pageflipping, but blitting/exchanging, we need to use 1274de2362d3Smrg * DRM_VBLANK_NEXTONMISS to avoid unreliable timestamping later 1275de2362d3Smrg * on. 1276de2362d3Smrg */ 1277de2362d3Smrg if (flip == 0) 12788bf5c682Smrg type |= DRM_VBLANK_NEXTONMISS; 1279de2362d3Smrg 1280de2362d3Smrg /* If target_msc already reached or passed, set it to 1281de2362d3Smrg * current_msc to ensure we return a reasonable value back 1282de2362d3Smrg * to the caller. This makes swap_interval logic more robust. 1283de2362d3Smrg */ 1284de2362d3Smrg if (current_msc >= *target_msc) 1285de2362d3Smrg *target_msc = current_msc; 1286de2362d3Smrg 12878bf5c682Smrg if (!drmmode_wait_vblank(crtc, type, *target_msc - msc_delta, 12888bf5c682Smrg drm_queue_seq, NULL, &seq)) { 1289de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1290de2362d3Smrg "divisor 0 get vblank counter failed: %s\n", 1291de2362d3Smrg strerror(errno)); 129218781e08Smrg goto blit_fallback; 1293de2362d3Smrg } 1294de2362d3Smrg 12958bf5c682Smrg *target_msc = seq + flip + msc_delta; 1296de2362d3Smrg swap_info->frame = *target_msc; 1297de2362d3Smrg 1298de2362d3Smrg return TRUE; 1299de2362d3Smrg } 1300de2362d3Smrg 1301de2362d3Smrg /* 1302de2362d3Smrg * If we get here, target_msc has already passed or we don't have one, 1303de2362d3Smrg * and we need to queue an event that will satisfy the divisor/remainder 1304de2362d3Smrg * equation. 1305de2362d3Smrg */ 13068bf5c682Smrg type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; 1307de2362d3Smrg if (flip == 0) 13088bf5c682Smrg type |= DRM_VBLANK_NEXTONMISS; 1309de2362d3Smrg 13108bf5c682Smrg event_msc = current_msc - (current_msc % divisor) + remainder - msc_delta; 1311de2362d3Smrg 1312de2362d3Smrg /* 1313de2362d3Smrg * If the calculated deadline vbl.request.sequence is smaller than 1314de2362d3Smrg * or equal to current_msc, it means we've passed the last point 1315de2362d3Smrg * when effective onset frame seq could satisfy 1316de2362d3Smrg * seq % divisor == remainder, so we need to wait for the next time 1317de2362d3Smrg * this will happen. 1318de2362d3Smrg 1319de2362d3Smrg * This comparison takes the 1 frame swap delay in pageflipping mode 1320de2362d3Smrg * into account, as well as a potential DRM_VBLANK_NEXTONMISS delay 1321de2362d3Smrg * if we are blitting/exchanging instead of flipping. 1322de2362d3Smrg */ 13238bf5c682Smrg if (event_msc <= current_msc) 13248bf5c682Smrg event_msc += divisor; 1325de2362d3Smrg 1326de2362d3Smrg /* Account for 1 frame extra pageflip delay if flip > 0 */ 13278bf5c682Smrg event_msc -= flip; 1328de2362d3Smrg 13298bf5c682Smrg if (!drmmode_wait_vblank(crtc, type, event_msc, drm_queue_seq, NULL, &seq)) { 1330de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1331de2362d3Smrg "final get vblank counter failed: %s\n", 1332de2362d3Smrg strerror(errno)); 133318781e08Smrg goto blit_fallback; 1334de2362d3Smrg } 1335de2362d3Smrg 1336de2362d3Smrg /* Adjust returned value for 1 fame pageflip offset of flip > 0 */ 13378bf5c682Smrg *target_msc = seq + flip + msc_delta; 133818781e08Smrg *target_msc &= 0xffffffff; 1339de2362d3Smrg swap_info->frame = *target_msc; 1340de2362d3Smrg 1341de2362d3Smrg return TRUE; 1342de2362d3Smrg 1343de2362d3Smrgblit_fallback: 134418781e08Smrg if (swap_info) { 134518781e08Smrg swap_info->type = DRI2_SWAP; 134618781e08Smrg radeon_dri2_schedule_event(FALLBACK_SWAP_DELAY, swap_info); 134718781e08Smrg } else { 134818781e08Smrg box.x1 = 0; 134918781e08Smrg box.y1 = 0; 135018781e08Smrg box.x2 = draw->width; 135118781e08Smrg box.y2 = draw->height; 135218781e08Smrg REGION_INIT(pScreen, ®ion, &box, 0); 1353de2362d3Smrg 13548bf5c682Smrg radeon_dri2_copy_region2(draw->pScreen, draw, ®ion, front, back); 1355de2362d3Smrg 135618781e08Smrg DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data); 1357de2362d3Smrg 135818781e08Smrg radeon_dri2_unref_buffer(front); 135918781e08Smrg radeon_dri2_unref_buffer(back); 136018781e08Smrg } 13617821949aSmrg 1362de2362d3Smrg *target_msc = 0; /* offscreen, so zero out target vblank count */ 1363de2362d3Smrg return TRUE; 1364de2362d3Smrg} 1365de2362d3Smrg 1366de2362d3Smrg 1367de2362d3SmrgBool 1368de2362d3Smrgradeon_dri2_screen_init(ScreenPtr pScreen) 1369de2362d3Smrg{ 1370de2362d3Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 13718bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 1372de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1373de2362d3Smrg DRI2InfoRec dri2_info = { 0 }; 1374de2362d3Smrg const char *driverNames[2]; 1375de2362d3Smrg Bool scheduling_works = TRUE; 1376de2362d3Smrg 137718781e08Smrg if (!info->dri2.available) 1378de2362d3Smrg return FALSE; 1379de2362d3Smrg 13808bf5c682Smrg info->dri2.device_name = drmGetDeviceNameFromFd(pRADEONEnt->fd); 1381de2362d3Smrg 138218781e08Smrg if ( (info->ChipFamily >= CHIP_FAMILY_TAHITI) ) { 138318781e08Smrg dri2_info.driverName = SI_DRIVER_NAME; 138418781e08Smrg } else if ( (info->ChipFamily >= CHIP_FAMILY_R600) ) { 1385de2362d3Smrg dri2_info.driverName = R600_DRIVER_NAME; 1386de2362d3Smrg } else if ( (info->ChipFamily >= CHIP_FAMILY_R300) ) { 1387de2362d3Smrg dri2_info.driverName = R300_DRIVER_NAME; 1388de2362d3Smrg } else if ( info->ChipFamily >= CHIP_FAMILY_R200 ) { 1389de2362d3Smrg dri2_info.driverName = R200_DRIVER_NAME; 1390de2362d3Smrg } else { 1391de2362d3Smrg dri2_info.driverName = RADEON_DRIVER_NAME; 1392de2362d3Smrg } 13938bf5c682Smrg dri2_info.fd = pRADEONEnt->fd; 1394de2362d3Smrg dri2_info.deviceName = info->dri2.device_name; 1395de2362d3Smrg 139618781e08Smrg if (info->dri2.pKernelDRMVersion->version_minor < 4) { 1397de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "You need a newer kernel for " 1398de2362d3Smrg "sync extension\n"); 1399de2362d3Smrg scheduling_works = FALSE; 1400de2362d3Smrg } 1401de2362d3Smrg 140218781e08Smrg if (scheduling_works && info->drmmode.count_crtcs > 2) { 1403de2362d3Smrg#ifdef DRM_CAP_VBLANK_HIGH_CRTC 1404de2362d3Smrg uint64_t cap_value; 1405de2362d3Smrg 14068bf5c682Smrg if (drmGetCap(pRADEONEnt->fd, DRM_CAP_VBLANK_HIGH_CRTC, &cap_value)) { 1407de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "You need a newer kernel " 1408de2362d3Smrg "for VBLANKs on CRTC > 1\n"); 1409de2362d3Smrg scheduling_works = FALSE; 1410de2362d3Smrg } else if (!cap_value) { 1411de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Your kernel does not " 1412de2362d3Smrg "handle VBLANKs on CRTC > 1\n"); 1413de2362d3Smrg scheduling_works = FALSE; 1414de2362d3Smrg } 1415de2362d3Smrg#else 1416de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "You need to rebuild against a " 1417de2362d3Smrg "newer libdrm to handle VBLANKs on CRTC > 1\n"); 1418de2362d3Smrg scheduling_works = FALSE; 1419de2362d3Smrg#endif 1420de2362d3Smrg } 1421de2362d3Smrg 1422de2362d3Smrg if (scheduling_works) { 1423de2362d3Smrg dri2_info.ScheduleSwap = radeon_dri2_schedule_swap; 1424de2362d3Smrg dri2_info.GetMSC = radeon_dri2_get_msc; 1425de2362d3Smrg dri2_info.ScheduleWaitMSC = radeon_dri2_schedule_wait_msc; 14268bf5c682Smrg dri2_info.numDrivers = ARRAY_SIZE(driverNames); 1427de2362d3Smrg dri2_info.driverNames = driverNames; 142818781e08Smrg driverNames[0] = dri2_info.driverName; 142918781e08Smrg 143018781e08Smrg if (info->ChipFamily >= CHIP_FAMILY_R300) 143118781e08Smrg driverNames[1] = driverNames[0]; 143218781e08Smrg else 143318781e08Smrg driverNames[1] = NULL; /* no VDPAU support */ 143418781e08Smrg 143518781e08Smrg if (DRI2InfoCnt == 0) { 143618781e08Smrg if (!dixRegisterPrivateKey(dri2_window_private_key, 143718781e08Smrg PRIVATE_WINDOW, 143818781e08Smrg sizeof(struct dri2_window_priv))) { 143918781e08Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 144018781e08Smrg "Failed to get DRI2 window private\n"); 1441de2362d3Smrg return FALSE; 1442de2362d3Smrg } 1443de2362d3Smrg 1444de2362d3Smrg AddCallback(&ClientStateCallback, radeon_dri2_client_state_changed, 0); 1445de2362d3Smrg } 1446de2362d3Smrg 144718781e08Smrg DRI2InfoCnt++; 1448de2362d3Smrg } 144918781e08Smrg 145018781e08Smrg dri2_info.version = 9; 145118781e08Smrg dri2_info.CreateBuffer2 = radeon_dri2_create_buffer2; 145218781e08Smrg dri2_info.DestroyBuffer2 = radeon_dri2_destroy_buffer2; 145318781e08Smrg dri2_info.CopyRegion2 = radeon_dri2_copy_region2; 1454de2362d3Smrg 1455de2362d3Smrg info->dri2.enabled = DRI2ScreenInit(pScreen, &dri2_info); 1456de2362d3Smrg return info->dri2.enabled; 1457de2362d3Smrg} 1458de2362d3Smrg 1459de2362d3Smrgvoid radeon_dri2_close_screen(ScreenPtr pScreen) 1460de2362d3Smrg{ 1461de2362d3Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1462de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1463de2362d3Smrg 146418781e08Smrg if (--DRI2InfoCnt == 0) 1465de2362d3Smrg DeleteCallback(&ClientStateCallback, radeon_dri2_client_state_changed, 0); 146618781e08Smrg 1467de2362d3Smrg DRI2CloseScreen(pScreen); 1468de2362d3Smrg drmFree(info->dri2.device_name); 1469de2362d3Smrg} 1470de2362d3Smrg 147118781e08Smrg#endif /* DRI2 */ 147218781e08Smrg 1473