radeon_dri2.c revision 8bf5c682
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{ 8218781e08Smrg struct radeon_bo *bo = radeon_get_pixmap_bo(pixmap); 8318781e08Smrg struct drm_gem_flink flink; 840d16fef4Smrg 8518781e08Smrg if (bo) 8618781e08Smrg return radeon_gem_get_kernel_name(bo, name) == 0; 8718781e08Smrg 8818781e08Smrg if (radeon_get_pixmap_handle(pixmap, &flink.handle)) { 898bf5c682Smrg if (drmIoctl(pRADEONEnt->fd, DRM_IOCTL_GEM_FLINK, &flink) != 0) 9018781e08Smrg return FALSE; 910d16fef4Smrg 9218781e08Smrg *name = flink.name; 9318781e08Smrg return TRUE; 940d16fef4Smrg } 9518781e08Smrg 9618781e08Smrg return FALSE; 970d16fef4Smrg} 9818781e08Smrg 99de2362d3Smrgstatic BufferPtr 10018781e08Smrgradeon_dri2_create_buffer2(ScreenPtr pScreen, 10118781e08Smrg DrawablePtr drawable, 10218781e08Smrg unsigned int attachment, 10318781e08Smrg unsigned int format) 104de2362d3Smrg{ 105de2362d3Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1068bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 107de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 108de2362d3Smrg BufferPtr buffers; 109de2362d3Smrg struct dri2_buffer_priv *privates; 11018781e08Smrg PixmapPtr pixmap; 111de2362d3Smrg int flags; 112de2362d3Smrg unsigned front_width; 113de2362d3Smrg uint32_t tiling = 0; 114de2362d3Smrg unsigned aligned_width = drawable->width; 11518781e08Smrg unsigned height = drawable->height; 11618781e08Smrg Bool is_glamor_pixmap = FALSE; 11718781e08Smrg int depth; 11818781e08Smrg int cpp; 11918781e08Smrg 12018781e08Smrg if (format) { 12118781e08Smrg depth = format; 12218781e08Smrg 12318781e08Smrg switch (depth) { 12418781e08Smrg case 15: 12518781e08Smrg cpp = 2; 12618781e08Smrg break; 12718781e08Smrg case 24: 1288bf5c682Smrg case 30: 12918781e08Smrg cpp = 4; 13018781e08Smrg break; 13118781e08Smrg default: 13218781e08Smrg cpp = depth / 8; 13318781e08Smrg } 13418781e08Smrg } else { 13518781e08Smrg depth = drawable->depth; 13618781e08Smrg cpp = drawable->bitsPerPixel / 8; 13718781e08Smrg } 138de2362d3Smrg 13918781e08Smrg front_width = pScreen->GetScreenPixmap(pScreen)->drawable.width; 140de2362d3Smrg 14118781e08Smrg pixmap = NULL; 142de2362d3Smrg 143de2362d3Smrg if (attachment == DRI2BufferFrontLeft) { 14418781e08Smrg uint32_t handle; 14518781e08Smrg 14618781e08Smrg pixmap = get_drawable_pixmap(drawable); 14718781e08Smrg if (pScreen != pixmap->drawable.pScreen) 14818781e08Smrg pixmap = NULL; 14918781e08Smrg else if (info->use_glamor && !radeon_get_pixmap_handle(pixmap, &handle)) { 15018781e08Smrg is_glamor_pixmap = TRUE; 15118781e08Smrg aligned_width = pixmap->drawable.width; 15218781e08Smrg height = pixmap->drawable.height; 15318781e08Smrg pixmap = NULL; 15418781e08Smrg } else 15518781e08Smrg pixmap->refcnt++; 15618781e08Smrg } 15718781e08Smrg 15818781e08Smrg if (!pixmap && (is_glamor_pixmap || attachment != DRI2BufferFrontLeft)) { 159de2362d3Smrg /* tile the back buffer */ 160de2362d3Smrg switch(attachment) { 161de2362d3Smrg case DRI2BufferDepth: 162de2362d3Smrg /* macro is the preferred setting, but the 2D detiling for software 163de2362d3Smrg * fallbacks in mesa still has issues on some configurations 164de2362d3Smrg */ 165de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 166de2362d3Smrg if (info->allowColorTiling2D) { 167de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO; 168de2362d3Smrg } else { 169de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MICRO; 170de2362d3Smrg } 171de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_CEDAR) 172de2362d3Smrg flags |= RADEON_CREATE_PIXMAP_SZBUFFER; 17318781e08Smrg } else if (cpp == 2 && info->ChipFamily >= CHIP_FAMILY_R300) 17418781e08Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO | RADEON_CREATE_PIXMAP_TILING_MICRO_SQUARE; 17518781e08Smrg else 176de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO | RADEON_CREATE_PIXMAP_TILING_MICRO; 177de2362d3Smrg if (IS_R200_3D || info->ChipFamily == CHIP_FAMILY_RV200 || info->ChipFamily == CHIP_FAMILY_RADEON) 178de2362d3Smrg flags |= RADEON_CREATE_PIXMAP_DEPTH; 179de2362d3Smrg break; 180de2362d3Smrg case DRI2BufferDepthStencil: 181de2362d3Smrg /* macro is the preferred setting, but the 2D detiling for software 182de2362d3Smrg * fallbacks in mesa still has issues on some configurations 183de2362d3Smrg */ 184de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 185de2362d3Smrg if (info->allowColorTiling2D) { 186de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO; 187de2362d3Smrg } else { 188de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MICRO; 189de2362d3Smrg } 190de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_CEDAR) 191de2362d3Smrg flags |= RADEON_CREATE_PIXMAP_SZBUFFER; 19218781e08Smrg } else if (cpp == 2 && info->ChipFamily >= CHIP_FAMILY_R300) 19318781e08Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO | RADEON_CREATE_PIXMAP_TILING_MICRO_SQUARE; 19418781e08Smrg else 195de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO | RADEON_CREATE_PIXMAP_TILING_MICRO; 196de2362d3Smrg if (IS_R200_3D || info->ChipFamily == CHIP_FAMILY_RV200 || info->ChipFamily == CHIP_FAMILY_RADEON) 197de2362d3Smrg flags |= RADEON_CREATE_PIXMAP_DEPTH; 198de2362d3Smrg 199de2362d3Smrg break; 200de2362d3Smrg case DRI2BufferBackLeft: 201de2362d3Smrg case DRI2BufferBackRight: 20218781e08Smrg case DRI2BufferFrontLeft: 20318781e08Smrg case DRI2BufferFrontRight: 204de2362d3Smrg case DRI2BufferFakeFrontLeft: 205de2362d3Smrg case DRI2BufferFakeFrontRight: 206de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 207de2362d3Smrg if (info->allowColorTiling2D) { 208de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO; 209de2362d3Smrg } else { 210de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MICRO; 211de2362d3Smrg } 212de2362d3Smrg } else 213de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO; 214de2362d3Smrg break; 215de2362d3Smrg default: 216de2362d3Smrg flags = 0; 217de2362d3Smrg } 218de2362d3Smrg 219de2362d3Smrg if (flags & RADEON_CREATE_PIXMAP_TILING_MICRO) 220de2362d3Smrg tiling |= RADEON_TILING_MICRO; 22118781e08Smrg if (flags & RADEON_CREATE_PIXMAP_TILING_MICRO_SQUARE) 22218781e08Smrg tiling |= RADEON_TILING_MICRO_SQUARE; 223de2362d3Smrg if (flags & RADEON_CREATE_PIXMAP_TILING_MACRO) 224de2362d3Smrg tiling |= RADEON_TILING_MACRO; 225de2362d3Smrg 22618781e08Smrg if (aligned_width == front_width) 22718781e08Smrg aligned_width = pScrn->virtualX; 228de2362d3Smrg 22918781e08Smrg pixmap = (*pScreen->CreatePixmap)(pScreen, 23018781e08Smrg aligned_width, 23118781e08Smrg height, 23218781e08Smrg depth, 23318781e08Smrg flags | RADEON_CREATE_PIXMAP_DRI2); 234de2362d3Smrg } 235de2362d3Smrg 236de2362d3Smrg buffers = calloc(1, sizeof *buffers); 237de2362d3Smrg if (buffers == NULL) 238de2362d3Smrg goto error; 239de2362d3Smrg 24018781e08Smrg if (pixmap) { 24118781e08Smrg if (!info->use_glamor) { 24218781e08Smrg info->exa_force_create = TRUE; 24318781e08Smrg exaMoveInPixmap(pixmap); 24418781e08Smrg info->exa_force_create = FALSE; 24518781e08Smrg if (exaGetPixmapDriverPrivate(pixmap) == NULL) { 24618781e08Smrg /* this happen if pixmap is non accelerable */ 24718781e08Smrg goto error; 24818781e08Smrg } 24918781e08Smrg } else if (is_glamor_pixmap) { 25018781e08Smrg pixmap = radeon_glamor_set_pixmap_bo(drawable, pixmap); 25118781e08Smrg pixmap->refcnt++; 25218781e08Smrg } 25318781e08Smrg 2548bf5c682Smrg if (!radeon_get_flink_name(pRADEONEnt, pixmap, &buffers->name)) 25518781e08Smrg goto error; 256de2362d3Smrg } 257de2362d3Smrg 258de2362d3Smrg privates = calloc(1, sizeof(struct dri2_buffer_priv)); 259de2362d3Smrg if (privates == NULL) 260de2362d3Smrg goto error; 261de2362d3Smrg 262de2362d3Smrg buffers->attachment = attachment; 26318781e08Smrg if (pixmap) { 26418781e08Smrg buffers->pitch = pixmap->devKind; 26518781e08Smrg buffers->cpp = cpp; 26618781e08Smrg } 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); 278de2362d3Smrg if (pixmap) 279de2362d3Smrg (*pScreen->DestroyPixmap)(pixmap); 280de2362d3Smrg return NULL; 281de2362d3Smrg} 282de2362d3Smrg 283de2362d3Smrgstatic void 28418781e08Smrgradeon_dri2_destroy_buffer2(ScreenPtr pScreen, 28518781e08Smrg DrawablePtr drawable, BufferPtr buffers) 286de2362d3Smrg{ 287de2362d3Smrg if(buffers) 288de2362d3Smrg { 289de2362d3Smrg struct dri2_buffer_priv *private = buffers->driverPrivate; 290de2362d3Smrg 291de2362d3Smrg /* Trying to free an already freed buffer is unlikely to end well */ 292de2362d3Smrg if (private->refcnt == 0) { 293de2362d3Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 294de2362d3Smrg 295de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 296de2362d3Smrg "Attempted to destroy previously destroyed buffer.\ 297de2362d3Smrg This is a programming error\n"); 298de2362d3Smrg return; 299de2362d3Smrg } 300de2362d3Smrg 301de2362d3Smrg private->refcnt--; 302de2362d3Smrg if (private->refcnt == 0) 303de2362d3Smrg { 30418781e08Smrg if (private->pixmap) 30518781e08Smrg (*pScreen->DestroyPixmap)(private->pixmap); 306de2362d3Smrg 307de2362d3Smrg free(buffers->driverPrivate); 308de2362d3Smrg free(buffers); 309de2362d3Smrg } 310de2362d3Smrg } 311de2362d3Smrg} 312de2362d3Smrg 31318781e08Smrg 31418781e08Smrgstatic inline PixmapPtr GetDrawablePixmap(DrawablePtr drawable) 31518781e08Smrg{ 31618781e08Smrg if (drawable->type == DRAWABLE_PIXMAP) 31718781e08Smrg return (PixmapPtr)drawable; 31818781e08Smrg else { 31918781e08Smrg struct _Window *pWin = (struct _Window *)drawable; 32018781e08Smrg return drawable->pScreen->GetWindowPixmap(pWin); 32118781e08Smrg } 32218781e08Smrg} 323de2362d3Smrgstatic void 32418781e08Smrgradeon_dri2_copy_region2(ScreenPtr pScreen, 32518781e08Smrg DrawablePtr drawable, 32618781e08Smrg RegionPtr region, 32718781e08Smrg BufferPtr dest_buffer, 32818781e08Smrg BufferPtr src_buffer) 329de2362d3Smrg{ 330de2362d3Smrg struct dri2_buffer_priv *src_private = src_buffer->driverPrivate; 331de2362d3Smrg struct dri2_buffer_priv *dst_private = dest_buffer->driverPrivate; 332de2362d3Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 333de2362d3Smrg DrawablePtr src_drawable; 334de2362d3Smrg DrawablePtr dst_drawable; 335de2362d3Smrg RegionPtr copy_clip; 336de2362d3Smrg GCPtr gc; 337de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 338de2362d3Smrg Bool vsync; 33918781e08Smrg Bool translate = FALSE; 34018781e08Smrg int off_x = 0, off_y = 0; 34118781e08Smrg PixmapPtr dst_ppix; 34218781e08Smrg 34318781e08Smrg dst_ppix = dst_private->pixmap; 34418781e08Smrg src_drawable = &src_private->pixmap->drawable; 34518781e08Smrg dst_drawable = &dst_private->pixmap->drawable; 346de2362d3Smrg 347de2362d3Smrg if (src_private->attachment == DRI2BufferFrontLeft) { 34818781e08Smrg if (drawable->pScreen != pScreen) { 34918781e08Smrg src_drawable = DRI2UpdatePrime(drawable, src_buffer); 35018781e08Smrg if (!src_drawable) 35118781e08Smrg return; 35218781e08Smrg } else 35318781e08Smrg src_drawable = drawable; 354de2362d3Smrg } 355de2362d3Smrg if (dst_private->attachment == DRI2BufferFrontLeft) { 35618781e08Smrg if (drawable->pScreen != pScreen) { 35718781e08Smrg dst_drawable = DRI2UpdatePrime(drawable, dest_buffer); 35818781e08Smrg if (!dst_drawable) 35918781e08Smrg return; 36018781e08Smrg dst_ppix = (PixmapPtr)dst_drawable; 36118781e08Smrg if (dst_drawable != drawable) 36218781e08Smrg translate = TRUE; 36318781e08Smrg } else 36418781e08Smrg dst_drawable = drawable; 36518781e08Smrg } 36618781e08Smrg 36718781e08Smrg if (translate && drawable->type == DRAWABLE_WINDOW) { 36818781e08Smrg PixmapPtr pPix = GetDrawablePixmap(drawable); 36918781e08Smrg 37018781e08Smrg off_x = drawable->x - pPix->screen_x; 37118781e08Smrg off_y = drawable->y - pPix->screen_y; 372de2362d3Smrg } 373de2362d3Smrg gc = GetScratchGC(dst_drawable->depth, pScreen); 374de2362d3Smrg copy_clip = REGION_CREATE(pScreen, NULL, 0); 375de2362d3Smrg REGION_COPY(pScreen, copy_clip, region); 37618781e08Smrg 37718781e08Smrg if (translate) { 37818781e08Smrg REGION_TRANSLATE(pScreen, copy_clip, off_x, off_y); 37918781e08Smrg } 38018781e08Smrg 381de2362d3Smrg (*gc->funcs->ChangeClip) (gc, CT_REGION, copy_clip, 0); 382de2362d3Smrg ValidateGC(dst_drawable, gc); 383de2362d3Smrg 384de2362d3Smrg /* If this is a full buffer swap or frontbuffer flush, throttle on the 385de2362d3Smrg * previous one 386de2362d3Smrg */ 387de2362d3Smrg if (dst_private->attachment == DRI2BufferFrontLeft) { 388de2362d3Smrg if (REGION_NUM_RECTS(region) == 1) { 389de2362d3Smrg BoxPtr extents = REGION_EXTENTS(pScreen, region); 390de2362d3Smrg 391de2362d3Smrg if (extents->x1 == 0 && extents->y1 == 0 && 392de2362d3Smrg extents->x2 == drawable->width && 393de2362d3Smrg extents->y2 == drawable->height) { 39418781e08Smrg struct radeon_bo *bo = radeon_get_pixmap_bo(dst_ppix); 395de2362d3Smrg 39618781e08Smrg if (bo) 39718781e08Smrg radeon_bo_wait(bo); 398de2362d3Smrg } 399de2362d3Smrg } 400de2362d3Smrg } 401de2362d3Smrg 402de2362d3Smrg vsync = info->accel_state->vsync; 403de2362d3Smrg 404de2362d3Smrg /* Driver option "SwapbuffersWait" defines if we vsync DRI2 copy-swaps. */ 405de2362d3Smrg info->accel_state->vsync = info->swapBuffersWait; 40618781e08Smrg info->accel_state->force = TRUE; 407de2362d3Smrg 408de2362d3Smrg (*gc->ops->CopyArea)(src_drawable, dst_drawable, gc, 40918781e08Smrg 0, 0, drawable->width, drawable->height, off_x, off_y); 410de2362d3Smrg 41118781e08Smrg info->accel_state->force = FALSE; 412de2362d3Smrg info->accel_state->vsync = vsync; 413de2362d3Smrg 414de2362d3Smrg FreeScratchGC(gc); 415de2362d3Smrg} 416de2362d3Smrg 417de2362d3Smrgenum DRI2FrameEventType { 418de2362d3Smrg DRI2_SWAP, 419de2362d3Smrg DRI2_FLIP, 420de2362d3Smrg DRI2_WAITMSC, 421de2362d3Smrg}; 422de2362d3Smrg 423de2362d3Smrgtypedef struct _DRI2FrameEvent { 424de2362d3Smrg XID drawable_id; 425de2362d3Smrg ClientPtr client; 426de2362d3Smrg enum DRI2FrameEventType type; 42718781e08Smrg unsigned frame; 42818781e08Smrg xf86CrtcPtr crtc; 42918781e08Smrg OsTimerPtr timer; 43018781e08Smrg uintptr_t drm_queue_seq; 431de2362d3Smrg 432de2362d3Smrg /* for swaps & flips only */ 433de2362d3Smrg DRI2SwapEventPtr event_complete; 434de2362d3Smrg void *event_data; 435de2362d3Smrg DRI2BufferPtr front; 436de2362d3Smrg DRI2BufferPtr back; 437de2362d3Smrg} DRI2FrameEventRec, *DRI2FrameEventPtr; 438de2362d3Smrg 43918781e08Smrgstatic int DRI2InfoCnt; 440de2362d3Smrg 441de2362d3Smrgstatic void 442de2362d3Smrgradeon_dri2_ref_buffer(BufferPtr buffer) 443de2362d3Smrg{ 444de2362d3Smrg struct dri2_buffer_priv *private = buffer->driverPrivate; 445de2362d3Smrg private->refcnt++; 446de2362d3Smrg} 447de2362d3Smrg 448de2362d3Smrgstatic void 449de2362d3Smrgradeon_dri2_unref_buffer(BufferPtr buffer) 450de2362d3Smrg{ 451de2362d3Smrg if (buffer) { 452de2362d3Smrg struct dri2_buffer_priv *private = buffer->driverPrivate; 4538bf5c682Smrg DrawablePtr draw = &private->pixmap->drawable; 4548bf5c682Smrg 4558bf5c682Smrg radeon_dri2_destroy_buffer2(draw->pScreen, draw, buffer); 456de2362d3Smrg } 457de2362d3Smrg} 458de2362d3Smrg 459de2362d3Smrgstatic void 460de2362d3Smrgradeon_dri2_client_state_changed(CallbackListPtr *ClientStateCallback, pointer data, pointer calldata) 461de2362d3Smrg{ 462de2362d3Smrg NewClientInfoRec *clientinfo = calldata; 463de2362d3Smrg ClientPtr pClient = clientinfo->client; 464de2362d3Smrg 465de2362d3Smrg switch (pClient->clientState) { 466de2362d3Smrg case ClientStateRetained: 467de2362d3Smrg case ClientStateGone: 46818781e08Smrg radeon_drm_abort_client(pClient); 469de2362d3Smrg break; 470de2362d3Smrg default: 471de2362d3Smrg break; 472de2362d3Smrg } 473de2362d3Smrg} 474de2362d3Smrg 47518781e08Smrg/* 47618781e08Smrg * Get current frame count delta for the specified drawable and CRTC 47718781e08Smrg */ 47818781e08Smrgstatic uint32_t radeon_get_msc_delta(DrawablePtr pDraw, xf86CrtcPtr crtc) 47918781e08Smrg{ 48018781e08Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 48118781e08Smrg 48218781e08Smrg if (pDraw && pDraw->type == DRAWABLE_WINDOW) 48318781e08Smrg return drmmode_crtc->interpolated_vblanks + 48418781e08Smrg get_dri2_window_priv((WindowPtr)pDraw)->vblank_delta; 48518781e08Smrg 48618781e08Smrg return drmmode_crtc->interpolated_vblanks; 48718781e08Smrg} 48818781e08Smrg 48918781e08Smrg/* 49018781e08Smrg * Get current frame count and timestamp of the specified CRTC 49118781e08Smrg */ 49218781e08Smrgstatic Bool radeon_dri2_get_crtc_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc) 49318781e08Smrg{ 49418781e08Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 49518781e08Smrg 49618781e08Smrg if (!radeon_crtc_is_enabled(crtc) || 49718781e08Smrg drmmode_crtc_get_ust_msc(crtc, ust, msc) != Success) { 49818781e08Smrg /* CRTC is not running, extrapolate MSC and timestamp */ 49918781e08Smrg ScrnInfoPtr scrn = crtc->scrn; 5008bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 50118781e08Smrg CARD64 now, delta_t, delta_seq; 50218781e08Smrg 50318781e08Smrg if (!drmmode_crtc->dpms_last_ust) 50418781e08Smrg return FALSE; 50518781e08Smrg 5068bf5c682Smrg if (drmmode_get_current_ust(pRADEONEnt->fd, &now) != 0) { 50718781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 50818781e08Smrg "%s cannot get current time\n", __func__); 50918781e08Smrg return FALSE; 51018781e08Smrg } 51118781e08Smrg 51218781e08Smrg delta_t = now - drmmode_crtc->dpms_last_ust; 51318781e08Smrg delta_seq = delta_t * drmmode_crtc->dpms_last_fps; 51418781e08Smrg delta_seq /= 1000000; 51518781e08Smrg *ust = drmmode_crtc->dpms_last_ust; 51618781e08Smrg delta_t = delta_seq * 1000000; 51718781e08Smrg delta_t /= drmmode_crtc->dpms_last_fps; 51818781e08Smrg *ust += delta_t; 51918781e08Smrg *msc = drmmode_crtc->dpms_last_seq; 52018781e08Smrg *msc += delta_seq; 52118781e08Smrg } 52218781e08Smrg 52318781e08Smrg *msc += drmmode_crtc->interpolated_vblanks; 52418781e08Smrg 52518781e08Smrg return TRUE; 52618781e08Smrg} 52718781e08Smrg 52818781e08Smrgstatic 52918781e08Smrgxf86CrtcPtr radeon_dri2_drawable_crtc(DrawablePtr pDraw, Bool consider_disabled) 530de2362d3Smrg{ 531de2362d3Smrg ScreenPtr pScreen = pDraw->pScreen; 532de2362d3Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 53318781e08Smrg xf86CrtcPtr crtc = radeon_pick_best_crtc(pScrn, consider_disabled, 53418781e08Smrg pDraw->x, pDraw->x + pDraw->width, 53518781e08Smrg pDraw->y, pDraw->y + pDraw->height); 53618781e08Smrg 53718781e08Smrg if (crtc && pDraw->type == DRAWABLE_WINDOW) { 53818781e08Smrg struct dri2_window_priv *priv = get_dri2_window_priv((WindowPtr)pDraw); 53918781e08Smrg 54018781e08Smrg if (priv->crtc && priv->crtc != crtc) { 54118781e08Smrg CARD64 ust, mscold, mscnew; 54218781e08Smrg 54318781e08Smrg if (radeon_dri2_get_crtc_msc(priv->crtc, &ust, &mscold) && 54418781e08Smrg radeon_dri2_get_crtc_msc(crtc, &ust, &mscnew)) 54518781e08Smrg priv->vblank_delta += mscold - mscnew; 54618781e08Smrg } 54718781e08Smrg 54818781e08Smrg priv->crtc = crtc; 54918781e08Smrg } 55018781e08Smrg 55118781e08Smrg return crtc; 55218781e08Smrg} 55318781e08Smrg 55418781e08Smrgstatic void 55518781e08Smrgradeon_dri2_flip_event_abort(xf86CrtcPtr crtc, void *event_data) 55618781e08Smrg{ 5573ed65abbSmrg if (crtc) 5583ed65abbSmrg RADEONPTR(crtc->scrn)->drmmode.dri2_flipping = FALSE; 55918781e08Smrg 56018781e08Smrg free(event_data); 56118781e08Smrg} 56218781e08Smrg 56318781e08Smrgstatic void 56418781e08Smrgradeon_dri2_flip_event_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, 56518781e08Smrg void *event_data) 56618781e08Smrg{ 56718781e08Smrg DRI2FrameEventPtr flip = event_data; 56818781e08Smrg ScrnInfoPtr scrn = crtc->scrn; 56918781e08Smrg unsigned tv_sec, tv_usec; 57018781e08Smrg DrawablePtr drawable; 57118781e08Smrg ScreenPtr screen; 57218781e08Smrg int status; 57318781e08Smrg PixmapPtr pixmap; 57418781e08Smrg 57518781e08Smrg status = dixLookupDrawable(&drawable, flip->drawable_id, serverClient, 57618781e08Smrg M_ANY, DixWriteAccess); 57718781e08Smrg if (status != Success) 57818781e08Smrg goto abort; 57918781e08Smrg 58018781e08Smrg frame += radeon_get_msc_delta(drawable, crtc); 5810d16fef4Smrg 58218781e08Smrg screen = scrn->pScreen; 58318781e08Smrg pixmap = screen->GetScreenPixmap(screen); 58418781e08Smrg xf86DrvMsgVerb(scrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 58518781e08Smrg "%s:%d fevent[%p] width %d pitch %d (/4 %d)\n", 58618781e08Smrg __func__, __LINE__, flip, pixmap->drawable.width, pixmap->devKind, pixmap->devKind/4); 58718781e08Smrg 58818781e08Smrg tv_sec = usec / 1000000; 58918781e08Smrg tv_usec = usec % 1000000; 59018781e08Smrg 59118781e08Smrg /* We assume our flips arrive in order, so we don't check the frame */ 59218781e08Smrg switch (flip->type) { 59318781e08Smrg case DRI2_SWAP: 59418781e08Smrg /* Check for too small vblank count of pageflip completion, taking wraparound 59518781e08Smrg * into account. This usually means some defective kms pageflip completion, 59618781e08Smrg * causing wrong (msc, ust) return values and possible visual corruption. 59718781e08Smrg */ 59818781e08Smrg if ((frame < flip->frame) && (flip->frame - frame < 5)) { 59918781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 60018781e08Smrg "%s: Pageflip completion event has impossible msc %u < target_msc %u\n", 60118781e08Smrg __func__, frame, flip->frame); 60218781e08Smrg /* All-Zero values signal failure of (msc, ust) timestamping to client. */ 60318781e08Smrg frame = tv_sec = tv_usec = 0; 60418781e08Smrg } 6050d16fef4Smrg 60618781e08Smrg DRI2SwapComplete(flip->client, drawable, frame, tv_sec, tv_usec, 60718781e08Smrg DRI2_FLIP_COMPLETE, flip->event_complete, 60818781e08Smrg flip->event_data); 60918781e08Smrg break; 61018781e08Smrg default: 61118781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, "%s: unknown vblank event received\n", __func__); 61218781e08Smrg /* Unknown type */ 61318781e08Smrg break; 6140d16fef4Smrg } 61518781e08Smrg 61618781e08Smrgabort: 61718781e08Smrg radeon_dri2_flip_event_abort(crtc, event_data); 618de2362d3Smrg} 619de2362d3Smrg 620de2362d3Smrgstatic Bool 62118781e08Smrgradeon_dri2_schedule_flip(xf86CrtcPtr crtc, ClientPtr client, 622de2362d3Smrg DrawablePtr draw, DRI2BufferPtr front, 623de2362d3Smrg DRI2BufferPtr back, DRI2SwapEventPtr func, 624de2362d3Smrg void *data, unsigned int target_msc) 625de2362d3Smrg{ 62618781e08Smrg ScrnInfoPtr scrn = crtc->scrn; 62718781e08Smrg RADEONInfoPtr info = RADEONPTR(scrn); 628de2362d3Smrg struct dri2_buffer_priv *back_priv; 629de2362d3Smrg DRI2FrameEventPtr flip_info; 630de2362d3Smrg 631de2362d3Smrg flip_info = calloc(1, sizeof(DRI2FrameEventRec)); 632de2362d3Smrg if (!flip_info) 633de2362d3Smrg return FALSE; 634de2362d3Smrg 635de2362d3Smrg flip_info->drawable_id = draw->id; 636de2362d3Smrg flip_info->client = client; 637de2362d3Smrg flip_info->type = DRI2_SWAP; 638de2362d3Smrg flip_info->event_complete = func; 639de2362d3Smrg flip_info->event_data = data; 640de2362d3Smrg flip_info->frame = target_msc; 64118781e08Smrg flip_info->crtc = crtc; 642de2362d3Smrg 643de2362d3Smrg xf86DrvMsgVerb(scrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 644de2362d3Smrg "%s:%d fevent[%p]\n", __func__, __LINE__, flip_info); 645de2362d3Smrg 646de2362d3Smrg /* Page flip the full screen buffer */ 647de2362d3Smrg back_priv = back->driverPrivate; 6488bf5c682Smrg if (radeon_do_pageflip(scrn, client, back_priv->pixmap, 6498bf5c682Smrg RADEON_DRM_QUEUE_ID_DEFAULT, flip_info, crtc, 65018781e08Smrg radeon_dri2_flip_event_handler, 6513ed65abbSmrg radeon_dri2_flip_event_abort, FLIP_VSYNC, 6523ed65abbSmrg target_msc - radeon_get_msc_delta(draw, crtc))) { 65318781e08Smrg info->drmmode.dri2_flipping = TRUE; 65418781e08Smrg return TRUE; 65518781e08Smrg } 6560d16fef4Smrg 65718781e08Smrg return FALSE; 658de2362d3Smrg} 659de2362d3Smrg 660de2362d3Smrgstatic Bool 661de2362d3Smrgupdate_front(DrawablePtr draw, DRI2BufferPtr front) 662de2362d3Smrg{ 663de2362d3Smrg PixmapPtr pixmap; 6648bf5c682Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen); 6658bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 6668bf5c682Smrg RADEONInfoPtr info = RADEONPTR(scrn); 667de2362d3Smrg struct dri2_buffer_priv *priv = front->driverPrivate; 668de2362d3Smrg 66918781e08Smrg pixmap = get_drawable_pixmap(draw); 670de2362d3Smrg pixmap->refcnt++; 671de2362d3Smrg 67218781e08Smrg if (!info->use_glamor) 67318781e08Smrg exaMoveInPixmap(pixmap); 6748bf5c682Smrg if (!radeon_get_flink_name(pRADEONEnt, pixmap, &front->name)) { 675de2362d3Smrg (*draw->pScreen->DestroyPixmap)(pixmap); 676de2362d3Smrg return FALSE; 677de2362d3Smrg } 678de2362d3Smrg (*draw->pScreen->DestroyPixmap)(priv->pixmap); 679de2362d3Smrg front->pitch = pixmap->devKind; 680de2362d3Smrg front->cpp = pixmap->drawable.bitsPerPixel / 8; 681de2362d3Smrg priv->pixmap = pixmap; 682de2362d3Smrg 683de2362d3Smrg return TRUE; 684de2362d3Smrg} 685de2362d3Smrg 686de2362d3Smrgstatic Bool 687de2362d3Smrgcan_exchange(ScrnInfoPtr pScrn, DrawablePtr draw, 688de2362d3Smrg DRI2BufferPtr front, DRI2BufferPtr back) 689de2362d3Smrg{ 690de2362d3Smrg struct dri2_buffer_priv *front_priv = front->driverPrivate; 691de2362d3Smrg struct dri2_buffer_priv *back_priv = back->driverPrivate; 692de2362d3Smrg PixmapPtr front_pixmap; 693de2362d3Smrg PixmapPtr back_pixmap = back_priv->pixmap; 694de2362d3Smrg 695de2362d3Smrg if (!update_front(draw, front)) 696de2362d3Smrg return FALSE; 697de2362d3Smrg 698de2362d3Smrg front_pixmap = front_priv->pixmap; 699de2362d3Smrg 700de2362d3Smrg if (front_pixmap->drawable.width != back_pixmap->drawable.width) 701de2362d3Smrg return FALSE; 702de2362d3Smrg 703de2362d3Smrg if (front_pixmap->drawable.height != back_pixmap->drawable.height) 704de2362d3Smrg return FALSE; 705de2362d3Smrg 706de2362d3Smrg if (front_pixmap->drawable.bitsPerPixel != back_pixmap->drawable.bitsPerPixel) 707de2362d3Smrg return FALSE; 708de2362d3Smrg 709de2362d3Smrg if (front_pixmap->devKind != back_pixmap->devKind) 710de2362d3Smrg return FALSE; 711de2362d3Smrg 712de2362d3Smrg return TRUE; 713de2362d3Smrg} 714de2362d3Smrg 715de2362d3Smrgstatic Bool 7168bf5c682Smrgcan_flip(xf86CrtcPtr crtc, DrawablePtr draw, 717de2362d3Smrg DRI2BufferPtr front, DRI2BufferPtr back) 718de2362d3Smrg{ 7198bf5c682Smrg ScrnInfoPtr pScrn = crtc->scrn; 72018781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 7213ed65abbSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 7223ed65abbSmrg int num_crtcs_on; 7233ed65abbSmrg int i; 7243ed65abbSmrg 7253ed65abbSmrg if (draw->type != DRAWABLE_WINDOW || 7263ed65abbSmrg !info->allowPageFlip || 7278bf5c682Smrg info->sprites_visible > 0 || 7283ed65abbSmrg info->drmmode.present_flipping || 7293ed65abbSmrg !pScrn->vtSema || 7303ed65abbSmrg !DRI2CanFlip(draw)) 7313ed65abbSmrg return FALSE; 7323ed65abbSmrg 7333ed65abbSmrg for (i = 0, num_crtcs_on = 0; i < config->num_crtc; i++) { 7348bf5c682Smrg if (drmmode_crtc_can_flip(config->crtc[i])) 7353ed65abbSmrg num_crtcs_on++; 7363ed65abbSmrg } 73718781e08Smrg 7383ed65abbSmrg return num_crtcs_on > 0 && can_exchange(pScrn, draw, front, back); 739de2362d3Smrg} 740de2362d3Smrg 741de2362d3Smrgstatic void 742de2362d3Smrgradeon_dri2_exchange_buffers(DrawablePtr draw, DRI2BufferPtr front, DRI2BufferPtr back) 743de2362d3Smrg{ 744de2362d3Smrg struct dri2_buffer_priv *front_priv = front->driverPrivate; 745de2362d3Smrg struct dri2_buffer_priv *back_priv = back->driverPrivate; 74618781e08Smrg struct radeon_bo *front_bo, *back_bo; 747de2362d3Smrg ScreenPtr screen; 748de2362d3Smrg RADEONInfoPtr info; 74918781e08Smrg RegionRec region; 750de2362d3Smrg int tmp; 751de2362d3Smrg 75218781e08Smrg region.extents.x1 = region.extents.y1 = 0; 75318781e08Smrg region.extents.x2 = front_priv->pixmap->drawable.width; 75418781e08Smrg region.extents.y2 = front_priv->pixmap->drawable.height; 75518781e08Smrg region.data = NULL; 75618781e08Smrg DamageRegionAppend(&front_priv->pixmap->drawable, ®ion); 75718781e08Smrg 758de2362d3Smrg /* Swap BO names so DRI works */ 759de2362d3Smrg tmp = front->name; 760de2362d3Smrg front->name = back->name; 761de2362d3Smrg back->name = tmp; 762de2362d3Smrg 763de2362d3Smrg /* Swap pixmap bos */ 76418781e08Smrg front_bo = radeon_get_pixmap_bo(front_priv->pixmap); 76518781e08Smrg back_bo = radeon_get_pixmap_bo(back_priv->pixmap); 76618781e08Smrg radeon_set_pixmap_bo(front_priv->pixmap, back_bo); 76718781e08Smrg radeon_set_pixmap_bo(back_priv->pixmap, front_bo); 768de2362d3Smrg 769de2362d3Smrg /* Do we need to update the Screen? */ 770de2362d3Smrg screen = draw->pScreen; 771de2362d3Smrg info = RADEONPTR(xf86ScreenToScrn(screen)); 77218781e08Smrg if (front_bo == info->front_bo) { 77318781e08Smrg radeon_bo_ref(back_bo); 774de2362d3Smrg radeon_bo_unref(info->front_bo); 77518781e08Smrg info->front_bo = back_bo; 77618781e08Smrg radeon_set_pixmap_bo(screen->GetScreenPixmap(screen), back_bo); 777de2362d3Smrg } 77818781e08Smrg 77918781e08Smrg radeon_glamor_exchange_buffers(front_priv->pixmap, back_priv->pixmap); 78018781e08Smrg 78118781e08Smrg DamageRegionProcessPending(&front_priv->pixmap->drawable); 782de2362d3Smrg} 783de2362d3Smrg 78418781e08Smrgstatic void radeon_dri2_frame_event_abort(xf86CrtcPtr crtc, void *event_data) 785de2362d3Smrg{ 786de2362d3Smrg DRI2FrameEventPtr event = event_data; 78718781e08Smrg 78818781e08Smrg TimerCancel(event->timer); 78918781e08Smrg TimerFree(event->timer); 79018781e08Smrg radeon_dri2_unref_buffer(event->front); 79118781e08Smrg radeon_dri2_unref_buffer(event->back); 79218781e08Smrg free(event); 79318781e08Smrg} 79418781e08Smrg 79518781e08Smrgstatic void radeon_dri2_frame_event_handler(xf86CrtcPtr crtc, uint32_t seq, 79618781e08Smrg uint64_t usec, void *event_data) 79718781e08Smrg{ 79818781e08Smrg DRI2FrameEventPtr event = event_data; 79918781e08Smrg ScrnInfoPtr scrn = crtc->scrn; 800de2362d3Smrg DrawablePtr drawable; 801de2362d3Smrg int status; 802de2362d3Smrg int swap_type; 803de2362d3Smrg BoxRec box; 804de2362d3Smrg RegionRec region; 805de2362d3Smrg 806de2362d3Smrg status = dixLookupDrawable(&drawable, event->drawable_id, serverClient, 807de2362d3Smrg M_ANY, DixWriteAccess); 808de2362d3Smrg if (status != Success) 809de2362d3Smrg goto cleanup; 810de2362d3Smrg 81118781e08Smrg seq += radeon_get_msc_delta(drawable, crtc); 812de2362d3Smrg 813de2362d3Smrg switch (event->type) { 814de2362d3Smrg case DRI2_FLIP: 8158bf5c682Smrg if (can_flip(crtc, drawable, event->front, event->back) && 81618781e08Smrg radeon_dri2_schedule_flip(crtc, 817de2362d3Smrg event->client, 818de2362d3Smrg drawable, 819de2362d3Smrg event->front, 820de2362d3Smrg event->back, 821de2362d3Smrg event->event_complete, 822de2362d3Smrg event->event_data, 823de2362d3Smrg event->frame)) { 824de2362d3Smrg radeon_dri2_exchange_buffers(drawable, event->front, event->back); 825de2362d3Smrg break; 826de2362d3Smrg } 827de2362d3Smrg /* else fall through to exchange/blit */ 828de2362d3Smrg case DRI2_SWAP: 829de2362d3Smrg if (DRI2CanExchange(drawable) && 830de2362d3Smrg can_exchange(scrn, drawable, event->front, event->back)) { 831de2362d3Smrg radeon_dri2_exchange_buffers(drawable, event->front, event->back); 832de2362d3Smrg swap_type = DRI2_EXCHANGE_COMPLETE; 833de2362d3Smrg } else { 834de2362d3Smrg box.x1 = 0; 835de2362d3Smrg box.y1 = 0; 836de2362d3Smrg box.x2 = drawable->width; 837de2362d3Smrg box.y2 = drawable->height; 838de2362d3Smrg REGION_INIT(pScreen, ®ion, &box, 0); 8398bf5c682Smrg radeon_dri2_copy_region2(drawable->pScreen, drawable, ®ion, 8408bf5c682Smrg event->front, event->back); 841de2362d3Smrg swap_type = DRI2_BLIT_COMPLETE; 842de2362d3Smrg } 843de2362d3Smrg 84418781e08Smrg DRI2SwapComplete(event->client, drawable, seq, usec / 1000000, 84518781e08Smrg usec % 1000000, swap_type, event->event_complete, 84618781e08Smrg event->event_data); 847de2362d3Smrg 848de2362d3Smrg break; 849de2362d3Smrg case DRI2_WAITMSC: 85018781e08Smrg DRI2WaitMSCComplete(event->client, drawable, seq, usec / 1000000, 85118781e08Smrg usec % 1000000); 852de2362d3Smrg break; 853de2362d3Smrg default: 854de2362d3Smrg /* Unknown type */ 855de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 856de2362d3Smrg "%s: unknown vblank event received\n", __func__); 857de2362d3Smrg break; 858de2362d3Smrg } 859de2362d3Smrg 860de2362d3Smrgcleanup: 86118781e08Smrg radeon_dri2_frame_event_abort(crtc, event_data); 862de2362d3Smrg} 863de2362d3Smrg 864de2362d3Smrg/* 86518781e08Smrg * This function should be called on a disabled CRTC only (i.e., CRTC 86618781e08Smrg * in DPMS-off state). It will calculate the delay necessary to reach 86718781e08Smrg * target_msc from present time if the CRTC were running. 868de2362d3Smrg */ 86918781e08Smrgstatic 87018781e08SmrgCARD32 radeon_dri2_extrapolate_msc_delay(xf86CrtcPtr crtc, CARD64 *target_msc, 87118781e08Smrg CARD64 divisor, CARD64 remainder) 872de2362d3Smrg{ 87318781e08Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 87418781e08Smrg ScrnInfoPtr pScrn = crtc->scrn; 8758bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 87618781e08Smrg int nominal_frame_rate = drmmode_crtc->dpms_last_fps; 87718781e08Smrg CARD64 last_vblank_ust = drmmode_crtc->dpms_last_ust; 87818781e08Smrg uint32_t last_vblank_seq = drmmode_crtc->dpms_last_seq; 87918781e08Smrg CARD64 now, target_time, delta_t; 88018781e08Smrg int64_t d, delta_seq; 8817821949aSmrg int ret; 88218781e08Smrg CARD32 d_ms; 88318781e08Smrg 88418781e08Smrg if (!last_vblank_ust) { 88518781e08Smrg *target_msc = 0; 88618781e08Smrg return FALLBACK_SWAP_DELAY; 88718781e08Smrg } 8888bf5c682Smrg ret = drmmode_get_current_ust(pRADEONEnt->fd, &now); 88918781e08Smrg if (ret) { 89018781e08Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 89118781e08Smrg "%s cannot get current time\n", __func__); 89218781e08Smrg *target_msc = 0; 89318781e08Smrg return FALLBACK_SWAP_DELAY; 89418781e08Smrg } 89518781e08Smrg delta_seq = *target_msc - last_vblank_seq; 89618781e08Smrg delta_seq *= 1000000; 89718781e08Smrg target_time = last_vblank_ust; 89818781e08Smrg target_time += delta_seq / nominal_frame_rate; 89918781e08Smrg d = target_time - now; 90018781e08Smrg if (d < 0) { 90118781e08Smrg /* we missed the event, adjust target_msc, do the divisor magic */ 90218781e08Smrg CARD64 current_msc = last_vblank_seq; 90318781e08Smrg 90418781e08Smrg delta_t = now - last_vblank_ust; 90518781e08Smrg delta_seq = delta_t * nominal_frame_rate; 90618781e08Smrg current_msc += delta_seq / 1000000; 90718781e08Smrg current_msc &= 0xffffffff; 90818781e08Smrg if (divisor == 0) { 90918781e08Smrg *target_msc = current_msc; 91018781e08Smrg d = 0; 91118781e08Smrg } else { 91218781e08Smrg *target_msc = current_msc - (current_msc % divisor) + remainder; 91318781e08Smrg if ((current_msc % divisor) >= remainder) 91418781e08Smrg *target_msc += divisor; 91518781e08Smrg *target_msc &= 0xffffffff; 91618781e08Smrg delta_seq = *target_msc - last_vblank_seq; 91718781e08Smrg delta_seq *= 1000000; 91818781e08Smrg target_time = last_vblank_ust; 91918781e08Smrg target_time += delta_seq / nominal_frame_rate; 92018781e08Smrg d = target_time - now; 92118781e08Smrg } 92218781e08Smrg } 92318781e08Smrg /* 92418781e08Smrg * convert delay to milliseconds and add margin to prevent the client 92518781e08Smrg * from coming back early (due to timer granularity and rounding 92618781e08Smrg * errors) and getting the same MSC it just got 92718781e08Smrg */ 92818781e08Smrg d_ms = (CARD32)d / 1000; 92918781e08Smrg if ((CARD32)d - d_ms * 1000 > 0) 93018781e08Smrg d_ms += 2; 93118781e08Smrg else 93218781e08Smrg d_ms++; 93318781e08Smrg return d_ms; 93418781e08Smrg} 93518781e08Smrg 93618781e08Smrg/* 93718781e08Smrg * Get current interpolated frame count and frame count timestamp, based on 93818781e08Smrg * drawable's crtc. 93918781e08Smrg */ 94018781e08Smrgstatic int radeon_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc) 94118781e08Smrg{ 94218781e08Smrg xf86CrtcPtr crtc = radeon_dri2_drawable_crtc(draw, TRUE); 943de2362d3Smrg 944de2362d3Smrg /* Drawable not displayed, make up a value */ 94518781e08Smrg if (crtc == NULL) { 946de2362d3Smrg *ust = 0; 947de2362d3Smrg *msc = 0; 948de2362d3Smrg return TRUE; 949de2362d3Smrg } 950de2362d3Smrg 95118781e08Smrg if (!radeon_dri2_get_crtc_msc(crtc, ust, msc)) 95218781e08Smrg return FALSE; 95318781e08Smrg 95418781e08Smrg if (draw && draw->type == DRAWABLE_WINDOW) 95518781e08Smrg *msc += get_dri2_window_priv((WindowPtr)draw)->vblank_delta; 95618781e08Smrg *msc &= 0xffffffff; 95718781e08Smrg return TRUE; 95818781e08Smrg} 95918781e08Smrg 96018781e08Smrgstatic 96118781e08SmrgCARD32 radeon_dri2_deferred_event(OsTimerPtr timer, CARD32 now, pointer data) 96218781e08Smrg{ 96318781e08Smrg DRI2FrameEventPtr event_info = (DRI2FrameEventPtr)data; 96418781e08Smrg xf86CrtcPtr crtc = event_info->crtc; 96518781e08Smrg ScrnInfoPtr scrn; 9668bf5c682Smrg RADEONEntPtr pRADEONEnt; 96718781e08Smrg CARD64 drm_now; 96818781e08Smrg int ret; 96918781e08Smrg CARD64 delta_t, delta_seq, frame; 97018781e08Smrg drmmode_crtc_private_ptr drmmode_crtc; 97118781e08Smrg 97218781e08Smrg /* 97318781e08Smrg * This is emulated event, so its time is current time, which we 97418781e08Smrg * have to get in DRM-compatible form (which is a bit messy given 97518781e08Smrg * the information that we have at this point). Can't use now argument 97618781e08Smrg * because DRM event time may come from monotonic clock, while 97718781e08Smrg * DIX timer facility uses real-time clock. 97818781e08Smrg */ 97918781e08Smrg if (!event_info->crtc) { 98018781e08Smrg ErrorF("%s no crtc\n", __func__); 98118781e08Smrg if (event_info->drm_queue_seq) 98218781e08Smrg radeon_drm_abort_entry(event_info->drm_queue_seq); 98318781e08Smrg else 98418781e08Smrg radeon_dri2_frame_event_abort(NULL, data); 98518781e08Smrg return 0; 986de2362d3Smrg } 987de2362d3Smrg 98818781e08Smrg scrn = crtc->scrn; 9898bf5c682Smrg pRADEONEnt = RADEONEntPriv(scrn); 9908bf5c682Smrg ret = drmmode_get_current_ust(pRADEONEnt->fd, &drm_now); 99118781e08Smrg if (ret) { 99218781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 99318781e08Smrg "%s cannot get current time\n", __func__); 99418781e08Smrg if (event_info->drm_queue_seq) 9958bf5c682Smrg radeon_drm_queue_handler(pRADEONEnt->fd, 0, 0, 0, 99618781e08Smrg (void*)event_info->drm_queue_seq); 99718781e08Smrg else 99818781e08Smrg radeon_dri2_frame_event_handler(crtc, 0, 0, data); 99918781e08Smrg return 0; 100018781e08Smrg } 100118781e08Smrg /* 100218781e08Smrg * calculate the frame number from current time 100318781e08Smrg * that would come from CRTC if it were running 100418781e08Smrg */ 100518781e08Smrg drmmode_crtc = event_info->crtc->driver_private; 100618781e08Smrg delta_t = drm_now - (CARD64)drmmode_crtc->dpms_last_ust; 100718781e08Smrg delta_seq = delta_t * drmmode_crtc->dpms_last_fps; 100818781e08Smrg delta_seq /= 1000000; 100918781e08Smrg frame = (CARD64)drmmode_crtc->dpms_last_seq + delta_seq; 101018781e08Smrg if (event_info->drm_queue_seq) 10118bf5c682Smrg radeon_drm_queue_handler(pRADEONEnt->fd, frame, drm_now / 1000000, 101218781e08Smrg drm_now % 1000000, 101318781e08Smrg (void*)event_info->drm_queue_seq); 101418781e08Smrg else 101518781e08Smrg radeon_dri2_frame_event_handler(crtc, frame, drm_now, data); 101618781e08Smrg return 0; 101718781e08Smrg} 10187821949aSmrg 101918781e08Smrgstatic 102018781e08Smrgvoid radeon_dri2_schedule_event(CARD32 delay, DRI2FrameEventPtr event_info) 102118781e08Smrg{ 102218781e08Smrg event_info->timer = TimerSet(NULL, 0, delay, radeon_dri2_deferred_event, 102318781e08Smrg event_info); 102418781e08Smrg if (delay == 0) { 102518781e08Smrg CARD32 now = GetTimeInMillis(); 102618781e08Smrg radeon_dri2_deferred_event(event_info->timer, now, event_info); 102718781e08Smrg } 1028de2362d3Smrg} 1029de2362d3Smrg 1030de2362d3Smrg/* 1031de2362d3Smrg * Request a DRM event when the requested conditions will be satisfied. 1032de2362d3Smrg * 1033de2362d3Smrg * We need to handle the event and ask the server to wake up the client when 1034de2362d3Smrg * we receive it. 1035de2362d3Smrg */ 1036de2362d3Smrgstatic int radeon_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, 1037de2362d3Smrg CARD64 target_msc, CARD64 divisor, 1038de2362d3Smrg CARD64 remainder) 1039de2362d3Smrg{ 1040de2362d3Smrg ScreenPtr screen = draw->pScreen; 1041de2362d3Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 1042de2362d3Smrg DRI2FrameEventPtr wait_info = NULL; 104318781e08Smrg uintptr_t drm_queue_seq = 0; 104418781e08Smrg xf86CrtcPtr crtc = radeon_dri2_drawable_crtc(draw, TRUE); 104518781e08Smrg uint32_t msc_delta; 10468bf5c682Smrg uint32_t seq; 1047de2362d3Smrg CARD64 current_msc; 1048de2362d3Smrg 1049de2362d3Smrg /* Truncate to match kernel interfaces; means occasional overflow 1050de2362d3Smrg * misses, but that's generally not a big deal */ 1051de2362d3Smrg target_msc &= 0xffffffff; 1052de2362d3Smrg divisor &= 0xffffffff; 1053de2362d3Smrg remainder &= 0xffffffff; 1054de2362d3Smrg 1055de2362d3Smrg /* Drawable not visible, return immediately */ 105618781e08Smrg if (crtc == NULL) 1057de2362d3Smrg goto out_complete; 1058de2362d3Smrg 105918781e08Smrg msc_delta = radeon_get_msc_delta(draw, crtc); 106018781e08Smrg 1061de2362d3Smrg wait_info = calloc(1, sizeof(DRI2FrameEventRec)); 1062de2362d3Smrg if (!wait_info) 1063de2362d3Smrg goto out_complete; 1064de2362d3Smrg 1065de2362d3Smrg wait_info->drawable_id = draw->id; 1066de2362d3Smrg wait_info->client = client; 1067de2362d3Smrg wait_info->type = DRI2_WAITMSC; 106818781e08Smrg wait_info->crtc = crtc; 1069de2362d3Smrg 107018781e08Smrg /* 107118781e08Smrg * CRTC is in DPMS off state, calculate wait time from current time, 107218781e08Smrg * target_msc and last vblank time/sequence when CRTC was turned off 107318781e08Smrg */ 107418781e08Smrg if (!radeon_crtc_is_enabled(crtc)) { 107518781e08Smrg CARD32 delay; 107618781e08Smrg target_msc -= msc_delta; 107718781e08Smrg delay = radeon_dri2_extrapolate_msc_delay(crtc, &target_msc, 107818781e08Smrg divisor, remainder); 107918781e08Smrg radeon_dri2_schedule_event(delay, wait_info); 108018781e08Smrg DRI2BlockClient(client, draw); 108118781e08Smrg return TRUE; 1082de2362d3Smrg } 1083de2362d3Smrg 1084de2362d3Smrg /* Get current count */ 10858bf5c682Smrg if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, NULL, &seq)) { 1086de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1087de2362d3Smrg "get vblank counter failed: %s\n", strerror(errno)); 1088de2362d3Smrg goto out_complete; 1089de2362d3Smrg } 1090de2362d3Smrg 10918bf5c682Smrg current_msc = seq + msc_delta; 109218781e08Smrg current_msc &= 0xffffffff; 109318781e08Smrg 109418781e08Smrg drm_queue_seq = radeon_drm_queue_alloc(crtc, client, RADEON_DRM_QUEUE_ID_DEFAULT, 109518781e08Smrg wait_info, radeon_dri2_frame_event_handler, 109618781e08Smrg radeon_dri2_frame_event_abort); 109718781e08Smrg if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) { 109818781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 109918781e08Smrg "Allocating DRM queue event entry failed.\n"); 110018781e08Smrg goto out_complete; 110118781e08Smrg } 110218781e08Smrg wait_info->drm_queue_seq = drm_queue_seq; 11030d16fef4Smrg 1104de2362d3Smrg /* 1105de2362d3Smrg * If divisor is zero, or current_msc is smaller than target_msc, 1106de2362d3Smrg * we just need to make sure target_msc passes before waking up the 1107de2362d3Smrg * client. 1108de2362d3Smrg */ 1109de2362d3Smrg if (divisor == 0 || current_msc < target_msc) { 1110de2362d3Smrg /* If target_msc already reached or passed, set it to 1111de2362d3Smrg * current_msc to ensure we return a reasonable value back 1112de2362d3Smrg * to the caller. This keeps the client from continually 1113de2362d3Smrg * sending us MSC targets from the past by forcibly updating 1114de2362d3Smrg * their count on this call. 1115de2362d3Smrg */ 1116de2362d3Smrg if (current_msc >= target_msc) 1117de2362d3Smrg target_msc = current_msc; 11188bf5c682Smrg if (!drmmode_wait_vblank(crtc, DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT, 11198bf5c682Smrg target_msc - msc_delta, drm_queue_seq, NULL, 11208bf5c682Smrg NULL)) { 1121de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1122de2362d3Smrg "get vblank counter failed: %s\n", strerror(errno)); 1123de2362d3Smrg goto out_complete; 1124de2362d3Smrg } 1125de2362d3Smrg 1126de2362d3Smrg DRI2BlockClient(client, draw); 1127de2362d3Smrg return TRUE; 1128de2362d3Smrg } 1129de2362d3Smrg 1130de2362d3Smrg /* 1131de2362d3Smrg * If we get here, target_msc has already passed or we don't have one, 1132de2362d3Smrg * so we queue an event that will satisfy the divisor/remainder equation. 1133de2362d3Smrg */ 11348bf5c682Smrg target_msc = current_msc - (current_msc % divisor) + remainder - msc_delta; 1135de2362d3Smrg 1136de2362d3Smrg /* 1137de2362d3Smrg * If calculated remainder is larger than requested remainder, 1138de2362d3Smrg * it means we've passed the last point where 1139de2362d3Smrg * seq % divisor == remainder, so we need to wait for the next time 1140de2362d3Smrg * that will happen. 1141de2362d3Smrg */ 1142de2362d3Smrg if ((current_msc % divisor) >= remainder) 11438bf5c682Smrg target_msc += divisor; 1144de2362d3Smrg 11458bf5c682Smrg if (!drmmode_wait_vblank(crtc, DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT, 11468bf5c682Smrg target_msc, drm_queue_seq, NULL, NULL)) { 1147de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1148de2362d3Smrg "get vblank counter failed: %s\n", strerror(errno)); 1149de2362d3Smrg goto out_complete; 1150de2362d3Smrg } 1151de2362d3Smrg 1152de2362d3Smrg DRI2BlockClient(client, draw); 1153de2362d3Smrg 1154de2362d3Smrg return TRUE; 1155de2362d3Smrg 1156de2362d3Smrgout_complete: 115718781e08Smrg if (wait_info) 115818781e08Smrg radeon_dri2_deferred_event(NULL, 0, wait_info); 1159de2362d3Smrg return TRUE; 1160de2362d3Smrg} 1161de2362d3Smrg 1162de2362d3Smrg/* 1163de2362d3Smrg * ScheduleSwap is responsible for requesting a DRM vblank event for the 1164de2362d3Smrg * appropriate frame. 1165de2362d3Smrg * 1166de2362d3Smrg * In the case of a blit (e.g. for a windowed swap) or buffer exchange, 1167de2362d3Smrg * the vblank requested can simply be the last queued swap frame + the swap 1168de2362d3Smrg * interval for the drawable. 1169de2362d3Smrg * 1170de2362d3Smrg * In the case of a page flip, we request an event for the last queued swap 1171de2362d3Smrg * frame + swap interval - 1, since we'll need to queue the flip for the frame 1172de2362d3Smrg * immediately following the received event. 1173de2362d3Smrg * 1174de2362d3Smrg * The client will be blocked if it tries to perform further GL commands 1175de2362d3Smrg * after queueing a swap, though in the Intel case after queueing a flip, the 1176de2362d3Smrg * client is free to queue more commands; they'll block in the kernel if 1177de2362d3Smrg * they access buffers busy with the flip. 1178de2362d3Smrg * 1179de2362d3Smrg * When the swap is complete, the driver should call into the server so it 1180de2362d3Smrg * can send any swap complete events that have been requested. 1181de2362d3Smrg */ 1182de2362d3Smrgstatic int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, 1183de2362d3Smrg DRI2BufferPtr front, DRI2BufferPtr back, 1184de2362d3Smrg CARD64 *target_msc, CARD64 divisor, 1185de2362d3Smrg CARD64 remainder, DRI2SwapEventPtr func, 1186de2362d3Smrg void *data) 1187de2362d3Smrg{ 1188de2362d3Smrg ScreenPtr screen = draw->pScreen; 1189de2362d3Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 119018781e08Smrg xf86CrtcPtr crtc = radeon_dri2_drawable_crtc(draw, TRUE); 119118781e08Smrg uint32_t msc_delta; 11928bf5c682Smrg drmVBlankSeqType type; 11938bf5c682Smrg uint32_t seq; 11948bf5c682Smrg int flip = 0; 1195de2362d3Smrg DRI2FrameEventPtr swap_info = NULL; 119618781e08Smrg uintptr_t drm_queue_seq; 11978bf5c682Smrg CARD64 current_msc, event_msc; 1198de2362d3Smrg BoxRec box; 1199de2362d3Smrg RegionRec region; 1200de2362d3Smrg 1201de2362d3Smrg /* Truncate to match kernel interfaces; means occasional overflow 1202de2362d3Smrg * misses, but that's generally not a big deal */ 1203de2362d3Smrg *target_msc &= 0xffffffff; 1204de2362d3Smrg divisor &= 0xffffffff; 1205de2362d3Smrg remainder &= 0xffffffff; 1206de2362d3Smrg 1207de2362d3Smrg /* radeon_dri2_frame_event_handler will get called some unknown time in the 1208de2362d3Smrg * future with these buffers. Take a reference to ensure that they won't 1209de2362d3Smrg * get destroyed before then. 1210de2362d3Smrg */ 1211de2362d3Smrg radeon_dri2_ref_buffer(front); 1212de2362d3Smrg radeon_dri2_ref_buffer(back); 1213de2362d3Smrg 121418781e08Smrg /* either off-screen or CRTC not usable... just complete the swap */ 121518781e08Smrg if (crtc == NULL) 1216de2362d3Smrg goto blit_fallback; 1217de2362d3Smrg 121818781e08Smrg msc_delta = radeon_get_msc_delta(draw, crtc); 121918781e08Smrg 1220de2362d3Smrg swap_info = calloc(1, sizeof(DRI2FrameEventRec)); 1221de2362d3Smrg if (!swap_info) 1222de2362d3Smrg goto blit_fallback; 1223de2362d3Smrg 122418781e08Smrg swap_info->type = DRI2_SWAP; 1225de2362d3Smrg swap_info->drawable_id = draw->id; 1226de2362d3Smrg swap_info->client = client; 1227de2362d3Smrg swap_info->event_complete = func; 1228de2362d3Smrg swap_info->event_data = data; 1229de2362d3Smrg swap_info->front = front; 1230de2362d3Smrg swap_info->back = back; 123118781e08Smrg swap_info->crtc = crtc; 123218781e08Smrg 123318781e08Smrg drm_queue_seq = radeon_drm_queue_alloc(crtc, client, RADEON_DRM_QUEUE_ID_DEFAULT, 123418781e08Smrg swap_info, radeon_dri2_frame_event_handler, 123518781e08Smrg radeon_dri2_frame_event_abort); 123618781e08Smrg if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) { 1237de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 123818781e08Smrg "Allocating DRM queue entry failed.\n"); 1239de2362d3Smrg goto blit_fallback; 1240de2362d3Smrg } 124118781e08Smrg swap_info->drm_queue_seq = drm_queue_seq; 124218781e08Smrg 124318781e08Smrg /* 124418781e08Smrg * CRTC is in DPMS off state, fallback to blit, but calculate 124518781e08Smrg * wait time from current time, target_msc and last vblank 124618781e08Smrg * time/sequence when CRTC was turned off 124718781e08Smrg */ 124818781e08Smrg if (!radeon_crtc_is_enabled(crtc)) { 124918781e08Smrg CARD32 delay; 125018781e08Smrg *target_msc -= msc_delta; 125118781e08Smrg delay = radeon_dri2_extrapolate_msc_delay(crtc, target_msc, 125218781e08Smrg divisor, remainder); 125318781e08Smrg *target_msc += msc_delta; 125418781e08Smrg *target_msc &= 0xffffffff; 125518781e08Smrg radeon_dri2_schedule_event(delay, swap_info); 125618781e08Smrg return TRUE; 125718781e08Smrg } 1258de2362d3Smrg 1259de2362d3Smrg /* Get current count */ 12608bf5c682Smrg if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, NULL, &seq)) { 1261de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1262de2362d3Smrg "first get vblank counter failed: %s\n", 1263de2362d3Smrg strerror(errno)); 126418781e08Smrg goto blit_fallback; 1265de2362d3Smrg } 1266de2362d3Smrg 12678bf5c682Smrg current_msc = seq + msc_delta; 126818781e08Smrg current_msc &= 0xffffffff; 1269de2362d3Smrg 1270de2362d3Smrg /* Flips need to be submitted one frame before */ 12718bf5c682Smrg if (can_flip(crtc, draw, front, back)) { 127218781e08Smrg swap_info->type = DRI2_FLIP; 1273de2362d3Smrg flip = 1; 1274de2362d3Smrg } 1275de2362d3Smrg 127618781e08Smrg /* Correct target_msc by 'flip' if swap_info->type == DRI2_FLIP. 1277de2362d3Smrg * Do it early, so handling of different timing constraints 1278de2362d3Smrg * for divisor, remainder and msc vs. target_msc works. 1279de2362d3Smrg */ 1280de2362d3Smrg if (*target_msc > 0) 1281de2362d3Smrg *target_msc -= flip; 1282de2362d3Smrg 1283de2362d3Smrg /* 1284de2362d3Smrg * If divisor is zero, or current_msc is smaller than target_msc 1285de2362d3Smrg * we just need to make sure target_msc passes before initiating 1286de2362d3Smrg * the swap. 1287de2362d3Smrg */ 1288de2362d3Smrg if (divisor == 0 || current_msc < *target_msc) { 12898bf5c682Smrg type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; 1290de2362d3Smrg /* If non-pageflipping, but blitting/exchanging, we need to use 1291de2362d3Smrg * DRM_VBLANK_NEXTONMISS to avoid unreliable timestamping later 1292de2362d3Smrg * on. 1293de2362d3Smrg */ 1294de2362d3Smrg if (flip == 0) 12958bf5c682Smrg type |= DRM_VBLANK_NEXTONMISS; 1296de2362d3Smrg 1297de2362d3Smrg /* If target_msc already reached or passed, set it to 1298de2362d3Smrg * current_msc to ensure we return a reasonable value back 1299de2362d3Smrg * to the caller. This makes swap_interval logic more robust. 1300de2362d3Smrg */ 1301de2362d3Smrg if (current_msc >= *target_msc) 1302de2362d3Smrg *target_msc = current_msc; 1303de2362d3Smrg 13048bf5c682Smrg if (!drmmode_wait_vblank(crtc, type, *target_msc - msc_delta, 13058bf5c682Smrg drm_queue_seq, NULL, &seq)) { 1306de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1307de2362d3Smrg "divisor 0 get vblank counter failed: %s\n", 1308de2362d3Smrg strerror(errno)); 130918781e08Smrg goto blit_fallback; 1310de2362d3Smrg } 1311de2362d3Smrg 13128bf5c682Smrg *target_msc = seq + flip + msc_delta; 1313de2362d3Smrg swap_info->frame = *target_msc; 1314de2362d3Smrg 1315de2362d3Smrg return TRUE; 1316de2362d3Smrg } 1317de2362d3Smrg 1318de2362d3Smrg /* 1319de2362d3Smrg * If we get here, target_msc has already passed or we don't have one, 1320de2362d3Smrg * and we need to queue an event that will satisfy the divisor/remainder 1321de2362d3Smrg * equation. 1322de2362d3Smrg */ 13238bf5c682Smrg type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; 1324de2362d3Smrg if (flip == 0) 13258bf5c682Smrg type |= DRM_VBLANK_NEXTONMISS; 1326de2362d3Smrg 13278bf5c682Smrg event_msc = current_msc - (current_msc % divisor) + remainder - msc_delta; 1328de2362d3Smrg 1329de2362d3Smrg /* 1330de2362d3Smrg * If the calculated deadline vbl.request.sequence is smaller than 1331de2362d3Smrg * or equal to current_msc, it means we've passed the last point 1332de2362d3Smrg * when effective onset frame seq could satisfy 1333de2362d3Smrg * seq % divisor == remainder, so we need to wait for the next time 1334de2362d3Smrg * this will happen. 1335de2362d3Smrg 1336de2362d3Smrg * This comparison takes the 1 frame swap delay in pageflipping mode 1337de2362d3Smrg * into account, as well as a potential DRM_VBLANK_NEXTONMISS delay 1338de2362d3Smrg * if we are blitting/exchanging instead of flipping. 1339de2362d3Smrg */ 13408bf5c682Smrg if (event_msc <= current_msc) 13418bf5c682Smrg event_msc += divisor; 1342de2362d3Smrg 1343de2362d3Smrg /* Account for 1 frame extra pageflip delay if flip > 0 */ 13448bf5c682Smrg event_msc -= flip; 1345de2362d3Smrg 13468bf5c682Smrg if (!drmmode_wait_vblank(crtc, type, event_msc, drm_queue_seq, NULL, &seq)) { 1347de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1348de2362d3Smrg "final get vblank counter failed: %s\n", 1349de2362d3Smrg strerror(errno)); 135018781e08Smrg goto blit_fallback; 1351de2362d3Smrg } 1352de2362d3Smrg 1353de2362d3Smrg /* Adjust returned value for 1 fame pageflip offset of flip > 0 */ 13548bf5c682Smrg *target_msc = seq + flip + msc_delta; 135518781e08Smrg *target_msc &= 0xffffffff; 1356de2362d3Smrg swap_info->frame = *target_msc; 1357de2362d3Smrg 1358de2362d3Smrg return TRUE; 1359de2362d3Smrg 1360de2362d3Smrgblit_fallback: 136118781e08Smrg if (swap_info) { 136218781e08Smrg swap_info->type = DRI2_SWAP; 136318781e08Smrg radeon_dri2_schedule_event(FALLBACK_SWAP_DELAY, swap_info); 136418781e08Smrg } else { 136518781e08Smrg box.x1 = 0; 136618781e08Smrg box.y1 = 0; 136718781e08Smrg box.x2 = draw->width; 136818781e08Smrg box.y2 = draw->height; 136918781e08Smrg REGION_INIT(pScreen, ®ion, &box, 0); 1370de2362d3Smrg 13718bf5c682Smrg radeon_dri2_copy_region2(draw->pScreen, draw, ®ion, front, back); 1372de2362d3Smrg 137318781e08Smrg DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data); 1374de2362d3Smrg 137518781e08Smrg radeon_dri2_unref_buffer(front); 137618781e08Smrg radeon_dri2_unref_buffer(back); 137718781e08Smrg } 13787821949aSmrg 1379de2362d3Smrg *target_msc = 0; /* offscreen, so zero out target vblank count */ 1380de2362d3Smrg return TRUE; 1381de2362d3Smrg} 1382de2362d3Smrg 1383de2362d3Smrg 1384de2362d3SmrgBool 1385de2362d3Smrgradeon_dri2_screen_init(ScreenPtr pScreen) 1386de2362d3Smrg{ 1387de2362d3Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 13888bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 1389de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1390de2362d3Smrg DRI2InfoRec dri2_info = { 0 }; 1391de2362d3Smrg const char *driverNames[2]; 1392de2362d3Smrg Bool scheduling_works = TRUE; 1393de2362d3Smrg 139418781e08Smrg if (!info->dri2.available) 1395de2362d3Smrg return FALSE; 1396de2362d3Smrg 13978bf5c682Smrg info->dri2.device_name = drmGetDeviceNameFromFd(pRADEONEnt->fd); 1398de2362d3Smrg 139918781e08Smrg if ( (info->ChipFamily >= CHIP_FAMILY_TAHITI) ) { 140018781e08Smrg dri2_info.driverName = SI_DRIVER_NAME; 140118781e08Smrg } else if ( (info->ChipFamily >= CHIP_FAMILY_R600) ) { 1402de2362d3Smrg dri2_info.driverName = R600_DRIVER_NAME; 1403de2362d3Smrg } else if ( (info->ChipFamily >= CHIP_FAMILY_R300) ) { 1404de2362d3Smrg dri2_info.driverName = R300_DRIVER_NAME; 1405de2362d3Smrg } else if ( info->ChipFamily >= CHIP_FAMILY_R200 ) { 1406de2362d3Smrg dri2_info.driverName = R200_DRIVER_NAME; 1407de2362d3Smrg } else { 1408de2362d3Smrg dri2_info.driverName = RADEON_DRIVER_NAME; 1409de2362d3Smrg } 14108bf5c682Smrg dri2_info.fd = pRADEONEnt->fd; 1411de2362d3Smrg dri2_info.deviceName = info->dri2.device_name; 1412de2362d3Smrg 141318781e08Smrg if (info->dri2.pKernelDRMVersion->version_minor < 4) { 1414de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "You need a newer kernel for " 1415de2362d3Smrg "sync extension\n"); 1416de2362d3Smrg scheduling_works = FALSE; 1417de2362d3Smrg } 1418de2362d3Smrg 141918781e08Smrg if (scheduling_works && info->drmmode.count_crtcs > 2) { 1420de2362d3Smrg#ifdef DRM_CAP_VBLANK_HIGH_CRTC 1421de2362d3Smrg uint64_t cap_value; 1422de2362d3Smrg 14238bf5c682Smrg if (drmGetCap(pRADEONEnt->fd, DRM_CAP_VBLANK_HIGH_CRTC, &cap_value)) { 1424de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "You need a newer kernel " 1425de2362d3Smrg "for VBLANKs on CRTC > 1\n"); 1426de2362d3Smrg scheduling_works = FALSE; 1427de2362d3Smrg } else if (!cap_value) { 1428de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Your kernel does not " 1429de2362d3Smrg "handle VBLANKs on CRTC > 1\n"); 1430de2362d3Smrg scheduling_works = FALSE; 1431de2362d3Smrg } 1432de2362d3Smrg#else 1433de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "You need to rebuild against a " 1434de2362d3Smrg "newer libdrm to handle VBLANKs on CRTC > 1\n"); 1435de2362d3Smrg scheduling_works = FALSE; 1436de2362d3Smrg#endif 1437de2362d3Smrg } 1438de2362d3Smrg 1439de2362d3Smrg if (scheduling_works) { 1440de2362d3Smrg dri2_info.ScheduleSwap = radeon_dri2_schedule_swap; 1441de2362d3Smrg dri2_info.GetMSC = radeon_dri2_get_msc; 1442de2362d3Smrg dri2_info.ScheduleWaitMSC = radeon_dri2_schedule_wait_msc; 14438bf5c682Smrg dri2_info.numDrivers = ARRAY_SIZE(driverNames); 1444de2362d3Smrg dri2_info.driverNames = driverNames; 144518781e08Smrg driverNames[0] = dri2_info.driverName; 144618781e08Smrg 144718781e08Smrg if (info->ChipFamily >= CHIP_FAMILY_R300) 144818781e08Smrg driverNames[1] = driverNames[0]; 144918781e08Smrg else 145018781e08Smrg driverNames[1] = NULL; /* no VDPAU support */ 145118781e08Smrg 145218781e08Smrg if (DRI2InfoCnt == 0) { 145318781e08Smrg if (!dixRegisterPrivateKey(dri2_window_private_key, 145418781e08Smrg PRIVATE_WINDOW, 145518781e08Smrg sizeof(struct dri2_window_priv))) { 145618781e08Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 145718781e08Smrg "Failed to get DRI2 window private\n"); 1458de2362d3Smrg return FALSE; 1459de2362d3Smrg } 1460de2362d3Smrg 1461de2362d3Smrg AddCallback(&ClientStateCallback, radeon_dri2_client_state_changed, 0); 1462de2362d3Smrg } 1463de2362d3Smrg 146418781e08Smrg DRI2InfoCnt++; 1465de2362d3Smrg } 146618781e08Smrg 146718781e08Smrg dri2_info.version = 9; 146818781e08Smrg dri2_info.CreateBuffer2 = radeon_dri2_create_buffer2; 146918781e08Smrg dri2_info.DestroyBuffer2 = radeon_dri2_destroy_buffer2; 147018781e08Smrg dri2_info.CopyRegion2 = radeon_dri2_copy_region2; 1471de2362d3Smrg 1472de2362d3Smrg info->dri2.enabled = DRI2ScreenInit(pScreen, &dri2_info); 1473de2362d3Smrg return info->dri2.enabled; 1474de2362d3Smrg} 1475de2362d3Smrg 1476de2362d3Smrgvoid radeon_dri2_close_screen(ScreenPtr pScreen) 1477de2362d3Smrg{ 1478de2362d3Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1479de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1480de2362d3Smrg 148118781e08Smrg if (--DRI2InfoCnt == 0) 1482de2362d3Smrg DeleteCallback(&ClientStateCallback, radeon_dri2_client_state_changed, 0); 148318781e08Smrg 1484de2362d3Smrg DRI2CloseScreen(pScreen); 1485de2362d3Smrg drmFree(info->dri2.device_name); 1486de2362d3Smrg} 1487de2362d3Smrg 148818781e08Smrg#endif /* DRI2 */ 148918781e08Smrg 1490