radeon_dri2.c revision 3ed65abb
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" 4518781e08Smrg#include "radeon_list.h" 46de2362d3Smrg 477821949aSmrg#include "radeon_bo_gem.h" 48de2362d3Smrg 4918781e08Smrg#include <xf86Priv.h> 503ed65abbSmrg#include <X11/extensions/dpmsconst.h> 51de2362d3Smrg 5218781e08Smrg#if DRI2INFOREC_VERSION >= 9 5318781e08Smrg#define USE_DRI2_PRIME 547821949aSmrg#endif 55de2362d3Smrg 5618781e08Smrg#define FALLBACK_SWAP_DELAY 16 5718781e08Smrg 5818781e08Smrg#include "radeon_glamor.h" 5918781e08Smrg 60de2362d3Smrgtypedef DRI2BufferPtr BufferPtr; 61de2362d3Smrg 62de2362d3Smrgstruct dri2_buffer_priv { 63de2362d3Smrg PixmapPtr pixmap; 64de2362d3Smrg unsigned int attachment; 65de2362d3Smrg unsigned int refcnt; 66de2362d3Smrg}; 67de2362d3Smrg 68de2362d3Smrg 6918781e08Smrgstruct dri2_window_priv { 7018781e08Smrg xf86CrtcPtr crtc; 7118781e08Smrg int vblank_delta; 7218781e08Smrg}; 730d16fef4Smrg 7418781e08Smrgstatic DevPrivateKeyRec dri2_window_private_key_rec; 7518781e08Smrg#define dri2_window_private_key (&dri2_window_private_key_rec) 760d16fef4Smrg 7718781e08Smrg#define get_dri2_window_priv(window) \ 7818781e08Smrg ((struct dri2_window_priv*) \ 7918781e08Smrg dixLookupPrivate(&(window)->devPrivates, dri2_window_private_key)) 800d16fef4Smrg 810d16fef4Smrg 8218781e08Smrg/* Get GEM flink name for a pixmap */ 8318781e08Smrgstatic Bool 8418781e08Smrgradeon_get_flink_name(RADEONInfoPtr info, PixmapPtr pixmap, uint32_t *name) 8518781e08Smrg{ 8618781e08Smrg struct radeon_bo *bo = radeon_get_pixmap_bo(pixmap); 8718781e08Smrg struct drm_gem_flink flink; 880d16fef4Smrg 8918781e08Smrg if (bo) 9018781e08Smrg return radeon_gem_get_kernel_name(bo, name) == 0; 9118781e08Smrg 9218781e08Smrg if (radeon_get_pixmap_handle(pixmap, &flink.handle)) { 9318781e08Smrg if (drmIoctl(info->dri2.drm_fd, DRM_IOCTL_GEM_FLINK, &flink) != 0) 9418781e08Smrg return FALSE; 950d16fef4Smrg 9618781e08Smrg *name = flink.name; 9718781e08Smrg return TRUE; 980d16fef4Smrg } 9918781e08Smrg 10018781e08Smrg return FALSE; 1010d16fef4Smrg} 10218781e08Smrg 103de2362d3Smrgstatic BufferPtr 10418781e08Smrgradeon_dri2_create_buffer2(ScreenPtr pScreen, 10518781e08Smrg DrawablePtr drawable, 10618781e08Smrg unsigned int attachment, 10718781e08Smrg unsigned int format) 108de2362d3Smrg{ 109de2362d3Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 110de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 111de2362d3Smrg BufferPtr buffers; 112de2362d3Smrg struct dri2_buffer_priv *privates; 11318781e08Smrg PixmapPtr pixmap; 114de2362d3Smrg int flags; 115de2362d3Smrg unsigned front_width; 116de2362d3Smrg uint32_t tiling = 0; 117de2362d3Smrg unsigned aligned_width = drawable->width; 11818781e08Smrg unsigned height = drawable->height; 11918781e08Smrg Bool is_glamor_pixmap = FALSE; 12018781e08Smrg int depth; 12118781e08Smrg int cpp; 12218781e08Smrg 12318781e08Smrg if (format) { 12418781e08Smrg depth = format; 12518781e08Smrg 12618781e08Smrg switch (depth) { 12718781e08Smrg case 15: 12818781e08Smrg cpp = 2; 12918781e08Smrg break; 13018781e08Smrg case 24: 13118781e08Smrg cpp = 4; 13218781e08Smrg break; 13318781e08Smrg default: 13418781e08Smrg cpp = depth / 8; 13518781e08Smrg } 13618781e08Smrg } else { 13718781e08Smrg depth = drawable->depth; 13818781e08Smrg cpp = drawable->bitsPerPixel / 8; 13918781e08Smrg } 140de2362d3Smrg 14118781e08Smrg front_width = pScreen->GetScreenPixmap(pScreen)->drawable.width; 142de2362d3Smrg 14318781e08Smrg pixmap = NULL; 144de2362d3Smrg 145de2362d3Smrg if (attachment == DRI2BufferFrontLeft) { 14618781e08Smrg uint32_t handle; 14718781e08Smrg 14818781e08Smrg pixmap = get_drawable_pixmap(drawable); 14918781e08Smrg if (pScreen != pixmap->drawable.pScreen) 15018781e08Smrg pixmap = NULL; 15118781e08Smrg else if (info->use_glamor && !radeon_get_pixmap_handle(pixmap, &handle)) { 15218781e08Smrg is_glamor_pixmap = TRUE; 15318781e08Smrg aligned_width = pixmap->drawable.width; 15418781e08Smrg height = pixmap->drawable.height; 15518781e08Smrg pixmap = NULL; 15618781e08Smrg } else 15718781e08Smrg pixmap->refcnt++; 15818781e08Smrg } 15918781e08Smrg 16018781e08Smrg if (!pixmap && (is_glamor_pixmap || attachment != DRI2BufferFrontLeft)) { 161de2362d3Smrg /* tile the back buffer */ 162de2362d3Smrg switch(attachment) { 163de2362d3Smrg case DRI2BufferDepth: 164de2362d3Smrg /* macro is the preferred setting, but the 2D detiling for software 165de2362d3Smrg * fallbacks in mesa still has issues on some configurations 166de2362d3Smrg */ 167de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 168de2362d3Smrg if (info->allowColorTiling2D) { 169de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO; 170de2362d3Smrg } else { 171de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MICRO; 172de2362d3Smrg } 173de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_CEDAR) 174de2362d3Smrg flags |= RADEON_CREATE_PIXMAP_SZBUFFER; 17518781e08Smrg } else if (cpp == 2 && info->ChipFamily >= CHIP_FAMILY_R300) 17618781e08Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO | RADEON_CREATE_PIXMAP_TILING_MICRO_SQUARE; 17718781e08Smrg else 178de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO | RADEON_CREATE_PIXMAP_TILING_MICRO; 179de2362d3Smrg if (IS_R200_3D || info->ChipFamily == CHIP_FAMILY_RV200 || info->ChipFamily == CHIP_FAMILY_RADEON) 180de2362d3Smrg flags |= RADEON_CREATE_PIXMAP_DEPTH; 181de2362d3Smrg break; 182de2362d3Smrg case DRI2BufferDepthStencil: 183de2362d3Smrg /* macro is the preferred setting, but the 2D detiling for software 184de2362d3Smrg * fallbacks in mesa still has issues on some configurations 185de2362d3Smrg */ 186de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 187de2362d3Smrg if (info->allowColorTiling2D) { 188de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO; 189de2362d3Smrg } else { 190de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MICRO; 191de2362d3Smrg } 192de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_CEDAR) 193de2362d3Smrg flags |= RADEON_CREATE_PIXMAP_SZBUFFER; 19418781e08Smrg } else if (cpp == 2 && info->ChipFamily >= CHIP_FAMILY_R300) 19518781e08Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO | RADEON_CREATE_PIXMAP_TILING_MICRO_SQUARE; 19618781e08Smrg else 197de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO | RADEON_CREATE_PIXMAP_TILING_MICRO; 198de2362d3Smrg if (IS_R200_3D || info->ChipFamily == CHIP_FAMILY_RV200 || info->ChipFamily == CHIP_FAMILY_RADEON) 199de2362d3Smrg flags |= RADEON_CREATE_PIXMAP_DEPTH; 200de2362d3Smrg 201de2362d3Smrg break; 202de2362d3Smrg case DRI2BufferBackLeft: 203de2362d3Smrg case DRI2BufferBackRight: 20418781e08Smrg case DRI2BufferFrontLeft: 20518781e08Smrg case DRI2BufferFrontRight: 206de2362d3Smrg case DRI2BufferFakeFrontLeft: 207de2362d3Smrg case DRI2BufferFakeFrontRight: 208de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 209de2362d3Smrg if (info->allowColorTiling2D) { 210de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO; 211de2362d3Smrg } else { 212de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MICRO; 213de2362d3Smrg } 214de2362d3Smrg } else 215de2362d3Smrg flags = RADEON_CREATE_PIXMAP_TILING_MACRO; 216de2362d3Smrg break; 217de2362d3Smrg default: 218de2362d3Smrg flags = 0; 219de2362d3Smrg } 220de2362d3Smrg 221de2362d3Smrg if (flags & RADEON_CREATE_PIXMAP_TILING_MICRO) 222de2362d3Smrg tiling |= RADEON_TILING_MICRO; 22318781e08Smrg if (flags & RADEON_CREATE_PIXMAP_TILING_MICRO_SQUARE) 22418781e08Smrg tiling |= RADEON_TILING_MICRO_SQUARE; 225de2362d3Smrg if (flags & RADEON_CREATE_PIXMAP_TILING_MACRO) 226de2362d3Smrg tiling |= RADEON_TILING_MACRO; 227de2362d3Smrg 22818781e08Smrg if (aligned_width == front_width) 22918781e08Smrg aligned_width = pScrn->virtualX; 230de2362d3Smrg 23118781e08Smrg pixmap = (*pScreen->CreatePixmap)(pScreen, 23218781e08Smrg aligned_width, 23318781e08Smrg height, 23418781e08Smrg depth, 23518781e08Smrg flags | RADEON_CREATE_PIXMAP_DRI2); 236de2362d3Smrg } 237de2362d3Smrg 238de2362d3Smrg buffers = calloc(1, sizeof *buffers); 239de2362d3Smrg if (buffers == NULL) 240de2362d3Smrg goto error; 241de2362d3Smrg 24218781e08Smrg if (pixmap) { 24318781e08Smrg if (!info->use_glamor) { 24418781e08Smrg info->exa_force_create = TRUE; 24518781e08Smrg exaMoveInPixmap(pixmap); 24618781e08Smrg info->exa_force_create = FALSE; 24718781e08Smrg if (exaGetPixmapDriverPrivate(pixmap) == NULL) { 24818781e08Smrg /* this happen if pixmap is non accelerable */ 24918781e08Smrg goto error; 25018781e08Smrg } 25118781e08Smrg } else if (is_glamor_pixmap) { 25218781e08Smrg pixmap = radeon_glamor_set_pixmap_bo(drawable, pixmap); 25318781e08Smrg pixmap->refcnt++; 25418781e08Smrg } 25518781e08Smrg 25618781e08Smrg if (!radeon_get_flink_name(info, pixmap, &buffers->name)) 25718781e08Smrg goto error; 258de2362d3Smrg } 259de2362d3Smrg 260de2362d3Smrg privates = calloc(1, sizeof(struct dri2_buffer_priv)); 261de2362d3Smrg if (privates == NULL) 262de2362d3Smrg goto error; 263de2362d3Smrg 264de2362d3Smrg buffers->attachment = attachment; 26518781e08Smrg if (pixmap) { 26618781e08Smrg buffers->pitch = pixmap->devKind; 26718781e08Smrg buffers->cpp = cpp; 26818781e08Smrg } 269de2362d3Smrg buffers->driverPrivate = privates; 270de2362d3Smrg buffers->format = format; 271de2362d3Smrg buffers->flags = 0; /* not tiled */ 272de2362d3Smrg privates->pixmap = pixmap; 273de2362d3Smrg privates->attachment = attachment; 274de2362d3Smrg privates->refcnt = 1; 275de2362d3Smrg 276de2362d3Smrg return buffers; 277de2362d3Smrg 278de2362d3Smrgerror: 279de2362d3Smrg free(buffers); 280de2362d3Smrg if (pixmap) 281de2362d3Smrg (*pScreen->DestroyPixmap)(pixmap); 282de2362d3Smrg return NULL; 283de2362d3Smrg} 284de2362d3Smrg 28518781e08SmrgDRI2BufferPtr 28618781e08Smrgradeon_dri2_create_buffer(DrawablePtr pDraw, unsigned int attachment, 28718781e08Smrg unsigned int format) 288de2362d3Smrg{ 28918781e08Smrg return radeon_dri2_create_buffer2(pDraw->pScreen, pDraw, 29018781e08Smrg attachment, format); 2917821949aSmrg} 29218781e08Smrg 293de2362d3Smrgstatic void 29418781e08Smrgradeon_dri2_destroy_buffer2(ScreenPtr pScreen, 29518781e08Smrg DrawablePtr drawable, BufferPtr buffers) 296de2362d3Smrg{ 297de2362d3Smrg if(buffers) 298de2362d3Smrg { 299de2362d3Smrg struct dri2_buffer_priv *private = buffers->driverPrivate; 300de2362d3Smrg 301de2362d3Smrg /* Trying to free an already freed buffer is unlikely to end well */ 302de2362d3Smrg if (private->refcnt == 0) { 303de2362d3Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 304de2362d3Smrg 305de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 306de2362d3Smrg "Attempted to destroy previously destroyed buffer.\ 307de2362d3Smrg This is a programming error\n"); 308de2362d3Smrg return; 309de2362d3Smrg } 310de2362d3Smrg 311de2362d3Smrg private->refcnt--; 312de2362d3Smrg if (private->refcnt == 0) 313de2362d3Smrg { 31418781e08Smrg if (private->pixmap) 31518781e08Smrg (*pScreen->DestroyPixmap)(private->pixmap); 316de2362d3Smrg 317de2362d3Smrg free(buffers->driverPrivate); 318de2362d3Smrg free(buffers); 319de2362d3Smrg } 320de2362d3Smrg } 321de2362d3Smrg} 322de2362d3Smrg 32318781e08Smrgvoid 32418781e08Smrgradeon_dri2_destroy_buffer(DrawablePtr pDraw, DRI2BufferPtr buf) 32518781e08Smrg{ 32618781e08Smrg radeon_dri2_destroy_buffer2(pDraw->pScreen, pDraw, buf); 32718781e08Smrg} 32818781e08Smrg 32918781e08Smrg 33018781e08Smrgstatic inline PixmapPtr GetDrawablePixmap(DrawablePtr drawable) 33118781e08Smrg{ 33218781e08Smrg if (drawable->type == DRAWABLE_PIXMAP) 33318781e08Smrg return (PixmapPtr)drawable; 33418781e08Smrg else { 33518781e08Smrg struct _Window *pWin = (struct _Window *)drawable; 33618781e08Smrg return drawable->pScreen->GetWindowPixmap(pWin); 33718781e08Smrg } 33818781e08Smrg} 339de2362d3Smrgstatic void 34018781e08Smrgradeon_dri2_copy_region2(ScreenPtr pScreen, 34118781e08Smrg DrawablePtr drawable, 34218781e08Smrg RegionPtr region, 34318781e08Smrg BufferPtr dest_buffer, 34418781e08Smrg BufferPtr src_buffer) 345de2362d3Smrg{ 346de2362d3Smrg struct dri2_buffer_priv *src_private = src_buffer->driverPrivate; 347de2362d3Smrg struct dri2_buffer_priv *dst_private = dest_buffer->driverPrivate; 348de2362d3Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 349de2362d3Smrg DrawablePtr src_drawable; 350de2362d3Smrg DrawablePtr dst_drawable; 351de2362d3Smrg RegionPtr copy_clip; 352de2362d3Smrg GCPtr gc; 353de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 354de2362d3Smrg Bool vsync; 35518781e08Smrg Bool translate = FALSE; 35618781e08Smrg int off_x = 0, off_y = 0; 35718781e08Smrg PixmapPtr dst_ppix; 35818781e08Smrg 35918781e08Smrg dst_ppix = dst_private->pixmap; 36018781e08Smrg src_drawable = &src_private->pixmap->drawable; 36118781e08Smrg dst_drawable = &dst_private->pixmap->drawable; 362de2362d3Smrg 363de2362d3Smrg if (src_private->attachment == DRI2BufferFrontLeft) { 36418781e08Smrg#ifdef USE_DRI2_PRIME 36518781e08Smrg if (drawable->pScreen != pScreen) { 36618781e08Smrg src_drawable = DRI2UpdatePrime(drawable, src_buffer); 36718781e08Smrg if (!src_drawable) 36818781e08Smrg return; 36918781e08Smrg } else 37018781e08Smrg#endif 37118781e08Smrg src_drawable = drawable; 372de2362d3Smrg } 373de2362d3Smrg if (dst_private->attachment == DRI2BufferFrontLeft) { 37418781e08Smrg#ifdef USE_DRI2_PRIME 37518781e08Smrg if (drawable->pScreen != pScreen) { 37618781e08Smrg dst_drawable = DRI2UpdatePrime(drawable, dest_buffer); 37718781e08Smrg if (!dst_drawable) 37818781e08Smrg return; 37918781e08Smrg dst_ppix = (PixmapPtr)dst_drawable; 38018781e08Smrg if (dst_drawable != drawable) 38118781e08Smrg translate = TRUE; 38218781e08Smrg } else 38318781e08Smrg#endif 38418781e08Smrg dst_drawable = drawable; 38518781e08Smrg } 38618781e08Smrg 38718781e08Smrg if (translate && drawable->type == DRAWABLE_WINDOW) { 38818781e08Smrg PixmapPtr pPix = GetDrawablePixmap(drawable); 38918781e08Smrg 39018781e08Smrg off_x = drawable->x - pPix->screen_x; 39118781e08Smrg off_y = drawable->y - pPix->screen_y; 392de2362d3Smrg } 393de2362d3Smrg gc = GetScratchGC(dst_drawable->depth, pScreen); 394de2362d3Smrg copy_clip = REGION_CREATE(pScreen, NULL, 0); 395de2362d3Smrg REGION_COPY(pScreen, copy_clip, region); 39618781e08Smrg 39718781e08Smrg if (translate) { 39818781e08Smrg REGION_TRANSLATE(pScreen, copy_clip, off_x, off_y); 39918781e08Smrg } 40018781e08Smrg 401de2362d3Smrg (*gc->funcs->ChangeClip) (gc, CT_REGION, copy_clip, 0); 402de2362d3Smrg ValidateGC(dst_drawable, gc); 403de2362d3Smrg 404de2362d3Smrg /* If this is a full buffer swap or frontbuffer flush, throttle on the 405de2362d3Smrg * previous one 406de2362d3Smrg */ 407de2362d3Smrg if (dst_private->attachment == DRI2BufferFrontLeft) { 408de2362d3Smrg if (REGION_NUM_RECTS(region) == 1) { 409de2362d3Smrg BoxPtr extents = REGION_EXTENTS(pScreen, region); 410de2362d3Smrg 411de2362d3Smrg if (extents->x1 == 0 && extents->y1 == 0 && 412de2362d3Smrg extents->x2 == drawable->width && 413de2362d3Smrg extents->y2 == drawable->height) { 41418781e08Smrg struct radeon_bo *bo = radeon_get_pixmap_bo(dst_ppix); 415de2362d3Smrg 41618781e08Smrg if (bo) 41718781e08Smrg radeon_bo_wait(bo); 418de2362d3Smrg } 419de2362d3Smrg } 420de2362d3Smrg } 421de2362d3Smrg 422de2362d3Smrg vsync = info->accel_state->vsync; 423de2362d3Smrg 424de2362d3Smrg /* Driver option "SwapbuffersWait" defines if we vsync DRI2 copy-swaps. */ 425de2362d3Smrg info->accel_state->vsync = info->swapBuffersWait; 42618781e08Smrg info->accel_state->force = TRUE; 427de2362d3Smrg 428de2362d3Smrg (*gc->ops->CopyArea)(src_drawable, dst_drawable, gc, 42918781e08Smrg 0, 0, drawable->width, drawable->height, off_x, off_y); 430de2362d3Smrg 43118781e08Smrg info->accel_state->force = FALSE; 432de2362d3Smrg info->accel_state->vsync = vsync; 433de2362d3Smrg 434de2362d3Smrg FreeScratchGC(gc); 435de2362d3Smrg} 436de2362d3Smrg 43718781e08Smrgvoid 43818781e08Smrgradeon_dri2_copy_region(DrawablePtr pDraw, RegionPtr pRegion, 43918781e08Smrg DRI2BufferPtr pDstBuffer, DRI2BufferPtr pSrcBuffer) 44018781e08Smrg{ 44118781e08Smrg return radeon_dri2_copy_region2(pDraw->pScreen, pDraw, pRegion, 44218781e08Smrg pDstBuffer, pSrcBuffer); 44318781e08Smrg} 444de2362d3Smrg 445de2362d3Smrgenum DRI2FrameEventType { 446de2362d3Smrg DRI2_SWAP, 447de2362d3Smrg DRI2_FLIP, 448de2362d3Smrg DRI2_WAITMSC, 449de2362d3Smrg}; 450de2362d3Smrg 451de2362d3Smrgtypedef struct _DRI2FrameEvent { 452de2362d3Smrg XID drawable_id; 453de2362d3Smrg ClientPtr client; 454de2362d3Smrg enum DRI2FrameEventType type; 45518781e08Smrg unsigned frame; 45618781e08Smrg xf86CrtcPtr crtc; 45718781e08Smrg OsTimerPtr timer; 45818781e08Smrg uintptr_t drm_queue_seq; 459de2362d3Smrg 460de2362d3Smrg /* for swaps & flips only */ 461de2362d3Smrg DRI2SwapEventPtr event_complete; 462de2362d3Smrg void *event_data; 463de2362d3Smrg DRI2BufferPtr front; 464de2362d3Smrg DRI2BufferPtr back; 465de2362d3Smrg} DRI2FrameEventRec, *DRI2FrameEventPtr; 466de2362d3Smrg 46718781e08Smrgstatic int DRI2InfoCnt; 468de2362d3Smrg 469de2362d3Smrgstatic void 470de2362d3Smrgradeon_dri2_ref_buffer(BufferPtr buffer) 471de2362d3Smrg{ 472de2362d3Smrg struct dri2_buffer_priv *private = buffer->driverPrivate; 473de2362d3Smrg private->refcnt++; 474de2362d3Smrg} 475de2362d3Smrg 476de2362d3Smrgstatic void 477de2362d3Smrgradeon_dri2_unref_buffer(BufferPtr buffer) 478de2362d3Smrg{ 479de2362d3Smrg if (buffer) { 480de2362d3Smrg struct dri2_buffer_priv *private = buffer->driverPrivate; 481de2362d3Smrg radeon_dri2_destroy_buffer(&(private->pixmap->drawable), buffer); 482de2362d3Smrg } 483de2362d3Smrg} 484de2362d3Smrg 485de2362d3Smrgstatic void 486de2362d3Smrgradeon_dri2_client_state_changed(CallbackListPtr *ClientStateCallback, pointer data, pointer calldata) 487de2362d3Smrg{ 488de2362d3Smrg NewClientInfoRec *clientinfo = calldata; 489de2362d3Smrg ClientPtr pClient = clientinfo->client; 490de2362d3Smrg 491de2362d3Smrg switch (pClient->clientState) { 492de2362d3Smrg case ClientStateRetained: 493de2362d3Smrg case ClientStateGone: 49418781e08Smrg radeon_drm_abort_client(pClient); 495de2362d3Smrg break; 496de2362d3Smrg default: 497de2362d3Smrg break; 498de2362d3Smrg } 499de2362d3Smrg} 500de2362d3Smrg 50118781e08Smrg/* 50218781e08Smrg * Get current frame count delta for the specified drawable and CRTC 50318781e08Smrg */ 50418781e08Smrgstatic uint32_t radeon_get_msc_delta(DrawablePtr pDraw, xf86CrtcPtr crtc) 50518781e08Smrg{ 50618781e08Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 50718781e08Smrg 50818781e08Smrg if (pDraw && pDraw->type == DRAWABLE_WINDOW) 50918781e08Smrg return drmmode_crtc->interpolated_vblanks + 51018781e08Smrg get_dri2_window_priv((WindowPtr)pDraw)->vblank_delta; 51118781e08Smrg 51218781e08Smrg return drmmode_crtc->interpolated_vblanks; 51318781e08Smrg} 51418781e08Smrg 51518781e08Smrg/* 51618781e08Smrg * Get current frame count and timestamp of the specified CRTC 51718781e08Smrg */ 51818781e08Smrgstatic Bool radeon_dri2_get_crtc_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc) 51918781e08Smrg{ 52018781e08Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 52118781e08Smrg 52218781e08Smrg if (!radeon_crtc_is_enabled(crtc) || 52318781e08Smrg drmmode_crtc_get_ust_msc(crtc, ust, msc) != Success) { 52418781e08Smrg /* CRTC is not running, extrapolate MSC and timestamp */ 52518781e08Smrg ScrnInfoPtr scrn = crtc->scrn; 52618781e08Smrg RADEONInfoPtr info = RADEONPTR(scrn); 52718781e08Smrg CARD64 now, delta_t, delta_seq; 52818781e08Smrg 52918781e08Smrg if (!drmmode_crtc->dpms_last_ust) 53018781e08Smrg return FALSE; 53118781e08Smrg 53218781e08Smrg if (drmmode_get_current_ust(info->dri2.drm_fd, &now) != 0) { 53318781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 53418781e08Smrg "%s cannot get current time\n", __func__); 53518781e08Smrg return FALSE; 53618781e08Smrg } 53718781e08Smrg 53818781e08Smrg delta_t = now - drmmode_crtc->dpms_last_ust; 53918781e08Smrg delta_seq = delta_t * drmmode_crtc->dpms_last_fps; 54018781e08Smrg delta_seq /= 1000000; 54118781e08Smrg *ust = drmmode_crtc->dpms_last_ust; 54218781e08Smrg delta_t = delta_seq * 1000000; 54318781e08Smrg delta_t /= drmmode_crtc->dpms_last_fps; 54418781e08Smrg *ust += delta_t; 54518781e08Smrg *msc = drmmode_crtc->dpms_last_seq; 54618781e08Smrg *msc += delta_seq; 54718781e08Smrg } 54818781e08Smrg 54918781e08Smrg *msc += drmmode_crtc->interpolated_vblanks; 55018781e08Smrg 55118781e08Smrg return TRUE; 55218781e08Smrg} 55318781e08Smrg 55418781e08Smrgstatic 55518781e08Smrgxf86CrtcPtr radeon_dri2_drawable_crtc(DrawablePtr pDraw, Bool consider_disabled) 556de2362d3Smrg{ 557de2362d3Smrg ScreenPtr pScreen = pDraw->pScreen; 558de2362d3Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 55918781e08Smrg xf86CrtcPtr crtc = radeon_pick_best_crtc(pScrn, consider_disabled, 56018781e08Smrg pDraw->x, pDraw->x + pDraw->width, 56118781e08Smrg pDraw->y, pDraw->y + pDraw->height); 56218781e08Smrg 56318781e08Smrg if (crtc && pDraw->type == DRAWABLE_WINDOW) { 56418781e08Smrg struct dri2_window_priv *priv = get_dri2_window_priv((WindowPtr)pDraw); 56518781e08Smrg 56618781e08Smrg if (priv->crtc && priv->crtc != crtc) { 56718781e08Smrg CARD64 ust, mscold, mscnew; 56818781e08Smrg 56918781e08Smrg if (radeon_dri2_get_crtc_msc(priv->crtc, &ust, &mscold) && 57018781e08Smrg radeon_dri2_get_crtc_msc(crtc, &ust, &mscnew)) 57118781e08Smrg priv->vblank_delta += mscold - mscnew; 57218781e08Smrg } 57318781e08Smrg 57418781e08Smrg priv->crtc = crtc; 57518781e08Smrg } 57618781e08Smrg 57718781e08Smrg return crtc; 57818781e08Smrg} 57918781e08Smrg 58018781e08Smrgstatic void 58118781e08Smrgradeon_dri2_flip_event_abort(xf86CrtcPtr crtc, void *event_data) 58218781e08Smrg{ 5833ed65abbSmrg if (crtc) 5843ed65abbSmrg RADEONPTR(crtc->scrn)->drmmode.dri2_flipping = FALSE; 58518781e08Smrg 58618781e08Smrg free(event_data); 58718781e08Smrg} 58818781e08Smrg 58918781e08Smrgstatic void 59018781e08Smrgradeon_dri2_flip_event_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, 59118781e08Smrg void *event_data) 59218781e08Smrg{ 59318781e08Smrg DRI2FrameEventPtr flip = event_data; 59418781e08Smrg ScrnInfoPtr scrn = crtc->scrn; 59518781e08Smrg unsigned tv_sec, tv_usec; 59618781e08Smrg DrawablePtr drawable; 59718781e08Smrg ScreenPtr screen; 59818781e08Smrg int status; 59918781e08Smrg PixmapPtr pixmap; 60018781e08Smrg 60118781e08Smrg status = dixLookupDrawable(&drawable, flip->drawable_id, serverClient, 60218781e08Smrg M_ANY, DixWriteAccess); 60318781e08Smrg if (status != Success) 60418781e08Smrg goto abort; 60518781e08Smrg 60618781e08Smrg frame += radeon_get_msc_delta(drawable, crtc); 6070d16fef4Smrg 60818781e08Smrg screen = scrn->pScreen; 60918781e08Smrg pixmap = screen->GetScreenPixmap(screen); 61018781e08Smrg xf86DrvMsgVerb(scrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 61118781e08Smrg "%s:%d fevent[%p] width %d pitch %d (/4 %d)\n", 61218781e08Smrg __func__, __LINE__, flip, pixmap->drawable.width, pixmap->devKind, pixmap->devKind/4); 61318781e08Smrg 61418781e08Smrg tv_sec = usec / 1000000; 61518781e08Smrg tv_usec = usec % 1000000; 61618781e08Smrg 61718781e08Smrg /* We assume our flips arrive in order, so we don't check the frame */ 61818781e08Smrg switch (flip->type) { 61918781e08Smrg case DRI2_SWAP: 62018781e08Smrg /* Check for too small vblank count of pageflip completion, taking wraparound 62118781e08Smrg * into account. This usually means some defective kms pageflip completion, 62218781e08Smrg * causing wrong (msc, ust) return values and possible visual corruption. 62318781e08Smrg */ 62418781e08Smrg if ((frame < flip->frame) && (flip->frame - frame < 5)) { 62518781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 62618781e08Smrg "%s: Pageflip completion event has impossible msc %u < target_msc %u\n", 62718781e08Smrg __func__, frame, flip->frame); 62818781e08Smrg /* All-Zero values signal failure of (msc, ust) timestamping to client. */ 62918781e08Smrg frame = tv_sec = tv_usec = 0; 63018781e08Smrg } 6310d16fef4Smrg 63218781e08Smrg DRI2SwapComplete(flip->client, drawable, frame, tv_sec, tv_usec, 63318781e08Smrg DRI2_FLIP_COMPLETE, flip->event_complete, 63418781e08Smrg flip->event_data); 63518781e08Smrg break; 63618781e08Smrg default: 63718781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, "%s: unknown vblank event received\n", __func__); 63818781e08Smrg /* Unknown type */ 63918781e08Smrg break; 6400d16fef4Smrg } 64118781e08Smrg 64218781e08Smrgabort: 64318781e08Smrg radeon_dri2_flip_event_abort(crtc, event_data); 644de2362d3Smrg} 645de2362d3Smrg 646de2362d3Smrgstatic Bool 64718781e08Smrgradeon_dri2_schedule_flip(xf86CrtcPtr crtc, ClientPtr client, 648de2362d3Smrg DrawablePtr draw, DRI2BufferPtr front, 649de2362d3Smrg DRI2BufferPtr back, DRI2SwapEventPtr func, 650de2362d3Smrg void *data, unsigned int target_msc) 651de2362d3Smrg{ 65218781e08Smrg ScrnInfoPtr scrn = crtc->scrn; 65318781e08Smrg RADEONInfoPtr info = RADEONPTR(scrn); 654de2362d3Smrg struct dri2_buffer_priv *back_priv; 65518781e08Smrg struct radeon_bo *bo; 656de2362d3Smrg DRI2FrameEventPtr flip_info; 65718781e08Smrg int ref_crtc_hw_id = drmmode_get_crtc_id(crtc); 658de2362d3Smrg 659de2362d3Smrg flip_info = calloc(1, sizeof(DRI2FrameEventRec)); 660de2362d3Smrg if (!flip_info) 661de2362d3Smrg return FALSE; 662de2362d3Smrg 663de2362d3Smrg flip_info->drawable_id = draw->id; 664de2362d3Smrg flip_info->client = client; 665de2362d3Smrg flip_info->type = DRI2_SWAP; 666de2362d3Smrg flip_info->event_complete = func; 667de2362d3Smrg flip_info->event_data = data; 668de2362d3Smrg flip_info->frame = target_msc; 66918781e08Smrg flip_info->crtc = crtc; 670de2362d3Smrg 671de2362d3Smrg xf86DrvMsgVerb(scrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 672de2362d3Smrg "%s:%d fevent[%p]\n", __func__, __LINE__, flip_info); 673de2362d3Smrg 674de2362d3Smrg /* Page flip the full screen buffer */ 675de2362d3Smrg back_priv = back->driverPrivate; 67618781e08Smrg bo = radeon_get_pixmap_bo(back_priv->pixmap); 67718781e08Smrg 67818781e08Smrg if (radeon_do_pageflip(scrn, client, bo->handle, 67918781e08Smrg RADEON_DRM_QUEUE_ID_DEFAULT, flip_info, 68018781e08Smrg ref_crtc_hw_id, 68118781e08Smrg radeon_dri2_flip_event_handler, 6823ed65abbSmrg radeon_dri2_flip_event_abort, FLIP_VSYNC, 6833ed65abbSmrg target_msc - radeon_get_msc_delta(draw, crtc))) { 68418781e08Smrg info->drmmode.dri2_flipping = TRUE; 68518781e08Smrg return TRUE; 68618781e08Smrg } 6870d16fef4Smrg 68818781e08Smrg return FALSE; 689de2362d3Smrg} 690de2362d3Smrg 691de2362d3Smrgstatic Bool 692de2362d3Smrgupdate_front(DrawablePtr draw, DRI2BufferPtr front) 693de2362d3Smrg{ 694de2362d3Smrg PixmapPtr pixmap; 69518781e08Smrg RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(draw->pScreen)); 696de2362d3Smrg struct dri2_buffer_priv *priv = front->driverPrivate; 697de2362d3Smrg 69818781e08Smrg pixmap = get_drawable_pixmap(draw); 699de2362d3Smrg pixmap->refcnt++; 700de2362d3Smrg 70118781e08Smrg if (!info->use_glamor) 70218781e08Smrg exaMoveInPixmap(pixmap); 70318781e08Smrg if (!radeon_get_flink_name(info, pixmap, &front->name)) { 704de2362d3Smrg (*draw->pScreen->DestroyPixmap)(pixmap); 705de2362d3Smrg return FALSE; 706de2362d3Smrg } 707de2362d3Smrg (*draw->pScreen->DestroyPixmap)(priv->pixmap); 708de2362d3Smrg front->pitch = pixmap->devKind; 709de2362d3Smrg front->cpp = pixmap->drawable.bitsPerPixel / 8; 710de2362d3Smrg priv->pixmap = pixmap; 711de2362d3Smrg 712de2362d3Smrg return TRUE; 713de2362d3Smrg} 714de2362d3Smrg 715de2362d3Smrgstatic Bool 716de2362d3Smrgcan_exchange(ScrnInfoPtr pScrn, DrawablePtr draw, 717de2362d3Smrg DRI2BufferPtr front, DRI2BufferPtr back) 718de2362d3Smrg{ 719de2362d3Smrg struct dri2_buffer_priv *front_priv = front->driverPrivate; 720de2362d3Smrg struct dri2_buffer_priv *back_priv = back->driverPrivate; 721de2362d3Smrg PixmapPtr front_pixmap; 722de2362d3Smrg PixmapPtr back_pixmap = back_priv->pixmap; 723de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 724de2362d3Smrg int i; 725de2362d3Smrg 726de2362d3Smrg for (i = 0; i < xf86_config->num_crtc; i++) { 727de2362d3Smrg xf86CrtcPtr crtc = xf86_config->crtc[i]; 72818781e08Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 72918781e08Smrg 73018781e08Smrg if (crtc->enabled && 73118781e08Smrg (crtc->rotatedData || drmmode_crtc->scanout[0].bo)) 732de2362d3Smrg return FALSE; 733de2362d3Smrg } 734de2362d3Smrg 735de2362d3Smrg if (!update_front(draw, front)) 736de2362d3Smrg return FALSE; 737de2362d3Smrg 738de2362d3Smrg front_pixmap = front_priv->pixmap; 739de2362d3Smrg 740de2362d3Smrg if (front_pixmap->drawable.width != back_pixmap->drawable.width) 741de2362d3Smrg return FALSE; 742de2362d3Smrg 743de2362d3Smrg if (front_pixmap->drawable.height != back_pixmap->drawable.height) 744de2362d3Smrg return FALSE; 745de2362d3Smrg 746de2362d3Smrg if (front_pixmap->drawable.bitsPerPixel != back_pixmap->drawable.bitsPerPixel) 747de2362d3Smrg return FALSE; 748de2362d3Smrg 749de2362d3Smrg if (front_pixmap->devKind != back_pixmap->devKind) 750de2362d3Smrg return FALSE; 751de2362d3Smrg 752de2362d3Smrg return TRUE; 753de2362d3Smrg} 754de2362d3Smrg 755de2362d3Smrgstatic Bool 756de2362d3Smrgcan_flip(ScrnInfoPtr pScrn, DrawablePtr draw, 757de2362d3Smrg DRI2BufferPtr front, DRI2BufferPtr back) 758de2362d3Smrg{ 75918781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 7603ed65abbSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 7613ed65abbSmrg int num_crtcs_on; 7623ed65abbSmrg int i; 7633ed65abbSmrg 7643ed65abbSmrg if (draw->type != DRAWABLE_WINDOW || 7653ed65abbSmrg !info->allowPageFlip || 7663ed65abbSmrg info->hwcursor_disabled || 7673ed65abbSmrg info->drmmode.present_flipping || 7683ed65abbSmrg !pScrn->vtSema || 7693ed65abbSmrg !DRI2CanFlip(draw)) 7703ed65abbSmrg return FALSE; 7713ed65abbSmrg 7723ed65abbSmrg for (i = 0, num_crtcs_on = 0; i < config->num_crtc; i++) { 7733ed65abbSmrg xf86CrtcPtr crtc = config->crtc[i]; 7743ed65abbSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 7753ed65abbSmrg 7763ed65abbSmrg if (!crtc->enabled) 7773ed65abbSmrg continue; 7783ed65abbSmrg 7793ed65abbSmrg if (!drmmode_crtc || drmmode_crtc->rotate.bo || 7803ed65abbSmrg drmmode_crtc->scanout[0].bo) 7813ed65abbSmrg return FALSE; 7823ed65abbSmrg 7833ed65abbSmrg if (drmmode_crtc->pending_dpms_mode == DPMSModeOn) 7843ed65abbSmrg num_crtcs_on++; 7853ed65abbSmrg } 78618781e08Smrg 7873ed65abbSmrg return num_crtcs_on > 0 && can_exchange(pScrn, draw, front, back); 788de2362d3Smrg} 789de2362d3Smrg 790de2362d3Smrgstatic void 791de2362d3Smrgradeon_dri2_exchange_buffers(DrawablePtr draw, DRI2BufferPtr front, DRI2BufferPtr back) 792de2362d3Smrg{ 793de2362d3Smrg struct dri2_buffer_priv *front_priv = front->driverPrivate; 794de2362d3Smrg struct dri2_buffer_priv *back_priv = back->driverPrivate; 79518781e08Smrg struct radeon_bo *front_bo, *back_bo; 796de2362d3Smrg ScreenPtr screen; 797de2362d3Smrg RADEONInfoPtr info; 79818781e08Smrg RegionRec region; 799de2362d3Smrg int tmp; 800de2362d3Smrg 80118781e08Smrg region.extents.x1 = region.extents.y1 = 0; 80218781e08Smrg region.extents.x2 = front_priv->pixmap->drawable.width; 80318781e08Smrg region.extents.y2 = front_priv->pixmap->drawable.height; 80418781e08Smrg region.data = NULL; 80518781e08Smrg DamageRegionAppend(&front_priv->pixmap->drawable, ®ion); 80618781e08Smrg 807de2362d3Smrg /* Swap BO names so DRI works */ 808de2362d3Smrg tmp = front->name; 809de2362d3Smrg front->name = back->name; 810de2362d3Smrg back->name = tmp; 811de2362d3Smrg 812de2362d3Smrg /* Swap pixmap bos */ 81318781e08Smrg front_bo = radeon_get_pixmap_bo(front_priv->pixmap); 81418781e08Smrg back_bo = radeon_get_pixmap_bo(back_priv->pixmap); 81518781e08Smrg radeon_set_pixmap_bo(front_priv->pixmap, back_bo); 81618781e08Smrg radeon_set_pixmap_bo(back_priv->pixmap, front_bo); 817de2362d3Smrg 818de2362d3Smrg /* Do we need to update the Screen? */ 819de2362d3Smrg screen = draw->pScreen; 820de2362d3Smrg info = RADEONPTR(xf86ScreenToScrn(screen)); 82118781e08Smrg if (front_bo == info->front_bo) { 82218781e08Smrg radeon_bo_ref(back_bo); 823de2362d3Smrg radeon_bo_unref(info->front_bo); 82418781e08Smrg info->front_bo = back_bo; 82518781e08Smrg radeon_set_pixmap_bo(screen->GetScreenPixmap(screen), back_bo); 826de2362d3Smrg } 82718781e08Smrg 82818781e08Smrg radeon_glamor_exchange_buffers(front_priv->pixmap, back_priv->pixmap); 82918781e08Smrg 83018781e08Smrg DamageRegionProcessPending(&front_priv->pixmap->drawable); 831de2362d3Smrg} 832de2362d3Smrg 83318781e08Smrgstatic void radeon_dri2_frame_event_abort(xf86CrtcPtr crtc, void *event_data) 834de2362d3Smrg{ 835de2362d3Smrg DRI2FrameEventPtr event = event_data; 83618781e08Smrg 83718781e08Smrg TimerCancel(event->timer); 83818781e08Smrg TimerFree(event->timer); 83918781e08Smrg radeon_dri2_unref_buffer(event->front); 84018781e08Smrg radeon_dri2_unref_buffer(event->back); 84118781e08Smrg free(event); 84218781e08Smrg} 84318781e08Smrg 84418781e08Smrgstatic void radeon_dri2_frame_event_handler(xf86CrtcPtr crtc, uint32_t seq, 84518781e08Smrg uint64_t usec, void *event_data) 84618781e08Smrg{ 84718781e08Smrg DRI2FrameEventPtr event = event_data; 84818781e08Smrg ScrnInfoPtr scrn = crtc->scrn; 849de2362d3Smrg DrawablePtr drawable; 850de2362d3Smrg int status; 851de2362d3Smrg int swap_type; 852de2362d3Smrg BoxRec box; 853de2362d3Smrg RegionRec region; 854de2362d3Smrg 855de2362d3Smrg status = dixLookupDrawable(&drawable, event->drawable_id, serverClient, 856de2362d3Smrg M_ANY, DixWriteAccess); 857de2362d3Smrg if (status != Success) 858de2362d3Smrg goto cleanup; 859de2362d3Smrg 86018781e08Smrg seq += radeon_get_msc_delta(drawable, crtc); 861de2362d3Smrg 862de2362d3Smrg switch (event->type) { 863de2362d3Smrg case DRI2_FLIP: 864de2362d3Smrg if (can_flip(scrn, drawable, event->front, event->back) && 86518781e08Smrg radeon_dri2_schedule_flip(crtc, 866de2362d3Smrg event->client, 867de2362d3Smrg drawable, 868de2362d3Smrg event->front, 869de2362d3Smrg event->back, 870de2362d3Smrg event->event_complete, 871de2362d3Smrg event->event_data, 872de2362d3Smrg event->frame)) { 873de2362d3Smrg radeon_dri2_exchange_buffers(drawable, event->front, event->back); 874de2362d3Smrg break; 875de2362d3Smrg } 876de2362d3Smrg /* else fall through to exchange/blit */ 877de2362d3Smrg case DRI2_SWAP: 878de2362d3Smrg if (DRI2CanExchange(drawable) && 879de2362d3Smrg can_exchange(scrn, drawable, event->front, event->back)) { 880de2362d3Smrg radeon_dri2_exchange_buffers(drawable, event->front, event->back); 881de2362d3Smrg swap_type = DRI2_EXCHANGE_COMPLETE; 882de2362d3Smrg } else { 883de2362d3Smrg box.x1 = 0; 884de2362d3Smrg box.y1 = 0; 885de2362d3Smrg box.x2 = drawable->width; 886de2362d3Smrg box.y2 = drawable->height; 887de2362d3Smrg REGION_INIT(pScreen, ®ion, &box, 0); 888de2362d3Smrg radeon_dri2_copy_region(drawable, ®ion, event->front, event->back); 889de2362d3Smrg swap_type = DRI2_BLIT_COMPLETE; 890de2362d3Smrg } 891de2362d3Smrg 89218781e08Smrg DRI2SwapComplete(event->client, drawable, seq, usec / 1000000, 89318781e08Smrg usec % 1000000, swap_type, event->event_complete, 89418781e08Smrg event->event_data); 895de2362d3Smrg 896de2362d3Smrg break; 897de2362d3Smrg case DRI2_WAITMSC: 89818781e08Smrg DRI2WaitMSCComplete(event->client, drawable, seq, usec / 1000000, 89918781e08Smrg usec % 1000000); 900de2362d3Smrg break; 901de2362d3Smrg default: 902de2362d3Smrg /* Unknown type */ 903de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 904de2362d3Smrg "%s: unknown vblank event received\n", __func__); 905de2362d3Smrg break; 906de2362d3Smrg } 907de2362d3Smrg 908de2362d3Smrgcleanup: 90918781e08Smrg radeon_dri2_frame_event_abort(crtc, event_data); 910de2362d3Smrg} 911de2362d3Smrg 91218781e08SmrgdrmVBlankSeqType radeon_populate_vbl_request_type(xf86CrtcPtr crtc) 913de2362d3Smrg{ 914de2362d3Smrg drmVBlankSeqType type = 0; 91518781e08Smrg int crtc_id = drmmode_get_crtc_id(crtc); 916de2362d3Smrg 91718781e08Smrg if (crtc_id == 1) 918de2362d3Smrg type |= DRM_VBLANK_SECONDARY; 91918781e08Smrg else if (crtc_id > 1) 920de2362d3Smrg#ifdef DRM_VBLANK_HIGH_CRTC_SHIFT 92118781e08Smrg type |= (crtc_id << DRM_VBLANK_HIGH_CRTC_SHIFT) & 922de2362d3Smrg DRM_VBLANK_HIGH_CRTC_MASK; 923de2362d3Smrg#else 924de2362d3Smrg ErrorF("radeon driver bug: %s called for CRTC %d > 1, but " 925de2362d3Smrg "DRM_VBLANK_HIGH_CRTC_MASK not defined at build time\n", 92618781e08Smrg __func__, crtc_id); 927de2362d3Smrg#endif 928de2362d3Smrg 929de2362d3Smrg return type; 930de2362d3Smrg} 931de2362d3Smrg 932de2362d3Smrg/* 93318781e08Smrg * This function should be called on a disabled CRTC only (i.e., CRTC 93418781e08Smrg * in DPMS-off state). It will calculate the delay necessary to reach 93518781e08Smrg * target_msc from present time if the CRTC were running. 936de2362d3Smrg */ 93718781e08Smrgstatic 93818781e08SmrgCARD32 radeon_dri2_extrapolate_msc_delay(xf86CrtcPtr crtc, CARD64 *target_msc, 93918781e08Smrg CARD64 divisor, CARD64 remainder) 940de2362d3Smrg{ 94118781e08Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 94218781e08Smrg ScrnInfoPtr pScrn = crtc->scrn; 94318781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 94418781e08Smrg int nominal_frame_rate = drmmode_crtc->dpms_last_fps; 94518781e08Smrg CARD64 last_vblank_ust = drmmode_crtc->dpms_last_ust; 94618781e08Smrg uint32_t last_vblank_seq = drmmode_crtc->dpms_last_seq; 94718781e08Smrg CARD64 now, target_time, delta_t; 94818781e08Smrg int64_t d, delta_seq; 9497821949aSmrg int ret; 95018781e08Smrg CARD32 d_ms; 95118781e08Smrg 95218781e08Smrg if (!last_vblank_ust) { 95318781e08Smrg *target_msc = 0; 95418781e08Smrg return FALLBACK_SWAP_DELAY; 95518781e08Smrg } 95618781e08Smrg ret = drmmode_get_current_ust(info->dri2.drm_fd, &now); 95718781e08Smrg if (ret) { 95818781e08Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 95918781e08Smrg "%s cannot get current time\n", __func__); 96018781e08Smrg *target_msc = 0; 96118781e08Smrg return FALLBACK_SWAP_DELAY; 96218781e08Smrg } 96318781e08Smrg delta_seq = *target_msc - last_vblank_seq; 96418781e08Smrg delta_seq *= 1000000; 96518781e08Smrg target_time = last_vblank_ust; 96618781e08Smrg target_time += delta_seq / nominal_frame_rate; 96718781e08Smrg d = target_time - now; 96818781e08Smrg if (d < 0) { 96918781e08Smrg /* we missed the event, adjust target_msc, do the divisor magic */ 97018781e08Smrg CARD64 current_msc = last_vblank_seq; 97118781e08Smrg 97218781e08Smrg delta_t = now - last_vblank_ust; 97318781e08Smrg delta_seq = delta_t * nominal_frame_rate; 97418781e08Smrg current_msc += delta_seq / 1000000; 97518781e08Smrg current_msc &= 0xffffffff; 97618781e08Smrg if (divisor == 0) { 97718781e08Smrg *target_msc = current_msc; 97818781e08Smrg d = 0; 97918781e08Smrg } else { 98018781e08Smrg *target_msc = current_msc - (current_msc % divisor) + remainder; 98118781e08Smrg if ((current_msc % divisor) >= remainder) 98218781e08Smrg *target_msc += divisor; 98318781e08Smrg *target_msc &= 0xffffffff; 98418781e08Smrg delta_seq = *target_msc - last_vblank_seq; 98518781e08Smrg delta_seq *= 1000000; 98618781e08Smrg target_time = last_vblank_ust; 98718781e08Smrg target_time += delta_seq / nominal_frame_rate; 98818781e08Smrg d = target_time - now; 98918781e08Smrg } 99018781e08Smrg } 99118781e08Smrg /* 99218781e08Smrg * convert delay to milliseconds and add margin to prevent the client 99318781e08Smrg * from coming back early (due to timer granularity and rounding 99418781e08Smrg * errors) and getting the same MSC it just got 99518781e08Smrg */ 99618781e08Smrg d_ms = (CARD32)d / 1000; 99718781e08Smrg if ((CARD32)d - d_ms * 1000 > 0) 99818781e08Smrg d_ms += 2; 99918781e08Smrg else 100018781e08Smrg d_ms++; 100118781e08Smrg return d_ms; 100218781e08Smrg} 100318781e08Smrg 100418781e08Smrg/* 100518781e08Smrg * Get current interpolated frame count and frame count timestamp, based on 100618781e08Smrg * drawable's crtc. 100718781e08Smrg */ 100818781e08Smrgstatic int radeon_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc) 100918781e08Smrg{ 101018781e08Smrg xf86CrtcPtr crtc = radeon_dri2_drawable_crtc(draw, TRUE); 1011de2362d3Smrg 1012de2362d3Smrg /* Drawable not displayed, make up a value */ 101318781e08Smrg if (crtc == NULL) { 1014de2362d3Smrg *ust = 0; 1015de2362d3Smrg *msc = 0; 1016de2362d3Smrg return TRUE; 1017de2362d3Smrg } 1018de2362d3Smrg 101918781e08Smrg if (!radeon_dri2_get_crtc_msc(crtc, ust, msc)) 102018781e08Smrg return FALSE; 102118781e08Smrg 102218781e08Smrg if (draw && draw->type == DRAWABLE_WINDOW) 102318781e08Smrg *msc += get_dri2_window_priv((WindowPtr)draw)->vblank_delta; 102418781e08Smrg *msc &= 0xffffffff; 102518781e08Smrg return TRUE; 102618781e08Smrg} 102718781e08Smrg 102818781e08Smrgstatic 102918781e08SmrgCARD32 radeon_dri2_deferred_event(OsTimerPtr timer, CARD32 now, pointer data) 103018781e08Smrg{ 103118781e08Smrg DRI2FrameEventPtr event_info = (DRI2FrameEventPtr)data; 103218781e08Smrg xf86CrtcPtr crtc = event_info->crtc; 103318781e08Smrg ScrnInfoPtr scrn; 103418781e08Smrg RADEONInfoPtr info; 103518781e08Smrg CARD64 drm_now; 103618781e08Smrg int ret; 103718781e08Smrg CARD64 delta_t, delta_seq, frame; 103818781e08Smrg drmmode_crtc_private_ptr drmmode_crtc; 103918781e08Smrg 104018781e08Smrg /* 104118781e08Smrg * This is emulated event, so its time is current time, which we 104218781e08Smrg * have to get in DRM-compatible form (which is a bit messy given 104318781e08Smrg * the information that we have at this point). Can't use now argument 104418781e08Smrg * because DRM event time may come from monotonic clock, while 104518781e08Smrg * DIX timer facility uses real-time clock. 104618781e08Smrg */ 104718781e08Smrg if (!event_info->crtc) { 104818781e08Smrg ErrorF("%s no crtc\n", __func__); 104918781e08Smrg if (event_info->drm_queue_seq) 105018781e08Smrg radeon_drm_abort_entry(event_info->drm_queue_seq); 105118781e08Smrg else 105218781e08Smrg radeon_dri2_frame_event_abort(NULL, data); 105318781e08Smrg return 0; 1054de2362d3Smrg } 1055de2362d3Smrg 105618781e08Smrg scrn = crtc->scrn; 105718781e08Smrg info = RADEONPTR(scrn); 105818781e08Smrg ret = drmmode_get_current_ust(info->dri2.drm_fd, &drm_now); 105918781e08Smrg if (ret) { 106018781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 106118781e08Smrg "%s cannot get current time\n", __func__); 106218781e08Smrg if (event_info->drm_queue_seq) 106318781e08Smrg radeon_drm_queue_handler(info->dri2.drm_fd, 0, 0, 0, 106418781e08Smrg (void*)event_info->drm_queue_seq); 106518781e08Smrg else 106618781e08Smrg radeon_dri2_frame_event_handler(crtc, 0, 0, data); 106718781e08Smrg return 0; 106818781e08Smrg } 106918781e08Smrg /* 107018781e08Smrg * calculate the frame number from current time 107118781e08Smrg * that would come from CRTC if it were running 107218781e08Smrg */ 107318781e08Smrg drmmode_crtc = event_info->crtc->driver_private; 107418781e08Smrg delta_t = drm_now - (CARD64)drmmode_crtc->dpms_last_ust; 107518781e08Smrg delta_seq = delta_t * drmmode_crtc->dpms_last_fps; 107618781e08Smrg delta_seq /= 1000000; 107718781e08Smrg frame = (CARD64)drmmode_crtc->dpms_last_seq + delta_seq; 107818781e08Smrg if (event_info->drm_queue_seq) 107918781e08Smrg radeon_drm_queue_handler(info->dri2.drm_fd, frame, drm_now / 1000000, 108018781e08Smrg drm_now % 1000000, 108118781e08Smrg (void*)event_info->drm_queue_seq); 108218781e08Smrg else 108318781e08Smrg radeon_dri2_frame_event_handler(crtc, frame, drm_now, data); 108418781e08Smrg return 0; 108518781e08Smrg} 10867821949aSmrg 108718781e08Smrgstatic 108818781e08Smrgvoid radeon_dri2_schedule_event(CARD32 delay, DRI2FrameEventPtr event_info) 108918781e08Smrg{ 109018781e08Smrg event_info->timer = TimerSet(NULL, 0, delay, radeon_dri2_deferred_event, 109118781e08Smrg event_info); 109218781e08Smrg if (delay == 0) { 109318781e08Smrg CARD32 now = GetTimeInMillis(); 109418781e08Smrg radeon_dri2_deferred_event(event_info->timer, now, event_info); 109518781e08Smrg } 1096de2362d3Smrg} 1097de2362d3Smrg 1098de2362d3Smrg/* 1099de2362d3Smrg * Request a DRM event when the requested conditions will be satisfied. 1100de2362d3Smrg * 1101de2362d3Smrg * We need to handle the event and ask the server to wake up the client when 1102de2362d3Smrg * we receive it. 1103de2362d3Smrg */ 1104de2362d3Smrgstatic int radeon_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, 1105de2362d3Smrg CARD64 target_msc, CARD64 divisor, 1106de2362d3Smrg CARD64 remainder) 1107de2362d3Smrg{ 1108de2362d3Smrg ScreenPtr screen = draw->pScreen; 1109de2362d3Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 1110de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 1111de2362d3Smrg DRI2FrameEventPtr wait_info = NULL; 111218781e08Smrg uintptr_t drm_queue_seq = 0; 111318781e08Smrg xf86CrtcPtr crtc = radeon_dri2_drawable_crtc(draw, TRUE); 111418781e08Smrg uint32_t msc_delta; 1115de2362d3Smrg drmVBlank vbl; 111618781e08Smrg int ret; 1117de2362d3Smrg CARD64 current_msc; 1118de2362d3Smrg 1119de2362d3Smrg /* Truncate to match kernel interfaces; means occasional overflow 1120de2362d3Smrg * misses, but that's generally not a big deal */ 1121de2362d3Smrg target_msc &= 0xffffffff; 1122de2362d3Smrg divisor &= 0xffffffff; 1123de2362d3Smrg remainder &= 0xffffffff; 1124de2362d3Smrg 1125de2362d3Smrg /* Drawable not visible, return immediately */ 112618781e08Smrg if (crtc == NULL) 1127de2362d3Smrg goto out_complete; 1128de2362d3Smrg 112918781e08Smrg msc_delta = radeon_get_msc_delta(draw, crtc); 113018781e08Smrg 1131de2362d3Smrg wait_info = calloc(1, sizeof(DRI2FrameEventRec)); 1132de2362d3Smrg if (!wait_info) 1133de2362d3Smrg goto out_complete; 1134de2362d3Smrg 1135de2362d3Smrg wait_info->drawable_id = draw->id; 1136de2362d3Smrg wait_info->client = client; 1137de2362d3Smrg wait_info->type = DRI2_WAITMSC; 113818781e08Smrg wait_info->crtc = crtc; 1139de2362d3Smrg 114018781e08Smrg /* 114118781e08Smrg * CRTC is in DPMS off state, calculate wait time from current time, 114218781e08Smrg * target_msc and last vblank time/sequence when CRTC was turned off 114318781e08Smrg */ 114418781e08Smrg if (!radeon_crtc_is_enabled(crtc)) { 114518781e08Smrg CARD32 delay; 114618781e08Smrg target_msc -= msc_delta; 114718781e08Smrg delay = radeon_dri2_extrapolate_msc_delay(crtc, &target_msc, 114818781e08Smrg divisor, remainder); 114918781e08Smrg radeon_dri2_schedule_event(delay, wait_info); 115018781e08Smrg DRI2BlockClient(client, draw); 115118781e08Smrg return TRUE; 1152de2362d3Smrg } 1153de2362d3Smrg 1154de2362d3Smrg /* Get current count */ 1155de2362d3Smrg vbl.request.type = DRM_VBLANK_RELATIVE; 115618781e08Smrg vbl.request.type |= radeon_populate_vbl_request_type(crtc); 1157de2362d3Smrg vbl.request.sequence = 0; 1158de2362d3Smrg ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); 1159de2362d3Smrg if (ret) { 1160de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1161de2362d3Smrg "get vblank counter failed: %s\n", strerror(errno)); 1162de2362d3Smrg goto out_complete; 1163de2362d3Smrg } 1164de2362d3Smrg 116518781e08Smrg current_msc = vbl.reply.sequence + msc_delta; 116618781e08Smrg current_msc &= 0xffffffff; 116718781e08Smrg 116818781e08Smrg drm_queue_seq = radeon_drm_queue_alloc(crtc, client, RADEON_DRM_QUEUE_ID_DEFAULT, 116918781e08Smrg wait_info, radeon_dri2_frame_event_handler, 117018781e08Smrg radeon_dri2_frame_event_abort); 117118781e08Smrg if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) { 117218781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 117318781e08Smrg "Allocating DRM queue event entry failed.\n"); 117418781e08Smrg goto out_complete; 117518781e08Smrg } 117618781e08Smrg wait_info->drm_queue_seq = drm_queue_seq; 11770d16fef4Smrg 1178de2362d3Smrg /* 1179de2362d3Smrg * If divisor is zero, or current_msc is smaller than target_msc, 1180de2362d3Smrg * we just need to make sure target_msc passes before waking up the 1181de2362d3Smrg * client. 1182de2362d3Smrg */ 1183de2362d3Smrg if (divisor == 0 || current_msc < target_msc) { 1184de2362d3Smrg /* If target_msc already reached or passed, set it to 1185de2362d3Smrg * current_msc to ensure we return a reasonable value back 1186de2362d3Smrg * to the caller. This keeps the client from continually 1187de2362d3Smrg * sending us MSC targets from the past by forcibly updating 1188de2362d3Smrg * their count on this call. 1189de2362d3Smrg */ 1190de2362d3Smrg if (current_msc >= target_msc) 1191de2362d3Smrg target_msc = current_msc; 1192de2362d3Smrg vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; 119318781e08Smrg vbl.request.type |= radeon_populate_vbl_request_type(crtc); 119418781e08Smrg vbl.request.sequence = target_msc - msc_delta; 119518781e08Smrg vbl.request.signal = drm_queue_seq; 1196de2362d3Smrg ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); 1197de2362d3Smrg if (ret) { 1198de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1199de2362d3Smrg "get vblank counter failed: %s\n", strerror(errno)); 1200de2362d3Smrg goto out_complete; 1201de2362d3Smrg } 1202de2362d3Smrg 1203de2362d3Smrg DRI2BlockClient(client, draw); 1204de2362d3Smrg return TRUE; 1205de2362d3Smrg } 1206de2362d3Smrg 1207de2362d3Smrg /* 1208de2362d3Smrg * If we get here, target_msc has already passed or we don't have one, 1209de2362d3Smrg * so we queue an event that will satisfy the divisor/remainder equation. 1210de2362d3Smrg */ 1211de2362d3Smrg vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; 121218781e08Smrg vbl.request.type |= radeon_populate_vbl_request_type(crtc); 1213de2362d3Smrg 1214de2362d3Smrg vbl.request.sequence = current_msc - (current_msc % divisor) + 121518781e08Smrg remainder - msc_delta; 1216de2362d3Smrg 1217de2362d3Smrg /* 1218de2362d3Smrg * If calculated remainder is larger than requested remainder, 1219de2362d3Smrg * it means we've passed the last point where 1220de2362d3Smrg * seq % divisor == remainder, so we need to wait for the next time 1221de2362d3Smrg * that will happen. 1222de2362d3Smrg */ 1223de2362d3Smrg if ((current_msc % divisor) >= remainder) 1224de2362d3Smrg vbl.request.sequence += divisor; 1225de2362d3Smrg 122618781e08Smrg vbl.request.signal = drm_queue_seq; 1227de2362d3Smrg ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); 1228de2362d3Smrg if (ret) { 1229de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1230de2362d3Smrg "get vblank counter failed: %s\n", strerror(errno)); 1231de2362d3Smrg goto out_complete; 1232de2362d3Smrg } 1233de2362d3Smrg 1234de2362d3Smrg DRI2BlockClient(client, draw); 1235de2362d3Smrg 1236de2362d3Smrg return TRUE; 1237de2362d3Smrg 1238de2362d3Smrgout_complete: 123918781e08Smrg if (wait_info) 124018781e08Smrg radeon_dri2_deferred_event(NULL, 0, wait_info); 1241de2362d3Smrg return TRUE; 1242de2362d3Smrg} 1243de2362d3Smrg 1244de2362d3Smrg/* 1245de2362d3Smrg * ScheduleSwap is responsible for requesting a DRM vblank event for the 1246de2362d3Smrg * appropriate frame. 1247de2362d3Smrg * 1248de2362d3Smrg * In the case of a blit (e.g. for a windowed swap) or buffer exchange, 1249de2362d3Smrg * the vblank requested can simply be the last queued swap frame + the swap 1250de2362d3Smrg * interval for the drawable. 1251de2362d3Smrg * 1252de2362d3Smrg * In the case of a page flip, we request an event for the last queued swap 1253de2362d3Smrg * frame + swap interval - 1, since we'll need to queue the flip for the frame 1254de2362d3Smrg * immediately following the received event. 1255de2362d3Smrg * 1256de2362d3Smrg * The client will be blocked if it tries to perform further GL commands 1257de2362d3Smrg * after queueing a swap, though in the Intel case after queueing a flip, the 1258de2362d3Smrg * client is free to queue more commands; they'll block in the kernel if 1259de2362d3Smrg * they access buffers busy with the flip. 1260de2362d3Smrg * 1261de2362d3Smrg * When the swap is complete, the driver should call into the server so it 1262de2362d3Smrg * can send any swap complete events that have been requested. 1263de2362d3Smrg */ 1264de2362d3Smrgstatic int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, 1265de2362d3Smrg DRI2BufferPtr front, DRI2BufferPtr back, 1266de2362d3Smrg CARD64 *target_msc, CARD64 divisor, 1267de2362d3Smrg CARD64 remainder, DRI2SwapEventPtr func, 1268de2362d3Smrg void *data) 1269de2362d3Smrg{ 1270de2362d3Smrg ScreenPtr screen = draw->pScreen; 1271de2362d3Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 1272de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 127318781e08Smrg xf86CrtcPtr crtc = radeon_dri2_drawable_crtc(draw, TRUE); 127418781e08Smrg uint32_t msc_delta; 1275de2362d3Smrg drmVBlank vbl; 127618781e08Smrg int ret, flip = 0; 1277de2362d3Smrg DRI2FrameEventPtr swap_info = NULL; 127818781e08Smrg uintptr_t drm_queue_seq; 1279de2362d3Smrg CARD64 current_msc; 1280de2362d3Smrg BoxRec box; 1281de2362d3Smrg RegionRec region; 1282de2362d3Smrg 1283de2362d3Smrg /* Truncate to match kernel interfaces; means occasional overflow 1284de2362d3Smrg * misses, but that's generally not a big deal */ 1285de2362d3Smrg *target_msc &= 0xffffffff; 1286de2362d3Smrg divisor &= 0xffffffff; 1287de2362d3Smrg remainder &= 0xffffffff; 1288de2362d3Smrg 1289de2362d3Smrg /* radeon_dri2_frame_event_handler will get called some unknown time in the 1290de2362d3Smrg * future with these buffers. Take a reference to ensure that they won't 1291de2362d3Smrg * get destroyed before then. 1292de2362d3Smrg */ 1293de2362d3Smrg radeon_dri2_ref_buffer(front); 1294de2362d3Smrg radeon_dri2_ref_buffer(back); 1295de2362d3Smrg 129618781e08Smrg /* either off-screen or CRTC not usable... just complete the swap */ 129718781e08Smrg if (crtc == NULL) 1298de2362d3Smrg goto blit_fallback; 1299de2362d3Smrg 130018781e08Smrg msc_delta = radeon_get_msc_delta(draw, crtc); 130118781e08Smrg 1302de2362d3Smrg swap_info = calloc(1, sizeof(DRI2FrameEventRec)); 1303de2362d3Smrg if (!swap_info) 1304de2362d3Smrg goto blit_fallback; 1305de2362d3Smrg 130618781e08Smrg swap_info->type = DRI2_SWAP; 1307de2362d3Smrg swap_info->drawable_id = draw->id; 1308de2362d3Smrg swap_info->client = client; 1309de2362d3Smrg swap_info->event_complete = func; 1310de2362d3Smrg swap_info->event_data = data; 1311de2362d3Smrg swap_info->front = front; 1312de2362d3Smrg swap_info->back = back; 131318781e08Smrg swap_info->crtc = crtc; 131418781e08Smrg 131518781e08Smrg drm_queue_seq = radeon_drm_queue_alloc(crtc, client, RADEON_DRM_QUEUE_ID_DEFAULT, 131618781e08Smrg swap_info, radeon_dri2_frame_event_handler, 131718781e08Smrg radeon_dri2_frame_event_abort); 131818781e08Smrg if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) { 1319de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 132018781e08Smrg "Allocating DRM queue entry failed.\n"); 1321de2362d3Smrg goto blit_fallback; 1322de2362d3Smrg } 132318781e08Smrg swap_info->drm_queue_seq = drm_queue_seq; 132418781e08Smrg 132518781e08Smrg /* 132618781e08Smrg * CRTC is in DPMS off state, fallback to blit, but calculate 132718781e08Smrg * wait time from current time, target_msc and last vblank 132818781e08Smrg * time/sequence when CRTC was turned off 132918781e08Smrg */ 133018781e08Smrg if (!radeon_crtc_is_enabled(crtc)) { 133118781e08Smrg CARD32 delay; 133218781e08Smrg *target_msc -= msc_delta; 133318781e08Smrg delay = radeon_dri2_extrapolate_msc_delay(crtc, target_msc, 133418781e08Smrg divisor, remainder); 133518781e08Smrg *target_msc += msc_delta; 133618781e08Smrg *target_msc &= 0xffffffff; 133718781e08Smrg radeon_dri2_schedule_event(delay, swap_info); 133818781e08Smrg return TRUE; 133918781e08Smrg } 1340de2362d3Smrg 1341de2362d3Smrg /* Get current count */ 1342de2362d3Smrg vbl.request.type = DRM_VBLANK_RELATIVE; 134318781e08Smrg vbl.request.type |= radeon_populate_vbl_request_type(crtc); 1344de2362d3Smrg vbl.request.sequence = 0; 1345de2362d3Smrg ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); 1346de2362d3Smrg if (ret) { 1347de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1348de2362d3Smrg "first get vblank counter failed: %s\n", 1349de2362d3Smrg strerror(errno)); 135018781e08Smrg goto blit_fallback; 1351de2362d3Smrg } 1352de2362d3Smrg 135318781e08Smrg current_msc = vbl.reply.sequence + msc_delta; 135418781e08Smrg current_msc &= 0xffffffff; 1355de2362d3Smrg 1356de2362d3Smrg /* Flips need to be submitted one frame before */ 1357de2362d3Smrg if (can_flip(scrn, draw, front, back)) { 135818781e08Smrg swap_info->type = DRI2_FLIP; 1359de2362d3Smrg flip = 1; 1360de2362d3Smrg } 1361de2362d3Smrg 136218781e08Smrg /* Correct target_msc by 'flip' if swap_info->type == DRI2_FLIP. 1363de2362d3Smrg * Do it early, so handling of different timing constraints 1364de2362d3Smrg * for divisor, remainder and msc vs. target_msc works. 1365de2362d3Smrg */ 1366de2362d3Smrg if (*target_msc > 0) 1367de2362d3Smrg *target_msc -= flip; 1368de2362d3Smrg 1369de2362d3Smrg /* 1370de2362d3Smrg * If divisor is zero, or current_msc is smaller than target_msc 1371de2362d3Smrg * we just need to make sure target_msc passes before initiating 1372de2362d3Smrg * the swap. 1373de2362d3Smrg */ 1374de2362d3Smrg if (divisor == 0 || current_msc < *target_msc) { 1375de2362d3Smrg vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; 1376de2362d3Smrg /* If non-pageflipping, but blitting/exchanging, we need to use 1377de2362d3Smrg * DRM_VBLANK_NEXTONMISS to avoid unreliable timestamping later 1378de2362d3Smrg * on. 1379de2362d3Smrg */ 1380de2362d3Smrg if (flip == 0) 1381de2362d3Smrg vbl.request.type |= DRM_VBLANK_NEXTONMISS; 138218781e08Smrg vbl.request.type |= radeon_populate_vbl_request_type(crtc); 1383de2362d3Smrg 1384de2362d3Smrg /* If target_msc already reached or passed, set it to 1385de2362d3Smrg * current_msc to ensure we return a reasonable value back 1386de2362d3Smrg * to the caller. This makes swap_interval logic more robust. 1387de2362d3Smrg */ 1388de2362d3Smrg if (current_msc >= *target_msc) 1389de2362d3Smrg *target_msc = current_msc; 1390de2362d3Smrg 139118781e08Smrg vbl.request.sequence = *target_msc - msc_delta; 139218781e08Smrg vbl.request.signal = drm_queue_seq; 1393de2362d3Smrg ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); 1394de2362d3Smrg if (ret) { 1395de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1396de2362d3Smrg "divisor 0 get vblank counter failed: %s\n", 1397de2362d3Smrg strerror(errno)); 139818781e08Smrg goto blit_fallback; 1399de2362d3Smrg } 1400de2362d3Smrg 140118781e08Smrg *target_msc = vbl.reply.sequence + flip + msc_delta; 1402de2362d3Smrg swap_info->frame = *target_msc; 1403de2362d3Smrg 1404de2362d3Smrg return TRUE; 1405de2362d3Smrg } 1406de2362d3Smrg 1407de2362d3Smrg /* 1408de2362d3Smrg * If we get here, target_msc has already passed or we don't have one, 1409de2362d3Smrg * and we need to queue an event that will satisfy the divisor/remainder 1410de2362d3Smrg * equation. 1411de2362d3Smrg */ 1412de2362d3Smrg vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; 1413de2362d3Smrg if (flip == 0) 1414de2362d3Smrg vbl.request.type |= DRM_VBLANK_NEXTONMISS; 141518781e08Smrg vbl.request.type |= radeon_populate_vbl_request_type(crtc); 1416de2362d3Smrg 1417de2362d3Smrg vbl.request.sequence = current_msc - (current_msc % divisor) + 141818781e08Smrg remainder - msc_delta; 1419de2362d3Smrg 1420de2362d3Smrg /* 1421de2362d3Smrg * If the calculated deadline vbl.request.sequence is smaller than 1422de2362d3Smrg * or equal to current_msc, it means we've passed the last point 1423de2362d3Smrg * when effective onset frame seq could satisfy 1424de2362d3Smrg * seq % divisor == remainder, so we need to wait for the next time 1425de2362d3Smrg * this will happen. 1426de2362d3Smrg 1427de2362d3Smrg * This comparison takes the 1 frame swap delay in pageflipping mode 1428de2362d3Smrg * into account, as well as a potential DRM_VBLANK_NEXTONMISS delay 1429de2362d3Smrg * if we are blitting/exchanging instead of flipping. 1430de2362d3Smrg */ 1431de2362d3Smrg if (vbl.request.sequence <= current_msc) 1432de2362d3Smrg vbl.request.sequence += divisor; 1433de2362d3Smrg 1434de2362d3Smrg /* Account for 1 frame extra pageflip delay if flip > 0 */ 1435de2362d3Smrg vbl.request.sequence -= flip; 1436de2362d3Smrg 143718781e08Smrg vbl.request.signal = drm_queue_seq; 1438de2362d3Smrg ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); 1439de2362d3Smrg if (ret) { 1440de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1441de2362d3Smrg "final get vblank counter failed: %s\n", 1442de2362d3Smrg strerror(errno)); 144318781e08Smrg goto blit_fallback; 1444de2362d3Smrg } 1445de2362d3Smrg 1446de2362d3Smrg /* Adjust returned value for 1 fame pageflip offset of flip > 0 */ 144718781e08Smrg *target_msc = vbl.reply.sequence + flip + msc_delta; 144818781e08Smrg *target_msc &= 0xffffffff; 1449de2362d3Smrg swap_info->frame = *target_msc; 1450de2362d3Smrg 1451de2362d3Smrg return TRUE; 1452de2362d3Smrg 1453de2362d3Smrgblit_fallback: 145418781e08Smrg if (swap_info) { 145518781e08Smrg swap_info->type = DRI2_SWAP; 145618781e08Smrg radeon_dri2_schedule_event(FALLBACK_SWAP_DELAY, swap_info); 145718781e08Smrg } else { 145818781e08Smrg box.x1 = 0; 145918781e08Smrg box.y1 = 0; 146018781e08Smrg box.x2 = draw->width; 146118781e08Smrg box.y2 = draw->height; 146218781e08Smrg REGION_INIT(pScreen, ®ion, &box, 0); 1463de2362d3Smrg 146418781e08Smrg radeon_dri2_copy_region(draw, ®ion, front, back); 1465de2362d3Smrg 146618781e08Smrg DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data); 1467de2362d3Smrg 146818781e08Smrg radeon_dri2_unref_buffer(front); 146918781e08Smrg radeon_dri2_unref_buffer(back); 147018781e08Smrg } 14717821949aSmrg 1472de2362d3Smrg *target_msc = 0; /* offscreen, so zero out target vblank count */ 1473de2362d3Smrg return TRUE; 1474de2362d3Smrg} 1475de2362d3Smrg 1476de2362d3Smrg 1477de2362d3SmrgBool 1478de2362d3Smrgradeon_dri2_screen_init(ScreenPtr pScreen) 1479de2362d3Smrg{ 1480de2362d3Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1481de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1482de2362d3Smrg DRI2InfoRec dri2_info = { 0 }; 1483de2362d3Smrg const char *driverNames[2]; 1484de2362d3Smrg Bool scheduling_works = TRUE; 1485de2362d3Smrg 148618781e08Smrg if (!info->dri2.available) 1487de2362d3Smrg return FALSE; 1488de2362d3Smrg 1489de2362d3Smrg info->dri2.device_name = drmGetDeviceNameFromFd(info->dri2.drm_fd); 1490de2362d3Smrg 149118781e08Smrg if ( (info->ChipFamily >= CHIP_FAMILY_TAHITI) ) { 149218781e08Smrg dri2_info.driverName = SI_DRIVER_NAME; 149318781e08Smrg } else if ( (info->ChipFamily >= CHIP_FAMILY_R600) ) { 1494de2362d3Smrg dri2_info.driverName = R600_DRIVER_NAME; 1495de2362d3Smrg } else if ( (info->ChipFamily >= CHIP_FAMILY_R300) ) { 1496de2362d3Smrg dri2_info.driverName = R300_DRIVER_NAME; 1497de2362d3Smrg } else if ( info->ChipFamily >= CHIP_FAMILY_R200 ) { 1498de2362d3Smrg dri2_info.driverName = R200_DRIVER_NAME; 1499de2362d3Smrg } else { 1500de2362d3Smrg dri2_info.driverName = RADEON_DRIVER_NAME; 1501de2362d3Smrg } 1502de2362d3Smrg dri2_info.fd = info->dri2.drm_fd; 1503de2362d3Smrg dri2_info.deviceName = info->dri2.device_name; 1504de2362d3Smrg dri2_info.version = DRI2INFOREC_VERSION; 1505de2362d3Smrg dri2_info.CreateBuffer = radeon_dri2_create_buffer; 1506de2362d3Smrg dri2_info.DestroyBuffer = radeon_dri2_destroy_buffer; 1507de2362d3Smrg dri2_info.CopyRegion = radeon_dri2_copy_region; 1508de2362d3Smrg 150918781e08Smrg if (info->dri2.pKernelDRMVersion->version_minor < 4) { 1510de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "You need a newer kernel for " 1511de2362d3Smrg "sync extension\n"); 1512de2362d3Smrg scheduling_works = FALSE; 1513de2362d3Smrg } 1514de2362d3Smrg 151518781e08Smrg if (scheduling_works && info->drmmode.count_crtcs > 2) { 1516de2362d3Smrg#ifdef DRM_CAP_VBLANK_HIGH_CRTC 1517de2362d3Smrg uint64_t cap_value; 1518de2362d3Smrg 1519de2362d3Smrg if (drmGetCap(info->dri2.drm_fd, DRM_CAP_VBLANK_HIGH_CRTC, &cap_value)) { 1520de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "You need a newer kernel " 1521de2362d3Smrg "for VBLANKs on CRTC > 1\n"); 1522de2362d3Smrg scheduling_works = FALSE; 1523de2362d3Smrg } else if (!cap_value) { 1524de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Your kernel does not " 1525de2362d3Smrg "handle VBLANKs on CRTC > 1\n"); 1526de2362d3Smrg scheduling_works = FALSE; 1527de2362d3Smrg } 1528de2362d3Smrg#else 1529de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "You need to rebuild against a " 1530de2362d3Smrg "newer libdrm to handle VBLANKs on CRTC > 1\n"); 1531de2362d3Smrg scheduling_works = FALSE; 1532de2362d3Smrg#endif 1533de2362d3Smrg } 1534de2362d3Smrg 1535de2362d3Smrg if (scheduling_works) { 1536de2362d3Smrg dri2_info.version = 4; 1537de2362d3Smrg dri2_info.ScheduleSwap = radeon_dri2_schedule_swap; 1538de2362d3Smrg dri2_info.GetMSC = radeon_dri2_get_msc; 1539de2362d3Smrg dri2_info.ScheduleWaitMSC = radeon_dri2_schedule_wait_msc; 1540de2362d3Smrg dri2_info.numDrivers = RADEON_ARRAY_SIZE(driverNames); 1541de2362d3Smrg dri2_info.driverNames = driverNames; 154218781e08Smrg driverNames[0] = dri2_info.driverName; 154318781e08Smrg 154418781e08Smrg if (info->ChipFamily >= CHIP_FAMILY_R300) 154518781e08Smrg driverNames[1] = driverNames[0]; 154618781e08Smrg else 154718781e08Smrg driverNames[1] = NULL; /* no VDPAU support */ 154818781e08Smrg 154918781e08Smrg if (DRI2InfoCnt == 0) { 155018781e08Smrg if (!dixRegisterPrivateKey(dri2_window_private_key, 155118781e08Smrg PRIVATE_WINDOW, 155218781e08Smrg sizeof(struct dri2_window_priv))) { 155318781e08Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 155418781e08Smrg "Failed to get DRI2 window private\n"); 1555de2362d3Smrg return FALSE; 1556de2362d3Smrg } 1557de2362d3Smrg 1558de2362d3Smrg AddCallback(&ClientStateCallback, radeon_dri2_client_state_changed, 0); 1559de2362d3Smrg } 1560de2362d3Smrg 156118781e08Smrg DRI2InfoCnt++; 1562de2362d3Smrg } 156318781e08Smrg 156418781e08Smrg#if DRI2INFOREC_VERSION >= 9 156518781e08Smrg dri2_info.version = 9; 156618781e08Smrg dri2_info.CreateBuffer2 = radeon_dri2_create_buffer2; 156718781e08Smrg dri2_info.DestroyBuffer2 = radeon_dri2_destroy_buffer2; 156818781e08Smrg dri2_info.CopyRegion2 = radeon_dri2_copy_region2; 1569de2362d3Smrg#endif 1570de2362d3Smrg 1571de2362d3Smrg info->dri2.enabled = DRI2ScreenInit(pScreen, &dri2_info); 1572de2362d3Smrg return info->dri2.enabled; 1573de2362d3Smrg} 1574de2362d3Smrg 1575de2362d3Smrgvoid radeon_dri2_close_screen(ScreenPtr pScreen) 1576de2362d3Smrg{ 1577de2362d3Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1578de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1579de2362d3Smrg 158018781e08Smrg if (--DRI2InfoCnt == 0) 1581de2362d3Smrg DeleteCallback(&ClientStateCallback, radeon_dri2_client_state_changed, 0); 158218781e08Smrg 1583de2362d3Smrg DRI2CloseScreen(pScreen); 1584de2362d3Smrg drmFree(info->dri2.device_name); 1585de2362d3Smrg} 1586de2362d3Smrg 158718781e08Smrg#endif /* DRI2 */ 158818781e08Smrg 1589