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++; 255446f62d6Smrg 256446f62d6Smrg /* The copy operation from radeon_glamor_set_pixmap_bo needs to 257446f62d6Smrg * be flushed to the kernel driver before the client starts 258446f62d6Smrg * using the pixmap storage for direct rendering. 259446f62d6Smrg */ 260446f62d6Smrg radeon_cs_flush_indirect(pScrn); 261de2362d3Smrg } 262de2362d3Smrg 26339413783Smrg if (!radeon_get_flink_name(pRADEONEnt, pixmap, &buffers->name)) 26439413783Smrg goto error; 26539413783Smrg 266de2362d3Smrg privates = calloc(1, sizeof(struct dri2_buffer_priv)); 26739413783Smrg if (!privates) 268de2362d3Smrg goto error; 269de2362d3Smrg 270de2362d3Smrg buffers->attachment = attachment; 27139413783Smrg buffers->pitch = pixmap->devKind; 27239413783Smrg buffers->cpp = cpp; 273de2362d3Smrg buffers->driverPrivate = privates; 274de2362d3Smrg buffers->format = format; 275de2362d3Smrg buffers->flags = 0; /* not tiled */ 276de2362d3Smrg privates->pixmap = pixmap; 277de2362d3Smrg privates->attachment = attachment; 278de2362d3Smrg privates->refcnt = 1; 279de2362d3Smrg 280de2362d3Smrg return buffers; 281de2362d3Smrg 282de2362d3Smrgerror: 283de2362d3Smrg free(buffers); 28439413783Smrg (*pScreen->DestroyPixmap)(pixmap); 285de2362d3Smrg return NULL; 286de2362d3Smrg} 287de2362d3Smrg 288de2362d3Smrgstatic void 28918781e08Smrgradeon_dri2_destroy_buffer2(ScreenPtr pScreen, 29018781e08Smrg DrawablePtr drawable, BufferPtr buffers) 291de2362d3Smrg{ 292de2362d3Smrg if(buffers) 293de2362d3Smrg { 294de2362d3Smrg struct dri2_buffer_priv *private = buffers->driverPrivate; 295de2362d3Smrg 296de2362d3Smrg /* Trying to free an already freed buffer is unlikely to end well */ 297de2362d3Smrg if (private->refcnt == 0) { 298de2362d3Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 299de2362d3Smrg 300de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 301de2362d3Smrg "Attempted to destroy previously destroyed buffer.\ 302de2362d3Smrg This is a programming error\n"); 303de2362d3Smrg return; 304de2362d3Smrg } 305de2362d3Smrg 306de2362d3Smrg private->refcnt--; 307de2362d3Smrg if (private->refcnt == 0) 308de2362d3Smrg { 30918781e08Smrg if (private->pixmap) 31018781e08Smrg (*pScreen->DestroyPixmap)(private->pixmap); 311de2362d3Smrg 312de2362d3Smrg free(buffers->driverPrivate); 313de2362d3Smrg free(buffers); 314de2362d3Smrg } 315de2362d3Smrg } 316de2362d3Smrg} 317de2362d3Smrg 31818781e08Smrg 31918781e08Smrgstatic inline PixmapPtr GetDrawablePixmap(DrawablePtr drawable) 32018781e08Smrg{ 32118781e08Smrg if (drawable->type == DRAWABLE_PIXMAP) 32218781e08Smrg return (PixmapPtr)drawable; 32318781e08Smrg else { 32418781e08Smrg struct _Window *pWin = (struct _Window *)drawable; 32518781e08Smrg return drawable->pScreen->GetWindowPixmap(pWin); 32618781e08Smrg } 32718781e08Smrg} 328de2362d3Smrgstatic void 32918781e08Smrgradeon_dri2_copy_region2(ScreenPtr pScreen, 33018781e08Smrg DrawablePtr drawable, 33118781e08Smrg RegionPtr region, 33218781e08Smrg BufferPtr dest_buffer, 33318781e08Smrg BufferPtr src_buffer) 334de2362d3Smrg{ 335de2362d3Smrg struct dri2_buffer_priv *src_private = src_buffer->driverPrivate; 336de2362d3Smrg struct dri2_buffer_priv *dst_private = dest_buffer->driverPrivate; 337de2362d3Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 338de2362d3Smrg DrawablePtr src_drawable; 339de2362d3Smrg DrawablePtr dst_drawable; 340de2362d3Smrg RegionPtr copy_clip; 341de2362d3Smrg GCPtr gc; 342de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 343de2362d3Smrg Bool vsync; 34418781e08Smrg Bool translate = FALSE; 34518781e08Smrg int off_x = 0, off_y = 0; 34618781e08Smrg 34718781e08Smrg src_drawable = &src_private->pixmap->drawable; 34818781e08Smrg dst_drawable = &dst_private->pixmap->drawable; 349de2362d3Smrg 350de2362d3Smrg if (src_private->attachment == DRI2BufferFrontLeft) { 35118781e08Smrg if (drawable->pScreen != pScreen) { 35218781e08Smrg src_drawable = DRI2UpdatePrime(drawable, src_buffer); 35318781e08Smrg if (!src_drawable) 35418781e08Smrg return; 35518781e08Smrg } else 35618781e08Smrg src_drawable = drawable; 357de2362d3Smrg } 358de2362d3Smrg if (dst_private->attachment == DRI2BufferFrontLeft) { 35918781e08Smrg if (drawable->pScreen != pScreen) { 36018781e08Smrg dst_drawable = DRI2UpdatePrime(drawable, dest_buffer); 36118781e08Smrg if (!dst_drawable) 36218781e08Smrg return; 36318781e08Smrg if (dst_drawable != drawable) 36418781e08Smrg translate = TRUE; 36518781e08Smrg } else 36618781e08Smrg dst_drawable = drawable; 36718781e08Smrg } 36818781e08Smrg 36918781e08Smrg if (translate && drawable->type == DRAWABLE_WINDOW) { 37018781e08Smrg PixmapPtr pPix = GetDrawablePixmap(drawable); 37118781e08Smrg 37218781e08Smrg off_x = drawable->x - pPix->screen_x; 37318781e08Smrg off_y = drawable->y - pPix->screen_y; 374de2362d3Smrg } 375de2362d3Smrg gc = GetScratchGC(dst_drawable->depth, pScreen); 376de2362d3Smrg copy_clip = REGION_CREATE(pScreen, NULL, 0); 377de2362d3Smrg REGION_COPY(pScreen, copy_clip, region); 37818781e08Smrg 37918781e08Smrg if (translate) { 38018781e08Smrg REGION_TRANSLATE(pScreen, copy_clip, off_x, off_y); 38118781e08Smrg } 38218781e08Smrg 383de2362d3Smrg (*gc->funcs->ChangeClip) (gc, CT_REGION, copy_clip, 0); 384de2362d3Smrg ValidateGC(dst_drawable, gc); 385de2362d3Smrg 386de2362d3Smrg vsync = info->accel_state->vsync; 387de2362d3Smrg /* Driver option "SwapbuffersWait" defines if we vsync DRI2 copy-swaps. */ 388de2362d3Smrg info->accel_state->vsync = info->swapBuffersWait; 38918781e08Smrg info->accel_state->force = TRUE; 390de2362d3Smrg 391de2362d3Smrg (*gc->ops->CopyArea)(src_drawable, dst_drawable, gc, 39218781e08Smrg 0, 0, drawable->width, drawable->height, off_x, off_y); 393de2362d3Smrg 39418781e08Smrg info->accel_state->force = FALSE; 395de2362d3Smrg info->accel_state->vsync = vsync; 396de2362d3Smrg 397de2362d3Smrg FreeScratchGC(gc); 398de2362d3Smrg} 399de2362d3Smrg 400de2362d3Smrgenum DRI2FrameEventType { 401de2362d3Smrg DRI2_SWAP, 402de2362d3Smrg DRI2_FLIP, 403de2362d3Smrg DRI2_WAITMSC, 404de2362d3Smrg}; 405de2362d3Smrg 406de2362d3Smrgtypedef struct _DRI2FrameEvent { 407de2362d3Smrg XID drawable_id; 408de2362d3Smrg ClientPtr client; 409de2362d3Smrg enum DRI2FrameEventType type; 41018781e08Smrg unsigned frame; 41118781e08Smrg xf86CrtcPtr crtc; 41218781e08Smrg OsTimerPtr timer; 41318781e08Smrg uintptr_t drm_queue_seq; 414de2362d3Smrg 415de2362d3Smrg /* for swaps & flips only */ 416de2362d3Smrg DRI2SwapEventPtr event_complete; 417de2362d3Smrg void *event_data; 418de2362d3Smrg DRI2BufferPtr front; 419de2362d3Smrg DRI2BufferPtr back; 420de2362d3Smrg} DRI2FrameEventRec, *DRI2FrameEventPtr; 421de2362d3Smrg 42218781e08Smrgstatic int DRI2InfoCnt; 423de2362d3Smrg 424de2362d3Smrgstatic void 425de2362d3Smrgradeon_dri2_ref_buffer(BufferPtr buffer) 426de2362d3Smrg{ 427de2362d3Smrg struct dri2_buffer_priv *private = buffer->driverPrivate; 428de2362d3Smrg private->refcnt++; 429de2362d3Smrg} 430de2362d3Smrg 431de2362d3Smrgstatic void 432de2362d3Smrgradeon_dri2_unref_buffer(BufferPtr buffer) 433de2362d3Smrg{ 434de2362d3Smrg if (buffer) { 435de2362d3Smrg struct dri2_buffer_priv *private = buffer->driverPrivate; 4368bf5c682Smrg DrawablePtr draw = &private->pixmap->drawable; 4378bf5c682Smrg 4388bf5c682Smrg radeon_dri2_destroy_buffer2(draw->pScreen, draw, buffer); 439de2362d3Smrg } 440de2362d3Smrg} 441de2362d3Smrg 442de2362d3Smrgstatic void 443de2362d3Smrgradeon_dri2_client_state_changed(CallbackListPtr *ClientStateCallback, pointer data, pointer calldata) 444de2362d3Smrg{ 445de2362d3Smrg NewClientInfoRec *clientinfo = calldata; 446de2362d3Smrg ClientPtr pClient = clientinfo->client; 447de2362d3Smrg 448de2362d3Smrg switch (pClient->clientState) { 449de2362d3Smrg case ClientStateRetained: 450de2362d3Smrg case ClientStateGone: 45118781e08Smrg radeon_drm_abort_client(pClient); 452de2362d3Smrg break; 453de2362d3Smrg default: 454de2362d3Smrg break; 455de2362d3Smrg } 456de2362d3Smrg} 457de2362d3Smrg 45818781e08Smrg/* 45918781e08Smrg * Get current frame count delta for the specified drawable and CRTC 46018781e08Smrg */ 46118781e08Smrgstatic uint32_t radeon_get_msc_delta(DrawablePtr pDraw, xf86CrtcPtr crtc) 46218781e08Smrg{ 46318781e08Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 46418781e08Smrg 46518781e08Smrg if (pDraw && pDraw->type == DRAWABLE_WINDOW) 46618781e08Smrg return drmmode_crtc->interpolated_vblanks + 46718781e08Smrg get_dri2_window_priv((WindowPtr)pDraw)->vblank_delta; 46818781e08Smrg 46918781e08Smrg return drmmode_crtc->interpolated_vblanks; 47018781e08Smrg} 47118781e08Smrg 47218781e08Smrg/* 47318781e08Smrg * Get current frame count and timestamp of the specified CRTC 47418781e08Smrg */ 47518781e08Smrgstatic Bool radeon_dri2_get_crtc_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc) 47618781e08Smrg{ 47718781e08Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 47818781e08Smrg 47918781e08Smrg if (!radeon_crtc_is_enabled(crtc) || 48018781e08Smrg drmmode_crtc_get_ust_msc(crtc, ust, msc) != Success) { 48118781e08Smrg /* CRTC is not running, extrapolate MSC and timestamp */ 48218781e08Smrg ScrnInfoPtr scrn = crtc->scrn; 4838bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 48418781e08Smrg CARD64 now, delta_t, delta_seq; 48518781e08Smrg 48618781e08Smrg if (!drmmode_crtc->dpms_last_ust) 48718781e08Smrg return FALSE; 48818781e08Smrg 4898bf5c682Smrg if (drmmode_get_current_ust(pRADEONEnt->fd, &now) != 0) { 49018781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 49118781e08Smrg "%s cannot get current time\n", __func__); 49218781e08Smrg return FALSE; 49318781e08Smrg } 49418781e08Smrg 49518781e08Smrg delta_t = now - drmmode_crtc->dpms_last_ust; 49618781e08Smrg delta_seq = delta_t * drmmode_crtc->dpms_last_fps; 49718781e08Smrg delta_seq /= 1000000; 49818781e08Smrg *ust = drmmode_crtc->dpms_last_ust; 49918781e08Smrg delta_t = delta_seq * 1000000; 50018781e08Smrg delta_t /= drmmode_crtc->dpms_last_fps; 50118781e08Smrg *ust += delta_t; 50218781e08Smrg *msc = drmmode_crtc->dpms_last_seq; 50318781e08Smrg *msc += delta_seq; 50418781e08Smrg } 50518781e08Smrg 50618781e08Smrg *msc += drmmode_crtc->interpolated_vblanks; 50718781e08Smrg 50818781e08Smrg return TRUE; 50918781e08Smrg} 51018781e08Smrg 51118781e08Smrgstatic 5120d2a5547Smrgxf86CrtcPtr radeon_dri2_drawable_crtc(DrawablePtr pDraw) 513de2362d3Smrg{ 514de2362d3Smrg ScreenPtr pScreen = pDraw->pScreen; 515de2362d3Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 5160d2a5547Smrg xf86CrtcPtr crtc = radeon_pick_best_crtc(pScrn, TRUE, 51718781e08Smrg pDraw->x, pDraw->x + pDraw->width, 51818781e08Smrg pDraw->y, pDraw->y + pDraw->height); 51918781e08Smrg 5200d2a5547Smrg if (pDraw->type == DRAWABLE_WINDOW) { 52118781e08Smrg struct dri2_window_priv *priv = get_dri2_window_priv((WindowPtr)pDraw); 52218781e08Smrg 5230d2a5547Smrg if (!crtc) { 5240d2a5547Smrg crtc = priv->crtc; 5250d2a5547Smrg } else if (priv->crtc && priv->crtc != crtc) { 52618781e08Smrg CARD64 ust, mscold, mscnew; 52718781e08Smrg 52818781e08Smrg if (radeon_dri2_get_crtc_msc(priv->crtc, &ust, &mscold) && 52918781e08Smrg radeon_dri2_get_crtc_msc(crtc, &ust, &mscnew)) 53018781e08Smrg priv->vblank_delta += mscold - mscnew; 53118781e08Smrg } 53218781e08Smrg 53318781e08Smrg priv->crtc = crtc; 53418781e08Smrg } 53518781e08Smrg 53618781e08Smrg return crtc; 53718781e08Smrg} 53818781e08Smrg 53918781e08Smrgstatic void 54018781e08Smrgradeon_dri2_flip_event_abort(xf86CrtcPtr crtc, void *event_data) 54118781e08Smrg{ 5423ed65abbSmrg if (crtc) 5433ed65abbSmrg RADEONPTR(crtc->scrn)->drmmode.dri2_flipping = FALSE; 54418781e08Smrg 54518781e08Smrg free(event_data); 54618781e08Smrg} 54718781e08Smrg 54818781e08Smrgstatic void 54918781e08Smrgradeon_dri2_flip_event_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, 55018781e08Smrg void *event_data) 55118781e08Smrg{ 55218781e08Smrg DRI2FrameEventPtr flip = event_data; 55318781e08Smrg ScrnInfoPtr scrn = crtc->scrn; 55418781e08Smrg unsigned tv_sec, tv_usec; 55518781e08Smrg DrawablePtr drawable; 55618781e08Smrg ScreenPtr screen; 55718781e08Smrg int status; 55818781e08Smrg PixmapPtr pixmap; 55918781e08Smrg 56018781e08Smrg status = dixLookupDrawable(&drawable, flip->drawable_id, serverClient, 56118781e08Smrg M_ANY, DixWriteAccess); 56218781e08Smrg if (status != Success) 56318781e08Smrg goto abort; 56418781e08Smrg 56518781e08Smrg frame += radeon_get_msc_delta(drawable, crtc); 5660d16fef4Smrg 56718781e08Smrg screen = scrn->pScreen; 56818781e08Smrg pixmap = screen->GetScreenPixmap(screen); 56918781e08Smrg xf86DrvMsgVerb(scrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 57018781e08Smrg "%s:%d fevent[%p] width %d pitch %d (/4 %d)\n", 57118781e08Smrg __func__, __LINE__, flip, pixmap->drawable.width, pixmap->devKind, pixmap->devKind/4); 57218781e08Smrg 57318781e08Smrg tv_sec = usec / 1000000; 57418781e08Smrg tv_usec = usec % 1000000; 57518781e08Smrg 57618781e08Smrg /* We assume our flips arrive in order, so we don't check the frame */ 57718781e08Smrg switch (flip->type) { 57818781e08Smrg case DRI2_SWAP: 57918781e08Smrg /* Check for too small vblank count of pageflip completion, taking wraparound 58018781e08Smrg * into account. This usually means some defective kms pageflip completion, 58118781e08Smrg * causing wrong (msc, ust) return values and possible visual corruption. 58218781e08Smrg */ 58318781e08Smrg if ((frame < flip->frame) && (flip->frame - frame < 5)) { 58418781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 58518781e08Smrg "%s: Pageflip completion event has impossible msc %u < target_msc %u\n", 58618781e08Smrg __func__, frame, flip->frame); 58718781e08Smrg /* All-Zero values signal failure of (msc, ust) timestamping to client. */ 58818781e08Smrg frame = tv_sec = tv_usec = 0; 58918781e08Smrg } 5900d16fef4Smrg 59118781e08Smrg DRI2SwapComplete(flip->client, drawable, frame, tv_sec, tv_usec, 59218781e08Smrg DRI2_FLIP_COMPLETE, flip->event_complete, 59318781e08Smrg flip->event_data); 59418781e08Smrg break; 59518781e08Smrg default: 59618781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, "%s: unknown vblank event received\n", __func__); 59718781e08Smrg /* Unknown type */ 59818781e08Smrg break; 5990d16fef4Smrg } 60018781e08Smrg 60118781e08Smrgabort: 60218781e08Smrg radeon_dri2_flip_event_abort(crtc, event_data); 603de2362d3Smrg} 604de2362d3Smrg 605de2362d3Smrgstatic Bool 60618781e08Smrgradeon_dri2_schedule_flip(xf86CrtcPtr crtc, ClientPtr client, 607de2362d3Smrg DrawablePtr draw, DRI2BufferPtr front, 608de2362d3Smrg DRI2BufferPtr back, DRI2SwapEventPtr func, 609de2362d3Smrg void *data, unsigned int target_msc) 610de2362d3Smrg{ 61118781e08Smrg ScrnInfoPtr scrn = crtc->scrn; 61218781e08Smrg RADEONInfoPtr info = RADEONPTR(scrn); 613de2362d3Smrg struct dri2_buffer_priv *back_priv; 614de2362d3Smrg DRI2FrameEventPtr flip_info; 615de2362d3Smrg 616de2362d3Smrg flip_info = calloc(1, sizeof(DRI2FrameEventRec)); 617de2362d3Smrg if (!flip_info) 618de2362d3Smrg return FALSE; 619de2362d3Smrg 620de2362d3Smrg flip_info->drawable_id = draw->id; 621de2362d3Smrg flip_info->client = client; 622de2362d3Smrg flip_info->type = DRI2_SWAP; 623de2362d3Smrg flip_info->event_complete = func; 624de2362d3Smrg flip_info->event_data = data; 625de2362d3Smrg flip_info->frame = target_msc; 62618781e08Smrg flip_info->crtc = crtc; 627de2362d3Smrg 628de2362d3Smrg xf86DrvMsgVerb(scrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 629de2362d3Smrg "%s:%d fevent[%p]\n", __func__, __LINE__, flip_info); 630de2362d3Smrg 631de2362d3Smrg /* Page flip the full screen buffer */ 632de2362d3Smrg back_priv = back->driverPrivate; 6338bf5c682Smrg if (radeon_do_pageflip(scrn, client, back_priv->pixmap, 6348bf5c682Smrg RADEON_DRM_QUEUE_ID_DEFAULT, flip_info, crtc, 63518781e08Smrg radeon_dri2_flip_event_handler, 6363ed65abbSmrg radeon_dri2_flip_event_abort, FLIP_VSYNC, 6373ed65abbSmrg target_msc - radeon_get_msc_delta(draw, crtc))) { 63818781e08Smrg info->drmmode.dri2_flipping = TRUE; 63918781e08Smrg return TRUE; 64018781e08Smrg } 6410d16fef4Smrg 64218781e08Smrg return FALSE; 643de2362d3Smrg} 644de2362d3Smrg 645de2362d3Smrgstatic Bool 646de2362d3Smrgupdate_front(DrawablePtr draw, DRI2BufferPtr front) 647de2362d3Smrg{ 648de2362d3Smrg PixmapPtr pixmap; 6498bf5c682Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen); 6508bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 6518bf5c682Smrg RADEONInfoPtr info = RADEONPTR(scrn); 652de2362d3Smrg struct dri2_buffer_priv *priv = front->driverPrivate; 653de2362d3Smrg 65418781e08Smrg pixmap = get_drawable_pixmap(draw); 655de2362d3Smrg pixmap->refcnt++; 656de2362d3Smrg 65718781e08Smrg if (!info->use_glamor) 65818781e08Smrg exaMoveInPixmap(pixmap); 6598bf5c682Smrg if (!radeon_get_flink_name(pRADEONEnt, pixmap, &front->name)) { 660de2362d3Smrg (*draw->pScreen->DestroyPixmap)(pixmap); 661de2362d3Smrg return FALSE; 662de2362d3Smrg } 663de2362d3Smrg (*draw->pScreen->DestroyPixmap)(priv->pixmap); 664de2362d3Smrg front->pitch = pixmap->devKind; 665de2362d3Smrg front->cpp = pixmap->drawable.bitsPerPixel / 8; 666de2362d3Smrg priv->pixmap = pixmap; 667de2362d3Smrg 668de2362d3Smrg return TRUE; 669de2362d3Smrg} 670de2362d3Smrg 671de2362d3Smrgstatic Bool 672de2362d3Smrgcan_exchange(ScrnInfoPtr pScrn, DrawablePtr draw, 673de2362d3Smrg DRI2BufferPtr front, DRI2BufferPtr back) 674de2362d3Smrg{ 675de2362d3Smrg struct dri2_buffer_priv *front_priv = front->driverPrivate; 676de2362d3Smrg struct dri2_buffer_priv *back_priv = back->driverPrivate; 677de2362d3Smrg PixmapPtr front_pixmap; 678de2362d3Smrg PixmapPtr back_pixmap = back_priv->pixmap; 679de2362d3Smrg 680de2362d3Smrg if (!update_front(draw, front)) 681de2362d3Smrg return FALSE; 682de2362d3Smrg 683de2362d3Smrg front_pixmap = front_priv->pixmap; 684de2362d3Smrg 685de2362d3Smrg if (front_pixmap->drawable.width != back_pixmap->drawable.width) 686de2362d3Smrg return FALSE; 687de2362d3Smrg 688de2362d3Smrg if (front_pixmap->drawable.height != back_pixmap->drawable.height) 689de2362d3Smrg return FALSE; 690de2362d3Smrg 691de2362d3Smrg if (front_pixmap->drawable.bitsPerPixel != back_pixmap->drawable.bitsPerPixel) 692de2362d3Smrg return FALSE; 693de2362d3Smrg 694de2362d3Smrg if (front_pixmap->devKind != back_pixmap->devKind) 695de2362d3Smrg return FALSE; 696de2362d3Smrg 697de2362d3Smrg return TRUE; 698de2362d3Smrg} 699de2362d3Smrg 700de2362d3Smrgstatic Bool 7018bf5c682Smrgcan_flip(xf86CrtcPtr crtc, DrawablePtr draw, 702de2362d3Smrg DRI2BufferPtr front, DRI2BufferPtr back) 703de2362d3Smrg{ 7048bf5c682Smrg ScrnInfoPtr pScrn = crtc->scrn; 70518781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 7063ed65abbSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 7073ed65abbSmrg int num_crtcs_on; 7083ed65abbSmrg int i; 7093ed65abbSmrg 7103ed65abbSmrg if (draw->type != DRAWABLE_WINDOW || 7113ed65abbSmrg !info->allowPageFlip || 7128bf5c682Smrg info->sprites_visible > 0 || 7133ed65abbSmrg info->drmmode.present_flipping || 7143ed65abbSmrg !pScrn->vtSema || 7153ed65abbSmrg !DRI2CanFlip(draw)) 7163ed65abbSmrg return FALSE; 7173ed65abbSmrg 7183ed65abbSmrg for (i = 0, num_crtcs_on = 0; i < config->num_crtc; i++) { 7198bf5c682Smrg if (drmmode_crtc_can_flip(config->crtc[i])) 7203ed65abbSmrg num_crtcs_on++; 7213ed65abbSmrg } 72218781e08Smrg 7233ed65abbSmrg return num_crtcs_on > 0 && can_exchange(pScrn, draw, front, back); 724de2362d3Smrg} 725de2362d3Smrg 726de2362d3Smrgstatic void 727de2362d3Smrgradeon_dri2_exchange_buffers(DrawablePtr draw, DRI2BufferPtr front, DRI2BufferPtr back) 728de2362d3Smrg{ 729de2362d3Smrg struct dri2_buffer_priv *front_priv = front->driverPrivate; 730de2362d3Smrg struct dri2_buffer_priv *back_priv = back->driverPrivate; 7310a1d3ae0Smrg#ifdef USE_GLAMOR 7320a1d3ae0Smrg RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(draw->pScreen)); 7330a1d3ae0Smrg#endif 73418781e08Smrg RegionRec region; 735de2362d3Smrg int tmp; 736de2362d3Smrg 73718781e08Smrg region.extents.x1 = region.extents.y1 = 0; 73818781e08Smrg region.extents.x2 = front_priv->pixmap->drawable.width; 73918781e08Smrg region.extents.y2 = front_priv->pixmap->drawable.height; 74018781e08Smrg region.data = NULL; 74118781e08Smrg DamageRegionAppend(&front_priv->pixmap->drawable, ®ion); 74218781e08Smrg 743de2362d3Smrg /* Swap BO names so DRI works */ 744de2362d3Smrg tmp = front->name; 745de2362d3Smrg front->name = back->name; 746de2362d3Smrg back->name = tmp; 747de2362d3Smrg 74839413783Smrg /* Swap pixmap privates */ 74939413783Smrg#ifdef USE_GLAMOR 75039413783Smrg if (info->use_glamor) { 75139413783Smrg struct radeon_pixmap *front_pix, *back_pix; 75218781e08Smrg 75339413783Smrg front_pix = radeon_get_pixmap_private(front_priv->pixmap); 75439413783Smrg back_pix = radeon_get_pixmap_private(back_priv->pixmap); 75539413783Smrg radeon_set_pixmap_private(front_priv->pixmap, back_pix); 75639413783Smrg radeon_set_pixmap_private(back_priv->pixmap, front_pix); 75739413783Smrg 75839413783Smrg radeon_glamor_exchange_buffers(front_priv->pixmap, back_priv->pixmap); 75939413783Smrg } else 76039413783Smrg#endif 76139413783Smrg { 76239413783Smrg struct radeon_exa_pixmap_priv driver_priv = *(struct radeon_exa_pixmap_priv*) 76339413783Smrg exaGetPixmapDriverPrivate(front_priv->pixmap); 76439413783Smrg 76539413783Smrg *(struct radeon_exa_pixmap_priv*)exaGetPixmapDriverPrivate(front_priv->pixmap) = 76639413783Smrg *(struct radeon_exa_pixmap_priv*)exaGetPixmapDriverPrivate(back_priv->pixmap); 76739413783Smrg *(struct radeon_exa_pixmap_priv*)exaGetPixmapDriverPrivate(back_priv->pixmap) = 76839413783Smrg driver_priv; 76939413783Smrg } 77018781e08Smrg 77118781e08Smrg DamageRegionProcessPending(&front_priv->pixmap->drawable); 772de2362d3Smrg} 773de2362d3Smrg 77418781e08Smrgstatic void radeon_dri2_frame_event_abort(xf86CrtcPtr crtc, void *event_data) 775de2362d3Smrg{ 776de2362d3Smrg DRI2FrameEventPtr event = event_data; 77718781e08Smrg 77818781e08Smrg TimerCancel(event->timer); 77918781e08Smrg TimerFree(event->timer); 78018781e08Smrg radeon_dri2_unref_buffer(event->front); 78118781e08Smrg radeon_dri2_unref_buffer(event->back); 78218781e08Smrg free(event); 78318781e08Smrg} 78418781e08Smrg 78518781e08Smrgstatic void radeon_dri2_frame_event_handler(xf86CrtcPtr crtc, uint32_t seq, 78618781e08Smrg uint64_t usec, void *event_data) 78718781e08Smrg{ 78818781e08Smrg DRI2FrameEventPtr event = event_data; 78918781e08Smrg ScrnInfoPtr scrn = crtc->scrn; 790de2362d3Smrg DrawablePtr drawable; 791de2362d3Smrg int status; 792de2362d3Smrg int swap_type; 793de2362d3Smrg BoxRec box; 794de2362d3Smrg RegionRec region; 795de2362d3Smrg 796de2362d3Smrg status = dixLookupDrawable(&drawable, event->drawable_id, serverClient, 797de2362d3Smrg M_ANY, DixWriteAccess); 798de2362d3Smrg if (status != Success) 799de2362d3Smrg goto cleanup; 800de2362d3Smrg 80118781e08Smrg seq += radeon_get_msc_delta(drawable, crtc); 802de2362d3Smrg 803de2362d3Smrg switch (event->type) { 804de2362d3Smrg case DRI2_FLIP: 8058bf5c682Smrg if (can_flip(crtc, drawable, event->front, event->back) && 80618781e08Smrg radeon_dri2_schedule_flip(crtc, 807de2362d3Smrg event->client, 808de2362d3Smrg drawable, 809de2362d3Smrg event->front, 810de2362d3Smrg event->back, 811de2362d3Smrg event->event_complete, 812de2362d3Smrg event->event_data, 813de2362d3Smrg event->frame)) { 814de2362d3Smrg radeon_dri2_exchange_buffers(drawable, event->front, event->back); 815de2362d3Smrg break; 816de2362d3Smrg } 817de2362d3Smrg /* else fall through to exchange/blit */ 818de2362d3Smrg case DRI2_SWAP: 819de2362d3Smrg if (DRI2CanExchange(drawable) && 820de2362d3Smrg can_exchange(scrn, drawable, event->front, event->back)) { 821de2362d3Smrg radeon_dri2_exchange_buffers(drawable, event->front, event->back); 822de2362d3Smrg swap_type = DRI2_EXCHANGE_COMPLETE; 823de2362d3Smrg } else { 824de2362d3Smrg box.x1 = 0; 825de2362d3Smrg box.y1 = 0; 826de2362d3Smrg box.x2 = drawable->width; 827de2362d3Smrg box.y2 = drawable->height; 828de2362d3Smrg REGION_INIT(pScreen, ®ion, &box, 0); 8298bf5c682Smrg radeon_dri2_copy_region2(drawable->pScreen, drawable, ®ion, 8308bf5c682Smrg event->front, event->back); 831de2362d3Smrg swap_type = DRI2_BLIT_COMPLETE; 832de2362d3Smrg } 833de2362d3Smrg 83418781e08Smrg DRI2SwapComplete(event->client, drawable, seq, usec / 1000000, 83518781e08Smrg usec % 1000000, swap_type, event->event_complete, 83618781e08Smrg event->event_data); 837de2362d3Smrg 838de2362d3Smrg break; 839de2362d3Smrg case DRI2_WAITMSC: 84018781e08Smrg DRI2WaitMSCComplete(event->client, drawable, seq, usec / 1000000, 84118781e08Smrg usec % 1000000); 842de2362d3Smrg break; 843de2362d3Smrg default: 844de2362d3Smrg /* Unknown type */ 845de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 846de2362d3Smrg "%s: unknown vblank event received\n", __func__); 847de2362d3Smrg break; 848de2362d3Smrg } 849de2362d3Smrg 850de2362d3Smrgcleanup: 85118781e08Smrg radeon_dri2_frame_event_abort(crtc, event_data); 852de2362d3Smrg} 853de2362d3Smrg 854de2362d3Smrg/* 85518781e08Smrg * This function should be called on a disabled CRTC only (i.e., CRTC 85618781e08Smrg * in DPMS-off state). It will calculate the delay necessary to reach 85718781e08Smrg * target_msc from present time if the CRTC were running. 858de2362d3Smrg */ 85918781e08Smrgstatic 86018781e08SmrgCARD32 radeon_dri2_extrapolate_msc_delay(xf86CrtcPtr crtc, CARD64 *target_msc, 86118781e08Smrg CARD64 divisor, CARD64 remainder) 862de2362d3Smrg{ 86318781e08Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 86418781e08Smrg ScrnInfoPtr pScrn = crtc->scrn; 8658bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 86618781e08Smrg int nominal_frame_rate = drmmode_crtc->dpms_last_fps; 86718781e08Smrg CARD64 last_vblank_ust = drmmode_crtc->dpms_last_ust; 86818781e08Smrg uint32_t last_vblank_seq = drmmode_crtc->dpms_last_seq; 86918781e08Smrg CARD64 now, target_time, delta_t; 87018781e08Smrg int64_t d, delta_seq; 8717821949aSmrg int ret; 87218781e08Smrg CARD32 d_ms; 87318781e08Smrg 87418781e08Smrg if (!last_vblank_ust) { 87518781e08Smrg *target_msc = 0; 87618781e08Smrg return FALLBACK_SWAP_DELAY; 87718781e08Smrg } 8788bf5c682Smrg ret = drmmode_get_current_ust(pRADEONEnt->fd, &now); 87918781e08Smrg if (ret) { 88018781e08Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 88118781e08Smrg "%s cannot get current time\n", __func__); 88218781e08Smrg *target_msc = 0; 88318781e08Smrg return FALLBACK_SWAP_DELAY; 88418781e08Smrg } 88518781e08Smrg delta_seq = *target_msc - last_vblank_seq; 88618781e08Smrg delta_seq *= 1000000; 88718781e08Smrg target_time = last_vblank_ust; 88818781e08Smrg target_time += delta_seq / nominal_frame_rate; 88918781e08Smrg d = target_time - now; 89018781e08Smrg if (d < 0) { 89118781e08Smrg /* we missed the event, adjust target_msc, do the divisor magic */ 89218781e08Smrg CARD64 current_msc = last_vblank_seq; 89318781e08Smrg 89418781e08Smrg delta_t = now - last_vblank_ust; 89518781e08Smrg delta_seq = delta_t * nominal_frame_rate; 89618781e08Smrg current_msc += delta_seq / 1000000; 89718781e08Smrg current_msc &= 0xffffffff; 89818781e08Smrg if (divisor == 0) { 89918781e08Smrg *target_msc = current_msc; 90018781e08Smrg d = 0; 90118781e08Smrg } else { 90218781e08Smrg *target_msc = current_msc - (current_msc % divisor) + remainder; 90318781e08Smrg if ((current_msc % divisor) >= remainder) 90418781e08Smrg *target_msc += divisor; 90518781e08Smrg *target_msc &= 0xffffffff; 90618781e08Smrg delta_seq = *target_msc - last_vblank_seq; 90718781e08Smrg delta_seq *= 1000000; 90818781e08Smrg target_time = last_vblank_ust; 90918781e08Smrg target_time += delta_seq / nominal_frame_rate; 91018781e08Smrg d = target_time - now; 91118781e08Smrg } 91218781e08Smrg } 91318781e08Smrg /* 91418781e08Smrg * convert delay to milliseconds and add margin to prevent the client 91518781e08Smrg * from coming back early (due to timer granularity and rounding 91618781e08Smrg * errors) and getting the same MSC it just got 91718781e08Smrg */ 91818781e08Smrg d_ms = (CARD32)d / 1000; 91918781e08Smrg if ((CARD32)d - d_ms * 1000 > 0) 92018781e08Smrg d_ms += 2; 92118781e08Smrg else 92218781e08Smrg d_ms++; 92318781e08Smrg return d_ms; 92418781e08Smrg} 92518781e08Smrg 92618781e08Smrg/* 92718781e08Smrg * Get current interpolated frame count and frame count timestamp, based on 92818781e08Smrg * drawable's crtc. 92918781e08Smrg */ 93018781e08Smrgstatic int radeon_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc) 93118781e08Smrg{ 9320d2a5547Smrg xf86CrtcPtr crtc = radeon_dri2_drawable_crtc(draw); 933de2362d3Smrg 934de2362d3Smrg /* Drawable not displayed, make up a value */ 93539413783Smrg if (!crtc) { 936de2362d3Smrg *ust = 0; 937de2362d3Smrg *msc = 0; 938de2362d3Smrg return TRUE; 939de2362d3Smrg } 940de2362d3Smrg 94118781e08Smrg if (!radeon_dri2_get_crtc_msc(crtc, ust, msc)) 94218781e08Smrg return FALSE; 94318781e08Smrg 94418781e08Smrg if (draw && draw->type == DRAWABLE_WINDOW) 94518781e08Smrg *msc += get_dri2_window_priv((WindowPtr)draw)->vblank_delta; 94618781e08Smrg *msc &= 0xffffffff; 94718781e08Smrg return TRUE; 94818781e08Smrg} 94918781e08Smrg 95018781e08Smrgstatic 95118781e08SmrgCARD32 radeon_dri2_deferred_event(OsTimerPtr timer, CARD32 now, pointer data) 95218781e08Smrg{ 95318781e08Smrg DRI2FrameEventPtr event_info = (DRI2FrameEventPtr)data; 95418781e08Smrg xf86CrtcPtr crtc = event_info->crtc; 95518781e08Smrg ScrnInfoPtr scrn; 9568bf5c682Smrg RADEONEntPtr pRADEONEnt; 95718781e08Smrg CARD64 drm_now; 95818781e08Smrg int ret; 95918781e08Smrg CARD64 delta_t, delta_seq, frame; 96018781e08Smrg drmmode_crtc_private_ptr drmmode_crtc; 96118781e08Smrg 96218781e08Smrg /* 96318781e08Smrg * This is emulated event, so its time is current time, which we 96418781e08Smrg * have to get in DRM-compatible form (which is a bit messy given 96518781e08Smrg * the information that we have at this point). Can't use now argument 96618781e08Smrg * because DRM event time may come from monotonic clock, while 96718781e08Smrg * DIX timer facility uses real-time clock. 96818781e08Smrg */ 96918781e08Smrg if (!event_info->crtc) { 97018781e08Smrg ErrorF("%s no crtc\n", __func__); 97118781e08Smrg if (event_info->drm_queue_seq) 97218781e08Smrg radeon_drm_abort_entry(event_info->drm_queue_seq); 97318781e08Smrg else 97418781e08Smrg radeon_dri2_frame_event_abort(NULL, data); 97518781e08Smrg return 0; 976de2362d3Smrg } 977de2362d3Smrg 97818781e08Smrg scrn = crtc->scrn; 9798bf5c682Smrg pRADEONEnt = RADEONEntPriv(scrn); 98039413783Smrg drmmode_crtc = event_info->crtc->driver_private; 9818bf5c682Smrg ret = drmmode_get_current_ust(pRADEONEnt->fd, &drm_now); 98218781e08Smrg if (ret) { 98318781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 98418781e08Smrg "%s cannot get current time\n", __func__); 985446f62d6Smrg 986446f62d6Smrg if (event_info->drm_queue_seq) { 98739413783Smrg drmmode_crtc->drmmode->event_context. 98839413783Smrg vblank_handler(pRADEONEnt->fd, 0, 0, 0, 98939413783Smrg (void*)event_info->drm_queue_seq); 990446f62d6Smrg drmmode_crtc->wait_flip_nesting_level++; 991446f62d6Smrg radeon_drm_queue_handle_deferred(crtc); 992446f62d6Smrg 993446f62d6Smrg } else { 99418781e08Smrg radeon_dri2_frame_event_handler(crtc, 0, 0, data); 995446f62d6Smrg } 996446f62d6Smrg 99718781e08Smrg return 0; 99818781e08Smrg } 99918781e08Smrg /* 100018781e08Smrg * calculate the frame number from current time 100118781e08Smrg * that would come from CRTC if it were running 100218781e08Smrg */ 100318781e08Smrg delta_t = drm_now - (CARD64)drmmode_crtc->dpms_last_ust; 100418781e08Smrg delta_seq = delta_t * drmmode_crtc->dpms_last_fps; 100518781e08Smrg delta_seq /= 1000000; 100618781e08Smrg frame = (CARD64)drmmode_crtc->dpms_last_seq + delta_seq; 1007446f62d6Smrg 1008446f62d6Smrg if (event_info->drm_queue_seq) { 100939413783Smrg drmmode_crtc->drmmode->event_context. 101039413783Smrg vblank_handler(pRADEONEnt->fd, frame, drm_now / 1000000, 101139413783Smrg drm_now % 1000000, 101239413783Smrg (void*)event_info->drm_queue_seq); 1013446f62d6Smrg drmmode_crtc->wait_flip_nesting_level++; 1014446f62d6Smrg radeon_drm_queue_handle_deferred(crtc); 1015446f62d6Smrg } else { 101618781e08Smrg radeon_dri2_frame_event_handler(crtc, frame, drm_now, data); 1017446f62d6Smrg } 1018446f62d6Smrg 101918781e08Smrg return 0; 102018781e08Smrg} 10217821949aSmrg 102218781e08Smrgstatic 102318781e08Smrgvoid radeon_dri2_schedule_event(CARD32 delay, DRI2FrameEventPtr event_info) 102418781e08Smrg{ 102518781e08Smrg event_info->timer = TimerSet(NULL, 0, delay, radeon_dri2_deferred_event, 102618781e08Smrg event_info); 102718781e08Smrg if (delay == 0) { 102818781e08Smrg CARD32 now = GetTimeInMillis(); 102918781e08Smrg radeon_dri2_deferred_event(event_info->timer, now, event_info); 103018781e08Smrg } 1031de2362d3Smrg} 1032de2362d3Smrg 1033de2362d3Smrg/* 1034de2362d3Smrg * Request a DRM event when the requested conditions will be satisfied. 1035de2362d3Smrg * 1036de2362d3Smrg * We need to handle the event and ask the server to wake up the client when 1037de2362d3Smrg * we receive it. 1038de2362d3Smrg */ 1039de2362d3Smrgstatic int radeon_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, 1040de2362d3Smrg CARD64 target_msc, CARD64 divisor, 1041de2362d3Smrg CARD64 remainder) 1042de2362d3Smrg{ 1043de2362d3Smrg ScreenPtr screen = draw->pScreen; 1044de2362d3Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 1045de2362d3Smrg DRI2FrameEventPtr wait_info = NULL; 104618781e08Smrg uintptr_t drm_queue_seq = 0; 10470d2a5547Smrg xf86CrtcPtr crtc = radeon_dri2_drawable_crtc(draw); 104818781e08Smrg uint32_t msc_delta; 10498bf5c682Smrg uint32_t seq; 1050de2362d3Smrg CARD64 current_msc; 1051de2362d3Smrg 1052de2362d3Smrg /* Truncate to match kernel interfaces; means occasional overflow 1053de2362d3Smrg * misses, but that's generally not a big deal */ 1054de2362d3Smrg target_msc &= 0xffffffff; 1055de2362d3Smrg divisor &= 0xffffffff; 1056de2362d3Smrg remainder &= 0xffffffff; 1057de2362d3Smrg 1058de2362d3Smrg /* Drawable not visible, return immediately */ 105939413783Smrg if (!crtc) 1060de2362d3Smrg goto out_complete; 1061de2362d3Smrg 106218781e08Smrg msc_delta = radeon_get_msc_delta(draw, crtc); 106318781e08Smrg 1064de2362d3Smrg wait_info = calloc(1, sizeof(DRI2FrameEventRec)); 1065de2362d3Smrg if (!wait_info) 1066de2362d3Smrg goto out_complete; 1067de2362d3Smrg 1068de2362d3Smrg wait_info->drawable_id = draw->id; 1069de2362d3Smrg wait_info->client = client; 1070de2362d3Smrg wait_info->type = DRI2_WAITMSC; 107118781e08Smrg wait_info->crtc = crtc; 1072de2362d3Smrg 107318781e08Smrg /* 107418781e08Smrg * CRTC is in DPMS off state, calculate wait time from current time, 107518781e08Smrg * target_msc and last vblank time/sequence when CRTC was turned off 107618781e08Smrg */ 107718781e08Smrg if (!radeon_crtc_is_enabled(crtc)) { 107818781e08Smrg CARD32 delay; 107918781e08Smrg target_msc -= msc_delta; 108018781e08Smrg delay = radeon_dri2_extrapolate_msc_delay(crtc, &target_msc, 108118781e08Smrg divisor, remainder); 108218781e08Smrg radeon_dri2_schedule_event(delay, wait_info); 108318781e08Smrg DRI2BlockClient(client, draw); 108418781e08Smrg return TRUE; 1085de2362d3Smrg } 1086de2362d3Smrg 1087de2362d3Smrg /* Get current count */ 10888bf5c682Smrg if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, NULL, &seq)) { 1089de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1090de2362d3Smrg "get vblank counter failed: %s\n", strerror(errno)); 1091de2362d3Smrg goto out_complete; 1092de2362d3Smrg } 1093de2362d3Smrg 10948bf5c682Smrg current_msc = seq + msc_delta; 109518781e08Smrg current_msc &= 0xffffffff; 109618781e08Smrg 109718781e08Smrg drm_queue_seq = radeon_drm_queue_alloc(crtc, client, RADEON_DRM_QUEUE_ID_DEFAULT, 109818781e08Smrg wait_info, radeon_dri2_frame_event_handler, 1099446f62d6Smrg radeon_dri2_frame_event_abort, FALSE); 110018781e08Smrg if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) { 110118781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 110218781e08Smrg "Allocating DRM queue event entry failed.\n"); 110318781e08Smrg goto out_complete; 110418781e08Smrg } 110518781e08Smrg wait_info->drm_queue_seq = drm_queue_seq; 11060d16fef4Smrg 1107de2362d3Smrg /* 1108de2362d3Smrg * If divisor is zero, or current_msc is smaller than target_msc, 1109de2362d3Smrg * we just need to make sure target_msc passes before waking up the 1110de2362d3Smrg * client. 1111de2362d3Smrg */ 1112de2362d3Smrg if (divisor == 0 || current_msc < target_msc) { 1113de2362d3Smrg /* If target_msc already reached or passed, set it to 1114de2362d3Smrg * current_msc to ensure we return a reasonable value back 1115de2362d3Smrg * to the caller. This keeps the client from continually 1116de2362d3Smrg * sending us MSC targets from the past by forcibly updating 1117de2362d3Smrg * their count on this call. 1118de2362d3Smrg */ 1119de2362d3Smrg if (current_msc >= target_msc) 1120de2362d3Smrg target_msc = current_msc; 11218bf5c682Smrg if (!drmmode_wait_vblank(crtc, DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT, 11228bf5c682Smrg target_msc - msc_delta, drm_queue_seq, NULL, 11238bf5c682Smrg NULL)) { 1124de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1125de2362d3Smrg "get vblank counter failed: %s\n", strerror(errno)); 1126de2362d3Smrg goto out_complete; 1127de2362d3Smrg } 1128de2362d3Smrg 1129de2362d3Smrg DRI2BlockClient(client, draw); 1130de2362d3Smrg return TRUE; 1131de2362d3Smrg } 1132de2362d3Smrg 1133de2362d3Smrg /* 1134de2362d3Smrg * If we get here, target_msc has already passed or we don't have one, 1135de2362d3Smrg * so we queue an event that will satisfy the divisor/remainder equation. 1136de2362d3Smrg */ 11378bf5c682Smrg target_msc = current_msc - (current_msc % divisor) + remainder - msc_delta; 1138de2362d3Smrg 1139de2362d3Smrg /* 1140de2362d3Smrg * If calculated remainder is larger than requested remainder, 1141de2362d3Smrg * it means we've passed the last point where 1142de2362d3Smrg * seq % divisor == remainder, so we need to wait for the next time 1143de2362d3Smrg * that will happen. 1144de2362d3Smrg */ 1145de2362d3Smrg if ((current_msc % divisor) >= remainder) 11468bf5c682Smrg target_msc += divisor; 1147de2362d3Smrg 11488bf5c682Smrg if (!drmmode_wait_vblank(crtc, DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT, 11498bf5c682Smrg target_msc, drm_queue_seq, NULL, NULL)) { 1150de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1151de2362d3Smrg "get vblank counter failed: %s\n", strerror(errno)); 1152de2362d3Smrg goto out_complete; 1153de2362d3Smrg } 1154de2362d3Smrg 1155de2362d3Smrg DRI2BlockClient(client, draw); 1156de2362d3Smrg 1157de2362d3Smrg return TRUE; 1158de2362d3Smrg 1159de2362d3Smrgout_complete: 116018781e08Smrg if (wait_info) 116118781e08Smrg radeon_dri2_deferred_event(NULL, 0, wait_info); 11620d2a5547Smrg else 11630d2a5547Smrg DRI2WaitMSCComplete(client, draw, 0, 0, 0); 11640d2a5547Smrg 1165de2362d3Smrg return TRUE; 1166de2362d3Smrg} 1167de2362d3Smrg 1168de2362d3Smrg/* 1169de2362d3Smrg * ScheduleSwap is responsible for requesting a DRM vblank event for the 1170de2362d3Smrg * appropriate frame. 1171de2362d3Smrg * 1172de2362d3Smrg * In the case of a blit (e.g. for a windowed swap) or buffer exchange, 1173de2362d3Smrg * the vblank requested can simply be the last queued swap frame + the swap 1174de2362d3Smrg * interval for the drawable. 1175de2362d3Smrg * 1176de2362d3Smrg * In the case of a page flip, we request an event for the last queued swap 1177de2362d3Smrg * frame + swap interval - 1, since we'll need to queue the flip for the frame 1178de2362d3Smrg * immediately following the received event. 1179de2362d3Smrg * 1180de2362d3Smrg * The client will be blocked if it tries to perform further GL commands 1181de2362d3Smrg * after queueing a swap, though in the Intel case after queueing a flip, the 1182de2362d3Smrg * client is free to queue more commands; they'll block in the kernel if 1183de2362d3Smrg * they access buffers busy with the flip. 1184de2362d3Smrg * 1185de2362d3Smrg * When the swap is complete, the driver should call into the server so it 1186de2362d3Smrg * can send any swap complete events that have been requested. 1187de2362d3Smrg */ 1188de2362d3Smrgstatic int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, 1189de2362d3Smrg DRI2BufferPtr front, DRI2BufferPtr back, 1190de2362d3Smrg CARD64 *target_msc, CARD64 divisor, 1191de2362d3Smrg CARD64 remainder, DRI2SwapEventPtr func, 1192de2362d3Smrg void *data) 1193de2362d3Smrg{ 1194de2362d3Smrg ScreenPtr screen = draw->pScreen; 1195de2362d3Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 11960d2a5547Smrg xf86CrtcPtr crtc = radeon_dri2_drawable_crtc(draw); 119718781e08Smrg uint32_t msc_delta; 11988bf5c682Smrg drmVBlankSeqType type; 11998bf5c682Smrg uint32_t seq; 12008bf5c682Smrg int flip = 0; 1201de2362d3Smrg DRI2FrameEventPtr swap_info = NULL; 120218781e08Smrg uintptr_t drm_queue_seq; 12038bf5c682Smrg CARD64 current_msc, event_msc; 1204de2362d3Smrg BoxRec box; 1205de2362d3Smrg RegionRec region; 1206de2362d3Smrg 1207de2362d3Smrg /* Truncate to match kernel interfaces; means occasional overflow 1208de2362d3Smrg * misses, but that's generally not a big deal */ 1209de2362d3Smrg *target_msc &= 0xffffffff; 1210de2362d3Smrg divisor &= 0xffffffff; 1211de2362d3Smrg remainder &= 0xffffffff; 1212de2362d3Smrg 1213de2362d3Smrg /* radeon_dri2_frame_event_handler will get called some unknown time in the 1214de2362d3Smrg * future with these buffers. Take a reference to ensure that they won't 1215de2362d3Smrg * get destroyed before then. 1216de2362d3Smrg */ 1217de2362d3Smrg radeon_dri2_ref_buffer(front); 1218de2362d3Smrg radeon_dri2_ref_buffer(back); 1219de2362d3Smrg 122018781e08Smrg /* either off-screen or CRTC not usable... just complete the swap */ 122139413783Smrg if (!crtc) 1222de2362d3Smrg goto blit_fallback; 1223de2362d3Smrg 122418781e08Smrg msc_delta = radeon_get_msc_delta(draw, crtc); 122518781e08Smrg 1226de2362d3Smrg swap_info = calloc(1, sizeof(DRI2FrameEventRec)); 1227de2362d3Smrg if (!swap_info) 1228de2362d3Smrg goto blit_fallback; 1229de2362d3Smrg 123018781e08Smrg swap_info->type = DRI2_SWAP; 1231de2362d3Smrg swap_info->drawable_id = draw->id; 1232de2362d3Smrg swap_info->client = client; 1233de2362d3Smrg swap_info->event_complete = func; 1234de2362d3Smrg swap_info->event_data = data; 1235de2362d3Smrg swap_info->front = front; 1236de2362d3Smrg swap_info->back = back; 123718781e08Smrg swap_info->crtc = crtc; 123818781e08Smrg 123918781e08Smrg drm_queue_seq = radeon_drm_queue_alloc(crtc, client, RADEON_DRM_QUEUE_ID_DEFAULT, 124018781e08Smrg swap_info, radeon_dri2_frame_event_handler, 1241446f62d6Smrg radeon_dri2_frame_event_abort, FALSE); 124218781e08Smrg if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) { 1243de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 124418781e08Smrg "Allocating DRM queue entry failed.\n"); 1245de2362d3Smrg goto blit_fallback; 1246de2362d3Smrg } 124718781e08Smrg swap_info->drm_queue_seq = drm_queue_seq; 124818781e08Smrg 124918781e08Smrg /* 125018781e08Smrg * CRTC is in DPMS off state, fallback to blit, but calculate 125118781e08Smrg * wait time from current time, target_msc and last vblank 125218781e08Smrg * time/sequence when CRTC was turned off 125318781e08Smrg */ 125418781e08Smrg if (!radeon_crtc_is_enabled(crtc)) { 125518781e08Smrg CARD32 delay; 125618781e08Smrg *target_msc -= msc_delta; 125718781e08Smrg delay = radeon_dri2_extrapolate_msc_delay(crtc, target_msc, 125818781e08Smrg divisor, remainder); 125918781e08Smrg *target_msc += msc_delta; 126018781e08Smrg *target_msc &= 0xffffffff; 126118781e08Smrg radeon_dri2_schedule_event(delay, swap_info); 126218781e08Smrg return TRUE; 126318781e08Smrg } 1264de2362d3Smrg 1265de2362d3Smrg /* Get current count */ 12668bf5c682Smrg if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, NULL, &seq)) { 1267de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1268de2362d3Smrg "first get vblank counter failed: %s\n", 1269de2362d3Smrg strerror(errno)); 127018781e08Smrg goto blit_fallback; 1271de2362d3Smrg } 1272de2362d3Smrg 12738bf5c682Smrg current_msc = seq + msc_delta; 127418781e08Smrg current_msc &= 0xffffffff; 1275de2362d3Smrg 1276de2362d3Smrg /* Flips need to be submitted one frame before */ 12778bf5c682Smrg if (can_flip(crtc, draw, front, back)) { 127818781e08Smrg swap_info->type = DRI2_FLIP; 1279de2362d3Smrg flip = 1; 1280de2362d3Smrg } 1281de2362d3Smrg 128218781e08Smrg /* Correct target_msc by 'flip' if swap_info->type == DRI2_FLIP. 1283de2362d3Smrg * Do it early, so handling of different timing constraints 1284de2362d3Smrg * for divisor, remainder and msc vs. target_msc works. 1285de2362d3Smrg */ 1286de2362d3Smrg if (*target_msc > 0) 1287de2362d3Smrg *target_msc -= flip; 1288de2362d3Smrg 1289de2362d3Smrg /* 1290de2362d3Smrg * If divisor is zero, or current_msc is smaller than target_msc 1291de2362d3Smrg * we just need to make sure target_msc passes before initiating 1292de2362d3Smrg * the swap. 1293de2362d3Smrg */ 1294de2362d3Smrg if (divisor == 0 || current_msc < *target_msc) { 12958bf5c682Smrg type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; 1296de2362d3Smrg /* If non-pageflipping, but blitting/exchanging, we need to use 1297de2362d3Smrg * DRM_VBLANK_NEXTONMISS to avoid unreliable timestamping later 1298de2362d3Smrg * on. 1299de2362d3Smrg */ 1300de2362d3Smrg if (flip == 0) 13018bf5c682Smrg type |= DRM_VBLANK_NEXTONMISS; 1302de2362d3Smrg 1303de2362d3Smrg /* If target_msc already reached or passed, set it to 1304de2362d3Smrg * current_msc to ensure we return a reasonable value back 1305de2362d3Smrg * to the caller. This makes swap_interval logic more robust. 1306de2362d3Smrg */ 1307de2362d3Smrg if (current_msc >= *target_msc) 1308de2362d3Smrg *target_msc = current_msc; 1309de2362d3Smrg 13108bf5c682Smrg if (!drmmode_wait_vblank(crtc, type, *target_msc - msc_delta, 13118bf5c682Smrg drm_queue_seq, NULL, &seq)) { 1312de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1313de2362d3Smrg "divisor 0 get vblank counter failed: %s\n", 1314de2362d3Smrg strerror(errno)); 131518781e08Smrg goto blit_fallback; 1316de2362d3Smrg } 1317de2362d3Smrg 13188bf5c682Smrg *target_msc = seq + flip + msc_delta; 1319de2362d3Smrg swap_info->frame = *target_msc; 1320de2362d3Smrg 1321de2362d3Smrg return TRUE; 1322de2362d3Smrg } 1323de2362d3Smrg 1324de2362d3Smrg /* 1325de2362d3Smrg * If we get here, target_msc has already passed or we don't have one, 1326de2362d3Smrg * and we need to queue an event that will satisfy the divisor/remainder 1327de2362d3Smrg * equation. 1328de2362d3Smrg */ 13298bf5c682Smrg type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; 1330de2362d3Smrg if (flip == 0) 13318bf5c682Smrg type |= DRM_VBLANK_NEXTONMISS; 1332de2362d3Smrg 13338bf5c682Smrg event_msc = current_msc - (current_msc % divisor) + remainder - msc_delta; 1334de2362d3Smrg 1335de2362d3Smrg /* 1336de2362d3Smrg * If the calculated deadline vbl.request.sequence is smaller than 1337de2362d3Smrg * or equal to current_msc, it means we've passed the last point 1338de2362d3Smrg * when effective onset frame seq could satisfy 1339de2362d3Smrg * seq % divisor == remainder, so we need to wait for the next time 1340de2362d3Smrg * this will happen. 1341de2362d3Smrg 1342de2362d3Smrg * This comparison takes the 1 frame swap delay in pageflipping mode 1343de2362d3Smrg * into account, as well as a potential DRM_VBLANK_NEXTONMISS delay 1344de2362d3Smrg * if we are blitting/exchanging instead of flipping. 1345de2362d3Smrg */ 13468bf5c682Smrg if (event_msc <= current_msc) 13478bf5c682Smrg event_msc += divisor; 1348de2362d3Smrg 1349de2362d3Smrg /* Account for 1 frame extra pageflip delay if flip > 0 */ 13508bf5c682Smrg event_msc -= flip; 1351de2362d3Smrg 13528bf5c682Smrg if (!drmmode_wait_vblank(crtc, type, event_msc, drm_queue_seq, NULL, &seq)) { 1353de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1354de2362d3Smrg "final get vblank counter failed: %s\n", 1355de2362d3Smrg strerror(errno)); 135618781e08Smrg goto blit_fallback; 1357de2362d3Smrg } 1358de2362d3Smrg 1359de2362d3Smrg /* Adjust returned value for 1 fame pageflip offset of flip > 0 */ 13608bf5c682Smrg *target_msc = seq + flip + msc_delta; 136118781e08Smrg *target_msc &= 0xffffffff; 1362de2362d3Smrg swap_info->frame = *target_msc; 1363de2362d3Smrg 1364de2362d3Smrg return TRUE; 1365de2362d3Smrg 1366de2362d3Smrgblit_fallback: 136718781e08Smrg if (swap_info) { 136818781e08Smrg swap_info->type = DRI2_SWAP; 136918781e08Smrg radeon_dri2_schedule_event(FALLBACK_SWAP_DELAY, swap_info); 137018781e08Smrg } else { 137118781e08Smrg box.x1 = 0; 137218781e08Smrg box.y1 = 0; 137318781e08Smrg box.x2 = draw->width; 137418781e08Smrg box.y2 = draw->height; 137518781e08Smrg REGION_INIT(pScreen, ®ion, &box, 0); 1376de2362d3Smrg 13778bf5c682Smrg radeon_dri2_copy_region2(draw->pScreen, draw, ®ion, front, back); 1378de2362d3Smrg 137918781e08Smrg DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data); 1380de2362d3Smrg 138118781e08Smrg radeon_dri2_unref_buffer(front); 138218781e08Smrg radeon_dri2_unref_buffer(back); 138318781e08Smrg } 13847821949aSmrg 1385de2362d3Smrg *target_msc = 0; /* offscreen, so zero out target vblank count */ 1386de2362d3Smrg return TRUE; 1387de2362d3Smrg} 1388de2362d3Smrg 1389de2362d3Smrg 1390de2362d3SmrgBool 1391de2362d3Smrgradeon_dri2_screen_init(ScreenPtr pScreen) 1392de2362d3Smrg{ 1393de2362d3Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 13948bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 1395de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1396de2362d3Smrg DRI2InfoRec dri2_info = { 0 }; 1397de2362d3Smrg const char *driverNames[2]; 1398de2362d3Smrg Bool scheduling_works = TRUE; 1399de2362d3Smrg 140018781e08Smrg if (!info->dri2.available) 1401de2362d3Smrg return FALSE; 1402de2362d3Smrg 14038bf5c682Smrg info->dri2.device_name = drmGetDeviceNameFromFd(pRADEONEnt->fd); 1404de2362d3Smrg 140518781e08Smrg if ( (info->ChipFamily >= CHIP_FAMILY_TAHITI) ) { 140618781e08Smrg dri2_info.driverName = SI_DRIVER_NAME; 140718781e08Smrg } else if ( (info->ChipFamily >= CHIP_FAMILY_R600) ) { 1408de2362d3Smrg dri2_info.driverName = R600_DRIVER_NAME; 1409de2362d3Smrg } else if ( (info->ChipFamily >= CHIP_FAMILY_R300) ) { 1410de2362d3Smrg dri2_info.driverName = R300_DRIVER_NAME; 1411de2362d3Smrg } else if ( info->ChipFamily >= CHIP_FAMILY_R200 ) { 1412de2362d3Smrg dri2_info.driverName = R200_DRIVER_NAME; 1413de2362d3Smrg } else { 1414de2362d3Smrg dri2_info.driverName = RADEON_DRIVER_NAME; 1415de2362d3Smrg } 14168bf5c682Smrg dri2_info.fd = pRADEONEnt->fd; 1417de2362d3Smrg dri2_info.deviceName = info->dri2.device_name; 1418de2362d3Smrg 141918781e08Smrg if (info->dri2.pKernelDRMVersion->version_minor < 4) { 1420de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "You need a newer kernel for " 1421de2362d3Smrg "sync extension\n"); 1422de2362d3Smrg scheduling_works = FALSE; 1423de2362d3Smrg } 1424de2362d3Smrg 142518781e08Smrg if (scheduling_works && info->drmmode.count_crtcs > 2) { 1426de2362d3Smrg#ifdef DRM_CAP_VBLANK_HIGH_CRTC 1427de2362d3Smrg uint64_t cap_value; 1428de2362d3Smrg 14298bf5c682Smrg if (drmGetCap(pRADEONEnt->fd, DRM_CAP_VBLANK_HIGH_CRTC, &cap_value)) { 1430de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "You need a newer kernel " 1431de2362d3Smrg "for VBLANKs on CRTC > 1\n"); 1432de2362d3Smrg scheduling_works = FALSE; 1433de2362d3Smrg } else if (!cap_value) { 1434de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Your kernel does not " 1435de2362d3Smrg "handle VBLANKs on CRTC > 1\n"); 1436de2362d3Smrg scheduling_works = FALSE; 1437de2362d3Smrg } 1438de2362d3Smrg#else 1439de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "You need to rebuild against a " 1440de2362d3Smrg "newer libdrm to handle VBLANKs on CRTC > 1\n"); 1441de2362d3Smrg scheduling_works = FALSE; 1442de2362d3Smrg#endif 1443de2362d3Smrg } 1444de2362d3Smrg 1445de2362d3Smrg if (scheduling_works) { 1446de2362d3Smrg dri2_info.ScheduleSwap = radeon_dri2_schedule_swap; 1447de2362d3Smrg dri2_info.GetMSC = radeon_dri2_get_msc; 1448de2362d3Smrg dri2_info.ScheduleWaitMSC = radeon_dri2_schedule_wait_msc; 14498bf5c682Smrg dri2_info.numDrivers = ARRAY_SIZE(driverNames); 1450de2362d3Smrg dri2_info.driverNames = driverNames; 145118781e08Smrg driverNames[0] = dri2_info.driverName; 145218781e08Smrg 145318781e08Smrg if (info->ChipFamily >= CHIP_FAMILY_R300) 145418781e08Smrg driverNames[1] = driverNames[0]; 145518781e08Smrg else 145618781e08Smrg driverNames[1] = NULL; /* no VDPAU support */ 145718781e08Smrg 145818781e08Smrg if (DRI2InfoCnt == 0) { 145918781e08Smrg if (!dixRegisterPrivateKey(dri2_window_private_key, 146018781e08Smrg PRIVATE_WINDOW, 146118781e08Smrg sizeof(struct dri2_window_priv))) { 146218781e08Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 146318781e08Smrg "Failed to get DRI2 window private\n"); 1464de2362d3Smrg return FALSE; 1465de2362d3Smrg } 1466de2362d3Smrg 1467de2362d3Smrg AddCallback(&ClientStateCallback, radeon_dri2_client_state_changed, 0); 1468de2362d3Smrg } 1469de2362d3Smrg 147018781e08Smrg DRI2InfoCnt++; 1471de2362d3Smrg } 147218781e08Smrg 147318781e08Smrg dri2_info.version = 9; 147418781e08Smrg dri2_info.CreateBuffer2 = radeon_dri2_create_buffer2; 147518781e08Smrg dri2_info.DestroyBuffer2 = radeon_dri2_destroy_buffer2; 147618781e08Smrg dri2_info.CopyRegion2 = radeon_dri2_copy_region2; 1477de2362d3Smrg 1478de2362d3Smrg info->dri2.enabled = DRI2ScreenInit(pScreen, &dri2_info); 1479de2362d3Smrg return info->dri2.enabled; 1480de2362d3Smrg} 1481de2362d3Smrg 1482de2362d3Smrgvoid radeon_dri2_close_screen(ScreenPtr pScreen) 1483de2362d3Smrg{ 1484de2362d3Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1485de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1486de2362d3Smrg 148718781e08Smrg if (--DRI2InfoCnt == 0) 1488de2362d3Smrg DeleteCallback(&ClientStateCallback, radeon_dri2_client_state_changed, 0); 148918781e08Smrg 1490de2362d3Smrg DRI2CloseScreen(pScreen); 1491de2362d3Smrg drmFree(info->dri2.device_name); 1492de2362d3Smrg} 1493de2362d3Smrg 149418781e08Smrg#endif /* DRI2 */ 149518781e08Smrg 1496